Modélisation · Schémas de données — contenu minimal

Schémas de données — contenu minimal par service

Ce que chaque base doit contenir a minima pour que son service tienne ses agrégats et que la reprise ait une cible. Établi en croisant trois sources — la modélisation (schémas SVG des fiches de service), le code réel (changelogs Liquibase), l'infrastructure déployée (Database CR CloudNativePG en staging) — et intégrant le retour du chantier migration du 21/07/2026.

Pourquoi croiser trois sources. Le retour du chantier migration pose une réserve juste sur la colonne « Schéma runtime » de la page Reprise des données legacy : c'était une intention de modélisation, pas un état constaté. Cette page lève la réserve en distinguant, pour chaque schéma, ce qui est modélisé, ce qui est provisionné et ce qui est réellement créé par Liquibase. Les trois ne coïncident pas encore — les écarts sont listés en §7.
15bases, une par service
15schémas métier
5modules sans base
2schémas métier créés en code
+1base pivot de migration

1. Où vit un schéma, et qui le crée

Cible (staging, prod)Une base PostgreSQL par service dans un cluster CNPG unique sigfga-pg : 19 Database CR déclarées en GitOps (gitops/envs/staging/databases.yaml), owner: sigfga, sync-wave 1. Le service se connecte à sa base : jdbc:…/claims, …/contributions.
Dev localUne seule base sigfga avec un schéma par service (currentSchema=claims, …=medical_care) — commodité du docker-compose, pas la maille cible. Ne pas conclure d'un « un schéma par service » vu en local.
Création des tablesLiquibase, exclusivement (ADR-0002) : changesets en SQL formaté, changelog maître = pur index d'includes, jamais de changeset dedans. Aucun DDL cible écrit à la main par le chantier de reprise.
Interdits structurelsAucune FK entre bases de services (rupture d'isolation des bounded contexts). Aucune vue ni foreign data wrapper inter-services. Les liens passent par événements Kafka ou appels REST.
Référence externeUn identifiant d'un autre service se porte en colonne nue (claim_id uuid, insurer_id uuid) — sans contrainte, avec index. Sa cohérence est garantie par le flux d'événements, pas par la base.
MontantsXOF entiers (bigint) ou numeric — jamais float (défaut structurel de LOGPROD à corriger à la reprise).

2. Socle technique obligatoire — présent dans tout schéma

Résumé ci-dessous ; formes SQL de référence, justification de chaque table et arbitrages ouverts sur la page du socle technique.

Ces tables ne sont pas du domaine : elles sont la condition pour qu'un service publie, consomme et rejoue sans doublon. La forme de référence est celle du code : outbox_events est déjà créée dans les bases de service.

TableRôleObligatoire pourÉtat
outbox_eventsPublication transactionnelle des événements (écrits dans la même transaction que l'agrégat, relayés ensuite vers Kafka). Colonnes de référence : id bigserial, event_id varchar(40) unique, event_type, subject, payload, occurred_at, published, published_at + index (published, id).Tout service qui détient un état et publie (14 des 15)EN CODE 14 services
processed_eventsIdempotence de consommation : event_id PK + processed_at. Un événement rejoué par Kafka ne produit pas d'effet en double.Tout service qui consomme1 service (svc-medical-care)
idempotency_keysIdempotence des commandes REST : key PK, fingerprint, référence produite, created_at. Un POST rejoué renvoie la même ressource au lieu d'en créer une seconde.Tout service à API de commande1 service (svc-claims)
known_<entité>Projections locales alimentées par événements (copie en lecture seule d'une donnée d'un autre service, pour éviter un appel synchrone). Nommage explicite known_* : la table dit qu'elle n'est pas maître. Exemple en code : known_claims dans svc-medical-care.Selon dépendances1 service
databasechangelog
databasechangeloglock
Créées par Liquibase. Le pipeline de reprise lit databasechangelog pour vérifier la version de schéma attendue avant tout chargement, et s'arrête proprement en cas d'écart.Toutes les basesAUTOMATIQUE
Deux normalisations à acter — la modélisation et le code divergent.
  • inbox_events (dans 12 schémas modélisés : id, event_type, aggregate_id, payload, processed, processed_at) vs processed_events (en code : event_id, processed_at). Ce ne sont pas deux noms du même objet : le premier stocke la charge utile reçue, le second ne mémorise que l'identifiant traité. Recommandation : garder processed_events (dédup pure, volume constant) et ne matérialiser une vraie table d'entrée que là où un rejeu local du payload est requis.
  • outbox_events modélisé avec aggregate_id / created_at vs code avec subject / occurred_at / event_id unique. Le code fait foi : c'est la forme réellement créée par Liquibase. Les SVG des fiches sont à réaligner.
  • audit_logs apparaît dans 12 schémas et un service svc-audit-trail centralise la piste d'audit. Doublon à trancher : soit ces tables locales sont une trace technique assumée (et le disent), soit elles disparaissent au profit du journal central. Elles ne peuvent pas être toutes deux « la » piste d'audit exigée par les CDC.

3. Récapitulatif des 20 modules

« Tables métier » = noyau minimal hors socle technique. « Base » = base dédiée déclarée en GitOps. « Créé » = tables métier réellement présentes dans les changelogs Liquibase.

ServiceBaseTables métier min.ModéliséCréé (code)Reprise (statut révisé)
svc-reference-data10À FAIREÀ CHARGER
svc-claims6PARTIELÀ CHARGER
svc-medical-care10PROJECTIONÀ CHARGER périmètre précisé
svc-medical-billing6À CHARGER détail à confirmer
svc-compensation7FINANCIER + INSTRUCTION
svc-compensation-engine7À FAIREPARAMÉTRAGE
svc-contributions12INCOMPLETÀ CHARGER LOGPROD seul
svc-field-inspections5À CHARGER révisé
svc-statistics4RECALCULÉ
svc-debt-recovery6SANS SOURCE reconstitution
svc-payments4À TRANCHER depense
svc-documents4À CHARGER
svc-notifications4VIDE
svc-signatures3À FAIREVIDE
svc-audit-trail2VIDE
asaci-edge0SANS BASE
psp-edge0SANS BASE
erp-edge0SANS BASE
mobile-bff0SANS BASE
portal-bff0SANS BASE

Total noyau métier : 99 tables minimales, hors socle technique (≈ 3 tables par base) et hors base pivot de migration.

4. Contenu minimal, schéma par schéma

Le détail de chaque base — MCD minimal, liste des tables du noyau et des compléments, sources legacy et transformations, points de vigilance — fait l'objet d'une sous-page par schéma. Elles sont générées depuis une spécification unique, de sorte que le diagramme et le tableau de tables ne peuvent pas diverger.

Où aller. Les noms de service du tableau ci-dessus renvoient directement à leur MCD. Voir aussi le socle technique (tables communes à tout schéma), la base pivot de migration et les edges et BFF.

5. Base pivot de migration

La base sigfga_migration — staging brut, correspondance d'identifiants, rejets, réconciliation, inventaire GED — est séparée des bases de service et n'est jamais lue au runtime. Son contenu minimal et son MCD sont détaillés sur sa page dédiée.

6. Retour du chantier migration — intégration point par point

Retour du 21/07/2026 sur le tableau « reprise par service » : 8 lignes validées, 5 clarifications demandées, 1 statut contesté, 1 réserve transverse. Traitement de chacun.

PointDemandeTraitement
svc-field-inspectionsStatut trop prudent — controle = 35 153 lignes documentées. Demande « À CHARGER ».ACCEPTÉ Statut passé à À CHARGER ici et dans la page Reprise. Reformulé : ce qui reste au profiling est la qualité du rapprochement contrôle ↔ production, pas l'existence. Le service passe dans le chemin nominal du fan-out.
svc-contributionsPréciser le rôle des bordereaux Excel — risque de double comptage de l'assiette.ACTÉ Rôle limitatif écrit noir sur blanc (§4) : attestation seule est chargée ; les Excel = justificatifs MinIO + référentiel compagnies + jeux de parité + rattrapage des seuls bordereaux jamais importés. Et conséquence non demandée mais nécessaire : les trois tables qui accueillent cette matière (statement_lines, statement_imports, statement_rejects) n'existaient pas dans le schéma modélisé — la source de vérité de l'assiette n'avait pas de cible.
svc-compensationSortir du binaire : les 61 dossiers et leurs montants sont en base ; c'est l'instruction qui manque.ACCEPTÉ Statut scindé : volet financier À CHARGER (compensation_claims, damage_assessments), volet instruction selon décision n°2 (reprise GED seule vs ressaisie ciblée).
svc-medical-care
svc-medical-billing
« À CHARGER » fondé, mais préciser les sous-périmètres non confirmés.ACCEPTÉ Statut maintenu ; les sous-périmètres sont marqués table par table : prescriptions et feuilles de suivi (suivi : 2 lignes), détail de facturation (acte_frais : 5, acte_fournisseur : 2).
svc-documentsActer la décision GED : « fichiers vers MinIO » vs page « Architecture technique » qui affiche encore SharePoint O365.TRAITÉ Coexistence explicitée sur la page Architecture technique : MinIO = GED applicative (pièces de dossiers, ADR-0008), SharePoint O365 = bureautique/collaboratif cité par le CDC ERP. Deux briques, deux usages — la reprise ne vise que MinIO.
Réserve transverseLa colonne « Schéma runtime » est une intention, pas un état constaté. Le pipeline vérifie la version de schéma (ADR-0002) avant chargement.LEVÉE Cette page distingue modélisé / provisionné / créé en code pour chaque module (§3) et matérialise le contrôle de version dans run_registry (§5). Constat : l'intention et l'état réel ne coïncident pas encore partout — les écarts subsistants sont listés en §7.
Deux apports du retour au-delà des statuts. D'abord la méthode : confronter chaque ligne aux compteurs réels plutôt qu'au périmètre fonctionnel a fait apparaître un manque structurel (les lignes d'attestation sans cible) qu'aucune relecture du découpage n'aurait montré. Ensuite l'épistémologie : distinguer « la donnée n'existe pas » de « la donnée existe, sa qualité est inconnue » change la planification — le premier cas est une branche conditionnelle, le second entre dans le chemin nominal.

7. Écarts et arbitrages ouverts

Classés par gravité. Les cinq premiers touchent la justesse des données ; les suivants la cohérence de la documentation.

#ÉcartConséquence si non traitéDécision attendue
aLignes d'attestation sans ciblestatement_lines, statement_imports, statement_rejects absentes de svc-contributionsLa source de vérité de l'assiette des 2 % (0,8–3 M lignes) n'a nulle part où atterrir. Le montant dû n'est ni recalculable ni auditable ligne à ligne. Bloquant pour le fan-out contributions.Compléter le schéma avant le premier chargement. Valider la clé fonctionnelle de dédoublonnage.
bDouble comptage depense (1 087 lignes) — medical-billing ou payments ?Le décaissé est compté deux fois, ou pas du tout.Trancher au profiling : dette vs décaissement.
cDeux tables de paiementcompensation.compensation_payments et payments.payment_ordersDeux vérités sur l'argent versé à une victime.Retirer compensation_payments → projection ou identifiant nu.
dVictime et dossier dupliquésvictims et claim_files maîtres dans svc-medical-careDeux sources de vérité, et deux cibles de reprise pour les 293 victimes.Appliquer le patron known_* déjà présent en code.
eFrontière attestation ↔ RC Autostatement_lines vs rc_auto_recordsLa même attestation chargée dans deux services.Écrire la règle de partage (assiette vs flux statistique).
fUn schéma modélisé pour un module sans état — portal-bffLe schéma décrit user_profiles, user_sessions (avec refresh_token), notification_preferences… Or l'identité et les sessions appartiennent à Keycloak, et les préférences de notification à svc-notifications. Stocker un jeton de rafraîchissement dans un BFF est de surcroît un risque inutile.Retirer ce schéma. Voir Edges et BFF.
gDeux bases de paramétrage vides de source — SMIG, échelle du décret 2009-107, cas DJGSsvc-compensation-engine ne peut pas calculer, et son jeu de rejeu n'existe pas.Obtenir les trois éléments du client (déjà en question consolidée).
haudit_logs local × 12 + svc-audit-trailDeux « pistes d'audit », aucune ne fait autorité pour les CDC.Trancher : trace technique locale assumée, ou journal central seul.
iinbox_events vs processed_events et forme de outbox_eventsLes SVG des fiches décrivent un socle que le code ne construit pas.Réaligner les SVG sur le code (le code fait foi).
jJetons push sans table — la décision les place dans svc-notifications, aucune table ne les porteLe mobile ne peut pas être notifié, ou mobile-bff recrée une base pour ça.Ajouter device_push_tokens.
kTrois schémas non modélisés — svc-reference-data, svc-compensation-engine, svc-signaturesDont svc-reference-data, qui est la première tranche de livraison et le pivot de tous les recodages de la reprise.Modéliser en priorité reference-data (§4 en donne le contenu minimal).

8. Ce qui reste à produire

  • Les 3 schémas manquants (reference-data, compensation-engine, signatures) au même niveau de détail que les 13 existants — le contenu minimal ci-dessus en est la base.
  • Les 3 tables manquantes de svc-contributions, avec stratégie de partitionnement et clé de dédoublonnage — préalable au chargement de LOGPROD.
  • Le réalignement des 13 SVG sur le socle technique du code, et le retrait des tables hors périmètre (§7.c, §7.d, §7.f).
  • Le DDL de la base pivot — livrable du chantier migration, pas de la modélisation, mais sa liste de tables est arrêtée (§5).
  • Les décisions ouvertes : historique & rejeu d'événements, décision n°2 (instruction), frontière ERP/Odoo, sort du realm usagers Keycloak.