Files
apf_portal/docs/decisions/README.md
T
Julien Gautier 161e2ecb1c
CI / scan (pull_request) Successful in 2m26s
CI / check (pull_request) Successful in 2m38s
CI / commits (pull_request) Successful in 2m44s
CI / a11y (pull_request) Successful in 1m17s
CI / perf (pull_request) Successful in 2m17s
docs(decisions): add ADR-0019 i18n + ADR-0020 portal-admin
ADR-0019 picks `@angular/localize` in build-time mode with two locales
(`fr` default, `en` source). URLs are always prefixed (`/fr/...`,
`/en/...`); `/` smart-redirects via cookie → Accept-Language → fr.
UI strings live in XLIFF; editorial content (CMS-served) is locked to
the admin-app pipeline. The locale switcher in the footer writes a
`__Host-portal_locale` cookie and hard-refreshes to the matching
bundle. The `@angular/localize` runtime mode, ngx-translate, and
transloco alternatives are recorded as considered-and-rejected.

ADR-0020 splits portal administration into a dedicated Angular SPA
(`portal-admin`) sharing the existing `portal-bff` via `/api/admin/*`
routes guarded by an Entra `admin` role plus fresh-MFA at entry. Same
identity / sessions / audit / observability primitives reused, no
infrastructure duplication. v1 ships four modules: CMS for static
multilingual pages, sidebar menu management (activating the
`requiredPermissions` field already on `MenuItem`), read-only user
list, and an audit log viewer. Bundle budget relaxed to 500 KB gzip
(vs 300 KB on `portal-shell`); same a11y + dark-mode baseline.

Together they answer the two questions raised after the footer
chantier: how the multilingual story works, and where the admin
surface lives. Implementation lands across follow-up feature PRs;
this commit is documentation only.

CLAUDE.md picks up summary entries for both decisions and bumps the
ADR coverage line to 0020.
2026-05-11 11:19:30 +02:00

67 lines
8.9 KiB
Markdown

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