Skip to content

Getting started#

This section takes you from a fresh checkout to a running Ticket Board with seeded data. Three pages:

  1. This page — the quickstart and what the running stack looks like.
  2. First-run walkthrough — log in, create a project, open a ticket, write a wiki page.
  3. Seed data — what make seed-dev actually creates and how to reset it.

Prerequisites#

You'll need:

  • A host with Docker (24+) and Docker Compose v2.
  • The repo checked out: git clone https://github.com/Sosoka-Labs/ticket-board.git.
  • A free pair of ports — the stack binds host ports 80 and 443 by default. If those are in use, override with HTTP_PORT and HTTPS_PORT in .env.

You do not need Python or Node installed to bring the stack up. Everything runs inside containers. Local Python and Node are only needed if you plan to hack on the backend or frontend code directly — see the backend dev workflow and the frontend dev workflow.

Quickstart#

Plan on a few minutes the first time — most of that is editing .env and waiting for migrations to run. From the repo root on a host with Docker:

# 1. Configure secrets
cp .env.example .env
# edit .env — at minimum set POSTGRES_PASSWORD and SECRET_KEY.
# For local dev on plain HTTP, leave COOKIE_SECURE=false.

# 2. Bring up the stack
docker compose up -d

# 3. Watch migrations and the backend healthcheck pass
docker compose ps
docker compose logs -f backend

The Compose stack runs four services in dependency order: postgresmigrate (one-shot Alembic) → backendfrontendproxy (Caddy). When backend reports healthy, the stack is ready.

Once it is up:

Single origin is intentional

Caddy fronts both the UI and the API on a single host. This is required for the SameSite=Lax session cookie to work — the browser must see the API and the UI as same-origin. Don't expose the backend on a separate hostname or port; the auth flow will silently break.

Generate SECRET_KEY and POSTGRES_PASSWORD#

The two values that matter in .env before first boot:

# Both produce a high-entropy random string.
python3 -c "import secrets; print(secrets.token_urlsafe(32))"   # POSTGRES_PASSWORD
python3 -c "import secrets; print(secrets.token_hex(32))"       # SECRET_KEY

The backend refuses to start if ENV=prod and COOKIE_SECURE=false, so a dev compose run on plain HTTP must keep ENV=dev. See Environment variables for the full list.

Seed a realistic dataset#

The empty stack is not very interesting. The seed script populates one workspace, one human user, two bots, two projects, ~31 tickets, five wiki pages, and four sticky notes. It is idempotent — re-running it on a populated database is a no-op.

make seed-dev

The script prints the bot tokens at the end. Capture them; they are shown once.

Seeded credentials (dev only — never reuse on a public deploy):

Actor Username Credential
Human admin password: changeme-please
Bot — research (write, both projects) bot-research token: tkb_devresearchtoken0000000000000001
Bot — reporting (read, INFRA only) bot-reporting token: tkb_devreportingtoken000000000000001

Once you're logged in, change the seeded human password under Settings → Security (/settings/security). For a full description of what gets seeded — including the deliberate broken wiki link — see Seed data.

What the working stack looks like#

After docker compose up -d and make seed-dev:

  • A login page at http://localhost/login. Sign in as admin / changeme-please.
  • A dashboard showing the two seeded projects (PROJ — Marketing Site, INFRA — Infrastructure) and a recent-activity feed populated by the seed.
  • A Kanban board for each project with ~15 tickets distributed across the default workflow states (Backlog, Todo, In Progress, Done). The seed only places tickets in Backlog, In Progress, and Done, so Todo starts empty.
  • A wiki with four resolved pages and one deliberately broken [[wikilink]] so you can see how broken-link rendering works.
  • Two bots ready to call the API. The research bot can call MCP at http://localhost/mcp/bot/tkb_devresearchtoken0000000000000001/mcp and the REST endpoints with the same token as X-API-Key.

The first-run walkthrough covers what to click next.

Tearing it down#

# Stop the stack but keep the database
docker compose down

# Stop and destroy the data volume (full reset)
docker compose down -v

The pgdata named volume survives docker compose down. Only down -v deletes it. For a reset that preserves the volume but rewinds the schema and re-seeds, see reset-db in the seed-data page.

Common first-run snags#

Port 80 already in use

macOS often has a system process bound to port 80. Set HTTP_PORT=8080 and HTTPS_PORT=8443 in .env, then reach the app at http://localhost:8080.

Backend refuses to start with ENV=prod

The backend enforces ENV=prodCOOKIE_SECURE=true at startup. For local dev on plain HTTP, set ENV=dev and COOKIE_SECURE=false. Either both go production-flavoured (Caddy with real TLS) or both stay dev-flavoured.

Migrations didn't run

The migrate service runs once and exits. If it exited non-zero, backend will refuse to start because it depends on migrate completing successfully. Check docker compose logs migrate for the failure.

Logged-in but seeing 'No projects yet'

The dashboard pulls projects with the session cookie. If your cookie was issued before make seed-dev ran, refresh the page — the seed adds projects but does not push to the browser.

When you're ready, head to the first-run walkthrough.