# Architectural Decision Records

This project records architecturally-significant decisions as **ADRs** in the [MADR 4.0.0](https://github.com/adr/madr) format. References: [adr.github.io](https://adr.github.io/).

## Why ADRs

ADRs capture the _why_ behind a decision — context, drivers, options considered, trade-offs accepted — at the moment the decision is made. They make architecture reviewable, onboarding faster, and prevent the same debate from being re-litigated later.

## Conventions

- **Format:** MADR 4.0.0. Start from [template.md](template.md).
- **Filename:** `NNNN-kebab-case-title.md`, e.g. `0007-adopt-tailwind-for-design-tokens.md`.
- **Numbering:** globally sequential 4-digit prefix. Numbers never reset, never get reused — even when an ADR is superseded or deprecated.
- **Layout:** flat folder. ADRs are not nested into category subfolders; topical organization happens via tags.
- **Tags:** every ADR carries a `tags:` array in the MADR frontmatter, drawn from the [tag vocabulary](#tag-vocabulary) below. An ADR may carry several tags. Propose new tags (or renames) in the same PR that needs them; never invent ad-hoc tags inline.
- **Status lifecycle:** `proposed` → `accepted` → optionally `deprecated` or `superseded by [ADR-NNNN](NNNN-other.md)`. Update the YAML frontmatter; never delete an ADR.
- **Index maintenance:** every ADR addition or status change must update the [Index](#index) below in the same commit.

## When to write an ADR

Write one whenever a development decision is non-trivial: tool or library choice, framework pattern, security control, perf budget, a11y target, naming convention, deprecation, breaking change, or any choice that future contributors would benefit from understanding the _why_ of.

## Tag vocabulary

The vocabulary below is the source of truth. It is intentionally coarse — propose extensions only when an existing tag genuinely doesn't fit, and avoid overly narrow tags.

| Tag              | Scope                                                               |
| ---------------- | ------------------------------------------------------------------- |
| `frontend`       | UI, Angular, components, design system, client-side state           |
| `backend`        | API, BFF, server-side services                                      |
| `security`       | AuthN, AuthZ, sessions, CSP, dependency scanning, secret management |
| `performance`    | Perf budgets, caching, bundle size, Lighthouse                      |
| `accessibility`  | WCAG, a11y testing, keyboard, ARIA, contrast                        |
| `infrastructure` | CI/CD, hosting, deployment, runtime                                 |
| `observability`  | Logs, metrics, traces, correlation IDs, monitoring                  |
| `data`           | Persistence, schemas, migrations, data flow                         |
| `process`        | Team conventions, workflows, repo policy                            |

> _Status: starter vocabulary, to be refined as ADRs accumulate. Update this table whenever a tag is added, renamed, or retired._

## Index

ADRs are listed in numerical order. To slice by topic, filter on the `Tags` column.

| #                                                            | Title                                                                                                            | Status   | Tags                                                           | Date       |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------- | ---------- |
| [0001](0001-use-adrs-to-record-architectural-decisions.md)   | Use ADRs to record architectural decisions                                                                       | accepted | `process`                                                      | 2026-04-29 |
| [0002](0002-adopt-nx-monorepo-apps-preset.md)                | Adopt Nx monorepo with the `apps` preset                                                                         | accepted | `infrastructure`, `frontend`, `backend`                        | 2026-04-29 |
| [0003](0003-workspace-and-app-naming-convention.md)          | Workspace and app naming convention                                                                              | accepted | `process`                                                      | 2026-04-29 |
| [0004](0004-frontend-stack-angular-csr-zoneless-signals.md)  | Frontend stack — Angular (latest LTS), standalone, zoneless, Signals, CSR-only, Vitest                           | accepted | `frontend`                                                     | 2026-04-29 |
| [0005](0005-backend-stack-nestjs.md)                         | Backend stack — NestJS over Express, Fastify, Hono                                                               | accepted | `backend`                                                      | 2026-04-29 |
| [0006](0006-persistence-postgresql-prisma.md)                | Persistence — PostgreSQL with Prisma                                                                             | accepted | `data`, `backend`                                              | 2026-04-29 |
| [0007](0007-pre-commit-hooks-and-conventional-commits.md)    | Pre-commit hooks and Conventional Commits                                                                        | accepted | `process`                                                      | 2026-04-29 |
| [0008](0008-identity-model-entra-workforce-dual-audience.md) | Identity model — multi-tenant Entra ID for workforce, dual-audience design for future External ID                | accepted | `security`, `data`                                             | 2026-04-29 |
| [0009](0009-auth-flow-oidc-pkce-msal-node.md)                | Authentication flow — OIDC Authorization Code + PKCE via MSAL Node, BFF session pattern                          | accepted | `security`, `backend`                                          | 2026-04-29 |
| [0010](0010-session-management-redis.md)                     | Session management — opaque session IDs in cookies, payload in self-hosted Redis with AES-GCM at rest            | accepted | `security`, `backend`, `infrastructure`                        | 2026-04-29 |
| [0011](0011-mfa-enforcement-entra-conditional-access.md)     | MFA enforcement — Entra ID Conditional Access baseline, BFF claim sanity-check, step-up hooks designed-in        | accepted | `security`                                                     | 2026-04-29 |
| [0012](0012-observability-pino-opentelemetry.md)             | Observability — Pino structured logs + OpenTelemetry tracing, W3C Trace Context propagation, stdout + collector  | accepted | `observability`, `backend`, `frontend`                         | 2026-04-29 |
| [0013](0013-audit-trail-separated-postgres-append-only.md)   | Audit trail — separated append-only Postgres schema, decoupled from app logs                                     | accepted | `security`, `observability`, `data`                            | 2026-04-29 |
| [0014](0014-downstream-api-access-obo-pattern.md)            | Downstream API access — On-Behalf-Of pattern, unified `DownstreamApiClient`, audience-aware authorization        | accepted | `security`, `backend`                                          | 2026-04-29 |
| [0015](0015-cicd-gitea-actions.md)                           | CI/CD pipeline — Gitea Actions, trunk-based + squash-merge, thin YAML over portable scripts                      | accepted | `infrastructure`, `process`                                    | 2026-04-30 |
| [0016](0016-accessibility-baseline-wcag-aa-targeted-aaa.md)  | Accessibility baseline — WCAG 2.2 AA + targeted AAA, Angular CDK + spartan-ng + Tailwind, APF panel testing      | accepted | `accessibility`, `frontend`, `process`                         | 2026-04-30 |
| [0017](0017-performance-budgets-lighthouse-ci.md)            | Performance budgets — Core Web Vitals + Lighthouse CI gates, bundle budgets, BFF p95/p99 SLOs                    | accepted | `performance`, `frontend`, `backend`, `process`                | 2026-04-30 |
| [0018](0018-environment-configuration-strategy.md)           | Environment configuration — Angular `environment.ts`, BFF env vars, audit pool split                             | accepted | `frontend`, `backend`, `infrastructure`, `process`             | 2026-05-10 |
| [0019](0019-internationalisation-angular-localize.md)        | Internationalisation — `@angular/localize`, build-time per-locale bundles, `/fr` + `/en` path-based routing      | accepted | `frontend`, `accessibility`, `performance`, `process`          | 2026-05-11 |
| [0020](0020-portal-admin-app.md)                             | `portal-admin` — dedicated SPA for portal administration, sharing the existing BFF                               | accepted | `frontend`, `backend`, `security`, `infrastructure`, `process` | 2026-05-11 |
| [0021](0021-phase-2-security-baseline.md)                    | Phase-2 security baseline — helmet, CORS allowlist, double-submit CSRF, rate limiting, structured error envelope | accepted | `security`, `backend`                                          | 2026-05-13 |
| [0022](0022-docs-site-vitepress.md)                          | Documentation site — VitePress + Mermaid plugin, separate static deployment                                      | accepted | `process`, `infrastructure`                                    | 2026-05-15 |
| [0023](0023-charts-d3-observable-plot.md)                    | Charts + dashboards — D3 + Observable Plot wrapped in `libs/shared/charts`                                       | accepted | `frontend`, `accessibility`, `performance`                     | 2026-05-16 |
| [0024](0024-ai-service-relay-grpc-sse-bridge.md)             | AI service relay — vendored gRPC protos, NestJS gRPC client, SSE bridge to the SPA, POC unsigned principal       | accepted | `backend`, `security`, `observability`                         | 2026-05-19 |
| [0025](0025-authorization-model-privileges-roles-scopes.md)  | Authorization model — three orthogonal axes (privileges × functional roles × scopes), Entra-backed               | accepted | `security`, `backend`, `data`                                  | 2026-05-20 |
| [0026](0026-person-user-portal-data-model.md)                | `Person` golden record + `User` portal-account — portal-side identity model                                      | accepted | `data`, `backend`, `security`                                  | 2026-05-24 |
| [0027](0027-portal-side-organisational-hierarchy.md)         | Portal-side organisational hierarchy — `Structure` with kind discriminator and nullable FINESS / SIRET           | accepted | `data`, `backend`                                              | 2026-05-24 |
| [0028](0028-migrate-cicd-and-git-hosting-to-gitlab.md)       | Migrate CI/CD + git hosting from Gitea to GitLab self-hosted                                                     | accepted | `infrastructure`, `process`                                    | 2026-05-26 |
