docs(development): refresh after phase-3a + add topology / trace diagrams (#160)
## Summary `docs/development.md` drifted as `portal-admin` shipped, the docs site landed, Prisma stayed pinned at 6.x, and a fair chunk of the phase-2 "to come" roadmap quietly turned into "shipped". Surgical refresh of the affected sections + two Mermaid diagrams where prose alone wasn't carrying the cognitive load. ## What changed ### Section 1 — Repo layout - `apps/portal-admin/` + `apps/portal-admin-e2e/` added (both exist on `main` since #134, were never reflected in the tree). - `prisma.config.ts` removed (phantom — Prisma 6.x doesn't ship one). The "Prisma 7" tag corrected to "Prisma 6.x" with the [ADR-0006](docs/decisions/0006-persistence-postgresql-prisma.md) pin reference. - `docs/index.md`, `docs/architecture.md`, `docs/.vitepress/` added. - New workflows listed: `docs-site.yml`, `renovate.yml`. ### Section 3 — Initial setup, new diagram Mermaid `flowchart` of the local-dev topology. Host-side dev servers (`portal-shell:4200`, `portal-admin:4300`, `portal-bff:3000`, `docs:5173`) ↔ Compose containers (Postgres, Redis, OTel) ↔ viewer profiles (Jaeger, pgweb). Replaces a ports/services context that was scattered across §3 and §5. ### Section 4 — Daily commands - `portal-admin` added to serve / test / generate examples. - Single-test-file recipe corrected: Nx's vitest executor rejects `--testFile` (we hit this empirically while debugging the sidebar spec for #151). The new wording recommends positional path for Vitest, `--testPathPattern=…` for Jest. - **New "Documentation site" subsection** with the three commands (`docs:dev`, `docs:build`, `docs:preview`), plus the recipe for adding an ADR. ### Section 5 — Observability, new diagram Mermaid `sequenceDiagram` showing how a click becomes a trace: browser `user_interaction` span → `traceparent` header → BFF span → Pino log line with matching `trace_id` → OTLP batch → Jaeger UI. Anchors the prose's "trace_id is the correlation point" rule with a visual. ### Section 6 — Renovate New subsection **"Transitive vulnerabilities — `pnpm.overrides`"**. Documents the pattern from #159 so the next contributor hitting a transitive vuln (Renovate silent, dashboard empty) has the playbook on hand without re-discovering it. ### Section 9 — Sections to come Restructured into two groups: - **Code shipped — doc to write** (Auth dev-loop, session inspection, MFA step-up debugging, admin surface walkthroughs, audit-log workflow, downstream API recipe, OpenAPI/Scalar workflow, capabilities-driven SPA UX). The code is on `main`; only the prose is missing. Each entry now cites the PR(s) that landed the implementation. - **Not yet** (component patterns library, a11y testing workflow, perf debugging, release workflow, GitLab migration runbook). Both code and doc still pending. ## Notes for the reviewer - **Why diagrams now, not at the next chantier?** Two pieces of context were genuinely easier to grasp visually than as prose lists: the local-dev topology (which port goes where), and the trace-correlation flow. The other sections (Renovate, conventional commits, CI gates) already read well as tables — adding diagrams there would be ornament, not signal. - **Why two diagrams rather than ten?** Per the user instruction "use diagrams when useful" — restraint applies. The two added are the ones that *replace* explanatory prose rather than add to it. - **Why didn't I rewrite the "to come" roadmap from scratch?** The phase mapping was useful intent — kept the same structure, just moved entries between the two columns as code-shipping unlocked them. Future re-shuffles stay cheap. - **The doc still has phase-1 framing in places** (e.g. the "this doc starts as a phase-1 reference" paragraph in §9). I left it — promoting the doc to "phase-3a reference" is a larger editorial pass than this refresh deserves; the new diagrams + section-9 split already do the practical work. - **Open questions deferred to a future pass**: the §2 "Prerequisites" table doesn't mention the docs site (`pnpm docs:dev` adds nothing to the prereqs list — just Node + pnpm, both already required). Leaving the table as is. ## Test plan - [x] `rm -rf docs/.vitepress/{cache,dist} && pnpm docs:build` — clean, 6.3 s. - [x] Mermaid renders inside `docs/.vitepress/dist/development.html` — both new diagrams produce `class="mermaid"` markers. `grep -c 'class="mermaid"\|<svg' development.html` → **2**. - [ ] Visual smoke: `pnpm docs:dev`, navigate to `/development`, confirm both diagrams render (topology with port labels readable, sequence diagram with the trace flow). Toggle dark mode, confirm diagrams flip theme. - [ ] Spot-check the "Code shipped — doc to write" table — for any contributor reading this PR, do the PR-number citations match their memory of when each chantier landed? (`auth ≈ ADR-0009 series`, `admin ≈ #127, #128, #134, #136, #140–142`, `downstream ≈ #137–139`, `OpenAPI ≈ #143`, `capabilities ≈ #151`). ## What's next The two largest "doc to write" entries (Auth dev-loop, Audit-log inspection workflow) are good candidates for the next docs chantier — both have shipped code, RSSI-relevant content, and would benefit from a guided walkthrough. Not blocking anything; pick when the team has bandwidth. --------- Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr> Reviewed-on: #160
This commit was merged in pull request #160.
This commit is contained in:
+145
-30
@@ -12,6 +12,8 @@ For decision rationale, see the [ADRs](decisions/). For onboarding the local env
|
|||||||
apf_portal/
|
apf_portal/
|
||||||
├── .gitea/workflows/ # CI pipelines (ADR-0015)
|
├── .gitea/workflows/ # CI pipelines (ADR-0015)
|
||||||
│ ├── ci.yml # per-PR + push to main: check / scan / commits / perf / a11y
|
│ ├── ci.yml # per-PR + push to main: check / scan / commits / perf / a11y
|
||||||
|
│ ├── docs-site.yml # build docs site on PR + push (ADR-0022)
|
||||||
|
│ ├── renovate.yml # daily Renovate run (cron 03:00 UTC)
|
||||||
│ └── security-scheduled.yml # weekly full-tree scan + prod Lighthouse
|
│ └── security-scheduled.yml # weekly full-tree scan + prod Lighthouse
|
||||||
├── .github/ # Nx AI-tooling skills, prompts, agents (Nx-managed)
|
├── .github/ # Nx AI-tooling skills, prompts, agents (Nx-managed)
|
||||||
├── .husky/ # local git hooks (ADR-0007)
|
├── .husky/ # local git hooks (ADR-0007)
|
||||||
@@ -19,34 +21,42 @@ apf_portal/
|
|||||||
│ └── commit-msg # → pnpm exec commitlint
|
│ └── commit-msg # → pnpm exec commitlint
|
||||||
├── apps/
|
├── apps/
|
||||||
│ ├── portal-shell/ # Angular 21 SPA (zoneless, standalone, Signals, Vitest, SCSS)
|
│ ├── portal-shell/ # Angular 21 SPA (zoneless, standalone, Signals, Vitest, SCSS)
|
||||||
│ │ ├── public/ # static assets
|
│ │ ├── public/ # static assets (incl. /logos)
|
||||||
│ │ ├── src/ # entry, app config, routes, styles
|
│ │ ├── src/ # entry, app config, routes, styles, locales
|
||||||
│ │ ├── .postcssrc.json # Tailwind PostCSS plugin (required by @angular/build esbuild — postcss.config.js is ignored)
|
│ │ ├── .postcssrc.json # Tailwind PostCSS plugin (required by @angular/build esbuild — postcss.config.js is ignored)
|
||||||
│ │ └── project.json # Nx project config (build, serve, test, lint targets)
|
│ │ └── project.json # Nx project config (build, serve, test, lint targets)
|
||||||
│ ├── portal-shell-e2e/ # Playwright e2e for portal-shell
|
│ ├── portal-shell-e2e/ # Playwright e2e for portal-shell
|
||||||
|
│ ├── portal-admin/ # Angular 21 SPA (admin surface, distinct origin + session per ADR-0020)
|
||||||
|
│ │ ├── public/ # static assets (incl. /logos)
|
||||||
|
│ │ ├── src/ # entry, app config, routes, audit + users + profile pages
|
||||||
|
│ │ └── project.json
|
||||||
|
│ ├── portal-admin-e2e/ # Playwright e2e for portal-admin
|
||||||
│ ├── portal-bff/ # NestJS 11 BFF (Express adapter, ValidationPipe, Jest)
|
│ ├── portal-bff/ # NestJS 11 BFF (Express adapter, ValidationPipe, Jest)
|
||||||
│ │ ├── src/ # main, app module, controllers, services
|
│ │ ├── src/ # main, app module, controllers, services
|
||||||
│ │ ├── prisma/schema.prisma # Prisma 7 schema (postgresql)
|
│ │ ├── prisma/schema.prisma # Prisma 6.x schema (PostgreSQL) — pin documented in ADR-0006
|
||||||
│ │ ├── prisma.config.ts # Prisma 7 TS config (loads DATABASE_URL from .env)
|
|
||||||
│ │ ├── .env.example # env-vars catalog (committed); .env stays gitignored
|
│ │ ├── .env.example # env-vars catalog (committed); .env stays gitignored
|
||||||
│ │ └── project.json
|
│ │ └── project.json
|
||||||
│ └── portal-bff-e2e/ # Jest e2e for portal-bff
|
│ └── portal-bff-e2e/ # Jest e2e for portal-bff
|
||||||
├── libs/
|
├── libs/
|
||||||
│ ├── feature/<name>/ # vertical feature libs (e.g. feature-auth)
|
│ ├── feature/<name>/ # vertical feature libs (e.g. feature-auth)
|
||||||
│ └── shared/<scope>/ # cross-cutting libs (tokens, ui, util)
|
│ └── shared/<scope>/ # cross-cutting libs (state, tokens, ui, util)
|
||||||
├── docs/
|
├── docs/
|
||||||
│ ├── README.md # doc index
|
│ ├── README.md # doc index (git/IDE side — excluded from the docs site)
|
||||||
|
│ ├── index.md # VitePress home (Hero layout, see ADR-0022)
|
||||||
|
│ ├── architecture.md # cross-cutting Mermaid diagrams (C4, module boundaries, CI)
|
||||||
|
│ ├── development.md # this file
|
||||||
│ ├── decisions/ # ADRs (MADR 4.0.0)
|
│ ├── decisions/ # ADRs (MADR 4.0.0)
|
||||||
│ ├── setup/ # local-environment onboarding (Zsh, pnpm, Nx workspace)
|
│ ├── setup/ # local-environment onboarding (Zsh, pnpm, Nx workspace)
|
||||||
│ └── development.md # this file
|
│ └── .vitepress/ # VitePress config + build cache (gitignored)
|
||||||
├── notes/ # personal scratchpad (gitignored)
|
├── notes/ # personal scratchpad (gitignored)
|
||||||
├── CLAUDE.md # project rules + architecture summary
|
├── CLAUDE.md # project rules + architecture summary
|
||||||
├── commitlint.config.cjs # Conventional Commits config
|
├── commitlint.config.cjs # Conventional Commits config
|
||||||
├── eslint.config.mjs # workspace ESLint with module boundaries
|
├── eslint.config.mjs # workspace ESLint with module boundaries
|
||||||
├── lighthouserc.js # Lighthouse CI thresholds (ADR-0017)
|
├── lighthouserc.js # Lighthouse CI thresholds (ADR-0017)
|
||||||
├── nx.json # Nx workspace config
|
├── nx.json # Nx workspace config
|
||||||
├── package.json # workspace deps + scripts
|
├── package.json # workspace deps + scripts (incl. pnpm.overrides for transitive remediation)
|
||||||
├── pnpm-workspace.yaml # apps/* + libs/**
|
├── pnpm-workspace.yaml # apps/* + libs/**
|
||||||
|
├── renovate.json # Renovate config (groupings, dashboard, vuln alerts)
|
||||||
├── tsconfig.base.json # shared TS strict config
|
├── tsconfig.base.json # shared TS strict config
|
||||||
└── vitest.workspace.ts # Vitest workspace projects
|
└── vitest.workspace.ts # Vitest workspace projects
|
||||||
```
|
```
|
||||||
@@ -123,6 +133,46 @@ cp apps/portal-bff/.env.example apps/portal-bff/.env
|
|||||||
|
|
||||||
`./infra/local/dev.sh help` lists the rest of the verbs (`down`, `status`, `logs`, `stop`, `restart`, `exec`). Full reference — service inventory, port table, persistence, bootstrap re-run procedure — lives in [`infra/README.md`](../infra/README.md) → "Local-dev stack".
|
`./infra/local/dev.sh help` lists the rest of the verbs (`down`, `status`, `logs`, `stop`, `restart`, `exec`). Full reference — service inventory, port table, persistence, bootstrap re-run procedure — lives in [`infra/README.md`](../infra/README.md) → "Local-dev stack".
|
||||||
|
|
||||||
|
### Topology at a glance
|
||||||
|
|
||||||
|
How the pieces fit together once the stack is up — three Node dev servers on the host, the infrastructure containers behind Docker Compose, optional viewer profiles for inspection:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph host["Dev host (WSL2 / Linux / macOS)"]
|
||||||
|
direction TB
|
||||||
|
shell["portal-shell<br/><code>:4200</code>"]
|
||||||
|
admin["portal-admin<br/><code>:4300</code>"]
|
||||||
|
bff["portal-bff<br/><code>:3000</code>"]
|
||||||
|
docs["docs site<br/><code>:5173</code><br/>(VitePress)"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph compose["infra/local/ (Docker Compose)"]
|
||||||
|
direction TB
|
||||||
|
pg[("Postgres<br/><code>:5432</code>")]
|
||||||
|
redis[("Redis<br/><code>:6379</code>")]
|
||||||
|
otel["OTel Collector<br/><code>:4318</code>"]
|
||||||
|
subgraph obs["observability profile"]
|
||||||
|
jaeger["Jaeger UI<br/><code>:16686</code>"]
|
||||||
|
end
|
||||||
|
subgraph dbt["dbtools profile"]
|
||||||
|
pgweb["pgweb<br/><code>:8081</code>"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shell -. "<code>/api/*</code>" .-> bff
|
||||||
|
admin -. "<code>/api/admin/*</code>" .-> bff
|
||||||
|
bff --> pg
|
||||||
|
bff --> redis
|
||||||
|
bff -- "OTLP" --> otel
|
||||||
|
shell -- "OTLP/HTTP<br/>spans" --> otel
|
||||||
|
admin -- "OTLP/HTTP<br/>spans" --> otel
|
||||||
|
otel --> jaeger
|
||||||
|
pgweb --- pg
|
||||||
|
```
|
||||||
|
|
||||||
|
The docs site lives off to the side — it has no runtime dependency on the BFF or the infra stack and only reads files under `docs/`. Same goes for the SPAs from `portal-shell` to `portal-admin`: each runs its own dev server with its own port, talks to the same BFF, but holds a **distinct session cookie** (per [ADR-0020](decisions/0020-portal-admin-app.md) §"Sessions — distinct from `portal-shell`").
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Daily commands
|
## 4. Daily commands
|
||||||
@@ -131,26 +181,27 @@ cp apps/portal-bff/.env.example apps/portal-bff/.env
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm nx serve portal-shell # http://localhost:4200 (Angular dev server)
|
pnpm nx serve portal-shell # http://localhost:4200 (Angular dev server)
|
||||||
|
pnpm nx serve portal-admin # http://localhost:4300 (Angular dev server)
|
||||||
pnpm nx serve portal-bff # http://localhost:3000/api (NestJS)
|
pnpm nx serve portal-bff # http://localhost:3000/api (NestJS)
|
||||||
```
|
```
|
||||||
|
|
||||||
Both can run in parallel in two terminals; the SPA proxies API calls to the BFF in dev.
|
All three can run in parallel in separate terminals; the SPAs proxy API calls to the BFF in dev. Each SPA holds its own cookie / session — signing in to one does not authenticate the other (per [ADR-0020](decisions/0020-portal-admin-app.md)).
|
||||||
|
|
||||||
### Test
|
### Test
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm nx test portal-shell # Vitest (single run; --configuration=watch for watch mode)
|
pnpm nx test portal-shell # Vitest (single run; --configuration=watch for watch mode)
|
||||||
|
pnpm nx test portal-admin # Vitest
|
||||||
pnpm nx test portal-bff # Jest
|
pnpm nx test portal-bff # Jest
|
||||||
|
|
||||||
pnpm nx run-many -t test # all projects
|
pnpm nx run-many -t test # all projects
|
||||||
pnpm nx affected -t test # only projects affected since main
|
pnpm nx affected -t test # only projects affected since main
|
||||||
```
|
```
|
||||||
|
|
||||||
Run a single Vitest file:
|
Run a single test file:
|
||||||
|
|
||||||
```bash
|
- **Vitest projects** (`portal-shell`, `portal-admin`, `feature-auth`, `shared-*`): use a positional path filter — `pnpm nx test portal-shell --skip-nx-cache src/app/app.spec.ts`. `--testFile` is not accepted by the Nx vitest executor (`'testFile' is not found in schema`).
|
||||||
pnpm nx test portal-shell --testFile=src/app/app.spec.ts
|
- **Jest projects** (`portal-bff`): `pnpm nx test portal-bff --testPathPattern=src/auth/auth.service`.
|
||||||
```
|
|
||||||
|
|
||||||
### Lint, type-check, format
|
### Lint, type-check, format
|
||||||
|
|
||||||
@@ -178,8 +229,9 @@ pnpm nx affected -t build
|
|||||||
### Generate
|
### Generate
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Component in portal-shell
|
# Component (specify the SPA — `portal-shell` or `portal-admin`)
|
||||||
pnpm nx g @nx/angular:component <name> --project=portal-shell --standalone
|
pnpm nx g @nx/angular:component <name> --project=portal-shell --standalone
|
||||||
|
pnpm nx g @nx/angular:component <name> --project=portal-admin --standalone
|
||||||
|
|
||||||
# Service / controller / module in portal-bff
|
# Service / controller / module in portal-bff
|
||||||
pnpm nx g @nx/nest:service <name> --project=portal-bff
|
pnpm nx g @nx/nest:service <name> --project=portal-bff
|
||||||
@@ -190,7 +242,7 @@ pnpm nx g @nx/js:library --name=shared-<scope> --directory=libs/shared/<scope> \
|
|||||||
--bundler=tsc --unitTestRunner=vitest \
|
--bundler=tsc --unitTestRunner=vitest \
|
||||||
--tags="scope:shared,type:shared" --no-interactive
|
--tags="scope:shared,type:shared" --no-interactive
|
||||||
|
|
||||||
# New Angular feature lib (front-only)
|
# New Angular feature lib (front-only — usable by either SPA)
|
||||||
pnpm nx g @nx/angular:library --name=feature-<name> --directory=libs/feature/<name> \
|
pnpm nx g @nx/angular:library --name=feature-<name> --directory=libs/feature/<name> \
|
||||||
--standalone=true --unitTestRunner=vitest-analog \
|
--standalone=true --unitTestRunner=vitest-analog \
|
||||||
--tags="scope:portal-shell,type:feature" --no-interactive
|
--tags="scope:portal-shell,type:feature" --no-interactive
|
||||||
@@ -198,6 +250,18 @@ pnpm nx g @nx/angular:library --name=feature-<name> --directory=libs/feature/<na
|
|||||||
|
|
||||||
> Sweep generated files for `process.env.X` (dot notation) → `process.env['X']` (bracket notation), required by the strict-TS option `noPropertyAccessFromIndexSignature: true`. The Nx generators don't emit bracket form.
|
> Sweep generated files for `process.env.X` (dot notation) → `process.env['X']` (bracket notation), required by the strict-TS option `noPropertyAccessFromIndexSignature: true`. The Nx generators don't emit bracket form.
|
||||||
|
|
||||||
|
### Documentation site
|
||||||
|
|
||||||
|
`docs/**/*.md` renders as a VitePress site per [ADR-0022](decisions/0022-docs-site-vitepress.md). No Nx project for it — pure pnpm scripts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm docs:dev # http://localhost:5173 (HMR — edit a .md, see it live)
|
||||||
|
pnpm docs:build # static site → docs/.vitepress/dist/
|
||||||
|
pnpm docs:preview # serve the built site locally to smoke-test
|
||||||
|
```
|
||||||
|
|
||||||
|
Adding a new ADR is a single-file change: drop `docs/decisions/NNNN-kebab-title.md` (MADR 4.0.0 frontmatter, see [`template.md`](decisions/template.md)) and the sidebar auto-lists it. Update [`decisions/README.md`](decisions/README.md) in the same PR so the curated tag-grouped index stays in sync.
|
||||||
|
|
||||||
### Prisma
|
### Prisma
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -233,6 +297,32 @@ pnpm ci:perf # production build + Lighthouse CI against the static-served
|
|||||||
|
|
||||||
The BFF and the SPA are both wired with OpenTelemetry tracing and structured Pino logging (per [ADR-0012](decisions/0012-observability-pino-opentelemetry.md)). This section is the practical guide to using them while debugging — finding a trace, reading the logs that go with it, untangling a slow request.
|
The BFF and the SPA are both wired with OpenTelemetry tracing and structured Pino logging (per [ADR-0012](decisions/0012-observability-pino-opentelemetry.md)). This section is the practical guide to using them while debugging — finding a trace, reading the logs that go with it, untangling a slow request.
|
||||||
|
|
||||||
|
### How a click becomes a trace
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
actor U as User
|
||||||
|
participant SPA as portal-shell
|
||||||
|
participant BFF as portal-bff
|
||||||
|
participant Pino as BFF stdout (Pino)
|
||||||
|
participant OC as OTel Collector
|
||||||
|
participant J as Jaeger UI
|
||||||
|
|
||||||
|
U->>SPA: click
|
||||||
|
Note over SPA: span `user_interaction`<br/>(root, generates trace_id)
|
||||||
|
SPA->>BFF: fetch /api/foo<br/>traceparent: 00-<trace_id>-<span_id>-01
|
||||||
|
Note over SPA: span `fetch` (child)
|
||||||
|
Note over BFF: span `HTTP GET /api/foo`<br/>(continues same trace)
|
||||||
|
BFF->>Pino: log line<br/>`{ ...payload, trace_id, span_id, request_id }`
|
||||||
|
BFF-->>SPA: 200 OK
|
||||||
|
SPA-)OC: OTLP/HTTP batch (every ~5 s)
|
||||||
|
BFF-)OC: OTLP batch
|
||||||
|
OC-)J: forward spans
|
||||||
|
Note over J: trace_id matches the one in Pino<br/>full nested timeline visible
|
||||||
|
```
|
||||||
|
|
||||||
|
The single point of correlation between the two pillars is **`trace_id`**: Jaeger's URL bar carries it (`/trace/<hex>`), and `@opentelemetry/instrumentation-pino` injects the same value on every BFF log line emitted inside that request's scope. Grep one, navigate the other.
|
||||||
|
|
||||||
### Bring up the observability stack
|
### Bring up the observability stack
|
||||||
|
|
||||||
Traces land in the Jaeger UI bundled in `infra/local/dev.compose.yml` under the `observability` profile. The OpenTelemetry Collector runs in the core profile; without Jaeger active, traces still go to the Collector but nothing visualises them — they appear as warnings in `dev.sh logs otel-collector` and are dropped after the buffer fills.
|
Traces land in the Jaeger UI bundled in `infra/local/dev.compose.yml` under the `observability` profile. The OpenTelemetry Collector runs in the core profile; without Jaeger active, traces still go to the Collector but nothing visualises them — they appear as warnings in `dev.sh logs otel-collector` and are dropped after the buffer fills.
|
||||||
@@ -346,6 +436,22 @@ Repo → Actions → "Renovate" workflow → Run workflow. Useful when you've ju
|
|||||||
- For a major bump that introduces breaking changes, **don't reflexively merge**: read the changelog, then either accept the work or close the PR with a "rejected" label. Renovate respects that label and won't keep re-opening the same major.
|
- For a major bump that introduces breaking changes, **don't reflexively merge**: read the changelog, then either accept the work or close the PR with a "rejected" label. Renovate respects that label and won't keep re-opening the same major.
|
||||||
- **Adding or removing** a dependency belongs in a feature PR, not in Renovate's scope. Renovate only updates _versions_ of existing deps.
|
- **Adding or removing** a dependency belongs in a feature PR, not in Renovate's scope. Renovate only updates _versions_ of existing deps.
|
||||||
|
|
||||||
|
### Transitive vulnerabilities — `pnpm.overrides`
|
||||||
|
|
||||||
|
Renovate's vulnerability remediation handles **direct** `package.json` deps. For **transitive** vulnerabilities (a vulnerable package pulled in by a healthy direct dep), Renovate stays silent in the dashboard — the v40 image doesn't write `pnpm.overrides` automatically. The manual pattern lives in [`package.json`](../package.json) → `pnpm.overrides`, version-selector form:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
"esbuild@<0.25.0": ">=0.25.0",
|
||||||
|
"vite@<6.4.2": ">=6.4.2",
|
||||||
|
```
|
||||||
|
|
||||||
|
Two properties of this form worth knowing:
|
||||||
|
|
||||||
|
1. **The override is gated on the vulnerable range** — it only kicks in when the resolved version is < the threshold, becoming a no-op the day the underlying dep's own bump ships a patched version.
|
||||||
|
2. **pnpm overrides bypass peer constraints** — if the parent dep declares `vite ^5.0.0` but no patched 5.x exists, pnpm will pick a patched 6.x/7.x. Verify the chantier still builds before merging the override.
|
||||||
|
|
||||||
|
The first instance of this pattern is preserved in [#159](https://git.unespace.com/julien/apf_portal/pulls/159) (vite + esbuild via VitePress 1.6.4). Next time `pnpm audit` fails with a transitive vuln and Renovate is silent, this is the playbook.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Conventional commit cycle
|
## 7. Conventional commit cycle
|
||||||
@@ -441,21 +547,30 @@ The template guides without enforcing — sections can be left blank when irrele
|
|||||||
|
|
||||||
## 9. Sections to come — roadmap by phase
|
## 9. Sections to come — roadmap by phase
|
||||||
|
|
||||||
This doc starts as a phase-1 + cross-cutting reference. As features for later phases land, the corresponding sections below are filled in directly. Each entry is mapped to the ADR / implementation work that unlocks it, so a contributor can see when each section becomes real and what triggers it.
|
As features for later phases land, the corresponding sections below are filled in directly. Entries are split between **code shipped — doc to write** (the work is on `main`, only the prose is missing) and **not yet** (neither code nor doc).
|
||||||
|
|
||||||
When a section grows beyond a short subsection, it is extracted to its own file under `docs/development/`. Per the documentation convention (see [README.md](README.md)), we group into a folder once we have at least three related files; this doc is then re-organised into an index pointing at the extracted files. Until then, all sections live here.
|
When a section grows beyond a short subsection, it is extracted to its own file under `docs/development/`. Per the documentation convention (see [README.md](README.md)), we group into a folder once we have at least three related files; this doc is then re-organised into an index pointing at the extracted files. Until then, all sections live here.
|
||||||
|
|
||||||
| Future section | Phase | Triggered by |
|
### Code shipped — doc to write
|
||||||
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| **Auth dev-loop** — Microsoft 365 Developer tenant configuration, MSAL Node connection, OIDC code-flow walkthrough, switching between dev and prod-like tenants. | 2 | Auth flow code lands ([ADR-0009](decisions/0009-auth-flow-oidc-pkce-msal-node.md)) once the dev tenant is provisioned by IT. |
|
| Future section | Code shipped in | What the section will cover |
|
||||||
| **Session inspection** — reading the Redis session store in dev, decrypting the AES-GCM `tokens` blob with the dev key, force-logout patterns. | 2 | Sessions module lands ([ADR-0010](decisions/0010-session-management-redis.md)). |
|
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| **MFA step-up debugging** — triggering claims-challenge flows, verifying `mfaVerifiedAt` freshness, testing the SPA HTTP interceptor that handles 401 + claims challenge. | 2 | First `@RequireMfa()` route lands ([ADR-0011](decisions/0011-mfa-enforcement-entra-conditional-access.md)). |
|
| **Auth dev-loop** | [ADR-0009](decisions/0009-auth-flow-oidc-pkce-msal-node.md) implementation series (PRs #100s) | Microsoft 365 Developer tenant configuration, MSAL Node connection, OIDC code-flow walkthrough, switching between dev and prod-like tenants. |
|
||||||
| **Audit-log inspection workflow** — querying `audit.events` as `audit_reader`, joining with app logs by `trace_id`, validating the append-only role grants in dev. | 2 | Audit module lands ([ADR-0013](decisions/0013-audit-trail-separated-postgres-append-only.md)). |
|
| **Session inspection** | [ADR-0010](decisions/0010-session-management-redis.md) implementation | Reading the Redis session store in dev (`redis-cli`), decrypting the AES-GCM `tokens` blob with the dev `SESSION_ENCRYPTION_KEY`, force-logout patterns. |
|
||||||
| **Downstream API integration recipe** — adding a new `DownstreamApiConfig`, choosing the auth strategy (OBO vs service+assertion), wiring resilience policies, testing with a mocked downstream. | 2 | First downstream client lands ([ADR-0014](decisions/0014-downstream-api-access-obo-pattern.md)). |
|
| **MFA step-up debugging** | `@RequireMfa()` decorator + freshness guard (#128) | Triggering claims-challenge flows when the first consumer route lands, verifying `amrAt` freshness, testing the SPA interceptor on 401 + claims challenge. _(Decorator exists; no consumer route yet — section lands together with that.)_ |
|
||||||
| **Component patterns library** — the in-house, spartan-style components (Angular CDK + Tailwind) as they ship, with a11y notes per component (keyboard model, ARIA, screen-reader expectations). | 5b suite | First non-placeholder component in `libs/shared/ui/`. |
|
| **Admin surface workflows** | [ADR-0020](decisions/0020-portal-admin-app.md) skeleton (#127) + audit viewer (#136) + user directory (#140–#142) | Walking through `/audit` and `/users` viewers, role assignment in Entra (`Portal.Admin`), cross-app navigation. |
|
||||||
| **a11y testing workflow** — running axe-core via Playwright locally, screen-reader testing notes (NVDA / VoiceOver / TalkBack), the APF user-panel cadence and how to triage findings. | 3a | First Playwright e2e suite touching real screens ([ADR-0016](decisions/0016-accessibility-baseline-wcag-aa-targeted-aaa.md)). |
|
| **Audit-log inspection workflow** | [ADR-0013](decisions/0013-audit-trail-separated-postgres-append-only.md) + admin viewer | Querying `audit.events` as `audit_reader`, joining with Pino logs by `trace_id` / `actor_id_hash`, validating the append-only role grants in dev. |
|
||||||
| **Performance debugging** — running Lighthouse CI locally with full config, reading the HTML reports, using `source-map-explorer` to investigate bundle bloat, interpreting BFF p95/p99 from OTel. | 3a | Lighthouse already wired in CI ([ADR-0017](decisions/0017-performance-budgets-lighthouse-ci.md)); section grows when first real route is added to the critical-routes list. |
|
| **Downstream API integration recipe** | [ADR-0014](decisions/0014-downstream-api-access-obo-pattern.md) strategies (OBO #137, signed-assertion + JWKS #138/#139) | Adding a new `DownstreamApiConfig`, choosing the auth strategy, wiring resilience policies, testing with a mocked downstream. _(Strategy layer ready; no v1 consumer yet — section grows with the first.)_ |
|
||||||
| **Debugging tips** — Angular DevTools, NestJS inspector, Prisma query log, OTel trace navigation, common gotchas. | cross | Accumulates organically as the team encounters them. |
|
| **OpenAPI / Scalar dev workflow** | [#143](https://git.unespace.com/julien/apf_portal/pulls/143) | Browsing `/api/docs`, annotating new controllers with `@ApiTags` / `@ApiOperation`, exporting the spec for Bruno / Postman, the CSRF caveat when hitting mutating routes from Scalar. |
|
||||||
| **Release workflow** — tag-driven release, what `release.yml` does, version bumping, changelog generation from Conventional Commits. | 3b | On-prem infrastructure ADR + populated `release.yml`. |
|
| **Capabilities-driven SPA UX** | `/api/me/capabilities` + cross-app menu links (#151) | When to add a new key to `CapabilitiesView`, how the SPA's `CapabilitiesService` consumes it, the "binary boolean, never the raw role" rule. |
|
||||||
| **GitLab migration runbook** — when the org migrates Gitea → GitLab, how the workflows are ported, which level-2 sections of [ADR-0015](decisions/0015-cicd-gitea-actions.md) get superseded. | future | GitLab migration ADR (6–18 months horizon). |
|
|
||||||
| **Architecture overview diagrams** — high-level component diagrams, data-flow diagrams, trust boundaries (for security review). | cross | First major architecture review or onboarding cohort ≥ 3 contributors. |
|
### Not yet
|
||||||
|
|
||||||
|
| Future section | Triggered by |
|
||||||
|
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| **Component patterns library** — in-house spartan-style components (Angular CDK + Tailwind), a11y notes per component (keyboard model, ARIA, screen-reader expectations). | First non-placeholder component in `libs/shared/ui/` beyond `Icon` and `UserMenu`. |
|
||||||
|
| **a11y testing workflow** — running axe-core via Playwright locally, screen-reader testing notes (NVDA / VoiceOver / TalkBack), the APF user-panel cadence and how to triage findings. | First Playwright e2e suite touching real screens ([ADR-0016](decisions/0016-accessibility-baseline-wcag-aa-targeted-aaa.md)). |
|
||||||
|
| **Performance debugging** — running Lighthouse CI locally with full config, reading the HTML reports, using `source-map-explorer` to investigate bundle bloat, interpreting BFF p95/p99 from OTel. | First real route added to the critical-routes list ([ADR-0017](decisions/0017-performance-budgets-lighthouse-ci.md)). |
|
||||||
|
| **Debugging tips** — Angular DevTools, NestJS inspector, Prisma query log, OTel trace navigation, common gotchas. | Accumulates organically as the team encounters them. |
|
||||||
|
| **Release workflow** — tag-driven release, what `release.yml` does, version bumping, changelog generation from Conventional Commits. | On-prem infrastructure ADR + populated `release.yml`. |
|
||||||
|
| **GitLab migration runbook** — when the org migrates Gitea → GitLab, how the workflows are ported, which level-2 sections of [ADR-0015](decisions/0015-cicd-gitea-actions.md) get superseded. | GitLab migration ADR (6–18 months horizon). |
|
||||||
|
|||||||
Reference in New Issue
Block a user