# Workflow : SYNC BIDIREC Docmost ↔ Baserow Orchestration de la synchronisation bidirectionnelle entre Docmost (wiki) et Baserow (DBs). Phase 2 — necessite que le bridge service soit deploye et operationnel. Equivalent BYAN-natif : event-driven workflow avec idempotence. ## Trigger L'un des suivants : - Webhook Baserow `row.created` / `row.updated` / `row.deleted` sur table donnee - Webhook Docmost `page.created` (si configure cote Docmost custom) - Action explicite admin : "Sync forcee projet 42 → Docmost" - Cron periodique de reconciliation (Phase 3+) ## Acteurs - **bridge-dev** (handler webhook + sync logic) - **acadenice-devops** (config webhooks + monitoring) - **bridge-tester** (validation idempotence + anti-loop) - **Corentin** (alerte si depassement capacite) ## Sequence — type webhook Baserow row.created sur table 'projet' ``` [1] Webhook recu (bridge endpoint POST /api/webhooks/baserow/projet-changed) - Verifier signature HMAC X-Baserow-Signature (anti-spoofing) - Si invalide : log + 401, ABORT - Output : event valide [2] Idempotence check (bridge + Redis) - Lire payload event_id - Redis : SET bridge:webhook:event: "1" EX 86400 NX - Si SET retourne null (key existait) : event deja traite, ABORT 200 - Sinon : continue - Output : event nouveau, marque traite [3] Anti-loop check - Verifier header X-Bridge-Origin sur la row Baserow - Si X-Bridge-Origin == "bridge" : c'est nous qui avons cree la row, ABORT - Sinon : c'est un user qui a cree, continue - Output : event source legitime [4] Logique metier (bridge service) - Pour 'row.created' sur 'projet' : * Fetch projet detail depuis Baserow (BaserowClient.getRow) * Fetch client lie (BaserowClient.getRow) * Calcul nom de page Docmost : "Projet [nom] - [client]" * Determiner space cible : "Agence" → fetch space ID - Output : payload pour creation Docmost [5] Action Docmost (bridge service via DocmostClient) - DocmostClient.createPage({ spaceId, title, content: template_projet(projet) }) - Header : X-Bridge-Origin: bridge (eviter loop futur) - Output : pageId Docmost cree [6] Update Baserow row (bridge service) - BaserowClient.updateRow(projet_id, { docmost_page_id: pageId }) - Header : X-Bridge-Origin: bridge - Output : projet Baserow enrichi avec docmost_page_id [7] Cache invalidation (bridge + Redis) - RedisCache.invalidatePattern("bridge:projet:*") - RedisCache.invalidatePattern("bridge:client::projets") - Output : caches invalides [8] Notif si capacite formateur depassee (cas attribution) - Si event = creation 'attribution' : * Recalculer Personne.heures_restantes_total * Si < 0 : notifier admin via SMTP/Slack - Output : notification envoyee si depassement [9] Audit log - Log structurel : { event_id, source: 'baserow', target: 'docmost', action: 'createPage', success: true, duration_ms, ... } - Output : trace persistee [10] Reponse webhook - Return 200 OK { processed: true, page_id: } ``` ## Patterns specifiques par event | Trigger | Action sync | |---------|-------------| | Baserow row.created sur `projet` | Auto-create page Docmost dans space Agence | | Baserow row.created sur `formation` | Auto-create collection Docmost (sub-pages par bloc) | | Baserow row.updated sur `projet`/`formation` (titre, statut) | Update title/icon page Docmost liee | | Baserow row.created sur `intervention` | Check capacite → notify admin si depassement | | Baserow row.created sur `attribution` | Notify formateur (email) + check capacite | | Docmost page.created (template specifique 'compte-rendu') | Auto-create row dans table `comptes_rendus` Baserow (Phase 3+) | | Docmost share.created | Log audit + notify admin (alerte data leak risk) | ## Gates humains Aucun gate bloquant — c'est event-driven temps reel. Mais : - Notif Corentin sur depassement capacite (asynchrone) - Notif Corentin sur erreurs critiques (sync echec apres 3 retry) ## Rollback / gestion d'erreurs | Echec | Strategy | |-------|----------| | Docmost API down | Retry 3x exponential backoff. Si tjrs KO : queue Redis pour retry batch | | Baserow row introuvable (race condition) | Fetch retry x2 avec 200ms delay. Sinon : log + skip event | | Cache invalidation echec | Log warning, continuer (TTL fallback 5 min) | | Notification SMTP fail | Log warning, alerte degraded | | Loop detecte (X-Bridge-Origin manquant cote bridge writes) | URGENT : alerte Corentin, audit code bridge | ## Anti-loop strategy (CRITICAL) Pour eviter Docmost → bridge → Baserow → bridge → Docmost → ... boucle infinie : 1. **Header X-Bridge-Origin** : tous les writes du bridge vers Baserow et Docmost ajoutent ce header 2. **Detection cote handler** : si l'event provient d'une row/page avec ce flag, ABORT 3. **Idempotence event_id** : meme si une boucle se forme, max 1 cycle (TTL 24h en Redis) 4. **Rate limit** : max 1 sync identique / 5 min sur entite (cle: `bridge:sync::`) 5. **Monitoring** : alerter si > 10 events identiques en 1 min (signe de boucle) ## Outputs - Pages Docmost crees automatiquement - Rows Baserow enrichies avec ids Docmost (lien bidirec) - Caches invalides - Audit log evenement traite - Notifications metier si necessaire ## Tests obligatoires - **Test idempotence** : envoyer le meme event 5 fois → un seul effet (bridge-tester) - **Test anti-loop** : simuler bridge-write → verifier que webhook ignore (bridge-tester) - **Test rate limit** : 100 events identiques en 1 min → verifier que rate limit kick in - **Test recovery** : Docmost down 5 min → events queues et processed apres recovery - **Test webhook signature invalid** : event avec mauvais HMAC → 401 (bridge-tester) ## Exemple invocation Trigger non-manuel — se declenche automatiquement quand Baserow envoie un webhook au bridge. Mais peut etre invoque manuellement pour : - Reconciliation : "WF SYNC : force re-sync de tous les projets non-mappes vers Docmost" - Debug : "WF SYNC : trace l'event ID xyz pour comprendre pourquoi il a abort" ## Notes - Webhooks Baserow : a configurer cote Baserow UI ou API (apres deploy bridge) - Endpoint signature secret : `BASEROW_WEBHOOK_SECRET` dans `.env` bridge - Logs : toutes les operations sync sont loguees structurellement (Pino) avec event_id pour traceability