Wiki/docs/19-bridge-api-design.md
Corentin JOGUET 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

26 KiB

Bridge API Design

Specification du bridge service : architecture, endpoints, auth, contrats, integration patterns. Service Node TS qui expose Baserow comme nodes Tiptap custom dans Docmost et orchestre les rollups cross-zone. Statut : design doc avant code Phase 2.

1. Mission du bridge

Le bridge est notre seul code custom. Il a 5 missions :

  1. Exposer les rows Baserow comme objets typed au reste de l'ecosysteme (typing strict, validation, cache)
  2. Recevoir les webhooks Baserow pour invalider caches et declencher actions (notifications, recalculs cross-zone)
  3. Servir les Tiptap node-views custom dans Docmost (mention @formateur, embed [projet], etc.) avec donnees fraiches
  4. Orchestrer les workflows metier que ni Docmost ni Baserow ne savent faire seuls (validation RG, notifications croisees, capacite Personne unifiee)
  5. Synchroniser bidirectionnel Docmost ↔ Baserow — c'est la mission centrale. Le bridge ecrit dans les deux systemes, pas juste lecture.

1.1 Bidirectionnalite — patterns de sync

Pattern Direction Trigger Effet
Auto-creation page Docmost Baserow → Docmost Webhook row.created sur projet Cree une page Docmost "Projet X" dans la collection [AGENCE] Projets avec template (statut, charge, taches embed)
Auto-creation collection Baserow → Docmost Webhook row.created sur formation Cree une collection Docmost [CFA] Formation X avec sub-pages par bloc
Maj metadata page Baserow → Docmost Webhook row.updated sur projet/formation Update title/icon/cover de la page Docmost liee
Auto-creation row Baserow Docmost → Baserow Webhook page created (si template specifique) Page "Compte-rendu reunion" cree → row dans table comptes_rendus
Mention enrichie Baserow → Docmost (lecture seule) User tape @personne:Pierre dans editeur Bridge resoud nom + capacite restante en live
Bouton action page Docmost → Baserow User clique "Cloturer projet" sur la page Docmost Bridge update projet.statut = cloture dans Baserow

Le bridge n'a pas d'etat metier propre (Phase 2). Source of truth = Baserow pour la donnee structurée + Docmost pour le contenu rich. Le bridge est stateless avec cache Redis pour les jointures.

1.2 Strategie anti-boucle infinie

Risque : un webhook Baserow declenche un write Docmost qui declenche un webhook Docmost qui re-declenche un write Baserow → boucle.

Mitigations :

  • Header X-Bridge-Origin: bridge sur les writes du bridge (les webhooks ignorent les rows ayant ce flag)
  • Idempotence par event_id en Redis (TTL 24h)
  • Rate limit cote bridge sur les sync auto (max 1 sync identique / 5 min)
  • Logging exhaustif pour debug

2. Tech stack

Composant Choix Justification
Runtime Node 22 LTS Stable, ecosysteme TS mature
Framework HTTP Hono Leger, performant, TypeScript-first, edge-ready si futur
Validation Zod Schemas TS-typed, runtime validation
HTTP client ofetch Wrapper fetch avec retry, timeout, JSON typing
Cache Redis 7 Partage avec Docmost ou dedie (decision Phase 2)
Tests Vitest + testcontainers Cf doc 16
Logger Pino Structured JSON logs, perf
Config dotenv + zod .env parse + valide au boot
Build TypeScript native + bundling esbuild Pas Webpack, simple
Deploy Docker image multi-stage Image < 100 Mo

3. Architecture interne

flowchart TB
    subgraph "Bridge service (Hono)"
        Routes[Routes layer<br/>endpoints REST + webhooks]
        Middleware[Middleware<br/>auth, logging, rate-limit, error]
        Services[Services layer<br/>PersonneService, ProjetService, etc.]
        Adapters[Adapters layer<br/>BaserowClient, DocmostClient, RedisCache]
        Domain[Domain layer<br/>Personne, Module, Tache classes pures]
    end

    Routes --> Middleware
    Middleware --> Services
    Services --> Domain
    Services --> Adapters

    Adapters -->|HTTP| Baserow[(Baserow API)]
    Adapters -->|HTTP| Docmost[(Docmost API)]
    Adapters -->|TCP| Redis[(Redis)]

Layers :

  • Routes : declaration endpoints + Zod schemas + delegation services
  • Middleware : transverse (auth, logs, rate-limiting, error handling)
  • Services : logique metier orchestree (Use Cases level)
  • Domain : classes pures (Personne, Module, Attribution... cf doc 12)
  • Adapters : isolation IO (Baserow API, Docmost API, Redis)

4. Conventions API REST

4.1 Style

  • REST-ish : endpoints orientes resources, verbes HTTP standards (GET, POST, PUT, PATCH, DELETE)
  • JSON uniquement (request + response)
  • Response shape standard :
// Success
{ "data": <payload>, "meta"?: { ... } }

// Error
{ "error": { "code": "ERR_CODE", "message": "Human readable", "details"?: {...} } }

4.2 Naming

  • Plural noms : /personnes, /projets, /attributions
  • IDs en path : /personnes/:id
  • Sub-resources : /projets/:id/taches
  • Actions : verb-style en POST si non-CRUD : /attributions/:id/cloturer

4.3 Versioning

  • Prefix /api/v1/ sur toutes les routes
  • Breaking change → nouvelle version /api/v2/ (en parallele pendant transition)
  • Deprecations annoncees minimum 3 mois avant retrait

4.4 Pagination, filtre, tri (pour les list endpoints)

GET /api/v1/personnes?
  page=1&            # default 1
  per_page=50&       # default 50, max 200
  sort=nom&          # default id desc
  filter[role]=formateur&
  filter[statut]=actif

Response :

{
  "data": [...],
  "meta": {
    "page": 1,
    "per_page": 50,
    "total": 127,
    "total_pages": 3
  }
}

5. Authentification

5.1 Strategies

Type Usage Header
API Token longue duree Service-to-service (Docmost ↔ Bridge, Cron ↔ Bridge) Authorization: Bearer brg_<token>
JWT court (Phase 3+) User authentifie via Docmost SSO Authorization: Bearer <jwt>
Webhook signature Verification webhook Baserow X-Baserow-Signature: <hmac-sha256>

5.2 Generation tokens

API tokens generes via CLI bridge :

npm run --prefix bridge token:create -- --name "docmost-prod" --scopes "read:* write:attributions"
# → "brg_a1b2c3d4..." stocke en .env.prod cote Docmost

Tokens stockes en clair dans une table api_tokens Postgres (Phase 3+) ou en memoire au boot via .env (Phase 2 simple).

5.3 Scopes

Scope Permissions
read:personnes GET /personnes/*
read:projets GET /projets/*
write:attributions POST/PATCH /attributions
write:interventions POST/PATCH /interventions
webhook:baserow POST /webhooks/baserow/*
admin:* Tout (Corentin/Yan tokens)

6. Endpoints REST

6.1 Personnes

Method Path Scope Description
GET /api/v1/personnes read:personnes Liste paginee, filtrable par role/statut
GET /api/v1/personnes/:id read:personnes Fiche detail avec heures restantes (formation + agence + total)
GET /api/v1/personnes/:id/attributions read:personnes Attributions actives + historiques
GET /api/v1/personnes/:id/interventions read:personnes Interventions sur taches (paginees)
GET /api/v1/personnes/:id/dashboard read:personnes Vue 360 : capacite, attributions, interventions, projets en cours

6.2 Formations / Blocs / Modules

Method Path Scope Description
GET /api/v1/formations read:formations Liste paginee
GET /api/v1/formations/:id read:formations Detail avec blocs/modules + rollups
GET /api/v1/blocs/:id read:formations Detail bloc + modules
GET /api/v1/modules/:id read:formations Detail module + attributions actives
POST /api/v1/modules/:id/attribuer write:attributions Cree une attribution avec validation RG

6.3 Attributions

Method Path Scope Description
GET /api/v1/attributions/:id read:attributions Detail
PATCH /api/v1/attributions/:id/heures-realisees write:attributions Saisir heures realisees (UC-13)
POST /api/v1/attributions/:id/cloturer write:attributions Statut → realise
POST /api/v1/attributions/:id/annuler write:attributions Statut → annule (justification requise)

6.4 Clients / Projets / Taches

Method Path Scope Description
GET /api/v1/clients read:projets Liste
GET /api/v1/clients/:id read:projets Detail + projets
GET /api/v1/projets read:projets Liste filtrable par statut/client
GET /api/v1/projets/:id read:projets Detail + taches + heures realisees rollup
GET /api/v1/projets/:id/timeline read:projets Vue chronologique interventions
GET /api/v1/taches/:id read:projets Detail + interventions

6.5 Interventions

Method Path Scope Description
POST /api/v1/interventions write:interventions Saisir intervention (UCA-07)
PATCH /api/v1/interventions/:id write:interventions Edit (heures, notes)
POST /api/v1/interventions/:id/annuler write:interventions Annulation

6.6 Rapports

Method Path Scope Description
GET /api/v1/rapports/formation/:id?format=pdf read:formations PDF rapport formation
GET /api/v1/rapports/personne/:id?format=pdf read:personnes PDF rapport personne (heures + attributions)
GET /api/v1/rapports/projet/:id?format=pdf read:projets PDF rapport projet

6.7 Docmost — write endpoints (sync bidirectionnel)

Method Path Scope Description
POST /api/v1/docmost/pages write:docmost Cree une page Docmost (avec template, parent, collection)
PATCH /api/v1/docmost/pages/:id write:docmost Update page (title, icon, cover, content partiel)
POST /api/v1/docmost/collections write:docmost Cree une collection Docmost
POST /api/v1/docmost/share-links write:docmost Genere un lien de partage (avec password/expiration)

6.8 Sync bidirectionnel — endpoints orchestration

Method Path Scope Description
POST /api/v1/sync/projet/:id admin:sync Force la sync d'un projet Baserow → page Docmost (utile pour reconciliation)
POST /api/v1/sync/formation/:id admin:sync Force la sync d'une formation → collection Docmost
POST /api/v1/sync/all admin:sync Sync complete batch (a executer manuellement, lent)
GET /api/v1/sync/status admin:sync Statut dernier sync, queue, erreurs

6.9 Health & metrics

Method Path Scope Description
GET /api/health (none) Healthcheck (200 si OK, 503 si degraded)
GET /api/ready (none) Readiness (Baserow + Docmost + Redis joignables)
GET /api/metrics admin:* Prometheus metrics format

7. Webhooks Baserow

Baserow envoie des webhooks sur les changements de rows. Bridge traite et reagit.

7.1 Endpoints webhook

Method Path Description
POST /api/webhooks/baserow/attribution-changed Row created/updated/deleted sur table attribution
POST /api/webhooks/baserow/intervention-changed Idem intervention
POST /api/webhooks/baserow/module-status-changed Quand module_statut change
POST /api/webhooks/baserow/projet-status-changed Quand projet_statut change

7.2 Format payload Baserow (extrait)

{
  "table_id": 123,
  "database_id": 1,
  "event_type": "rows.created",
  "items": [
    { "id": 42, "field_X": "...", ... }
  ]
}

7.3 Verification signature

// middleware/webhook-baserow.ts
const expected = hmacSha256(rawBody, env.BASEROW_WEBHOOK_SECRET);
const provided = req.headers['X-Baserow-Signature'];
if (!constantTimeEqual(expected, provided)) {
  throw new Error('Invalid signature');
}

7.4 Actions par webhook

Webhook Actions
attribution-changed Invalide cache Redis personne/module concernes ; si statut change vers realise ou annule → recalcul rollup module ; notif email formateur si nouvelle attribution
intervention-changed Invalide cache personne/tache ; check capacite Personne, alerte si depassement
module-status-changed Si tous modules d'une formation realise → declenche cloture formation auto (OP-07)
projet-status-changed Si livre → notif admin pour facturation

7.5 Idempotence

Chaque webhook a un event_id. Le bridge stocke en Redis avec TTL 24h les events deja traites :

const seen = await redis.get(`webhook:event:${event_id}`);
if (seen) return; // skip duplicate
await redis.set(`webhook:event:${event_id}`, '1', 'EX', 86400);

8. Cache strategy

8.1 Cles Redis

Cle TTL Contenu
bridge:personne:<id> 5 min JSON full Personne (avec rollups calcules)
bridge:projet:<id> 5 min JSON full Projet
bridge:formation:<id> 10 min JSON Formation (change moins souvent)
bridge:webhook:event:<event_id> 24h Idempotence webhook
bridge:rate-limit:<token>:<endpoint> 1 min Rate limit counter

8.2 Invalidation

  • Webhook Baserow invalide les cles concernees
  • TTL comme fallback (5-10 min)
  • Pattern : cache.invalidate('bridge:personne:42') apres write

8.3 Cache aside pattern

async getPersonne(id: number): Promise<Personne> {
  const cached = await cache.get(`bridge:personne:${id}`);
  if (cached) return Personne.fromJSON(cached);

  const fresh = await baserow.fetchPersonne(id);
  await cache.set(`bridge:personne:${id}`, fresh.toJSON(), 'EX', 300);
  return fresh;
}

9. Rate limiting

Par token + endpoint (sliding window 1 min) :

Endpoint Limite
Read endpoints 600 req/min
Write endpoints 60 req/min
Webhooks 1000 req/min
Rapports PDF 10 req/min

Reponse 429 si depasse :

{ "error": { "code": "RATE_LIMITED", "message": "Too many requests", "retry_after": 30 } }

10. Error handling

10.1 Codes d'erreur

Code HTTP Description
AUTH_REQUIRED 401 Token absent
AUTH_INVALID 401 Token invalide
FORBIDDEN_SCOPE 403 Token n'a pas le scope requis
NOT_FOUND 404 Ressource inexistante
VALIDATION_ERROR 400 Body invalide (Zod errors)
RG_VIOLATION 422 Regle de gestion violee (ex RG-01 depassement heures module)
CONFLICT 409 Etat incoherent (ex annuler une attribution deja annulee)
RATE_LIMITED 429 Trop de requetes
BASEROW_UNAVAILABLE 502 Baserow API down
INTERNAL 500 Bug bridge

10.2 Format

{
  "error": {
    "code": "RG_VIOLATION",
    "message": "Heures attribuees depassent la capacite du module",
    "details": {
      "rule": "RG-01",
      "module_id": 42,
      "heures_module": 30,
      "heures_deja_attribuees": 28,
      "heures_demandees": 5
    }
  }
}

11. Integration patterns Docmost

11.1 Tiptap node-view custom

Phase 2+ : on developpe (ou on commande a un freelance) des extensions Tiptap pour Docmost qui appellent le bridge.

Patterns :

  • Mention @formateur:Pierre → render carte avec capacite restante via GET /personnes/:id (slug → resolution)
  • Embed [projet:projet-alpha] → render card avec status + heures realisees
  • Database view [modules-a-attribuer] → embed kanban filtré

Ces nodes appellent le bridge via fetch + cache cote client (5 min).

11.2 Routes pages full

Phase 2+ : le bridge sert aussi des pages full /personne/:id, /projet/:id, /formation/:id qui ressemblent a des pages Docmost (header layout + content).

Implementation : Hono cote backend rend HTML avec layout Docmost mimique + content custom. Le user clique sur une mention dans Docmost, ouvre la page bridge, voit le meme look.

Ou en Phase 3 : on contribue au repo Docmost upstream pour ajouter ces nodes nativement.

12. Sample request/response

Saisir heures realisees

PATCH /api/v1/attributions/42/heures-realisees HTTP/1.1
Host: bridge.acadenice.fr
Authorization: Bearer brg_xxxxx
Content-Type: application/json

{
  "heures_realisees": 3.5,
  "comment": "Cours JS du 2026-05-07 OK"
}

Response 200 :

{
  "data": {
    "attribution_id": 42,
    "heures_attribuees": 10,
    "heures_realisees": 3.5,
    "statut": "en_cours",
    "module": {
      "module_id": 17,
      "module_nom": "JS Fondamentaux",
      "heures_realisees_total": 3.5
    },
    "personne": {
      "personne_id": 5,
      "nom_prenom": "Pierre Dupont",
      "heures_attribuees_formation": 80,
      "heures_restantes_formation": 670
    }
  }
}

Erreur RG violation

POST /api/v1/modules/17/attribuer HTTP/1.1
Authorization: Bearer brg_xxxxx
Content-Type: application/json

{
  "personne_id": 5,
  "heures_attribuees": 50,
  "date_debut": "2026-09-01"
}

Response 422 :

{
  "error": {
    "code": "RG_VIOLATION",
    "message": "Heures attribuees depassent la capacite du module",
    "details": {
      "rule": "RG-01",
      "module_id": 17,
      "heures_module": 30,
      "heures_deja_attribuees": 0,
      "heures_demandees": 50
    }
  }
}

13. Observabilite

13.1 Logs (Pino structured JSON)

Niveau info par defaut, debug en local. Format :

{
  "level": "info",
  "time": "2026-05-07T10:23:45.123Z",
  "msg": "PATCH /api/v1/attributions/42/heures-realisees",
  "method": "PATCH",
  "path": "/api/v1/attributions/42/heures-realisees",
  "status": 200,
  "duration_ms": 142,
  "user_token_id": "tok_abc123",
  "request_id": "req_xyz789"
}

Champs sensibles redactes : pas de body en logs, pas de token en clair.

13.2 Metrics Prometheus

Exposees sur /api/metrics :

  • http_requests_total{method,path,status} counter
  • http_request_duration_seconds{method,path} histogram
  • baserow_api_calls_total{endpoint,status} counter
  • cache_hits_total / cache_misses_total
  • webhook_events_processed_total{type,outcome}

13bis. MCP server (Phase 3+)

Idee retenue par Corentin le 2026-05-07 : exposer le bridge aussi comme MCP server pour permettre a Claude (et autres agents IA) d'interagir avec formation-hub.

13bis.1 Vision

Le bridge expose deux protocoles :

  • REST classique pour Docmost / Tiptap nodes / scripts (ce qui est specifie dans les sections 4-12)
  • MCP (Model Context Protocol) pour les agents IA — meme logique metier, transport different

Avec MCP, Claude peut :

  • Querier "donne-moi la capacite restante de Pierre Dupont"
  • Creer "attribue le module JS Fondamentaux a Pierre"
  • Generer rapports "fais-moi un rapport de la formation Dev Fullstack"
  • Detecter problemes "trouve les modules sans formateur attribue dans formation X"

Cas d'usage concret : un assistant IA pour l'admin pedagogique qui aide a equilibrer les charges, detecter les depassements, suggerer des reattributions.

13bis.2 Implementation

Stack :

  • @modelcontextprotocol/sdk (Node) — SDK officiel Anthropic
  • Le serveur MCP wrapping les services existants du bridge
  • Transport : stdio (pour Claude Code) OU HTTP/SSE (pour autres clients)

Co-localisation :

  • Meme codebase bridge/
  • Module bridge/src/mcp/ qui re-utilise les services REST
  • Build separe : npm run mcp:start (binaire MCP standalone)
  • Ou meme proces : Hono REST + MCP SDK en parallele

13bis.3 Tools MCP exposes

Tool Description Inputs
formation_hub_get_personne Detail personne avec capacite personne_id ou email
formation_hub_search_personnes Liste filtree roles, statut, capacite_min
formation_hub_get_formation Detail formation + blocs + modules formation_id
formation_hub_get_projet Detail projet + taches + interventions projet_id
formation_hub_create_attribution Cree attribution avec validation RG module_id, personne_id, heures, date_debut
formation_hub_saisir_intervention Saisie intervention dev tache_id, personne_id, heures, date
formation_hub_get_capacite_unifiee Vue 360 capacite Personne (formation + agence) personne_id
formation_hub_search_modules_a_attribuer Modules en attente d'attribution formation_id?
formation_hub_generer_rapport Genere rapport PDF type (formation/personne/projet), id, format
formation_hub_simulate_attribution Dry-run attribution avec impact rollups (sans ecrire) comme create_attribution

13bis.4 Resources MCP

Resources MCP = donnees exposees en lecture (vs tools qui sont des actions) :

  • formation-hub://personnes — liste des personnes
  • formation-hub://personnes/{id} — detail personne
  • formation-hub://formations — liste formations
  • formation-hub://projets/active — projets en cours
  • formation-hub://capacity-overview — synthese capacite globale equipe

13bis.5 Prompts MCP

Prompts MCP = templates Claude prets a l'emploi :

  • equilibrer-charges : Claude analyse les attributions et propose des rebalancing
  • detecter-depassements : Claude scan les capacites et signale les problemes
  • planifier-formation : Claude aide a decomposer une formation en blocs/modules
  • synthese-projet : Claude genere un rapport status pour un projet client

13bis.6 Auth MCP

  • API token bridge (brg_* tokens, scope admin:mcp)
  • Token configure dans le client MCP (.claude/settings.json cote Claude Code)
{
  "mcpServers": {
    "formation-hub": {
      "command": "node",
      "args": ["bridge/dist/mcp-server.js"],
      "env": {
        "BRIDGE_API_TOKEN": "brg_xxxx",
        "BRIDGE_URL": "https://bridge.acadenice.fr"
      }
    }
  }
}

13bis.7 Roadmap MCP

Phase Effort Livrable
Phase 3.0 (apres bridge REST stable) 1-2 semaines MCP server avec 5 tools cles (get_personne, get_formation, capacite_unifiee, search_modules_a_attribuer, simulate_attribution)
Phase 3.1 1 semaine Tools writes (create_attribution, saisir_intervention)
Phase 3.2 1 semaine Resources + prompts
Phase 4 continu Integration dans workflows admin (Yan/Corentin utilisent Claude pour piloter formation-hub)

13bis.8 Decisions a prendre Phase 3

  • Transport MCP : stdio only (Claude Code local) ou HTTP/SSE (multi-client web) ?
  • Co-localisation MCP + REST dans meme proces ou processus separes ?
  • MCP expose sur quel hostname ? (probablement pas accessible depuis internet, juste localhost ou VPN interne)
  • Authoring tools : Claude peut-il creer/modifier des entites ou seulement lire ? Decision selon trust ELO Claude vs human-in-the-loop pattern.

14. Tests

Cf doc 16 plan-de-tests :

  • Unit Vitest 80% coverage minimum sur domain
  • Integration tests avec testcontainers Baserow + Redis
  • E2E playwright sur staging

15. Roadmap implementation

Phase 2.0 — Bootstrap (semaine 1-2)

  • Setup Hono + zod + ofetch + pino
  • BaserowClient avec tests integration
  • DocmostClient skeleton
  • Healthcheck endpoint
  • Auth middleware basique (API token)
  • CI/CD complet (cf doc 17)
  • Deploy staging

Phase 2.1 — Read endpoints (semaine 3-4)

  • GET /personnes/:id avec rollups calcules
  • GET /projets/:id
  • GET /formations/:id
  • Cache Redis pattern cache-aside
  • Tests integration sur les endpoints

Phase 2.2 — Write endpoints + webhooks (semaine 5-7)

  • POST /interventions
  • PATCH /attributions/:id/heures-realisees
  • Webhooks Baserow handlers
  • Validation RG-01 a RG-06
  • Tests integration write

Phase 2.3 — Tiptap nodes (semaine 8-10)

  • Premier node Tiptap custom (mention @formateur)
  • Integration Docmost (fork ou plugin)
  • E2E playwright

Phase 2.4 — Pages full + rapports + sync bidirec (semaine 11-12)

  • Routes /personne/:id, /projet/:id en page Docmost-style
  • Endpoint /rapports/* PDF generation
  • Endpoints /docmost/pages write (auto-creation depuis evenements Baserow)
  • Endpoints /sync/* orchestration manuelle
  • Strategie anti-boucle infinie (header X-Bridge-Origin, idempotence)
  • Stabilisation, fix bugs, doc utilisateur

Phase 3.0 — MCP server (apres bridge REST stable)

  • Setup @modelcontextprotocol/sdk Node
  • 5 tools cles read-only
  • Auth via API token (scope admin:mcp)
  • Documentation client (Claude Code config)

16. Decisions a prendre

  • Source of truth tokens : .env (simple) vs Postgres dedie (rotation a chaud) ? Mon vote : .env Phase 2, Postgres Phase 3
  • Cache Redis partage Docmost ou dedie ? Partage Phase 2 (simple, sa marche), dedie Phase 3 si charge ou conflits
  • PDF generation : Puppeteer (lourd) vs PDFKit (manuel) vs service externe (gotenberg) ? Recommande PDFKit ou gotenberg self-host
  • OpenAPI 3 doc auto : generee depuis Zod schemas ? Lib @asteasolutions/zod-to-openapi. A faire Phase 2.1.
  • GraphQL au lieu de REST ? Pas pertinent pour notre scope (peu de endpoints, peu de variation queries). REST est plus simple.
  • Multi-tenant ? Pour l'instant non — Acadenice mono-instance. Si rachat / scaling : ajouter tenant_id partout. Pas avant Phase 4.

17. Decisions techniques notables (deja prises)

  • Bidirectionnalite : confirme par Corentin le 2026-05-07. Bridge ecrit dans Docmost ET Baserow (5 missions au lieu de 4).
  • MCP server : retenu pour Phase 3+. Expose les memes capacites bridge via le protocol MCP pour usage par Claude / autres agents IA.
  • Pas d'etat metier dans le bridge : reste stateless en Phase 2. Source of truth Baserow + Docmost.
  • Anti-boucle webhooks : header X-Bridge-Origin + idempotence Redis.

18. Glossaire

Terme Definition
Bridge Service custom qui se sert d'intermediaire entre Docmost (UI) et Baserow (data)
Tiptap node-view Composant React custom integre dans editeur Tiptap pour rendre un block specifique
Cache aside Pattern : check cache → if miss, fetch source + populate cache
Idempotence Une requete repetee a le meme effet qu'une requete unique (anti-doublon)
HMAC signature Hash crypto pour verifier l'authenticite d'un payload (webhook)
Sliding window rate limit Compteur sur fenetre glissante (ex: derniere minute)
RG Regle de Gestion (Merise)
Scope (token) Permission specifique (read:X, write:Y, admin:*)