Aller au contenu

Modèle de données

Les six typologies décrivent toutes une identité patient et la même réalité administrative (qui l’a soigné, où, quand). Deux mécanismes mutualisent ces champs. Les traits identifiants du patient (identité, adresse) vivent dans des tables dédiées partagées par toutes les typologies ; les autres champs transverses (source, prescripteur) restent des blocs de colonnes communs réutilisés à l’identique sur chaque table enfant. Dans les deux cas, un data manager réutilise le même mapping quelle que soit la source.

L’identité et l’adresse du patient vivent dans des tables dédiées (identities, addresses), partagées par toutes les typologies. À l’import, le pipeline crée (ou retrouve à l’identique) l’identité et l’adresse du signalement, puis les relie via reports.identity_id. Le détail du cycle est décrit dans Cycle de vie d’un signalement.

TableChamps
identitieslast_name, first_name, birth_name, birth_date, sex, nir_partial, + lieu de naissance (birth_commune, birth_postal_code, birth_insee_code)
addressesaddress, postal_code, city (+ ban_id, réservé à une vérification BAN ultérieure)

À savoir - le NIR complet n’est jamais stocké : seuls les 10 premiers chiffres (nir_partial) sont conservés. La troncature est faite par le SI Registres à l’import ; le data manager peut, par prudence, ne transmettre que ces 10 chiffres.

BlocChamps
Source & structuresource_structure_id, source_structure_label (+ finess pour traçabilité)
Prescripteur / médecinprescriber_name, prescriber_address, prescriber_postal_code, prescriber_city, prescriber_rpps

patient_ipp (identifiant patient interne à la structure source) est porté par la table enfant, pas par l’identité : ce n’est pas un trait d’identité partagé - deux structures peuvent réutiliser les mêmes numéros d’IPP.

Ces familles d’attributs sont les mêmes pour toutes les typologies et vivent donc sur la table parente, jamais dupliquées sur les enfants :

  • Lien identité / patient - identity_id (→ identities, toujours renseigné à l’import) et patient_id (raccourci vers le patient de l’identité, rempli en aval par l’identito-vigilance, null tant que le rapprochement n’a pas eu lieu).
  • Report controls - les décisions d’import par ligne (can_create_patient, can_create_tumor) - voir Report controls plus bas.
  • Exclusion - excluded, exclusion_origin, exclusion_reason_id, etc. - voir Exclusion plus bas.
  • Date de signalement (notification_date) - la date pivot du signalement : chaque pipeline la remplit avec la date clinique la plus pertinente de sa source, ce qui donne à toutes les typologies une seule colonne pour trier et paginer, indépendamment de la source.
    • ACP : prélèvement → enregistrement → validation (1ʳᵉ non nulle)
    • PMSI : entrée en hospitalisation
    • ALD : date d’ouverture
    • RCP : date de la RCP
    • Dépistage : date du test
    • Générique : la date saisie dans la colonne report_date à l’import

Le registre vise un codage CIM-O-3 (oncologie), composé d’une topographie (le site, Cxx.x) et d’une morphologie (l’histologie + le comportement, ex. 8140/3). Les sources, elles, arrivent dans des codages différents - d’où des transcodages distincts par typologie.

TypologieCodage sourceTranscodage vers CIM-O-3
ACPADICAP, SNOMED, ou texte libreÉclatement du code (organe → topo, lésion → morpho) via tables de référence ; fallback code générique C80.9 / 8000/3
PMSI, ALDCIM-10 (administratif)Topo = recopie du CIM-10 ; morpho dérivée par règle de préfixe (voir ci-dessous)
RCPCIM-O-3 natif (topo issue du CIM-10, morpho déjà en CIM-O)Aucun - codes conservés tels quels (warning si inconnu, jamais de rejet)
DépistageaucunTopo grossière dérivée du programme (breastC50, colorectalC18, cervixC53) ; pas de morphologie
GénériqueCIM-O-3 saisiAucun - stocké tel quel ; un code absent du référentiel CIM-O-3 (coquille, code inconnu) n’est pas rejeté à l’import, mais ne produira pas de tumeur

Règle de préfixe CIM-10 → comportement morphologique (PMSI, ALD) : C*/3 (malin), D00–D09/2 (in situ), D10–D36/0 (bénin), D37–D48/1 (incertain).

Code caractérisant (PMSI, ALD) - sur une source transcodée, le code CIM-10 retenu comme code cancer du signalement une fois passé le test « code cancer valide ». Quand le code n’est pas un cancer, le code caractérisant est NULL : le signalement est conservé (audit) mais ne produit pas de tumeur candidate. Pour le PMSI, qui porte plusieurs diagnostics par séjour, le code caractérisant est choisi par priorité DP → DR → DAS.

⚠️ Le périmètre précis des codes cancer valides se consolide encore et peut évoluer.

⚠️ Berg group / topo IARC - Encore en chantier : les référentiels topographiques et morphologiques européens servant de base à cette catégorisation restent à valider.


L’import et le rapprochement de l’identité à un patient sont deux étapes distinctes. Le pipeline d’import valide, transcode, met en qualité, puis injecte le signalement en créant (ou retrouvant à l’identique) son identité et son adresse. Un worker d’identito-vigilance distinct, en aval, tente ensuite de rattacher cette identité à un patient et décide de la suite.

flowchart TD
    F["Fichier source (CSV/Excel)<br/>au format canonique"] --> V{"Validation<br/>champs requis · formats · identité présente"}
    V -->|ligne invalide<br/>ou sans identité| REJ["Ligne rejetée<br/>(motif au preview)"]
    V -->|ligne valide| T["Transcodage + mise en qualité<br/>(CIM-O-3, code caractérisant, Berg/IARC)"]
    T --> INJ["Injection : identité + adresse (dédupliquées)<br/>+ reports (identity_id) + table enfant"]
    INJ --> IV{"Identito-vigilance<br/>(en aval)"}
    IV -->|patient rapproché| ATT["Identité rattachée au patient"]
    IV -->|aucun patient<br/>+ création autorisée| NEWP["Patient créé"]
    IV -->|aucun patient<br/>+ création interdite| ORP["Identité orpheline"]
    ATT --> TUM{"Création tumeur<br/>autorisée ?"}
    NEWP --> TUM
    TUM -->|oui + codage valide| NEWT["Tumeur créée / rattachée"]
    TUM -->|non| FLO["Signalement flottant<br/>(rattaché au patient, pas à une tumeur)"]
    INJ -. "si excluded renseigné" .-> EXC["Marqué exclu : jamais de tumeur"]

⚠️ Le worker d’identito-vigilance (rattachement de l’identité à un patient, gestion des orphelins) est en cours d’implémentation ; cette partie aval peut encore évoluer.

Report controls : can_create_patient / can_create_tumor

Section intitulée « Report controls : can_create_patient / can_create_tumor »

Deux booléens par ligne, fournis par le data manager dans le CSV, pilotent ce que l’identito-vigilance a le droit de faire en aval : créer un nouveau patient / lever une nouvelle tumeur, ou seulement rattacher à ce qui existe déjà (sinon l’identité reste orpheline). Le rattachement à un patient connu a toujours lieu ; seules les créations sont contrôlées.

Le défaut dépend de la typologie :

Typologiecan_create_patientcan_create_tumor
ACP, PMSI, Génériquetruetrue
ALD, Dépistage, RCPfalsefalse (rattachement seul)

La logique : pour une source de faible qualité (ALD), non diagnostique (Dépistage) ou souvent mal codée (RCP), le comportement sûr doit être le défaut - sinon on fabrique de faux patients et de fausses tumeurs que l’ARC devra nettoyer. Le data manager surcharge par ligne (ou par fichier) au besoin. Une cellule vide garde le défaut de la typologie.

⚠️ Même quand un data manager force can_create_tumor = true (ex. sur un dépistage), des garde-fous métier sont attendus en aval (refus de créer une tumeur sur un dépistage négatif, p. ex. via le diagnostic final). Ce job n’existe pas encore ; le défaut ci-dessus est le filet de sécurité actuel.

Un signalement exclu reste visible sur son patient (sa trace est conservée : dates, provenance) mais est retiré des tumeurs et de la file d’attachement. Distinct de l’orphelin (un exclu peut porter un patient). L’exclusion à l’import se fait via une cellule excluded :

  • vide / 0 / non → non exclu ;
  • 1 → exclu, motif par défaut non précisé (la ligne globale partagée par tous les registres) ;
  • 2, 3, 4… → exclu avec un motif spécifique que le registre a préalablement créé dans son catalogue de motifs.

excluded prime sur can_create_tumor : si les deux sont à true, aucune tumeur n’est créée - l’exclusion l’emporte et la création automatique de tumeur est ignorée.

Un ARC exclut aussi depuis l’interface : il choisit un motif du catalogue de son registre et peut ajouter une précision libre (exclusion_comment). Le signalement quitte alors la tumeur sur laquelle il était rattaché et retombe sur son patient.

À l’import, chaque signalement reçoit une identité, mais celle-ci démarre orpheline : tant que l’identito-vigilance ne l’a pas rattachée à un patient, identities.patient_id reste null. Faute de correspondance et si la création est interdite (can_create_patient = false), l’identité reste orpheline plutôt que d’être jetée : on pourra relancer l’identito-vigilance plus tard (ex. après correction d’une date de naissance qui débloque l’appariement) ou forcer la création a posteriori. La gestion fine des orphelins (purge, rétention) reste à construire.


Le SI Registres impose un contrat de colonnes par typologie - le format d’import canonique. C’est au data manager de remapper la source vers ce format avant import. Ce contrat est la source de vérité unique : en-têtes, types, champs obligatoires et nature de chaque champ y sont déclarés une seule fois.

Ce travail de remappage se mutualise entre registres : lorsqu’une même source arrive au même format dans plusieurs départements (un même laboratoire, une même caisse), le script de mapping de l’un pourrait servir aux autres.

Trois natures de champs :

  • Fourni - la valeur vient directement du fichier source (nom du patient, code CIM-10…).
  • Résolu - déterminé à l’import hors du fichier : choisi dans l’interface (la structure source) ou déduit d’une valeur fournie (structure résolue depuis le FINESS).
  • Calculé - dérivé par le pipeline (code caractérisant, CIM-O-3, Berg group). Jamais présent dans le fichier source.

Obligatoire à l’import : l’ensemble minimal de champs fournis qu’une ligne doit porter pour être acceptée. Une ligne qui en manque un est rejetée (motif rapporté au preview). À distinguer de la nullabilité en base : un champ peut être obligatoire à l’import mais nullable en stockage. Exemple : le nom du patient (patient_last_name) est obligatoire à l’import ACP, alors que la colonne correspondante (identities.last_name) reste nullable en base - l’identité est partagée par toutes les typologies, dont certaines ne l’imposent pas.

Le détail colonne par colonne, le pré-traitement à faire sur chaque source, et un exemple de CSV au format attendu sont dans les fiches pratiques par typologie.