feat(ADM-018): completed feature

This commit is contained in:
chattie
2026-08-17 22:23:10 +02:00
parent cf1c69fc8b
commit d595b4871f
871 changed files with 47411 additions and 281 deletions

View File

@@ -0,0 +1,64 @@
# DESIGN — F-002 Database foundation with module-owned schemas
## Affected modules
- `src/infrastructure/db` (new): pool factory + migration runner entry.
## Modules touched
- `src/infrastructure/db`
- `project/migrations/` (new folder, SQL files)
- `project/docker-compose.yml` (new)
## Modules NOT touched
- All business modules. No HTTP API change. No shared/ change.
## New interfaces
- `src/infrastructure/db/pool.ts`: `createPoolFromEnv(): Pool` (fail fast if `DATABASE_URL` missing), `query(text, params)` helper typed over pg.
- npm scripts: `db:up`, `db:down`, `db:status`, `docker:up`, `docker:down`, `test:integration`.
## API changes
- None.
## Database changes
- Baseline migration `001_baseline.js` (node-pg-migrate, pgm.sql):
- `CREATE EXTENSION IF NOT EXISTS citext;`
- `CREATE EXTENSION IF NOT EXISTS pgcrypto;`
- `CREATE TABLE app_meta (key text PRIMARY KEY, value text NOT NULL, updated_at timestamptz NOT NULL DEFAULT now());`
- Down: drop table, drop extensions.
- Migration version tracking table owned by the migration tool.
## Naming convention (documented rule)
```text
<module>_<table> e.g. catalog_products, inventory_stock, orders_orders
<module>_<table>_id_seq sequences owned by their table
```
- A module never queries tables without its own prefix.
- Migrations are immutable once merged; fixes ship as new migrations.
## Events
- None.
## External integrations
- Docker Compose: postgres:16-alpine (port 5432), redis:7-alpine (port 6379), named volumes.
## Cache changes
- None (Redis present but unused until cache ticket).
## Security considerations
- Compose credentials are dev-only and public by design; documented as such.
- `.env.example` committed, real `.env` gitignored.
- No secrets in migration files.
## Toolchain decisions
- Migration tool: **node-pg-migrate** (pure npm dependency, battle-tested, SQL-first via `pgm.sql`, supports up/down and dry-run). Rejected: hand-rolled runner (reinvention), Flyway/golang-migrate (foreign toolchains for a Node monolith).
- Driver: **pg** (standard).
- Env loading: Node 22 `--env-file` flag; no dotenv dependency.
## Test strategy
- Integration tests (`*.itest.ts`) run only when `TEST_DATABASE_URL` is set: `describe.skipIf` — explicit, no magic.
- They verify: fresh up creates schema; second up is no-op; down reverts cleanly; `app_meta` usable via pool helper.
## Migration strategy
- Greenfield; compose starts empty volume, migrations run from zero.
## Rollback strategy
- `db:down` reverts last migration; compose volumes can be removed with `docker compose down -v`.

View File

@@ -0,0 +1,58 @@
# SPEC — F-002 Database foundation with module-owned schemas
## Problem
Modules need PostgreSQL with clear ownership and safe migrations. No schema tooling exists yet.
## Goal
Migration tooling, table naming convention per module, and a local dev database (PostgreSQL + Redis) that starts with one command.
## Non-goals
- No business tables yet (they arrive with their modules).
- No Redis usage beyond making the service available for future tickets.
- No production deployment concerns.
## User story
As a developer, I can run one command to get PostgreSQL + Redis locally, apply migrations forward and backward deterministically, and every future module knows exactly how to name and own its tables.
## Functional requirements
1. SQL migrations run through a deterministic tool, tracked in the database, ordered, idempotent per version.
2. Migrations support up and down.
3. Naming convention `<module>_<table>` is documented and visible in the baseline migration.
4. `docker-compose.yml` provides PostgreSQL 16 and Redis 7 with one command.
5. A typed DB access point lives in `src/infrastructure/db/` (pool creation from env, fail fast on missing config).
6. Baseline migration: enable extensions + `app_meta` key/value table (foundation-only, not business).
## Business rules
- No schema change without migration.
- Modules own tables by prefix; cross-module table access is forbidden (enforced later at module API level, documented now).
## Inputs
- `DATABASE_URL` (runtime), `TEST_DATABASE_URL` (integration tests).
## Outputs
- Migration CLI exit codes 0/1, log lines per applied/reverted migration.
## Edge cases
- Re-running `migrate up` on an up-to-date DB is a no-op.
- `migrate down` reverts exactly the last applied migration.
- Missing `DATABASE_URL` → clear error, non-zero exit, no partial state.
## Acceptance criteria
1. Given a fresh database, When migrations run, Then schema is created and repeating the run is a no-op.
2. Given applied migrations, When down runs, Then schema rolls back cleanly.
3. Table naming convention documented and enforced (documented rule + exemplar).
4. Dev PostgreSQL and Redis start with one command.
5. `verify.sh` green.
## Dependencies
- F-001 (project skeleton).
## Security implications
- Dev credentials live only in docker-compose dev file and `.env.example`; never real secrets in repo.
- DB user for tests should be dedicated (documented).
## SEO implications
- None.
## Performance implications
- Pool defaults conservative (max 10); no caching layer yet.

View File

@@ -0,0 +1,10 @@
# TASKS — F-002 Database foundation with module-owned schemas
- TASK-001 Add deps: pg, node-pg-migrate (+ @types/pg dev); justify in spec/tech.md
- TASK-002 Add `project/docker-compose.yml` (postgres:16-alpine + redis:7-alpine, volumes, dev creds) and `.env.example`
- TASK-003 Add baseline migration `migrations/001_baseline.js` (node-pg-migrate; extensions + app_meta via pgm.sql, with down)
- TASK-004 Add `src/infrastructure/db/pool.ts` (createPoolFromEnv fail-fast + query helper)
- TASK-005 Wire npm scripts: db:up, db:down, db:status, docker:up, docker:down, test:integration
- TASK-006 Integration tests: fresh up / no-op rerun / down rollback / pool helper roundtrip (skipIf no TEST_DATABASE_URL)
- TASK-007 Document naming convention in project/README.md
- TASK-008 Run full verification and write implementer evidence

View File

@@ -0,0 +1,25 @@
# TESTS — F-002 Database foundation with module-owned schemas
## Integration (Vitest, `*.itest.ts`, run with TEST_DATABASE_URL set)
- `migrations.itest.ts`:
- fresh database + `migrate up``app_meta` exists
- second `migrate up` → no-op (no errors, same state)
- `migrate down``app_meta` gone
- `pool.itest.ts`:
- `createPoolFromEnv` connects and `SELECT 1` roundtrip
- insert/read/delete row in `app_meta` via query helper
## Manual/CI commands
- `npm run docker:up` starts PostgreSQL + Redis with one command
- `npm run db:up` on fresh DB exits 0; second run exits 0 with nothing applied
- `npm run db:down` exits 0 and drops baseline objects
- `npm test` stays green even without TEST_DATABASE_URL (integration tests skip explicitly)
## Acceptance traceability
| Criterion | Evidence |
|---|---|
| fresh up creates schema, rerun is no-op | migrations.itest.ts + db:up twice in implementer.md |
| down rolls back cleanly | migrations.itest.ts + db:down output |
| naming convention documented/enforced | README section + baseline migration exemplar |
| dev DBs start with one command | docker compose up output |
| verify.sh green | qa.json evidence |