docs(decisions): add ADR-0019 i18n + ADR-0020 portal-admin #89
Reference in New Issue
Block a user
Delete Branch "docs/adr-i18n-and-portal-admin"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Pure documentation PR. Two ADRs that answer the two strategic questions raised after the footer chantier:
Implementation will land across follow-up feature PRs, each consumable on its own.
ADR-0019 — Internationalisation
Decision:
@angular/localizein build-time mode, two locales (frdefault served at/,ensource). Path-based URLs always prefixed (/fr/...,/en/...);/smart-redirects via cookie →Accept-Language→fr. The locale switcher in the footer writes a__Host-portal_localecookie and hard-refreshes to the matching bundle.Considered and rejected:
@angular/localizeruntime mode (single bundle, higher LCP / payload cost).@ngx-translate/transloco(community libraries; tech-bar prefers Angular first-party for foundational primitives).<html lang>becomes harder).__Host-cookie scoping from ADR-0010).Scope boundary: UI strings owned by developers (templates +
$localizein code). Editorial content (CMS-managed pages, news, etc.) is BFF-served already localised — that's the admin-app pipeline (ADR-0020), not@angular/localize.First sweep consequence: the duplicate
/accessibility+/accessibiliteroutes collapse to one Angular route with locale-translated paths.ADR-0020 —
portal-adminDecision: new Angular SPA
portal-adminalongsideportal-shell, sharing the existingportal-bffvia/api/admin/*routes guarded by an Entraadminrole plus@RequireMfa({ freshness: 600 })at the entry route. Distinct origin + cookie + session (__Host-portal_admin_session).v1 modules (all four selected):
portal-shellvia the BFF).requiredPermissionsfield already onMenuItem).audit.eventstable per ADR-0013, via theaudit_readerrole).Out of v1: B2B invitations (stay in Entra Admin Center), feature flags (no substrate yet), CMS workflow / approval flows, theme customisation, live preview.
Considered and rejected:
/admin/*lazy-loaded insideportal-shell(admin code in the same origin → weaker defense in depth, admin URL not IP-restrictable independently).Performance budget for admin: ≤ 500 KB gzip initial (vs 300 KB for
portal-shell, per ADR-0017). Lighthouse Performance ≥ 85 on critical admin routes (vs ≥ 90 onportal-shell). Same a11y baseline (ADR-0016), same dark-mode support.Shared-libs graduation:
Icon,LayoutStateService, brand tokens, dark-mode SCSS helpers move fromportal-shelltolibs/shared/{ui,state}when both apps need them. Mechanical refactor; tracked as the first implementation PR.Implementation roadmap (out of scope of this PR)
ADR-0019:
@angular/localize, wire build target.portal-shellwithi18n+@@id; producemessages.fr.xlf./api/preferences/localeBFF route + smart redirect at/.nx build portal-shell --localizeis added toci:checkand fails on missing translation.ADR-0020:
nx g @nx/angular:app portal-adminskeleton.libs/shared/ui,libs/shared/state).AdminModule+AdminRoleGuard+ smokeGET /api/admin/me.Test plan
docs/decisions/README.mdindex updated in the same commit.CLAUDE.mdarchitecture summary picks up entries for both decisions and bumps the ADR coverage line to 0020.