The architect approved the four ADR-fix tickets. All four change what the architecture documents claim. No code changes. ADR-0001, ADR-C-001: the worked example claimed the POC has no real backend. It rewrites against `backend/src/BigRegister.Api`. Every path it named is repointed. The out-of-scope list drops two discharged bullets: 33 `parse*` boundaries exist, and `npm run gen:api` is real. ADR-0001, ADR-C-003: a new section states that the generated client is the wire contract. A hand-written `contracts/*.dto.ts` is the exception for two cases only. The four survivors stay, because NSwag emits every property as optional and flattens `RegistrationStatusDto` into five optional strings. The `parse*` trust boundary stays mandatory, because a generated type is a compile-time claim about the wire and not a runtime guarantee. ADR-0003, ADR-C-007: four paths moved in WP-67 and are repointed. Point 4 kept the principle and changed its example to `skeleton` and `spinner`. Two of its claims were false and the amendment says so: `app-alert` wraps the vendored `.feedback` classes, and `site-header` composes the vendored `.titlebar`. ADR-0004, ADR-C-009: the exception section states a four-part test instead of one named exception. `OrgTemplateStore` and `FeatureFlagStore` both pass it. RB-07 gated this ticket, because clause 4 needs an audited allow path. RB-07 landed that, so the ADR does not ratify a control that the code lacks. Three tickets need a matching CLAUDE.md correction in the same diff. CLAUDE.md section 2 loses the false `alert` example. Section 4 gets the generated-client rule and the four-part test. Two findings were wrong. ADR-C-001 asked to keep an out-of-scope bullet that reads "SessionStore is in-memory". The session persists to `localStorage` now, so the bullet covers multi-tab sync only. ADR-C-007 flagged one half of point 4 and missed that the other half is equally false. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.2 KiB
ADR-0003 — Adopt the CIBG Huisstijl (Bootstrap 5.2) as the design system
Status: Accepted · Date: 2026-07-02
Context
The portal must adhere visually to the CIBG design system (designsystem.cibg.nl) — CIBG runs
the real BIG-register. Until now the app was themed with Rijkshuisstijl-Community / Utrecht
(@rijkshuisstijl-community/components-css + design-tokens), emitting utrecht-*/rhc-* classes
and consuming a --rhc-* CSS-custom-property token set.
CIBG Huisstijl (@cibg/huisstijl, v3.22.0) is a customized build of Bootstrap 5.2.0: standard
Bootstrap CSS classes (btn, form-control, card, table, breadcrumb) themed via SCSS variable
overrides, with a full --bs-* runtime variable surface. For SPA frameworks it is CSS-only — no
Bootstrap JS (the framework drives interactivity). The two systems share neither class names nor
tokens, so adopting CIBG is a re-skin of the shared component layer plus a replacement of the token
layer — not a palette swap.
Decision
-
Vendor the package under
public/cibg-huisstijl/(not an npm dep — it was delivered as files), loaded via a<link>in each app'sindex.html(apps/ssp/src/index.htmlandapps/behandelportal/src/index.html— two since WP-67) so the CSS's relativeurl(../fonts|icons|images)references resolve at runtime.public/stays at the repo root and both apps'angular.jsontargets copy it. Both Storybook instances serve the same viastaticDirs: ['../public']. -
Token bridge over token rewrite.
libs/shared/styles.scss— one copy, both apps'angular.jsonpoint at it (WP-67) — redefines the app's ~54--rhc-*tokens onto CIBG values (--bs-*where one exists, CIBG palette hex otherwise). The--rhc-*names are now an internal alias set; the values are CIBG. This avoided rewriting 300+ token references and keeps the "components reference tokens" convention intact. (libs/shared/styles.scssis exempt fromcheck:tokens, so palette hex lives in that one file only.) -
Re-skin atoms, keep their
input()APIs. Eachshared/uiatom now emits Bootstrap/CIBG classes (app-button→btn btn-primary,text-input→form-control, radio/checkbox →form-check-*); domain pages compose the same atoms and barely changed. -
Hand-roll what CIBG's build drops, and mark it. Where the vendored build has no class for a concept, the component is a small token-styled surface carrying a
// CIBG-GAP EXTENSION:marker. The clearest live examples areskeletonandspinner: CIBG documents "Laadindicatie" but the vendored build ships no loading-skeleton or loading-spinner class, so both are built from the token bridge. Local class names that collide with Bootstrap components were renamed (.card→.app-card, badge →.status-badge).Two claims this point used to make were wrong and are corrected here.
.alertis not a gap:app-alertis a thin wrapper over the vendored.feedback feedback-*classes — the design system owns surface and icon, and the component adds only the icon's a11y label and a flex fix. It carries no gap marker, correctly. The header is not hand-rolled either:site-headercomposes the vendored.titlebarand.logo__*classes and leaves the robijn fill (--ro-layout) untouched. Theshelltemplate's.layout/.main/.contentclasses are page scaffolding, not a substitute for a missing design-system component, so they carry no marker either. -
System-font stack; no licensed fonts.
--bs-font-sans-serifis overridden tosystem-ui; the licensed RO/Rijks text woffs are removed from the vendored copy (CIBG icon font kept). Logo stays a text wordmark. Interactivity stays Angular-driven (no Bootstrap JS).
Consequences
- Wiring the design system touches
libs/shared/styles.scss(token bridge), both apps'index.html, bothangular.jsontargets (public/already copied), and both Storybook config dirs (.storybook-ssp/and.storybook-behandelportal/— separate since WP-67, because a single merged tsconfig cannot resolve both apps'@auth/*at once) — plus the class strings in ~40libs/shared/ui+libs/shared/layout+ a few domain components. The@rijkshuisstijl-community/*deps are dropped. check:tokensstill guards raw hex in components; the token bridge + hand-rolled surfaces comply.- Known benign build warning: "Unable to locate stylesheet: /cibg-huisstijl/css/huisstijl.min.css" —
Angular's index optimizer doesn't process a
public/stylesheet at build time. The asset is copied and the link is preserved (verified: served 200,.btn-primarypresent); the build exits green. The alternative (adding the CSS toangular.jsonstyles) would force-bundle the licensed fonts we intentionally dropped, so we accept the warning. - Renaming the internal token names from
--rhc-*to--app-*is possible later but out of scope. - Hand-rolled components (point 4) are tracked in the CIBG gap register
(
libs/shared/docs/cibg-gaps.mdx, Storybook "Foundations/CIBG Gap Register"): every deviation from the design system carries a// CIBG-GAP EXTENSION:marker so it's auditable rather than silently drifting.