Skip to main content

Local development

A single docker-compose.yml at the repository root brings up the backing infrastructure: PostgreSQL 16 (pgvector/pgvector:pg16), Redis 7, MinIO, Mailpit (SMTP capture), WireMock (SendGrid HTTP stub) and Sentry Spotlight.

cp .env.example .env.local
docker compose up -d
bash infra/local/healthcheck.sh # verify every service end to end

.env.local stays at the repository root: the backend loads it from there in src/config/load-env.ts (before Sentry and OpenTelemetry read process.env), and the shell frontend points Vite's envDir at the same directory. Variables already exported in your shell take precedence over the file.

Application services​

ServiceURLNotes
shell frontendhttp://localhost:5173Vite dev server (HMR)
shell backendhttp://localhost:3000NestJS API (hot reload)
Mailpit UIhttp://localhost:8025Captured outbound email
MinIO consolehttp://localhost:9001S3-compatible storage console
Sentry Spotlighthttp://localhost:8969Local Sentry equivalent

Firebase Auth​

Firebase Auth has no faithful local container. Local development uses the real chrono-dev Firebase project (credentials via env vars). The Firebase Emulator Suite (firebase emulators:start --only auth) is an optional offline alternative. Point both sides at it:

# .env.local — the browser session
VITE_FIREBASE_AUTH_EMULATOR_HOST=127.0.0.1:9099
# exported for the backend — read by firebase-admin itself
export FIREBASE_AUTH_EMULATOR_HOST=127.0.0.1:9099

e2e/run.sh does exactly this for the backend when it runs the API suite.

Mock auth for shell-only or e2e work​

Add ?mockAuth=1 to the shell URL to run with a canned identity — no Firebase project and no backend required. The flag is latched into sessionStorage, so it survives client-side navigation; you still land on the sign-in screen, but any email and password then signs you in as Marcus Vance with the admin global role. This is how the Playwright suite exercises the sign-in → dashboard → product flows.

The shell-sdk package​

The SDK is built first (it is consumed via the workspace protocol). Build it with pnpm --filter @chrono-one/shell-sdk build; its compiled output is committed so type-checking the consumers never depends on build order.