refactor(auth): share the actor-agnostic route guards (ADR-C-006)
authGuard and capabilityGuard were duplicated byte-for-byte across both
apps, along with their specs — 57 of the 211 duplicated lines BL-002
measured in the two auth contexts, the largest block after session.store.ts.
They are not actor-specific. They ask "is anyone logged in" and "may they do
X", never "who are you or how did you get here". ADR-0002 §3's non-sharing
decision scopes to identity and login flow — Principal, DigiD vs employee
SSO — and a route guard is neither; §Consequences names auth.guard.ts only
as a seam that localises the change, not as something that must be
duplicated.
Moves both to libs/shared/src/application/auth.guard.ts, reading SESSION_PORT
instead of an app-local SessionStore. The port gains one member,
isAuthenticated: Signal<boolean> — free, because both SessionStores already
expose exactly that (session.store.ts:40) and both apps already register
{ provide: SESSION_PORT, useExisting: SessionStore }. The seam existed; it
was just narrower than what it already carried.
Each app keeps a re-export at @auth/auth.guard so app.routes.ts is untouched
— routing asks the auth context for its guards, which is the direction the
boundary should read. The two identical specs collapse into one, plus a case
asserting the guard resolves through the port.
Deliberately NOT merged: session.store.ts, session.ts, digid.adapter.ts,
login-form.component.ts, login.page.ts. Those are identical only because
ADR-C-004 (Session -> Principal) was never executed. Merging them would make
a citizen DigiD/BSN login the backoffice's shared login.
Measured with tools/baseline-scan.mjs: ssp/auth duplicated lines 211 -> 151,
bhp/auth 86.8% -> 82.5%, repo-wide 7.1% -> 6.6%. Both guard clone pairs drop
out of the top-clones list. What remains is exactly the three files
ADR-C-004 should differentiate.
behaviour-spec.mdx regenerated (the spec moved libraries).
Verified: lint, typecheck, dep:check (0 violations, 224 modules), prettier,
ng build --localize for both apps, and 407 tests passing across all four
projects.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ tested where._
|
||||
|
||||
Every bullet below is a real test name from the suite — an `it()` title (frontend) or a test
|
||||
method name (backend), read as a sentence. Nothing here is hand-written prose: this page
|
||||
**is** the suite, reshaped for a business reader. 406 frontend behaviours across
|
||||
**is** the suite, reshaped for a business reader. 402 frontend behaviours across
|
||||
8 contexts; 217 backend behaviours across 36 test
|
||||
classes.
|
||||
|
||||
@@ -28,22 +28,6 @@ classes.
|
||||
|
||||
### auth
|
||||
|
||||
#### authGuard
|
||||
|
||||
- allows an authenticated user
|
||||
- redirects an anonymous user to /login
|
||||
- allows an authenticated user
|
||||
- redirects an anonymous user to /login
|
||||
|
||||
#### capabilityGuard
|
||||
|
||||
- waits for /me, then allows an entitled admin
|
||||
- sends an authenticated-but-unentitled user to /dashboard (not a login loop)
|
||||
- redirects an anonymous user to /login without waiting for caps
|
||||
- waits for /me, then allows an entitled admin
|
||||
- sends an authenticated-but-unentitled user to /dashboard (not a login loop)
|
||||
- redirects an anonymous user to /login without waiting for caps
|
||||
|
||||
#### isAuthenticated
|
||||
|
||||
- narrows a present session to Session
|
||||
@@ -614,6 +598,18 @@ classes.
|
||||
- map only touches Success
|
||||
- map2 precedence: Failure > Loading > Success
|
||||
|
||||
#### authGuard
|
||||
|
||||
- allows an authenticated user
|
||||
- redirects an anonymous user to /login
|
||||
|
||||
#### capabilityGuard
|
||||
|
||||
- waits for /me, then allows an entitled admin
|
||||
- sends an authenticated-but-unentitled user to /dashboard (not a login loop)
|
||||
- redirects an anonymous user to /login without waiting for caps
|
||||
- reads authentication through the port, not an app-local store
|
||||
|
||||
#### createDebouncedSave
|
||||
|
||||
- flushes after the delay when canSave is true
|
||||
|
||||
Reference in New Issue
Block a user