diff --git a/CLAUDE.md b/CLAUDE.md
index 954a524..6ce92e8 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -50,13 +50,14 @@ The structural, security, observability, and quality choices are recorded as ADR
- **Internationalisation:** `@angular/localize` in build-time mode, two locales (`fr` default served at `/`, `en`), source locale = English (project English-only rule). Path-based URLs always prefixed (`/fr/...`, `/en/...`); `/` smart-redirects via cookie → `Accept-Language` → `fr`. UI strings live in XLIFF (`messages.fr.xlf`); editorial / CMS content is BFF-served already localised (see admin app). Footer hosts the locale switcher; switching writes a `__Host-portal_locale` cookie and hard-refreshes — see [ADR-0019](docs/decisions/0019-internationalisation-angular-localize.md).
- **Admin application (`portal-admin`):** dedicated Angular SPA alongside `portal-shell`, sharing the same `portal-bff` via `/api/admin/*` routes guarded by an Entra `Portal.Admin` role + `@RequireMfa({ freshness: 600 })` at entry. Distinct origin / cookie / session from `portal-shell` (`__Host-portal_admin_session`). v1 modules: CMS for static pages (multilingual), menu management, user list (read-only), audit log viewer. Bundle budget relaxed to ≤ 500 KB gzip (vs 300 KB for `portal-shell`); same a11y + dark-mode baseline. Shared UI primitives (`Icon`, `LayoutStateService`, brand tokens) graduate to `libs/shared/*` as both apps need them — see [ADR-0020](docs/decisions/0020-portal-admin-app.md).
- **Local quality gates:** Husky + lint-staged + commitlint with Conventional Commits — see [ADR-0007](docs/decisions/0007-pre-commit-hooks-and-conventional-commits.md).
+- **Documentation site:** `docs/**/*.md` rendered as a separate static site via **VitePress** (Vite-based, Node-only toolchain, Markdown-first). Mermaid diagrams via `vitepress-plugin-mermaid`. Deployed on its own hostname behind the shared reverse-proxy; CI hook on `docs/` changes rebuilds + publishes. Decoupled from the apps — content lives in `docs/`, no in-app Markdown viewer — see [ADR-0022](docs/decisions/0022-docs-site-vitepress.md).
- **Runtime:** Node.js latest LTS major.
## Repository status
The Nx workspace is **scaffolded and operational**. The three apps (`portal-shell`, `portal-admin`, `portal-bff`) and the four lib roots (`libs/feature/`, `libs/shared/state`, `libs/shared/tokens`, `libs/shared/ui`, `libs/shared/util`) are in place; CI runs `format:check / lint / test / build` on every PR.
-ADRs 0001 → 0021 are accepted and cover the structural, security, observability, quality, i18n, and admin-app choices. **Shipped on `main`:**
+ADRs 0001 → 0022 are accepted and cover the structural, security, observability, quality, i18n, admin-app, and docs-site choices. **Shipped on `main`:**
- **Phase-1 foundation** — Nx workspace, Angular `portal-shell`, NestJS `portal-bff`, Prisma + Postgres, Pino + OpenTelemetry, Husky/lint-staged/commitlint, Gitea Actions CI.
- **Phase-2 auth + audit + security** — OIDC Auth Code + PKCE via MSAL Node, Redis sessions with AES-256-GCM at rest, idle 30 min sliding + absolute 12 h hard ceiling, RP-initiated logout, double-submit CSRF, `audit.events` append-only schema with role-based grants, helmet + env-driven CORS allowlist + rate limiting + structured error envelope (see [ADR-0021](docs/decisions/0021-phase-2-security-baseline.md)).
@@ -66,6 +67,7 @@ ADRs 0001 → 0021 are accepted and cover the structural, security, observabilit
- `DownstreamApiClient` + OBO ([ADR-0014](docs/decisions/0014-downstream-api-access-obo-pattern.md)) — no v1 consumer yet; will land when the first business route needs an Entra-protected API.
- `@RequireMfa()` / `@RequireAdmin()` guards ([ADR-0011](docs/decisions/0011-mfa-enforcement-entra-conditional-access.md), [ADR-0020](docs/decisions/0020-portal-admin-app.md)) — designed-in, awaiting first consumer route.
+- **Docs static-site implementation** ([ADR-0022](docs/decisions/0022-docs-site-vitepress.md)) — ADR accepted, chantier (VitePress install + `.vitepress/config.ts` + `docs-site.yml` workflow) lands next.
- **Strategic security baseline ADR** — separate from the implementation-level [ADR-0021](docs/decisions/0021-phase-2-security-baseline.md). Remains **paused** awaiting RSSI input on the OWASP ASVS reference level and adjacent frameworks (HDS, GDPR, possibly NIS 2). When it lands it will either confirm 0021 or supersede pieces of it.
## Commands once the workspace exists
diff --git a/apps/portal-admin/src/app/pages/audit/audit.html b/apps/portal-admin/src/app/pages/audit/audit.html
index 261f4e0..ed398b8 100644
--- a/apps/portal-admin/src/app/pages/audit/audit.html
+++ b/apps/portal-admin/src/app/pages/audit/audit.html
@@ -3,9 +3,13 @@
Audit log
Read-only view of audit.events per
- ADR-0013. Every query
- run on this page emits its own admin.audit.query row — read access is itself
- auditable.
+ ADR-0013. Every query run on this page emits its own admin.audit.query row — read access
+ is itself auditable.
Read-only directory of every identity that has signed in to portal-shell or portal-admin per
- ADR-0020. Every query
- run on this page emits an admin.users.query audit row — directory access is
- itself auditable.
+ ADR-0020. Every query run on this page emits an admin.users.query audit row — directory
+ access is itself auditable.
diff --git a/docs/decisions/0022-docs-site-vitepress.md b/docs/decisions/0022-docs-site-vitepress.md
new file mode 100644
index 0000000..a224282
--- /dev/null
+++ b/docs/decisions/0022-docs-site-vitepress.md
@@ -0,0 +1,159 @@
+---
+status: accepted
+date: 2026-05-15
+decision-makers: R&D Lead
+tags: [process, infrastructure]
+---
+
+# Documentation site — VitePress + Mermaid plugin, separate static deployment
+
+## Context and Problem Statement
+
+The project ships its documentation as Markdown under `docs/` (architecture diagrams, daily-dev guide, onboarding setup, 21 ADRs and growing). Today the only way to consult those files is `git clone` + IDE preview, or browse them directly on Gitea. Two recurring frictions surface from this:
+
+- Some pages in `portal-admin` reference ADRs in their intro copy; without a public URL for the ADR, the anchors had to either point at Gitea's source-view (raw markdown, ergonomic but no rendering of Mermaid, no search) or — as observed in [PR for `fix(portal-admin): adr refs point at gitea`](../../apps/portal-admin/src/app/pages/audit/audit.html) — at the **MADR template repo by mistake**.
+- A future RSSI / auditor / new contributor handed a link to an ADR would land on raw markdown on Gitea, without inter-ADR navigation, without a search box, without rendered Mermaid sequence diagrams (which carry a non-trivial part of the architecture rationale in [ADR-0009](0009-auth-flow-oidc-pkce-msal-node.md) and [architecture.md](../architecture.md)).
+
+Earlier discussion considered surfacing the `docs/` content **inside `portal-admin`** as a "Documentation" section. That option was rejected: `portal-admin`'s audience per [ADR-0020](0020-portal-admin-app.md) §"Audience is disjoint" is APF internal operators (CMS, audit, user directory) — not architects. Embedding dev-internal ADRs there blurs the surface and adds Markdown-rendering + BFF↔filesystem coupling for no audience win.
+
+The need is therefore: a **separately-deployed static site** that renders `docs/**/*.md` cleanly, auto-rebuilds on push, and stays decoupled from the runtime apps.
+
+## Decision Drivers
+
+- **Toolchain alignment.** The workspace is 100 % Node / pnpm / Vite / TypeScript. Adding a second runtime (Python, Go, Ruby) for the docs site is a permanent maintenance tax in CI.
+- **Stability bar.** Per [CLAUDE.md](../../CLAUDE.md) §"Project rules": stable, recognized, battle-tested choices. No pre-1.0 dependencies, no one-maintainer projects.
+- **Markdown-first content.** All current and foreseeable content is pure Markdown. MDX / framework-component embedding is not required.
+- **Mermaid rendering is a hard requirement.** [ADR-0009](0009-auth-flow-oidc-pkce-msal-node.md) and [architecture.md](../architecture.md) carry diagrams as ` ```mermaid ` fenced blocks; both must render.
+- **Audience is internal.** RSSI, future devs, ops. Not a marketing surface; theme polish is secondary, content density is primary.
+- **No versioning needed.** ADRs are immutable once accepted; supersession is by inter-ADR reference, not by version snapshot. The site never needs to host `v1.x` and `v2.x` side by side.
+- **No i18n needed for the docs themselves.** Per [CLAUDE.md](../../CLAUDE.md): all documentation is English-only. The site is single-locale.
+- **Build speed matters.** A CI hook on every `docs/` change should publish in seconds, not minutes — otherwise contributors will lose the "edit a sentence, see it live in 30 s" feedback loop.
+- **Cost of failure.** If the docs site is down, no app traffic is affected (it's strictly read-only reference content). Reliability bar is therefore relaxed compared to `portal-shell` / `portal-bff`.
+
+## Considered Options
+
+- **VitePress + `vitepress-plugin-mermaid`** (chosen).
+- **MkDocs Material** with the Mermaid `pymdownx` extension.
+- **Docusaurus 3** (Mermaid built-in since v2).
+- **Astro Starlight** (Mermaid via plugin).
+
+## Decision Outcome
+
+Chosen: **VitePress** as the static-site generator, **`vitepress-plugin-mermaid`** for the diagram support.
+
+**Why VitePress wins this matchup.**
+
+- **Zero new toolchain.** Vite is already in the workspace (`@nx/vite`, `vite-plugin-angular`, Vitest). Adding VitePress is a single dev-dep + a config file; no Python runtime to pin in CI, no Ruby gems, no separate cache layer.
+- **Vue ergonomics stay invisible for pure-Markdown content.** We never have to write a Vue component — but if we ever need a small interactive widget (an ADR-status badge, a "supersession chain" navigator), the escape valve exists and is mature.
+- **Build is sub-second incremental, ~2 s full** for the current `docs/` size — Vite's HMR carries over to the doc-site dev loop.
+- **Battle-tested by the tools we already use:** Vite, Vitest, Pinia, Vue Router all run their docs on VitePress. The project's own tech bar treats "used by the build-tool family we depend on" as a strong signal — it's the same logic that drove the Angular / NestJS / Prisma choices.
+- **Markdown-first config.** No MDX ceremony for content that is and will remain pure Markdown.
+
+### Site structure & source layout
+
+The site builds from `docs/` (configured as VitePress's `srcDir`). Mapping:
+
+```
+docs/index.md → / (Hero layout, landing)
+docs/development.md → /development
+docs/architecture.md → /architecture
+docs/decisions/README.md → /decisions/ (curated index — by tag)
+docs/decisions/0001-…md → 0021-…md → /decisions/00NN-…
+docs/setup/01-…md → 03-…md → /setup/0N-…
+```
+
+**`docs/index.md` is added in this chantier** with VitePress's `layout: home` frontmatter — Hero + features cards linking the three top-level sections (Architecture, Decisions, Onboarding). It lives alongside the existing **`docs/README.md`**, which stays as the git-side / IDE-preview index that contributors browse via Gitea's source view. The two artefacts serve different audiences and the duplication is light (the IDE index is a flat link list, the web home is a polished landing); `docs/README.md` is excluded from the site via `srcExclude`.
+
+**Excluded from the published site:**
+
+- `docs/README.md` — git-side index, redundant with the VitePress home.
+- `docs/decisions/template.md` — authoring scaffold, not reader content.
+
+**Sidebar generation:**
+
+- Top-level groups (Architecture, Decisions, Onboarding) are hand-curated in `.vitepress/config.ts` — three entries, low churn.
+- The Decisions sub-list is **auto-generated** by walking `docs/decisions/00*-*.md` so adding a new ADR is a single-file change (no `config.ts` edit). Numeric filename prefix gives natural ordering.
+
+The curated `docs/decisions/README.md` index (tag-grouped, supersession-aware) stays as the section's landing page — sidebar lists ADRs by number, README lists them by theme. Both are useful and don't duplicate effort.
+
+**Empty placeholder sections** of the current [docs/README.md](../README.md) (Operations & runbooks, Security/perf/a11y rationales) are NOT pre-created as empty pages. They appear in the sidebar when real content lands.
+
+### Mermaid integration
+
+`vitepress-plugin-mermaid` (community plugin, maintainer `emersonbottero`, ~500★, 2.x release stream, used by mainstream VitePress doc sites). Two lines in `.vitepress/config.ts` + ` ```mermaid ` fenced blocks render. Client-side rendering — acceptable for the document sizes in scope; if diagram count grows enough to warrant build-time SVG pre-rendering, the plugin offers an opt-in for that without changing source documents.
+
+Mermaid's `theme: 'default'` + plugin config follows the site's light/dark switcher — diagrams adapt to the reader's chosen theme without manual classes.
+
+### Deployment & CI
+
+- Build: `pnpm vitepress build docs` produces `docs/.vitepress/dist/`.
+- Hosting: served as static files behind the same Caddy reverse-proxy as `portal-shell` / `portal-admin`, on a dedicated hostname (provisional `docs.portal.apf.fr` — the exact host follows the future infrastructure ADR's domain plan; not locked here).
+- CI: a new Gitea Actions workflow `docs-site.yml` triggers on `push` to `main` when `docs/**` or `package.json` / `pnpm-lock.yaml` changes. Runs `pnpm vitepress build docs` and rsyncs to the static host. Per [ADR-0015](0015-cicd-gitea-actions.md) the YAML stays thin — orchestration in `package.json` scripts.
+- No PR-preview deployments in v1 — contributors render locally via `pnpm vitepress dev docs`. Preview deploys can land later if the cycle becomes painful.
+
+### Consequences
+
+- Good, because the broken-ADR-link class of bugs (PR #N pointing at `github.com/adr/madr`) is eliminated at source: anchors become stable site URLs that survive ADR renames.
+- Good, because Mermaid sequence diagrams in [ADR-0009](0009-auth-flow-oidc-pkce-msal-node.md) and the C4 diagrams in [architecture.md](../architecture.md) become readable without dev tooling — RSSI / new contributors can absorb them from a browser.
+- Good, because the toolchain stays Node-only. Single `pnpm install` boots both the apps and the docs site.
+- Good, because the site is decoupled: a docs deploy never threatens app uptime, and an app outage never blocks doc consultation.
+- Good, because new ADRs auto-surface in the sidebar with no `config.ts` edit — keeps the "write ADR, push, browse it" loop frictionless.
+- Bad, because we add a sub-1.0 dependency to the toolchain: `vitepress-plugin-mermaid` is community-maintained, not first-party. Mitigation: the plugin is a thin wrapper around Mermaid's official renderer; if it ever stalls, replacement with a direct `markdown-it-mermaid` integration is a half-day rewrite, not a regression.
+- Bad, because client-side Mermaid rendering produces a brief flash on diagram-heavy pages. Mitigation: in scope today (5-6 diagrams total), revisit with build-time SVG pre-render if it becomes user-visible.
+- Neutral, because we ship a tiny dependency on Vue (VitePress's runtime) even though the rest of the workspace is Angular. The Vue runtime ships _inside the docs site bundle only_; no impact on `portal-shell` / `portal-admin` bundles, no impact on `feature-auth` / `shared-*` libs.
+
+### Confirmation
+
+- The docs-site Gitea Actions workflow becomes a required check on PRs that touch `docs/**` — a syntactically broken Markdown or sidebar config fails the build before merge.
+- The build produces `docs/.vitepress/dist/` deterministically; size is monitored manually for now (no Lighthouse-style budget — site is internal, content density beats bundle size).
+- A smoke check in the workflow asserts that the generated HTML for [ADR-0009](0009-auth-flow-oidc-pkce-msal-node.md) and [architecture.md](../architecture.md) contains rendered Mermaid `