feat(ADM-018): completed feature
This commit is contained in:
64
legacy/specs-old/F-002-database-foundation/DESIGN.md
Normal file
64
legacy/specs-old/F-002-database-foundation/DESIGN.md
Normal 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`.
|
||||
58
legacy/specs-old/F-002-database-foundation/SPEC.md
Normal file
58
legacy/specs-old/F-002-database-foundation/SPEC.md
Normal 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.
|
||||
10
legacy/specs-old/F-002-database-foundation/TASKS.md
Normal file
10
legacy/specs-old/F-002-database-foundation/TASKS.md
Normal 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
|
||||
25
legacy/specs-old/F-002-database-foundation/TESTS.md
Normal file
25
legacy/specs-old/F-002-database-foundation/TESTS.md
Normal 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 |
|
||||
Reference in New Issue
Block a user