Julien Gautier 13a12e6591
CI / commits (pull_request) Successful in 1m9s
CI / scan (pull_request) Successful in 1m21s
CI / check (pull_request) Successful in 1m35s
CI / a11y (pull_request) Successful in 1m25s
CI / perf (pull_request) Successful in 2m38s
feat(portal-shell): wire spa-side opentelemetry tracing
Phase 2 of ADR-0012 — closes the loop SPA → BFF → DB. With this
PR a single user action (page load, click, form submit) produces
one trace whose root span is owned by the SPA and whose child
spans cover the BFF request, Postgres queries, and (eventually)
Redis / downstream-API hops.

Runtime libs added (production deps):

- @opentelemetry/sdk-trace-web              browser tracer + provider
- @opentelemetry/exporter-trace-otlp-http   OTLP/HTTP+JSON exporter
- @opentelemetry/instrumentation            auto-instrumentation runtime
- @opentelemetry/instrumentation-fetch      fetch + W3C traceparent propagation
- @opentelemetry/instrumentation-document-load  initial-paint timings
- @opentelemetry/instrumentation-user-interaction  click / keypress / submit

Code:

- apps/portal-shell/src/observability/tracing.ts — WebTracerProvider
  bootstrap. Documents the load-order constraint inline (must be
  the very first import of main.ts, same pattern as the BFF). No
  context-zone package because the workspace is zoneless (per
  ADR-0004); the default StackContextManager covers the
  auto-instrumentation cases.
- main.ts now imports the tracing module as line 1.

CORS plumbing for end-to-end propagation:

- BFF (apps/portal-bff/src/main.ts) calls enableCors with a
  minimal dev allowlist (http://localhost:4200) and explicit
  permission for the W3C traceparent and tracestate headers. The
  full security-grade CORS belongs to phase-2 security ADR; this
  is the strict minimum for the SPA→BFF link to keep the trace
  context across origins.
- OTel Collector (infra/local/otel-collector.yaml) gains a cors
  block on its OTLP/HTTP receiver so the browser's OTLP POST
  clears its own pre-flight.

ADR-0012 §Confirmation: a new "Wired in the SPA foundation PR
(phase 2)" block enumerates what landed here; the carry-over
"Wired as features land" list is updated to drop the SPA-side
SDK item that used to live there and to add a CORS-grade
follow-up note.

Verified locally:
- pnpm exec nx run-many -t lint test build → 8 projects green.
- pnpm audit clean.
- After ./infra/local/dev.sh up observability and nx serve
  portal-shell, opening http://localhost:4200 produces a
  document_load trace in Jaeger with the SPA service.name; a
  manual fetch from DevTools to /api/health on the BFF produces
  a child span on the same trace.
2026-05-09 23:18:42 +02:00

Documentation index

This is the entry point to all project documentation. It is maintained automatically: any addition, rename, or removal of a .md file under docs/ must be reflected here in the same change.

Conventions

  • Documentation is written in English.
  • One topic per file. Group related files into a folder when there are three or more.
  • Cross-reference with relative links so they keep working in GitHub, IDEs, and exported sites.
  • For architectural decisions, do not add them here — they belong in decisions/ as MADR 4.0.0 ADRs.

Sections

Daily development

  • development.md — repo layout, prerequisites, initial setup, daily commands, dependency updates (Renovate), conventional commit cycle. Day-to-day reference for working on the project.

Architecture

  • architecture.md — cross-cutting Mermaid diagrams: C4 system context, C4 containers, Nx module boundaries, CI/CD pipeline. Single-decision diagrams (auth sequence, ERD, etc.) live inline in their ADR.

Onboarding & environment

Setup guides for new contributors:

Operations & runbooks

Empty — to be populated when we deploy.

Security, performance, accessibility

Empty — placeholders to be filled with rationale docs alongside their corresponding ADRs.

S
Description
No description provided
Readme 42 MiB
Languages
TypeScript 85.3%
JavaScript 5.4%
SCSS 4.3%
HTML 3.9%
Shell 0.8%
Other 0.3%