feat(portal-admin): profile page on /profile guarded by authGuard
CI / scan (pull_request) Successful in 2m38s
CI / commits (pull_request) Successful in 2m47s
CI / check (pull_request) Successful in 4m31s
CI / a11y (pull_request) Successful in 1m51s
CI / perf (pull_request) Successful in 5m35s

PR 2 of 3 from the user-menu chantier.

* New lazy-loaded `/profile` route in `apps/portal-admin`. Renders
  the active admin session's identity card (displayName, username,
  oid, tid) plus an "App roles" card listing the Entra app-role
  claims attached to the session — `Portal.Admin` today, additional
  business roles when the strategic security baseline ADR lands.
* `authGuard` (from `feature-auth`) gates the route — anonymous
  visitors bounce through the BFF's `/api/admin/auth/login`. The
  template's `@if (user())` then narrows the type so the page can
  drop the anonymous branch.
* The `User Menu`'s Profile entry (PR 1) already points at `/profile`
  so the link starts working on this surface as soon as this lands.
* `CurrentUser.roles` extended with an optional `readonly string[]`
  — the admin-side `/api/admin/auth/me` already returns the claim;
  the type now captures it. User-portal `/me` keeps omitting it per
  ADR-0009 (PR 3 surfaces it via the dedicated capabilities endpoint).
* Lazy chunk lands at 5.37 KB raw / 1.57 KB gzip — comfortably under
  the lazy-chunk budget.
This commit is contained in:
Julien Gautier
2026-05-15 15:41:16 +02:00
parent a8ead65ea8
commit 3b3cd1dc66
7 changed files with 329 additions and 0 deletions
+8
View File
@@ -1,8 +1,10 @@
import { Route } from '@angular/router';
import { authGuard } from 'feature-auth';
const homeTitle = $localize`:@@route.home.title:APF Portal Admin`;
const auditTitle = $localize`:@@route.audit.title:Audit log — APF Portal Admin`;
const usersTitle = $localize`:@@route.users.title:Users — APF Portal Admin`;
const profileTitle = $localize`:@@route.profile.title:Profile — APF Portal Admin`;
export const appRoutes: Route[] = [
{
@@ -21,6 +23,12 @@ export const appRoutes: Route[] = [
loadComponent: () => import('./pages/users/users').then((m) => m.UsersPage),
title: usersTitle,
},
{
path: 'profile',
canActivate: [authGuard],
loadComponent: () => import('./pages/profile/profile').then((m) => m.ProfilePage),
title: profileTitle,
},
// Catch-all — unknown paths bounce to home. Same role as the
// wildcard in portal-shell (per PR #96): in production each locale
// bundle ships with its own `<base href="/{locale}/">` and the