Cuts the Nx scaffold's `NxWelcome` page (938 LOC of placeholder
markup) and lays down the actual portal layout — header, main,
footer landmarks plus a skip link — with a real home page and
the two RGAA-mandated accessibility statement routes. Bundle
budgets in `project.json` are tightened to match ADR-0017.
Layout shell (apps/portal-shell/src/app/):
- components/header/ — brand link + primary nav landmark stub
- components/footer/ — accessibility statement links (FR + EN)
+ version badge
- app.html / app.scss — flex column with sticky footer + skip
link to #main-content (WCAG 2.4.1)
Pages:
- pages/home/ — welcome heading + "system status" widget
that fetches /api/health from the BFF.
Doubles as a smoke test of the full
SPA → BFF stack: CORS, OTel trace
propagation, Pino log correlation.
- pages/accessibility/ — single component, content selected by
route data (`lang: 'fr' | 'en'`). Mounted
at /accessibility (en) and /accessibilite
(fr). v1 carries placeholder copy
explicitly framed as "awaiting APF user
panel review" — RGAA + ADR-0016 require
the routes to exist; the substantive
statement (audit grid, gaps list,
remediation plan) lands separately.
Routing & wiring:
- app.routes.ts adds the three routes, all lazy-loaded.
- app.config.ts adds `provideHttpClient(withFetch())` so
HttpClient delegates to the patched browser `fetch` and the
W3C `traceparent` header propagates automatically (ADR-0012
phase 2).
- nx-welcome.ts removed; app.ts no longer imports it.
Bundle budgets (apps/portal-shell/project.json):
- initial ≤ 1 MB raw (≈ 300 KB gzip target per ADR)
- anyScript ≤ 300 KB raw (≈ 100 KB gzip per lazy chunk)
- anyComponentStyle ≤ 6 KB raw (5 KB warning floor)
- bundle "styles" ≤ 150 KB raw
`maximumWarning == maximumError` so an overshoot fails the build
(matching `type: "error"` in spirit). Angular CLI compares raw
sizes; ADR-0017 §Confirmation is updated to record the gzip→raw
translation and the deferred follow-up that will add a CI check
on the actual gzipped transfer size (Angular has no native
gzip-mode budget).
Verified locally:
- `nx run-many -t lint test build` → 8 projects green, 12 tests
pass for portal-shell across 5 specs.
- `nx build portal-shell --configuration=production` → initial
bundle 326.99 KB raw / 89.82 KB transfer (gzip) — well under
the ADR-0017 300 KB gzip target. Lazy chunks: home 2.66 KB,
accessibility 2.90 KB.
Out of scope (separate PRs):
- Real RGAA audit content (APF user-panel review).
- Design tokens system in libs/shared/tokens.
- Reusable UI primitives in libs/shared/ui.
- User-preferences panel (ADR-0016 §"User-preferences panel").
- i18n machinery (@angular/localize) — for v1 the FR/EN copy is
inlined and route-driven; real i18n is a separate ADR.
- env-config (Angular environment.ts) — DATABASE-of-the-front
hard-coded URL `http://localhost:3000/api/health` will move
there alongside the OTLP endpoint when the env-config PR
lands.
- CI gzip-transfer-size assertion to complement the raw-size
Angular budgets.
Wire Tailwind CSS 4 in the portal-shell app per ADR-0016 (the future
host of spartan-ng components in libs/shared/ui will read from the
Tailwind tokens via the shared-tokens lib).
- pnpm add -D tailwindcss @tailwindcss/postcss postcss
- apps/portal-shell/postcss.config.js declares @tailwindcss/postcss
- apps/portal-shell/src/styles.scss renamed to styles.css and now
contains a single @import 'tailwindcss' directive. Plain CSS for the
global file avoids the Sass @import deprecation warning that fires
when Tailwind directives sit inside SCSS. Component-level styles can
still use SCSS.
- apps/portal-shell/project.json styles entry updated accordingly.
Side fix: align libs/shared/tokens and libs/shared/util tsconfigs from
module: commonjs to module: esnext. The Nx @nx/js:library --bundler=
tsc generator emits commonjs by default, but tsconfig.base.json
specifies moduleResolution: bundler, which TS only allows alongside
esnext or es2015+ modules. Without the alignment, those libs failed to
build (TS5095). All apps and libs now build green.
spartan-ng wiring is intentionally NOT in this commit. spartan-ng is
currently at 0.0.1-alpha.681 - clearly pre-1.0, which trips the
project rule against pre-1.0 dependencies. ADR-0016 chose spartan-ng
with the copy-paste mitigation, but the alpha state warrants an
explicit go/no-go decision before committing the workspace to it.
The Angular 21 unit-test builder (@angular/build:unit-test) defaults
to watch mode. Without an explicit option, 'pnpm nx test portal-shell'
hangs on 'Waiting for task' indefinitely - unsuitable for CI and
surprising for ad-hoc invocations.
Pin watch=false as the default in the target options. Add a 'watch'
configuration so developers who want continuous test running can opt
in with 'pnpm nx test portal-shell --configuration=watch'. portal-bff
uses Jest which defaults to no-watch and needs no change.
Add the @nx/angular, @nx/nest, @nx/vite, @nx/eslint plugins, then
generate the two apps. Adjust the empty-template tsconfig.base.json
to be Angular-compatible (drop project references and customConditions
that the empty-template defaults to but Angular doesn't support; keep
the strict-TS extensions from ADR-0004).
apps/portal-shell (Angular 21):
- standalone APIs, routing, SCSS, esbuild
- vitest-angular as unitTestRunner, playwright for e2e
- strict mode
- tags scope:portal-shell, type:app
- app.config.ts wired with provideZonelessChangeDetection() per
ADR-0004 (Angular 21 + Nx 22 generates without zone.js by default)
apps/portal-bff (NestJS 11):
- Express adapter (default per ADR-0005)
- Jest as unitTestRunner
- tags scope:portal-bff, type:app
- main.ts wired with a global ValidationPipe configured
whitelist + forbidNonWhitelisted + transform per ADR-0005
- Phase-2 security additions (helmet, CORS, sessions, CSRF, rate
limit, auth guards, error filter) deferred to their respective
ADRs - placeholder comment in main.ts
Workspace dependencies: class-validator + class-transformer added
(required by NestJS ValidationPipe at runtime). Nx-generated
.gitignore additions (.angular, __screenshots__) merged into ours.
.vscode/extensions.json and launch.json added by Nx are kept (do not
override our existing settings.json).