Commit graph

14 commits

Author SHA1 Message Date
a79c51e6f2 feat(auth): R2.3b bridge accepte JWT HMAC DocAdenice via DOCMOST_APP_SECRET
Some checks are pending
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Lint bridge (Biome) (push) Waiting to run
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
2026-05-07 23:02:01 +02:00
2ed73fa948 feat(bridge): R1 refactor proxy generique style Notion
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
Pivot strategique : DocAdenice = produit Notion-like generique. Le bridge
est livre vide a un user qui cree ses tables Baserow comme il veut. Code
sans aucune ontologie metier.

Suppressions :
- 9 entites domain metier (Personne, Formation, Bloc, Module, Attribution,
  Client, Projet, Tache, Intervention) + types.ts (Role, statuts)
- baserow-repo.ts (mega-fichier 554 LOC avec 9 repos heritant BaseRepo)
- 6 routes metier (personnes, formations, projets, modules, interventions,
  attributions) + tests associes
- Lookup PersonneRepo.findByEmail dans middleware auth
- Mapping DEFAULT_ROLE_SCOPES dans middleware/scopes.ts
- Cascade rollup metier dans webhooks/baserow-handler.ts

Ajouts :
- Domain generique : Table, Row, Field, View + schemas zod refondus
- 4 repos generiques : tables / rows / fields / views
- Route unique routes/tables.ts avec 9 endpoints REST CRUD generiques
- Claim JWT acadenice_permissions[] lu directement dans le middleware auth
  (alimente par RBAC dynamique cote DocAdenice en R2)
- examples/acadenice-formation-hub/ : README + seed-baserow.md schema
  9 tables + example-roles.md (Formateur, Developpeur, Direction, Support,
  Admin avec permissions generiques)

Refactors :
- BaserowClient etendu : listTables, getTable, listFields, listViews,
  getGridViewRows
- middleware/auth.ts : extractPermissions(payload), AuthenticatedUser
  remplace roles[] par permissions[]
- middleware/scopes.ts : computeOidcScopes(groups, permissions, map)
- webhooks/baserow-handler.ts : invalidation generique
  bridge:tables:<tableId>:* sans cascade cross-table
- lib/cache.ts : invalidateEntity -> invalidateTable(redis, tableId, rowId?)
- container.ts : drop tableIds, RepoSet={tables, rows, fields, views}
- 501 NOT_IMPLEMENTED si DB token sur endpoints /tables qui exigent JWT

Tests : 250/250 verts (depuis 319). Coverage : domain 98.9%, adapters 89%,
auth 97.08%, rate-limit 100%, cache 100%, webhooks 100%.

Quality gates verts : typecheck, lint biome, vitest, coverage thresholds.

Refs: R1 dans le pivot strategique DocAdenice Notion-like generique.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:12:32 +02:00
0cf6533885 feat(bridge): Bloc 5 rate limit + cache invalidation cote writes
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
2026-05-07 21:44:33 +02:00
571f5c3426 feat(auth): Bloc 4 — middleware OIDC-ready avec dual mode service-token + Authentik JWT
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
- Support JWT OIDC Authentik via jose + JWKS (cache 10min)
- Lookup Personne via PersonneRepo.findByEmail + cache Redis 60s
- Mapping groups Authentik + roles formation-hub vers scopes
- Mode OIDC active uniquement si AUTHENTIK_ISSUER + JWKS_URI + AUDIENCE set
- Service tokens brg_* inchanges, restent voie principale en local
2026-05-07 21:17:56 +02:00
022b1ee926 feat(webhooks): Bloc 7a Baserow complet + Bloc 7b Docmost stub avec HMAC verify et idempotence
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
2026-05-07 20:51:56 +02:00
1cdb1b6ca4 fix(redis-cache): membre ZSET unique pour eviter collision sub-ms dans checkRateLimit
Date.now() seul collisionne sur appels concurrents dans la meme milliseconde,
ce qui faisait compter 1 entry au lieu de N dans la fenetre glissante.
Suffixe randomUUID pour garantir l'unicite du membre. Ajoute test burst 10x
qui prouve les 5 allowed + 5 denied attendus.
2026-05-07 20:38:07 +02:00
1528017bab test(adapters): tests integration redis (testcontainers) + baserow/docmost (fake HTTP server)
- redis-cache.ts : 16 tests via testcontainers redis:7-alpine, coverage 100% lines / 95.2% branches
- baserow-client.ts : 18 tests via serveur node:http local, coverage 99% lines / 96.9% branches
- docmost-client.ts : 25 tests via serveur node:http local (login + cookie + envelope { data }), coverage 97.7% lines / 93.7% branches
- helper tests/helpers/http-server.ts : serveur Node natif reutilisable (request log + route registry)
- vitest.config.ts : ajout threshold 70% lines+branches sur src/adapters/**
- suppression sanity.test.ts (stub remplace par 3 vraies suites)
- justification fake HTTP vs container heavy en commentaire en tete de fichier

Resultat : 220/220 tests verts, coverage adapters >> seuil 70% requis.
2026-05-07 20:31:08 +02:00
7a3fbe455d fix(bridge): smoke test fixes — skip rows malformees + BASEROW_TABLE_IDS override
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
Decouverts via smoke test local contre Baserow + Docmost reels.

1. **BaseRepo.list robuste** : try/catch toDomain par row, skip + log warn
   si throw (ex Personne avec splits null != 100). Avant : 500 sur la liste
   entiere. Apres : 200 avec items valides + meta.skipped count pour visibilite.
   `get()` continue de propager (un get sur row corrompue = legitimement 500
   pour investigation manuelle).

2. **BASEROW_TABLE_IDS env override** : BaserowClient.resolveTableIds appelle
   /api/database/tables/database/:id/ qui requiert un JWT user (Baserow API
   distingue DB tokens reservees aux endpoints rows, et JWT pour les endpoints
   admin). En dev/prod simple on passe le mapping directement par env var :
   BASEROW_TABLE_IDS={"personne":609,"formation":610,...}. Le code resolveTableIds
   reste en place pour Phase 3+ (bridge avec JWT user).

Smoke test post-fix :
- GET /api/health, /api/ready : 200
- Auth : 401 absent / 401 invalide / 200 valide
- GET /personnes (rows test invalides) : 200 data:[] meta.skipped:2
- GET /formations, /projets : 200 avec rows
- GET /personnes/9999 : 404

Tests Vitest : 163/163 verts. tsc + biome ci verts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:09:27 +02:00
c8e9b4d4ea feat(bridge): bloc 3 — routes REST Tier 1 + auth + repos Baserow (10 endpoints)
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
Wiring HTTP du bridge service. 10 endpoints livres (cf docs/19 §6.1-6.5) :
- GET /api/v1/personnes (+ /:id, + /:id/dashboard)
- GET /api/v1/formations (+ /:id avec rollups blocs/modules)
- GET /api/v1/projets (+ /:id avec rollups taches)
- POST /api/v1/modules/:id/attribuer (RG-01 -> 422, role/heures invalides -> 400)
- POST /api/v1/interventions (validation role developpeur + heures > 0)
- PATCH /api/v1/attributions/:id/heures-realisees (409 si annule/realise)

Layers ajoutees :
- src/middleware/auth.ts : Bearer brg_*, scopes JSON-encoded BRIDGE_API_TOKENS, admin:* wildcard
- src/middleware/error-handler.ts : BridgeError -> JSON shape standard
- src/lib/container.ts : DI singleton (Baserow + Redis + 9 repos), setContainer testable
- src/lib/http.ts : parseListQuery + parseBody zod helper
- src/repos/baserow-repo.ts : BaseRepo<T> abstrait + 9 sous-classes (mapping Row<->Domain)
- src/routes/{personnes,formations,projets,modules,interventions,attributions}.ts

src/index.ts reecrit : buildApp() + initContainer + auth sur /api/v1/* + ready check Baserow+Redis.

Tests : 163/163 verts (12 suites domain + 8 nouvelles : auth, repos, 6 routes).
Coverage src global : 70.77% (cible 60%). Domain 97.86%, routes 96%, middleware 86%.

Choix : BaseRepo abstrait (pas mega-generic, Ockham) ; FakeRepos in-memory pour tests routes
(pas de testcontainers ici, c'est Bloc 7) ; mapping erreurs domain -> HTTP par message texte
(fragile, sera refactor en DomainError typees au Bloc 3.2).

Hors scope (a venir) :
- Bloc 5 : rate limiting Redis
- Bloc 7 : webhook handlers Baserow + sync bidirec + cache invalidation
- Bloc 3.2 : routes /docmost/*, /sync/*, /rapports/*

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:01:36 +02:00
2c5665bc44 feat(bridge/domain): bloc 2 — domain models + tests Vitest (coverage 97.86%)
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
Modele OO complet (cf docs/12-uml-class-diagram.md) en TypeScript strict :
- Personne (pivot multi-roles, splits formation/agence, heuresRestantes*)
- Formation -> Bloc -> Module composition + heuresRestantes rollup
- Module.creerAttribution avec validation RG-01 (capacite) + role formateur
- Attribution lifecycle : demarrer/saisirHeuresRealisees/cloturer/annuler
- Client -> Projet -> Tache composition + lierFormationPedagogique
- Tache.creerIntervention avec validation role developpeur + heures > 0 + actif
- Schemas zod pour runtime validation (z.infer types exposes)
- Decimal.js partout pour les heures (zero erreur flottante)

Patterns appliques :
- Statuts comme discriminated unions ('actif' | 'inactif' | ...)
- Statuts annules exclus des rollups (annulation libere capacite)
- _appliquerHeures* en pseudo-private (convention underscore, pas de friend en TS)
- Warn surcharge Personne non bloquant (overbooking volontaire possible) — RG-01 Module reste bloquante

Tests : 111 pass / 0 fail. Coverage domain : 97.86% lines, 98.57% funcs.
tsc strict EXIT 0, biome ci EXIT 0.

Hors scope (a venir) :
- Repository pattern (Bloc 3 avec routes Hono)
- rapportPDF (Phase 2.4)
- Tests adapters Bloc 1 (Bloc 6 via bridge-tester)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 19:48:22 +02:00
5b2abbc23c feat(bridge/adapters): bloc 1 propre — BaserowClient + DocmostClient + RedisCache
- BaserowClient : CRUD rows, listRows pagination/filter/search, resolveTableIds, healthCheck
- DocmostClient : auth session cookie auto-relogin, spaces/pages/shares CRUD, healthCheck
- RedisCache : cache-aside, invalidation pattern SCAN, idempotence webhooks, rate limit sliding window
- errors.ts : BridgeError typee + 11 ErrorCode (AUTH/RG_VIOLATION/BASEROW_UNAVAILABLE...)
- bumps mineurs deps (hono, ofetch, ioredis, zod, pino) + ajout pino-pretty dev

tsc strict mode clean, biome ci clean. Tests unit a venir (Bloc 6 via bridge-tester).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 19:39:58 +02:00
66ff9097a6 ops(ci): add vitest config + sanity tests stub
- bridge/vitest.config.ts : config + coverage v8 + passWithNoTests
- bridge/tests/unit/sanity.test.ts : stub (real tests Phase 2)
- bridge/tests/integration/sanity.test.ts : stub
- Remove tests/.gitkeep
2026-05-07 12:25:00 +02:00
d510bddc34 ops: fix CI run — generate package-lock + bump testcontainers + doc 19 sync bidirec
- Add bridge/package-lock.json (npm install) — fix setup-node@v4 cache fail
- Bump testcontainers 10.x -> 11.14.0 (fix high CVE undici)
- Apply Biome formatter on src/index.ts + src/lib/config.ts
- Update doc 19 Bridge API design :
  * Add 5th mission : sync bidirectionnel Docmost <-> Baserow
  * Add endpoints /docmost/* write + /sync/* orchestration
  * Add section MCP server (Phase 3+) with tools/resources/prompts
  * Add anti-loop strategy (X-Bridge-Origin + idempotence Redis)
2026-05-07 12:20:44 +02:00
668576cdc4 chore: initial commit — formation-hub conception phase
Conception complete (Phase 0) pour formation-hub Acadenice :

- 19 docs Merise Agile + UML + GitOps + plans (tests/deploy/ops/api)
  cf docs/00-readme.md pour l'index complet
- Stack Docker compose (Docmost + Baserow + Postgres + Redis + MinIO local FS)
  compose.yml + compose.staging.yml + compose.prod.yml
- CI/CD GitHub Actions skeleton (ci, deploy-staging, deploy-prod)
- Bridge service skeleton (Hono + TS + Biome + Vitest + zod + pino)
- Templates GitHub : PR + 3 issue types + CODEOWNERS + dependabot.yml
- Scripts ops : healthcheck, backup quotidien, smoke-test post-deploy
- LICENSE AGPL-3.0 + SECURITY.md + CONTRIBUTING.md + CHANGELOG.md
- Diagramme drawIO archi infra (XML importable dans diagrams.net)

Decisions structurelles enregistrees :
- Scope CFA + Agence avec entite PERSONNE pivot multi-roles (ADR-001)
- Stack composite Docmost AGPL + Baserow MIT + bridge custom (ADR-001)
- Path B : UX quasi-unified via Tiptap node-views custom (ADR-002)
- Monorepo trunk-based development (ADR-003)
- Postgres separe Docmost/Baserow (ADR-004)
- Bridge stack Node 22 + Hono (ADR-005)
- Repo neuf prefere a fork Docmost
- Prod-like des le jour 1 (pas MVP)
2026-05-07 12:16:19 +02:00