docs(decisions): add ADR-0019 i18n + ADR-0020 portal-admin
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

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.
This commit is contained in:
Julien Gautier
2026-05-11 11:19:30 +02:00
parent 8b986f3dc3
commit 161e2ecb1c
4 changed files with 439 additions and 21 deletions
+3 -1
View File
@@ -47,12 +47,14 @@ The structural, security, observability, and quality choices are recorded as ADR
- **Accessibility:** **WCAG 2.2 AA baseline + targeted AAA** on criteria with high impact for APF's user base (1.4.6 Contrast Enhanced, 2.2.3 No Timing, 2.3.3 Animation, 3.1.5 Reading Level, 1.4.8 Visual Presentation, 2.4.9 Link Purpose, 3.3.5 Help). RGAA 4.1 alignment for French audit. UI stack: **Angular CDK + TailwindCSS** (spartan-ng _library_ deferred until it reaches 1.0.0; v1 components are written in-house in `libs/shared/ui/` on Angular CDK, applying the spartan-ng _philosophy_ of headless primitives + utility CSS + copy-paste). User-preferences panel (contrast / text size / motion / spacing / cognitive simplification / reading focus) persisted in session. Tooling: `@angular-eslint/template/*` lint, `@axe-core/playwright` e2e (blocking on critical/serious), token-contrast CI check, touch-target check (44×44 min). Manual testing cadence with APF's internal user panel before each major release. Public accessibility statement page at `/accessibility` and `/accessibilite` — see [ADR-0016](docs/decisions/0016-accessibility-baseline-wcag-aa-targeted-aaa.md).
- **Performance budgets:** Core Web Vitals at Google "Good" thresholds (LCP ≤ 2.5 s, INP ≤ 200 ms, CLS ≤ 0.1, TBT ≤ 200 ms, TTFB ≤ 800 ms), Lighthouse Performance ≥ 90 on critical routes. **Lighthouse CI** (`@lhci/cli`) runs in CI with median-of-3 mitigation, blocking on threshold breach. Angular bundle `budgets` (`type: "error"`): initial ≤ 300 KB gzip, lazy chunks ≤ 100 KB gzip. BFF p95/p99 SLOs per endpoint family observed via OTel (advisory in CI, alerting in prod). Weekly scheduled Lighthouse run on prod env. **a11y wins over perf** when they conflict — see [ADR-0017](docs/decisions/0017-performance-budgets-lighthouse-ci.md).
- **Environment configuration:** SPA per-environment values via Angular `environment.ts` + `fileReplacements` at build time (no runtime config-fetch). BFF reads `process.env` directly with small per-key boot-time validators (no `@nestjs/config` overhead at this scale). The audit log uses a separate `AUDIT_DATABASE_URL` connection pool in production (`audit_writer`-only login, defense in depth) and falls back to the shared pool + `SET LOCAL ROLE` in dev — see [ADR-0018](docs/decisions/0018-environment-configuration-strategy.md).
- **Internationalisation:** `@angular/localize` in build-time mode, two locales (`fr` default served at `/`, `en`), source locale = English (project English-only rule). Path-based URLs always prefixed (`/fr/...`, `/en/...`); `/` smart-redirects via cookie → `Accept-Language``fr`. UI strings live in XLIFF (`messages.fr.xlf`); editorial / CMS content is BFF-served already localised (see admin app). Footer hosts the locale switcher; switching writes a `__Host-portal_locale` cookie and hard-refreshes — see [ADR-0019](docs/decisions/0019-internationalisation-angular-localize.md).
- **Admin application (`portal-admin`):** dedicated Angular SPA alongside `portal-shell`, sharing the same `portal-bff` via `/api/admin/*` routes guarded by an Entra `admin` role + `@RequireMfa({ freshness: 600 })` at entry. Distinct origin / cookie / session from `portal-shell` (`__Host-portal_admin_session`). v1 modules: CMS for static pages (multilingual), menu management, user list (read-only), audit log viewer. Bundle budget relaxed to ≤ 500 KB gzip (vs 300 KB for `portal-shell`); same a11y + dark-mode baseline. Shared UI primitives (`Icon`, `LayoutStateService`, brand tokens) graduate to `libs/shared/*` as both apps need them — see [ADR-0020](docs/decisions/0020-portal-admin-app.md).
- **Local quality gates:** Husky + lint-staged + commitlint with Conventional Commits — see [ADR-0007](docs/decisions/0007-pre-commit-hooks-and-conventional-commits.md).
- **Runtime:** Node.js latest LTS major.
## Repository status
The Nx workspace is **not yet bootstrapped** — there is no `package.json`, no source code, no tests. ADRs 0001 → 0017 cover the structural, security, observability, and quality choices for phase-1, phase-2, and phase-3a. The security baseline ADR is **paused** awaiting RSSI input on the OWASP ASVS reference level and adjacent frameworks (HDS, GDPR, possibly PCI DSS / NIS 2). The next step is to scaffold the workspace per [docs/setup/03-angular-nx-monorepo.md](docs/setup/03-angular-nx-monorepo.md), which has already been rewritten to align with the phase-1 ADRs.
The Nx workspace is **not yet bootstrapped** — there is no `package.json`, no source code, no tests. ADRs 0001 → 0020 cover the structural, security, observability, quality, i18n, and admin-app choices for phase-1, phase-2, and phase-3a. The security baseline ADR is **paused** awaiting RSSI input on the OWASP ASVS reference level and adjacent frameworks (HDS, GDPR, possibly PCI DSS / NIS 2). The next step is to scaffold the workspace per [docs/setup/03-angular-nx-monorepo.md](docs/setup/03-angular-nx-monorepo.md), which has already been rewritten to align with the phase-1 ADRs.
If asked to "build", "test", or "run" anything, first verify whether the workspace exists; if not, the right response is to scaffold it, not to invent commands.