# Repo Structure & GitOps > Specification du monorepo GitHub : arborescence, branching, CI/CD, DevOps, SecOps, quality gates. > A valider avant creation du repo public. > Audience : Corentin (DevOps owner), Yan, freelance ponctuel. ## 1. Principes | Principe | Pourquoi | |----------|----------| | **Monorepo** | Tout versionne ensemble (infra, donnees, code custom, docs) — un tag = etat coherent | | **Trunk-based development** | Branches courtes (max 2-3j), merge direct sur `main` apres review + CI | | **Infra as code** | Tout ce qui touche a l'infra (compose, traefik labels, makefile, ci) versionne | | **Secrets exclus du versioning** | Variables d'env via `.env` ignore + GitHub Secrets pour CI/CD | | **Quality gates obligatoires** | Pas de merge sans CI vert (lint + tests + security scan) | | **Reproductibilite** | `git clone + .env + make up` = stack identique, partout | ## 2. Arborescence cible du repo ``` formation-hub/ ├── .github/ │ ├── workflows/ │ │ ├── ci.yml # tests + lint + security scan a chaque push/PR │ │ ├── deploy-staging.yml # deploy automatique sur push main │ │ ├── deploy-prod.yml # deploy sur tag v* │ │ └── nightly-backup-test.yml # test mensuel restauration backup │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ └── security.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── CODEOWNERS # qui review quoi │ └── dependabot.yml # auto bumps deps │ ├── docs/ # documentation projet (push aussi sur Outline) │ ├── 01-discovery-recap.md │ ├── 02-scope-etendu-cfa-agence.md │ ├── 03-decision-record.md # ADR │ ├── 04-cahier-des-charges-techniques.md │ ├── 05-data-dictionary.md │ ├── 06-merise-mcd.md │ ├── 07-merise-mld.md │ ├── 08-merise-mct.md │ ├── 09-merise-mot.md │ ├── 10-state-diagrams.md │ ├── 11-uml-use-cases.md │ ├── 12-uml-class-diagram.md │ ├── 13-uml-activity-diagrams.md │ ├── 14-repo-structure-gitops.md # CE DOC │ ├── 15-baserow-mpd.md │ ├── 16-plan-tests.md │ ├── 17-plan-deployment.md │ └── 18-plan-operations.md │ ├── compose.yml # stack locale dev ├── compose.staging.yml # override staging (labels Traefik staging) ├── compose.prod.yml # override prod (labels prod, replicas, healthcheck strict) │ ├── docmost/ │ ├── README.md # specifique a la branche Docmost │ ├── patches/ # diffs upstream (Phase 2+ si fork) │ └── Dockerfile.fork # Phase 2+ si custom build │ ├── baserow/ │ ├── README.md │ ├── schemas/ # JSON exports des tables (versionnes) │ │ ├── personne.json │ │ ├── formation.json │ │ ├── ... │ ├── seed/ │ │ ├── seed.py # script idempotent setup initial │ │ └── fixtures/ # data de test │ └── migrations/ # migrations versionnees (apres setup initial) │ ├── bridge/ # service Node TS Phase 2+ │ ├── README.md │ ├── package.json │ ├── tsconfig.json │ ├── biome.json # lint + format Biome (rapide, no config) │ ├── Dockerfile │ ├── src/ │ │ ├── index.ts │ │ ├── domain/ # domain models (Personne, Module, Tache, ...) │ │ ├── adapters/ # baserow-client, docmost-client, redis-cache │ │ ├── routes/ # API endpoints │ │ ├── webhooks/ # baserow webhook handlers │ │ └── lib/ # utils │ ├── tests/ │ │ ├── unit/ │ │ ├── integration/ │ │ └── e2e/ │ └── .env.example │ ├── traefik/ # config Traefik si versionnee (sinon reseau Docker existant) │ ├── README.md │ └── dynamic-config.yml │ ├── scripts/ │ ├── backup.sh # appele par cron host │ ├── restore.sh # restauration assistee │ ├── healthcheck.sh # check rapide endpoints │ └── seed-baserow.sh # wrapper du baserow/seed/seed.py │ ├── .gitignore ├── .editorconfig ├── .env.example ├── Makefile # commandes ops standardisees ├── LICENSE # AGPL-3.0 (compatible avec Docmost AGPL) ├── SECURITY.md # politique de divulgation ├── CONTRIBUTING.md # convention commits, PR, branches ├── CHANGELOG.md # tenu a jour par release └── README.md # quickstart + lien vers docs/ ``` ## 3. Branching strategy **Trunk-based development simplifie** : ``` main (protege) ├── feat/saisie-heures-ui (max 2-3j vie) ├── fix/baserow-rollup-cache (max 1j vie) ├── chore/bump-deps (auto via dependabot) └── ... ``` | Aspect | Regle | |--------|-------| | Branche par defaut | `main` | | Protection `main` | Required reviews 1+, CI must pass, no force push | | Convention nom branche | `/` ou type = `feat \| fix \| chore \| docs \| refactor \| test` | | Duree de vie max d'une branche | 3 jours (rebase ou drop si plus vieux) | | Squash merge | Oui, un commit propre par PR | | Tags | `v..` (semver) declenche deploy prod | ## 4. Convention de commits Format : `(): ` | Type | Usage | |------|-------| | `feat` | Nouvelle fonctionnalite | | `fix` | Bug fix | | `docs` | Documentation seulement | | `refactor` | Refactor sans changement comportement | | `test` | Ajout/modif tests | | `chore` | Maintenance, deps, tooling | | `ops` | Infra, CI/CD, ops | | `sec` | Security fix ou hardening | Exemples : - `feat(bridge): add formateur mention tiptap node` - `fix(baserow): correct rollup cache invalidation on annulation` - `ops(ci): add SAST scan with semgrep` - `sec(deps): bump postgres to 16.4 for CVE-2026-XXXX` **Pas d'emoji** dans les commits, pas de signature Claude (regle Acadenice). ## 5. CI/CD GitHub Actions ### 5.1 Workflow `ci.yml` (a chaque push + PR) ```yaml name: CI on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npx biome check bridge/ type-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 22 } - run: cd bridge && npm ci && npm run typecheck test: runs-on: ubuntu-latest services: postgres: { image: postgres:16-alpine, env: { POSTGRES_PASSWORD: test }, ports: ["5432:5432"] } redis: { image: redis:7-alpine, ports: ["6379:6379"] } steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 22 } - run: cd bridge && npm ci && npm run test security: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Secret scanning uses: trufflesecurity/trufflehog@main - name: SAST uses: returntocorp/semgrep-action@v1 - name: Dependency check run: cd bridge && npm audit --audit-level=high - name: License check run: cd bridge && npx license-checker --failOn 'GPL-3.0;AGPL-3.0' --excludePackages 'bridge' docker-build: runs-on: ubuntu-latest needs: [lint, type-check, test, security] steps: - uses: actions/checkout@v4 - run: docker compose build - run: docker compose up -d - run: ./scripts/healthcheck.sh - run: docker compose down -v ``` ### 5.2 Workflow `deploy-staging.yml` (sur push main) ```yaml name: Deploy Staging on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest environment: staging steps: - uses: actions/checkout@v4 - name: Build & push images run: | docker build -t registry.acadenice.fr/formation-hub/bridge:${{ github.sha }} bridge/ echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.acadenice.fr -u "${{ secrets.REGISTRY_USER }}" --password-stdin docker push registry.acadenice.fr/formation-hub/bridge:${{ github.sha }} - name: Deploy via SSH uses: appleboy/ssh-action@v1 with: host: ${{ secrets.STAGING_HOST }} username: ${{ secrets.STAGING_USER }} key: ${{ secrets.STAGING_SSH_KEY }} script: | cd /opt/formation-hub git pull docker compose -f compose.yml -f compose.staging.yml pull docker compose -f compose.yml -f compose.staging.yml up -d ./scripts/healthcheck.sh ``` ### 5.3 Workflow `deploy-prod.yml` (sur tag v*) Identique a staging mais cible prod, requiert approbation manuelle (`environment: production` avec required reviewers dans GitHub UI). ### 5.4 Workflow `nightly-backup-test.yml` (mensuel) Restauration automatique d'un backup recent sur env isole + verification integrite. Alerte si fail. ## 6. DevOps — environnements | Env | Host | Domain | Branche source | Auto deploy | |-----|------|--------|----------------|-------------| | **local** | machine de dev | `localhost:3000/8080/4000` | n'importe | manuel via `make up` | | **staging** | VPS Hetzner staging | `wiki.staging.acadenice.fr` etc. | `main` | oui sur push | | **prod** | VPS Hetzner prod | `wiki.acadenice.fr` etc. | tags `v*` | oui mais avec approval review | ### Differences env | Aspect | local | staging | prod | |--------|-------|---------|------| | Donnees | seed fixtures | data realiste anonymisee | data reelle | | Backups | aucun | quotidien local | quotidien local + S3 distant | | Healthchecks | optional | active | strict + alerting | | Replicas | 1 | 1 | 1 (peut passer a 2 si charge) | | Logs | stdout | persisted 7j | persisted 90j + push central | | Monitoring | aucun | uptime basique | uptime + perf + alerting | ## 7. Secret management **Exclus de git, sans exception.** | Type secret | Stockage | |-------------|----------| | Local dev | `.env` (gitignored) | | GitHub Actions | GitHub Secrets (env-scoped : staging, production) | | Staging/Prod runtime | `.env.staging` / `.env.prod` sur le serveur, ownership root, perms 600 | | API tokens longue duree (Outline, etc.) | Vault / pass / 1Password en interne — exclus du disque non-encrypted | | Backup encryption key | Hors git, hors GitHub, conserve dans coffre-fort hors-bande | **Rotation** : tokens API rotates annuellement, secrets sensibles (DB, JWT) rotates trimestriellement. ## 8. SecOps ### 8.1 Quality gates avant merge Tous obligatoires (PR bloquee si rouge) : - [ ] CI lint vert (Biome) - [ ] Type-check vert (tsc) - [ ] Tests unit + integration verts - [ ] Coverage >= 70% sur fichiers modifies (decision a affiner) - [ ] Secret scanning (TruffleHog) zero hit - [ ] SAST (Semgrep) zero finding `error` severity - [ ] Dependency check (npm audit) zero CVE `high` ou `critical` - [ ] License check (license-checker) pas de GPL/AGPL non-compatibles - [ ] Docker build OK + healthcheck stack passe - [ ] Review humaine 1+ approval ### 8.2 Outils SecOps | Outil | Role | Frequence | |-------|------|-----------| | **TruffleHog** | Secret scanning dans le code | A chaque push | | **Semgrep** | SAST (Static Application Security Testing) | A chaque push | | **npm audit** | CVE deps Node | A chaque push | | **Dependabot** | Auto-bump deps + security alerts | Auto, hebdomadaire | | **Trivy** ou **Grype** | Scan vulnerabilities images Docker | Avant push registry | | **OWASP ZAP** | DAST sur staging (Phase 2+) | Hebdomadaire | | **Falco** ou logs analysis | Runtime intrusion detection | Continu prod | ### 8.3 Politique de divulgation (`SECURITY.md`) - Email contact : security@acadenice.fr - Reponse sous 48h ouvrees - Disclosure responsable, embargo coordonne - CVE assignee si publique ### 8.4 Audit log applicatif Operations sensibles loggees avec : - Acteur (personne_id) - Action (creation/modification/suppression/partage_externe) - Cible (entity_type + entity_id) - Timestamp - IP source - Justification (si fournie) Stockage : table dediee `audit_log` ou journal append-only fichier (a trancher MPD). Retention : 5 ans (Qualiopi-compatible). ## 9. PR template ```markdown ## Description ## Type de changement - [ ] feat - [ ] fix - [ ] docs - [ ] refactor - [ ] test - [ ] chore - [ ] ops - [ ] sec ## Issue liee Closes #... ## Tests realises - [ ] Tests unit ajoutes/modifies - [ ] Tests integration ajoutes/modifies - [ ] Test manuel local ## Checklist - [ ] CI vert - [ ] Pas de secret commit (verifier diff) - [ ] Doc mise a jour si necessaire - [ ] Migration data si schema change - [ ] Changelog mis a jour si user-facing ``` ## 10. Issue templates ### Bug report ```markdown ## Description ## Etapes pour reproduire 1. ... ## Comportement attendu ## Comportement observe ## Env (local/staging/prod) - Version (commit SHA ou tag) : - Browser/device : ## Logs / screenshots ``` ### Feature request ```markdown ## Probleme metier ## Solution proposee ## Alternatives considerees ## Impact estime ``` ### Security **Privee** par defaut. Reporting via email security@acadenice.fr. ## 11. Release process ``` 1. Merge PRs sur main → deploy staging auto 2. Tester sur staging (qualif metier + smoke tests) 3. Si OK : - Update CHANGELOG.md (section "Unreleased" → version) - Tag : git tag -a v1.2.3 -m "Release v1.2.3" - git push origin v1.2.3 4. GitHub Action deploy-prod se declenche 5. Approval manual review (Yan ou Corentin) 6. Deploy prod execute 7. Post-deploy : surveiller logs + metriques 30 min 8. Si issue : execute rollback (cf section 12) ``` Convention semver : - MAJOR : breaking changes (migration data forcee, rupture API) - MINOR : nouvelle feature, backward-compatible - PATCH : bug fix, security fix ## 12. Rollback process | Scenario | Action | |----------|--------| | Bug critique en prod (data loss / down) | Re-deploy version precedente : `git checkout v1.2.2 && deploy-prod.yml` | | Schema migration foireuse | Restore Postgres depuis backup precedant le deploy + redeploy version stable | | Compromission credentials | Rotate secrets immediate + audit logs + isoler env si necessaire | | Bug minor en staging | Hotfix sur main, redeploy staging, ne pas tag prod | Runbook detaille dans `18-plan-operations.md` (a venir). ## 13. CODEOWNERS ``` # Default * @corentin # Infra & ops /.github/workflows/ @corentin @yan /compose*.yml @corentin /Makefile @corentin /scripts/ @corentin # Code custom /bridge/ @corentin # Docs /docs/ @corentin ``` ## 14. Quickstart pour nouveau dev ```bash # 1. Clone git clone git@github.com:acadenice/formation-hub.git cd formation-hub # 2. Setup cp .env.example .env # editer .env avec secrets (cf SECURITY.md) # 3. Up make up # 4. Acces # - Docmost : http://localhost:3000 # - Baserow : http://localhost:8080 # - Bridge : http://localhost:4000 (Phase 2) # 5. Workflow contribution git checkout -b feat/ma-feature # code, test git commit -m "feat(bridge): description" git push origin feat/ma-feature # Ouvrir PR sur GitHub, attendre CI vert + review ``` ## 15. Etapes avant creation du repo public Checklist Corentin avant `git init` + `git push -u origin main` : - [ ] LICENSE (AGPL-3.0 par alignement avec Docmost) - [ ] SECURITY.md - [ ] CONTRIBUTING.md - [ ] README.md (quickstart + liens docs) - [ ] .gitignore complet (verifie pas de fichier sensible) - [ ] .env.example commite, .env exclu - [ ] Workflows CI/CD `.github/workflows/` prets (au moins ci.yml) - [ ] PR template + issue templates - [ ] CODEOWNERS - [ ] dependabot.yml configure - [ ] GitHub Secrets configures (`REGISTRY_*`, `STAGING_*`, `PROD_*`) - [ ] Branch protection rules sur `main` actives - [ ] Required reviewers configures sur `production` env Une fois tout vert : push `main`, configure Dependabot, enable security alerts. Le repo est pret. ## 16. Questions a trancher - [ ] Repo **public** (open-source) ou **prive** ? Implications RGPD si etudiants/clients dans audit logs visible. - [ ] Self-host GitLab interne plutot que GitHub (souverainete) ? Pas le cas aujourd'hui mais a noter. - [ ] Registry images Docker : GitHub Container Registry, Harbor self-host, ou registry.acadenice.fr (a deployer) ? - [ ] Couverture tests minimum : 70% / 80% / autre ? Strictesse vs vitesse. - [ ] Tooling lint/format : Biome (rapide, all-in-one) vs ESLint+Prettier classique ?