f4f9224c68d4b441d56efb5d7822a72e9a6a9eb4
manual smoke after #120 returned 500 on the first /auth/logout : PostgresError code 42501 — permission denied for table events acl looked correct (audit_writer=a/audit_owner), has_*_privilege returned t everywhere, and a manual psql `INSERT INTO audit.events` succeeded after SET LOCAL ROLE audit_writer. but the same INSERT WITH `RETURNING id` failed with the exact same error. root cause: tx.auditEvent.create() in prisma emits `INSERT … RETURNING *` to hydrate the entity it returns, and postgres requires SELECT on every column in RETURNING. audit_writer has INSERT only per adr-0013's append-only-by-role contract. RETURNING fails with "permission denied for table X" — and the message says nothing about SELECT or RETURNING, which made the bug take a long debug session to isolate. fix: AuditWriter.recordEvent now uses tx.$executeRawUnsafe with a parameterised raw INSERT instead of the orm create(). the role contract stays strict (audit_writer keeps INSERT only — no SELECT, UPDATE, DELETE, TRUNCATE). the alternative — GRANT SELECT to audit_writer — would have collapsed the writer / reader role separation that adr-0013 hinges on, so we went the other way. bonus: also fixes an env-sensitivity bug in auth.controller.spec.ts. the test asserting `session.absoluteExpiresAt == createdAt + 43_200 * 1000` was reading the default via readSessionTimeouts() but didn't override SESSION_ABSOLUTE_TIMEOUT_SECONDS. apps/portal-bff/ .env may carry a custom value (it did during the audit debugging), making the test fail non-deterministically. now it deletes the env var before, restores after — same pattern as the other env-touching tests in this file. 144/144 specs pass under the clean-env repro: env -u REDIS_URL -u SESSION_SECRET -u SESSION_ENCRYPTION_KEY \ -u SESSION_IDLE_TIMEOUT_SECONDS -u SESSION_ABSOLUTE_TIMEOUT_SECONDS \ -u LOG_USER_ID_SALT -u DATABASE_URL -u ENTRA_* \ pnpm exec nx run-many -t test lint build --projects=portal-bff notable shape choices: - gen_random_uuid() server-side instead of prisma's @default(uuid()) client-side. the model still declares @default for future orm reads by audit_reader; the write path now uses postgres's built-in (available since 13, target is 17). - explicit enum + jsonb casts ($2::"audit"."AuditAudience" etc.) because parameters travel as TEXT on the wire. - parameterised via $1, $2, …; never interpolated. a spec pins this with a sql-injection-shaped eventType input. unchanged: schema, migration, role grants, ADR-0013 contract.
Documentation index
This is the entry point to all project documentation. It is maintained automatically: any addition, rename, or removal of a .md file under docs/ must be reflected here in the same change.
Conventions
- Documentation is written in English.
- One topic per file. Group related files into a folder when there are three or more.
- Cross-reference with relative links so they keep working in GitHub, IDEs, and exported sites.
- For architectural decisions, do not add them here — they belong in decisions/ as MADR 4.0.0 ADRs.
Sections
Daily development
- development.md — repo layout, prerequisites, initial setup, daily commands, observability dev-loop (Jaeger UI, log ↔ trace correlation), dependency updates (Renovate), conventional commit cycle. Day-to-day reference for working on the project.
Architecture
- architecture.md — cross-cutting Mermaid diagrams: C4 system context, C4 containers, Nx module boundaries, CI/CD pipeline. Single-decision diagrams (auth sequence, ERD, etc.) live inline in their ADR.
Onboarding & environment
Setup guides for new contributors:
- setup/01-wsl-terminal-setup.md — modern WSL terminal (Zsh + Powerlevel10k + CLI tools)
- setup/02-dev-web-stack.md — Node via nvm, pnpm via corepack, Docker
- setup/03-angular-nx-monorepo.md — Angular + Nx monorepo bootstrap
Operations & runbooks
Empty — to be populated when we deploy.
Security, performance, accessibility
Empty — placeholders to be filled with rationale docs alongside their corresponding ADRs.
Description
Languages
TypeScript
85.3%
JavaScript
5.4%
SCSS
4.3%
HTML
3.9%
Shell
0.8%
Other
0.3%