# Implementer — F-005 Identity: register, login, sessions done -> work/artifacts/F-005/implementer.md ## Delivered - Migration `migrations/002_identity.js`: `identity_users` + `identity_sessions` (token_hash UNIQUE, FK ON DELETE CASCADE, user_id index). Reversible. - Hexagonal module `src/modules/identity`: - domain: user.ts, session.ts (7-day TTL), errors.ts, ports.ts - application: register-user.ts, login.ts, logout.ts, login-rate-limiter.ts - infrastructure: argon2-password-hasher.ts (argon2id m=19456 t=2 p=1), pg-user-repository.ts, pg-session-repository.ts, session-token.ts - api: identity.routes.ts (zod via parseJson, envelope v2 mapping) - Foundation wiring: `createPool(connectionString)`, `COOKIE_SECURE` in config (default true), `buildApp({ pool, cookieSecure })`, server creates pool from config. ## Deps added (justified in spec/tech.md) - argon2, @fastify/cookie ## Evidence - `npm run lint` ✅ (prettier clean after format pass) - `npm run lint:boundaries` ✅ (39 files, R1/R2 OK — module tests stay in-subtree, DB integration tests live in src/app/tests) - `npm run typecheck` / `npm run build` ✅ - `npm test`: 46 passed, 14 skipped (integration) ✅ - `npm run test:integration`: 14/14 ✅ (register argon2-only storage, dup 409, invalid 400, cookie flags, identical 401 bodies, revocation + idempotent logout, 10 failures → 429 + Retry-After, foundation-only app keeps /auth 404) - Live smoke (curl): 201 register / 200 login + `mdv_session …; HttpOnly; Secure; SameSite=Lax; Max-Age=604800` / 401 identical for wrong-password vs unknown-email / 204 logout clears cookie / 10×401 → 429 + `retry-after: 900` - `./scripts/verify.sh` ✅ ## Notes / deviations - F-002 migrations.itest baseline rollback test updated: `down` now uses `count: 0` (full revert) since the suite has two migrations; test asserts identity tables AND app_meta are gone. Helper `runMigrations` gained an optional count param. - Rate limiter is in-memory per instance (documented in DESIGN risks; interface ready for Redis swap). - `project/.env` (gitignored) supplies TEST_DATABASE_URL to the `test:integration` script via `node --env-file-if-exists=.env`.