Files
mercadodevida/work/artifacts/F-005/implementer.md
rikrdo 75293f39bc feat(identity): F-005 register/login/logout with argon2 sessions and rate limiting
- Hexagonal identity module: domain ports, use cases, argon2id hasher, pg repos
- Migration 002_identity: identity_users + identity_sessions (token hash only)
- Opaque 512-bit session tokens; DB stores SHA-256 hash; 7-day TTL in SQL
- Cookie HttpOnly + Secure (COOKIE_SECURE, default true) + SameSite=Lax
- LoginRateLimiter: 10 failures -> 429 + Retry-After, 15-min cooldown
- Anti-enumeration: identical generic 401 + dummy-hash timing equalization
- buildApp gains optional pool/cookieSecure; foundation-only app preserved
- 47 unit + 14 integration tests; live smoke covers all acceptance criteria
2026-08-14 22:58:32 +02:00

42 lines
2.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`.