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
| Service | URL | Notes |
|---|---|---|
| shell frontend | http://localhost:5173 | Vite dev server (HMR) |
| shell backend | http://localhost:3000 | NestJS API (hot reload) |
| Mailpit UI | http://localhost:8025 | Captured outbound email |
| MinIO console | http://localhost:9001 | S3-compatible storage console |
| Sentry Spotlight | http://localhost:8969 | Local 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.