50 lines
3.0 KiB
Markdown
50 lines
3.0 KiB
Markdown
# 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. |