Layout du monorepo
source : docs/adr/0004-monorepo-layout.md · versionné · MADR-lite
ADR-0004 — Layout du monorepo
- Statut : Accepted
- Date : 2026-04-24
- Décideurs : Core team OmbrysWeb
- Références : cahier des charges § 5.7.4, § 8
- Dépend de : ADR-0001 (Rust + Axum)
Contexte
OmbrysWeb regroupe :
- un frontend Next.js 16,
- 7 micro-services Rust,
- des packages partagés (UI Tailwind en M3, lib commune Rust
ombrys-common), - de l'IaC (Talos, Vault, SPIFFE, Linkerd, CrowdSec, Forgejo),
- une CI/CD non triviale (SLSA, cosign, SBOM, builds reproductibles),
- une documentation technique étendue (ADR, threat model, runbooks).
On doit choisir entre :
- Monorepo (tout ensemble),
- Polyrepo (un repo par composant),
- Hybride (monorepo pour le code applicatif + repos séparés pour IaC/docs).
Décision
Monorepo unique, layout pnpm workspace + Cargo workspace, avec séparation de premier niveau par intention.
/
├── apps/
│ └── web/ # Next.js 16 (pnpm workspace "@ombrys/web")
├── services/
│ ├── auth-svc/ # Rust — Axum + WebAuthn
│ ├── blog-svc/
│ ├── storage-svc/
│ ├── messaging-svc/
│ ├── audit-svc/
│ ├── vault-svc/
│ └── admin-svc/
├── packages/
│ ├── ombrys-common/ # Rust lib — health, tracing, shutdown, healthcheck
│ └── ui/ # (M3) Tailwind components package
├── infra/
│ ├── talos/ # machineconfig + patches + Cilium + Kyverno PSA
│ ├── vault/ # Helm values + policies HCL par service
│ ├── spiffe/ # SPIRE server/agent values + registration entries
│ ├── linkerd/ # annotations + Server/AuthorizationPolicy
│ ├── crowdsec/ # scenarios + config WAF
│ ├── forgejo/ # Helm values Forgejo self-hosted
│ └── k8s-base/ # namespaces, RBAC de base
├── ci/ # scripts utilisés dans les GitHub Actions
├── scripts/ # start.sh helpers (doctor, seed, gen-dev-certs)
├── docs/
│ ├── adr/
│ ├── security/
│ ├── operations/
│ └── policy/
├── .github/workflows/ # ci.yml, release.yml, reproducible.yml
├── Cargo.toml # workspace Rust
├── package.json # workspace pnpm
├── pnpm-workspace.yaml
├── rust-toolchain.toml
├── docker-compose.yml
├── start.sh
├── .env.example
├── Dockerfile.rust-service # Dockerfile partagé pour les 7 services Rust (ARG SERVICE)
└── CAHIER_DES_CHARGES.mdJustification
- Atomicité des changements : une feature qui touche frontend + auth-svc + doc change en un seul commit, visible dans un seul PR.
- Cohérence des versions : rust-toolchain.toml, pnpm lockfile, image de base Docker unifiés. Pas de dérive entre repos.
- CI/CD simplifiée : une seule provenance SLSA par release, un seul workflow à maintenir.
- Onboarding :
git clone+./start.shsuffit. Pas de navigation entre 10 repos. - Recherche de code globale : un seul
grep -r, un seul index IDE. - Threat model / audit : périmètre audit = un repo, plus simple à cartographier.
Conséquences
Positives
- Builds et scans de chaîne d'approvisionnement uniformes.
- Miroir public unique (GitHub), vue publique cohérente.
- Refactors transverses plus simples (renommage d'une API Rust utilisée par 3 services).
- Partage trivial du code commun (
packages/ombrys-common).
Négatives
- Poids du clone plus élevé à mesure que le projet grandit (mitigation : sparse-checkout possible, partial clone).
- Permissions granulaires plus limitées (pas de distinction par sous-repo). Mitigation : CODEOWNERS par dossier, branch protection par path.
cargo check --workspaceetpnpm -r builddeviennent longs → caching agressif dans CI (Swatinem/rust-cache, pnpm cache).
Neutres
- Les IaC et la documentation vivent dans le même repo — cohérent avec le principe "infrastructure = code", renforcé par la politique de revue (ADR, PR).
Conventions de commit et PR
- Commits petits et ciblés, focus sur une seule section du monorepo quand possible.
- Préfixe optionnel dans le titre pour grep :
web:,auth-svc:,infra:,docs:,ci:. - PR obligatoirement reliée à une issue GitHub M0–M7.
- CODEOWNERS :
/services/→ backend team + security lead/apps/web/+/packages/ui/→ frontend team/infra/→ SRE/docs/security/+/docs/policy/→ security lead + core team/docs/adr/→ core team (consensus requis)
Suivi
- En v2, si une partie (ex : SDK publique) nécessite un cycle de release vraiment disjoint, ADR de révision pour extraire un sous-repo dédié.
- Pas de split prématuré : attendre que la gêne soit mesurable.
Changelog
- 2026-04-24 : rédaction initiale, statut Accepted.