2026-03-10 17:13:23 +01:00
2026-03-10 17:13:23 +01:00
2026-03-10 17:13:23 +01:00
2026-03-10 17:13:23 +01:00
2026-03-09 16:45:29 +01:00
2026-03-10 17:13:23 +01:00
2026-03-10 17:13:23 +01:00
2026-03-10 17:13:23 +01:00
2026-03-10 17:13:23 +01:00
2026-03-10 17:13:23 +01:00
2026-03-10 17:13:23 +01:00

Campaign Manager

Campaign Manager is split into two Rust backend services, a SvelteKit web app, and a TaleSpire Symbiote frontend.

Architecture

  • backend/common: shared Rust crate for JWT and API error primitives.
  • backend/campaign-service: auth + campaign domain service.
  • backend/content-service: ruleset/content domain service.
  • web: SvelteKit Node server that uses server-side BFF proxy routes (/api/*).
  • symbiote: static Svelte app for TaleSpire.

Data layout

All databases run on one Postgres instance with separate logical databases:

  • cm_users: users/auth/session data.
  • cm_campaign: campaign and character data.
  • cm_content: rulesets/content data.

Environment

Copy .env.example to .env and set values.

Important variables:

  • USERS_DATABASE_URL
  • CAMPAIGN_DATABASE_URL
  • CONTENT_DATABASE_URL
  • JWT_SECRET
  • CAMPAIGN_API_BASE / CONTENT_API_BASE (web BFF upstreams)
  • VITE_CAMPAIGN_API_BASE / VITE_CONTENT_API_BASE (symbiote build-time)

Local development

# Install JS dependencies
pnpm install

# Run campaign service
pnpm dev:campaign

# Run content service
pnpm dev:content

# Run web app (SvelteKit dev server)
pnpm dev:web

# Run symbiote app
pnpm dev:symbiote

Build commands:

pnpm build:campaign
pnpm build:content
pnpm build:backend
pnpm build:web
pnpm build:symbiote

Run the same checks as CI locally:

pnpm ci:local

Web BFF routes

The web app proxies backend calls via SvelteKit server routes:

  • /api/auth/* -> campaign service (CAMPAIGN_API_BASE)
  • /api/campaign/* -> campaign service (CAMPAIGN_API_BASE)
  • /api/content/* -> content service (CONTENT_API_BASE)

The web app is intended to run as a server process (Node adapter) in production.

Docker compose

docker-compose.yml runs both backend services plus the web server and expects an external dev-infra network for Postgres connectivity.

Woodpecker without Public Ingress

If your Gitea is remote and your Woodpecker server runs locally, push/PR webhooks cannot reach your machine without a public endpoint.

Recommended workflow until ingress/tunnel exists:

  • Run pnpm ci:local before push.
  • Use local Woodpecker only for manual runs.

Local stack files are in ../../infra/woodpecker from this directory:

cp ../../infra/woodpecker/.env.example ../../infra/woodpecker/.env
docker compose -f ../../infra/woodpecker/docker-compose.yml up -d
Description
No description provided
Readme 232 KiB
Languages
TypeScript 52.6%
Rust 28.9%
Svelte 11.4%
Dockerfile 3.6%
HTML 2.1%
Other 1.4%