Files
apf_portal/apps/portal-shell/src/environments/environment.ts
T
Julien Gautier 04138b435a
CI / scan (pull_request) Successful in 4m4s
CI / commits (pull_request) Successful in 4m4s
CI / check (pull_request) Successful in 4m59s
CI / a11y (pull_request) Successful in 1m31s
CI / perf (pull_request) Successful in 5m25s
feat(portal): /api/me/capabilities + cross-app menu links + real role label
PR 3 of 3 — final piece of the user-menu / profile / cross-app
chantier.

BFF
  * New `MeModule` ships `GET /api/me/capabilities`, a curated view
    derived from the active user-portal session. Returns
    `{ canAccessAdmin: boolean }` today; the shape is deliberately
    binary so the SPA cannot reconstruct the raw `roles` claim. 401
    on missing session, consistent posture with `/auth/me`.
  * ADR-0009 amended: new "Curated public view" section codifies
    the "no raw roles on `/auth/me`, capabilities is the release
    valve" stance; the routes table grows a row for the endpoint.

portal-shell
  * New `CapabilitiesService` (app-local) calls the BFF on auth-state
    flip and exposes `canAccessAdmin` as a signal. Anonymous
    sessions short-circuit to the all-false default without firing
    a request.
  * Header's `userMenuItems` is now a `computed` — the "Open Portal
    Admin" entry appears in the dropdown only when
    `canAccessAdmin()` is true, pointing at
    `environment.adminAppUrl`.
  * Sidebar role widget reads the auth + capabilities signals to
    render one of three labels ("Anonymous" / "User" /
    "Administrator") in place of the hardcoded "Anonymous".

portal-admin
  * Symmetric: unconditional "Open Portal Shell" entry in the admin
    user menu, pointing at `environment.shellAppUrl`. Anyone who
    can reach portal-admin can reach portal-shell, so no
    capabilities check needed.

i18n
  * `header.userMenu.openAdmin`, `sidebar.role.{administrator,user}`,
    `sidebar.role.aria` reshaped to take the role as a placeholder.
2026-05-15 16:05:50 +02:00

54 lines
2.1 KiB
TypeScript

/**
* Per-environment configuration for the SPA, per ADR-0018.
*
* This file holds the **dev defaults** and is the one checked in.
* Per-environment siblings (`environment.staging.ts`,
* `environment.prod.ts`) land alongside this file later; the
* production / staging build configurations in `project.json` declare
* a `fileReplacements` entry that swaps this file for the target one
* at build time.
*
* Constraint: every sibling must export an `environment` object of
* the same shape. TypeScript will catch missing keys at the
* consuming site once a sibling exists.
*
* Nothing here is a secret. The SPA is a static bundle; secrets that
* ever needed to live here would, by definition, be public. Per-user
* / per-tenant secrets live in the BFF session payload (ADR-0010).
*/
export const environment = {
/**
* Origin + prefix of the BFF HTTP API. The SPA prepends this to
* every backend call (`${bffApiBaseUrl}/health`, etc.) and derives
* the OTel trace-header propagation pattern from its origin (see
* `observability/tracing.ts`).
*/
bffApiBaseUrl: 'http://localhost:3000/api',
/**
* Name of the BFF's CSRF cookie. Mirrors the BFF's
* `csrfCookieName()` convention: `__Host-portal_csrf` in
* production (Secure-required, hence excluded from HTTP dev),
* `portal_csrf` otherwise. Read by the `csrfInterceptor` to
* echo the value back in the `X-CSRF-Token` request header.
*/
bffCsrfCookieName: 'portal_csrf',
/**
* OTLP/HTTP traces endpoint. Targets the Collector in
* `infra/local/dev.compose.yml`. CORS is enabled there — see
* `infra/local/otel-collector.yaml`.
*/
otlpEndpoint: 'http://localhost:4318/v1/traces',
/**
* Origin of the sibling `portal-admin` SPA — driver of the
* cross-app "Open Portal Admin" entry in the user menu (gated on
* `CapabilitiesService.canAccessAdmin`). Per ADR-0020 the two
* SPAs live on distinct origins / cookies / sessions, so this is
* a raw cross-origin `<a href>` jump, not an Angular route.
* Per-env siblings override the host.
*/
adminAppUrl: 'http://localhost:4300',
};