# Schema strategy (dev) and persistence switching ## Goal Keep the core domain independent from persistence details, while still providing a fast dev loop. Persistence and schema behavior are configured at the application boundary (the API app), not inside the domain. ## Persistence modes (API runtime) The API supports two persistence modes, controlled by [`ProcessEnv.GRIDPILOT_API_PERSISTENCE`](apps/api/src/env.d.ts:7): - **`inmemory`**: no database required; the API runs with in-memory adapters. - **`postgres`**: the API uses Postgres via TypeORM. ### Default inference (dev ergonomics) If `GRIDPILOT_API_PERSISTENCE` is **unset**, the API infers persistence from `DATABASE_URL` via [`getApiPersistence()`](apps/api/src/env.ts:33): - If `DATABASE_URL` is set → `postgres` - Otherwise → `inmemory` This is why dev compose should not hard-code `GRIDPILOT_API_PERSISTENCE`; it should allow inference unless explicitly overridden. ## Schema strategy in development (TypeORM `synchronize`) When the API runs in Postgres mode, it loads [`DatabaseModule`](apps/api/src/domain/database/DatabaseModule.ts:1), which configures TypeORM with: - `synchronize: process.env.NODE_ENV !== 'production'` in [`TypeOrmModule.forRoot()`](apps/api/src/domain/database/DatabaseModule.ts:6) Practical meaning: - **Development/test:** TypeORM `synchronize` is enabled to keep schema aligned automatically during iteration. - **Production:** TypeORM `synchronize` is disabled. ### Migrations (deferred) Migrations are intentionally deferred for now: local dev relies on `synchronize` for speed, while production-grade migrations will be introduced later at the infrastructure boundary (without changing the domain). ## Switching modes locally ### Docker dev (recommended) In [`docker-compose.dev.yml`](docker-compose.dev.yml:1), `GRIDPILOT_API_PERSISTENCE` should be optional so the default inference works. To force a mode, set one of: - `GRIDPILOT_API_PERSISTENCE=inmemory` - `GRIDPILOT_API_PERSISTENCE=postgres` Example environment reference (dev): [`DATABASE_URL`](.env.development.example:20) and optional persistence override (commented) in [`.env.development.example`](.env.development.example:17). ## Dev seeding behavior (high level) Seeding/bootstrap runs at API startup via [`BootstrapModule`](apps/api/src/domain/bootstrap/BootstrapModule.ts:1), unless disabled with `GRIDPILOT_API_BOOTSTRAP=0` (parsed by [`getEnableBootstrap()`](apps/api/src/env.ts:49)). At startup: - Always runs `EnsureInitialData.execute()` in [`BootstrapModule.onModuleInit()`](apps/api/src/domain/bootstrap/BootstrapModule.ts:21). - Seeds racing data via `SeedRacingData` when: - persistence is `inmemory`, or - persistence is `postgres` AND `NODE_ENV !== 'production'` AND the racing DB appears empty (checked via the league repository) in [`BootstrapModule.shouldSeedRacingData()`](apps/api/src/domain/bootstrap/BootstrapModule.ts:42). This keeps dev environments usable without requiring manual seed steps, while avoiding unexpected reseeding in production.