gigafibre-fsm/docs/ENGINEERING_PRACTICES.md
louispaulb 8b23367939 docs: cadre best-practices « ne rien échapper » + automatisation closed-loop (tailored stack TARGO)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 11:34:10 -04:00

7.4 KiB

Best practices — « ne rien échapper » + automatiser au maximum

Cadre d'ingénierie pour la plateforme TARGO (ERPNext/PG · targo-hub Node · Ops Quasar · PWA tech · portail Lovable · ponts legacy MariaDB/osTicket/Ministra · intégrations Stripe/Twilio/GenieACS/Forti). Objectif double : fiabilité (rien ne tombe entre les craques) + automatisation closed-loop.

Principe directeur : toute action inter-systèmes doit être (1) idempotente, (2) observable, (3) réconciliée. Toute automatisation doit être closed-loop : agir → vérifier le résultat → réessayer/alerter si échec.


A. Intégrité des données — « rien ne tombe »

  1. Une seule source de vérité par domaine. Facturation = legacy jusqu'au cutover ; dispatch = ERPNext ; provisioning TV = Ministra. Jamais deux plumes sur la même donnée (cf. analyse Ministra : un 2ᵉ chemin = double facturation).
  2. Idempotence partout : clé naturelle externe sur chaque objet importé/synchronisé (déjà fait : legacy_ticket_id). Étendre aux webhooks Stripe (event.id), SMS, provisioning.
  3. Pattern Outbox pour les écritures « locale + appel externe » : écrire l'intention en base d'abord, un worker la pousse et marque done/failed. Évite « écrit en local mais l'API a échoué » (le risque exact du wizard Ministra).
  4. Réconciliation périodique : un job qui compare source ↔ ERPNext et signale la dérive (ex. tickets assign_to=3301 côté legacy vs Dispatch Jobs créés ; abonnements Ministra vs service). Le pont crée — la réconciliation prouve qu'aucun n'a été échappé.
  5. Soft-delete + audit trail : ne jamais perdre une donnée ; tracer qui/quand/quoi (ERPNext le fait nativement ; l'exposer côté hub pour les actions du hub).

B. Observabilité — « on SAIT quand ça casse »

  1. Logs structurés (JSON, pino) avec correlation_id par requête/job — finis les console.log. Un job legacy-sync = une ligne {job, created, errors, ms} traçable.
  2. /healthz + /readyz sur le hub (DB ok ? ERPNext ok ? legacy ok ?) → branchés sur Uptime-Kuma (déjà en place pour le réseau).
  3. Heartbeat sur CHAQUE tâche planifiée : le legacy-sync, le PPA cron, les pollers doivent « pinger » à chaque tick ; si un tick manque → alerte. (Un cron muet qui meurt = des tickets non importés sans que personne le sache.)
  4. Alerting : erreurs (Sentry/GlitchTip self-host) + métriques (Prometheus + Grafana, ou au minimum un endpoint /metrics). Alertes vers le canal ops existant (Twilio/email).
  5. Bannir le catch {} muet : tout catch logge + incrémente un compteur d'erreurs. (Plusieurs catch (e) {} actuels avalent des échecs silencieusement.)

C. Fiabilité des intégrations

  1. Retry + backoff exponentiel (généraliser retryWrite à tous les appels externes Ministra/Twilio/Stripe/GenieACS), avec plafond et dead-letter (file des échecs définitifs à rejouer).
  2. Webhooks idempotents + signés + rejouables (Stripe a déjà event.id ; vérifier la signature, stocker l'event, rejeu manuel possible).
  3. Circuit breaker sur un service externe en panne (ne pas marteler Ministra/legacy en boucle → respecte aussi fail2ban legacy).
  4. Timeouts explicites sur tous les appels réseau (déjà fait sur la DB legacy).
  5. Dégradation gracieuse : si Ministra est down, le job reste « à activer » et alerte — jamais d'échec silencieux.

D. Tests + CI/CD — « le scp manuel doit disparaître »

  1. Pipeline Gitea Actions par push : linttestbuild → deploy auto (staging puis prod sur tag). Remplace les scp à la main (source d'erreurs + pas de gate).
  2. Tests par couche : unitaires sur la logique pure (mapping pont, jobColor, firstFitStart, calculs facturation) ; intégration sur les endpoints hub (avec ERPNext/MariaDB de test) ; quelques E2E (Playwright) sur les parcours critiques (dispatch, booking, checkout).
  3. Environnement de staging iso-prod (« on est en lab » → formaliser un vrai staging séparé de la prod).
  4. Migrations versionnées (les Custom Fields via script idempotent → bon ; versionner toutes les migrations ERPNext + schéma).
  5. Rollback en 1 commande (garder les N derniers bundles ; le déploiement actuel écrase — conserver l'ancien pour rollback instantané).

E. Sécurité & secrets

  1. Gestion centralisée des secrets (Vault/Infisical/ou au moins des .env chiffrés + rotation) — aujourd'hui dispersés (creds Ministra en dur dans le PHP legacy, tokens en .env).
  2. Moindre privilège : la DB legacy en SELECT-only (bien) ; appliquer partout. Les liens tech non authentifiés (reply_ticket.php, connect_ministra.php) → tokens à expiration à terme.
  3. Audit d'accès + 2FA sur les surfaces admin (Authentik déjà là — généraliser).
  4. Sauvegardes testées + DR : backup auto ERPNext PG + MariaDB legacy + restauration testée (un backup jamais restauré n'existe pas).

F. Automatisation closed-loop — « le plus possible »

  1. Événementiel > polling quand possible : le pont legacy poll 15 min → ajouter un trigger côté legacy (webhook/INSERT trigger → ping hub) pour le quasi-temps-réel. Garder le poll comme filet de sécurité.
  2. Auto-dispatch : le solveur roster (déjà là) propose ; viser l'assignation auto des jobs simples + suggestion classée pour le reste (proximité quand la géo arrivera).
  3. Réconciliation auto-corrective (self-healing) : un job qui re-crée/re-aligne ce qui a dérivé, plutôt qu'un simple rapport.
  4. Moteur de flux : agent-flows existe déjà → en faire le squelette des automatisations métier (relance, escalade SLA, activation, avis client) plutôt que du code ad hoc dispersé.
  5. SLA monitors : alerte si un job reste non-assigné > X h, un ticket TV non-activé > X j, un paiement non réconcilié, un client hors quart (déjà le badge ).
  6. AI ciblée (déjà : OCR, copilote, outage) → étendre : matching compétence↔type de cas (historique), triage/priorisation des tickets, détection d'anomalies de facturation.

Roadmap priorisée (incrémental, sans tout casser)

Quick wins (jours) — fiabilité immédiate

  • /healthz + heartbeat du legacy-sync → Uptime-Kuma + alerte si tick manqué.
  • Logs structurés + suppression des catch {} muets (au moins compter + logguer).
  • Endpoint /dispatch/legacy-sync/reconcile : compte legacy(3301,open) vs Dispatch Jobs → signale les manquants.
  • Conserver le bundle N-1 au déploiement (rollback instantané).

Court terme (semaines) — arrêter l'érosion

  • Pipeline Gitea Actions (lint+build+deploy) → fin du scp manuel + staging réel.
  • Premiers tests unitaires sur la logique pure (pont, jobColor, firstFitStart, facturation).
  • Retry+backoff+dead-letter généralisés (Ministra/Twilio/Stripe).
  • Sentry/GlitchTip self-host + alerting.

Stratégique (mois) — automatiser & sécuriser

  • Outbox + réconciliation auto-corrective sur les ponts.
  • Événementiel (triggers legacy → hub) + SLA monitors via agent-flows.
  • Gestion centralisée des secrets + rotation + DR testé.
  • Cutover progressif des sources de vérité (legacy → ERPNext), domaine par domaine.

Règle d'or pour « ne rien échapper » : si une action peut échouer silencieusement, elle DOIT être (a) réessayée, (b) mise en dead-letter, et (c) visible sur un tableau de bord. Aucune exception.