161e2ecb1c
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.
67 lines
8.9 KiB
Markdown
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 |
|