Skip to content

00 · Environment setup

One-shot bring-up that every other playbook in this directory assumes. Run this once per machine and per branch checkout. If a playbook says "open mailpit" or "log in as admin@spade.local" it expects everything below to be in place.

0. Prerequisites

  • Node.js ≥ 22 (use nvm use if .nvmrc is present)
  • pnpm ≥ 10
  • Docker + Docker Compose

1. Bring up infra + dependencies

bash
pnpm install
docker compose up -d                  # postgres:17, minio, mailpit
cp .env.example .env                  # keep dev defaults unless noted

pnpm db:generate
pnpm db:migrate:deploy                # apply committed migrations (idempotent)
pnpm db:migrate:status                # expect "Database schema is up to date"
pnpm db:seed                          # creates ACME, GLOBEX, ZENITH
pnpm dev                              # api:3001, web:3000, worker (tsx)

The seed script logs every page URL, magic-link URL, batch ID, statement ID, and contact email at the end. Copy them from there rather than guessing — they change on every reseed.

2. Verification checklist

ServiceURLExpectation
API livenesshttp://localhost:3001/health/live{ status: "ok" }
API readinesshttp://localhost:3001/health/readyDB + S3 + SMTP all green
Swaggerhttp://localhost:3001/docsOpenAPI UI loads, both /ops and /ops/bookkeeping route groups visible
Webhttp://localhost:3000redirects to /login
Mailpithttp://localhost:8025empty mailbox
MinIO consolehttp://localhost:9001login minioadmin / minioadmin
Prisma Studiopnpm db:studiobrowse tables during the flow

3. Seeded staff accounts

Password is read from SEED_ADMIN_PASSWORD; if unset and NODE_ENV is not production, the dev fallback is DevAdmin-Password-1!.

EmailRoleUse for
admin@spade.localPLATFORM_ADMINClient config, ingestion channels, staff-user management, both products
lead@spade.localPAYROLL_LEADPayroll override approvals, template management
executive@spade.localPAYROLL_EXECUTIVEPayroll cycle ops, exports, output uploads

No bookkeeping-specific staff user is seeded by default. Either log in as admin@spade.local (PLATFORM_ADMIN has the bookkeeping action set) or create a BOOKKEEPER / SENIOR_ACCOUNTANT user via /dashboard/staff-users/new before running the bookkeeping flows.

4. Seeded clients

ClientCodeProduct(s)Notable state
ACME Pte LtdACMEPAYROLLOpen 2026-04 cycle in INTAKE_IN_PROGRESS. Closed 2026-03 prior cycle (powers baseline-roster dropdown + OCR prefill demo).
GLOBEX Pte LtdGLOBEXPAYROLLOpen 2026-04 cycle in CLIENT_REVIEW, approval round dispatched to bob@globex.sg.
Zenith Trading Pte LtdZENITHBOOKKEEPINGXero, SGD, materiality SGD 50. Draft 2026-04 batch with 4 entries (1 APPROVED, 2 FLAGGED, 1 DRAFT). UOB statement with 6 transactions and a reconciliation run in AWAITING_REVIEW.

The seed script also writes magic-link tokens for each contact and logs them — copy from the seed output.

5. Sample fixtures

Sample files used by the upload-driven flows live in scripts/fixtures/:

2026-04-ACME-attendance.xlsx
offer-letter-{marcus-lim,sarah-tan,wei-lin}.pdf
nric-{marcus-lim,sarah-tan}.pdf
fin-wei-lin.pdf
bank-details-{marcus-lim,sarah-tan,wei-lin}.pdf
change-letter-emp-001-increment.pdf
resignation-letter-rachel-goh.pdf

For bookkeeping uploads the seed already provisions sample documents in MinIO (ZENITH/bookkeeping/2026-04/*.pdf) — re-run pnpm db:seed to repopulate them. If you need a fresh PDF for ad-hoc tests, any small (< 5 MB) PDF works because the dev OcrAdapter is the mock by default.

6. Reset commands

When a flow leaves the system in a broken state:

bash
# Wipe everything and reseed
docker compose down -v && docker compose up -d
pnpm db:migrate:deploy && pnpm db:seed

# Re-seed without dropping the DB (cleans fixtures only)
pnpm db:seed

# Tail worker job activity
pnpm --filter @breezycorp/worker dev

# Browse / edit DB directly
pnpm db:studio

7. Environment variables you may need to flip

VariableEffect on flows
OCR_PROVIDER=mockDefault. Documents extract instantly with hand-picked sample fields. Set to vision+claude to exercise the real pipeline (requires ANTHROPIC_API_KEY + GOOGLE_VISION_CREDENTIALS_JSON).
SEED_ADMIN_PASSWORDSet before pnpm db:seed to control the staff-user password.
SMTP_HOST / SMTP_PORTDefault to mailpit on 1025. Point at a closed port to verify pg-boss retry behaviour during email-failure flows.
STAFF_APP_URL / PORTAL_BASE_URLDefault to http://localhost:3000. Change before re-seeding to test cross-domain magic-link delivery.

8. Where to ask

If anything in §1–§4 fails, fix it before opening a flow file. The flows assume green infra. Common failures:

  • pnpm db:migrate:deploy reports drift → use pnpm db:migrate:resolve --applied <name> only after verifying the DB matches.
  • Mailpit empty after a flow that should have sent mail → check outbox_events.dispatched_at in Prisma Studio; the worker poller runs every 10 s.
  • Worker silent → kill pnpm dev and run pnpm --filter @breezycorp/worker dev in its own terminal so you can read the handler logs.

Internal use only — BreezyCorp