import { readdirSync } from 'node:fs'; import { join } from 'node:path'; import { defineConfig } from 'vitepress'; import { withMermaid } from 'vitepress-plugin-mermaid'; /** * VitePress configuration for the APF Portal documentation site * per ADR-0022. * * Source tree maps directly to URLs: * docs/index.md → / * docs/development.md → /development * docs/architecture.md → /architecture * docs/decisions/README.md → /decisions/ * docs/decisions/00NN-…md → /decisions/00NN-… (auto-listed sidebar) * docs/setup/0N-…md → /setup/0N-… * * `docs/README.md` stays as the git-side / IDE-preview index and is * therefore excluded from the published site; `decisions/template.md` * is an authoring scaffold, also excluded. */ const DECISIONS_DIR = join(__dirname, '..', 'decisions'); const ADR_FILE_RE = /^\d{4}-[\w-]+\.md$/; /** * Walks `docs/decisions/` and returns one sidebar entry per accepted * ADR (`NNNN-kebab-title.md`), ordered by numeric prefix. Adding a * new ADR is then a single-file change — no `config.ts` edit * required (the convention spelled out in ADR-0022 §"Sidebar * generation"). * * The link text drops the numeric prefix's leading zeroes to read * naturally ("ADR-0009 — …") while the underlying URL keeps the * full filename for stable routing across renames. */ function adrSidebarItems(): { text: string; link: string }[] { return readdirSync(DECISIONS_DIR) .filter((name) => ADR_FILE_RE.test(name)) .sort() .map((name) => { const slug = name.replace(/\.md$/, ''); const num = slug.slice(0, 4); const title = slug.slice(5).replace(/-/g, ' '); return { text: `ADR-${num} — ${title}`, link: `/decisions/${slug}`, }; }); } export default withMermaid( defineConfig({ title: 'APF Portal Documentation', description: "Architecture decisions, development guide, and onboarding material for APF France Handicap's web portal.", // Root files (`README.md`) and authoring artefacts (`template.md`) // never make it to the rendered site — see ADR-0022. srcExclude: ['README.md', 'decisions/template.md'], // The curated decisions index lives in `decisions/README.md` // (git/IDE convention). VitePress expects `index.md` at a // folder root for clean URLs, so we rewrite at build time — // source layout stays git-friendly, the published URL resolves // `/decisions/` to the curated landing. rewrites: { 'decisions/README.md': 'decisions/index.md', }, // ADRs and the development guide carry deliberate references to // files that live OUTSIDE `docs/` (CLAUDE.md, apps/**, infra/**, // notes/**), localhost URLs that only resolve in a dev session, // and the authoring `template.md` we explicitly excluded. All of // those are valid from a git/IDE reader's perspective; VitePress // is told to skip them rather than fail the build. ignoreDeadLinks: [ /^https?:\/\/localhost/, /^\.{1,2}\//, /\/template$/, /\/README$/, ], // VitePress emits `.html` files by default; clean URLs hide the // extension. Mirrors what readers will see in the browser address // bar and what the inline ADR refs in `portal-admin` already use // when they target Gitea source-view (forward-compatible the day // we flip those refs to point at the docs site). cleanUrls: true, // The site is internal + read-only; we let crawlers in by // default but won't ship a sitemap until the hostname is locked // by the future infra ADR. lastUpdated: true, themeConfig: { nav: [ { text: 'Development', link: '/development' }, { text: 'Architecture', link: '/architecture' }, { text: 'Decisions', link: '/decisions/' }, { text: 'Onboarding', link: '/setup/01-wsl-terminal-setup' }, ], sidebar: { '/development': [ { text: 'Daily development', items: [{ text: 'Repo layout & commands', link: '/development' }], }, ], '/architecture': [ { text: 'Architecture', items: [{ text: 'C4 + module boundaries', link: '/architecture' }], }, ], '/decisions/': [ { text: 'Decisions', items: [ { text: 'Index by theme', link: '/decisions/' }, ...adrSidebarItems(), ], }, ], '/setup/': [ { text: 'Onboarding', items: [ { text: 'WSL terminal setup', link: '/setup/01-wsl-terminal-setup' }, { text: 'Dev web stack', link: '/setup/02-dev-web-stack' }, { text: 'Angular + Nx monorepo', link: '/setup/03-angular-nx-monorepo' }, ], }, ], }, socialLinks: [ { icon: 'git', link: 'https://git.unespace.com/julien/apf_portal' }, ], search: { provider: 'local', }, outline: { level: [2, 3], }, footer: { message: 'APF Portal — internal documentation', }, }, // `vitepress-plugin-mermaid` passes its `mermaid` key through to // the Mermaid runtime. Theme `default` follows VitePress's // light/dark switcher automatically; explicit `securityLevel` // tightens the renderer so diagrams can't inject arbitrary HTML // from the source markdown. mermaid: { securityLevel: 'strict', }, }), );