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 au signalement via reports.identity_id et reports.address_id. Le détail du cycle est décrit dans Cycle de vie d’un signalement.

Une adresse transmise plusieurs fois pour la même identité (à la casse et aux accents près) n’est stockée qu’une fois, mais chaque signalement garde le lien vers l’adresse qu’il a lui-même transmise : on retrouve donc, pour un signalement, l’adresse de la source, et pour une adresse, tous les signalements qui l’attestent. L’adresse retient aussi le signalement qui l’a créée (source_report_id), comme l’identité.

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é / adresse - identity_id (→ identities, toujours renseigné à l’import) et address_id (→ addresses, l’adresse portée par la ligne, null si elle n’en porte pas). Le patient se lit sur l’identité (identities.patient_id), 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 (breast→C50, colorectal→C18, cervix→C53) ; 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.

À partir du code CIM-O-3, chaque signalement reçoit deux groupes IARC, qui disent si deux codes désignent le même cancer malgré une variation de codage :

  • topo_iarc - l’organe (52 groupes : 10 colon, 11 rectum, 30 sein…), fixé par les 3 premiers caractères de la topographie ;
  • morpho_iarc - le type histologique (17 groupes : 3 adénocarcinomes, 17 non précisé…), fixé par les 4 chiffres de l’histologie, quel que soit le comportement.

Un groupe reste vide quand le code manque ou n’appartient pas au référentiel. Le PMSI et l’ALD, dont la morphologie est déduite du CIM-10, tombent dans le groupe 17 (non précisé) ; le dépistage n’a qu’un groupe topographique. La localisation FRANCIM (ref_cancer_sites) qui sert aux files de travail est une autre classification.


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/>(anomalies visibles à la pré-validation)"]
    V -->|ligne valide| T["Transcodage + mise en qualité<br/>(CIM-O-3, code caractérisant, groupes IARC)"]
    T --> INJ["Injection : identité + adresse (dédupliquées)<br/>+ reports (identity_id, address_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é en attente"]
    ATT --> TUM{"Rattachement<br/>des tumeurs"}
    NEWP --> TUM
    TUM -->|création| NEWT["Tumeur créée,<br/>signalement rattaché"]
    TUM -->|proposition| PRO["Signalement pré-rattaché<br/>à une tumeur existante"]
    TUM -->|sinon| FLO["Signalement à rattacher<br/>(porté par le patient, pas par 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 signalements en attente) est en cours d’implémentation ; cette partie aval peut encore évoluer. Le rattachement des signalements aux tumeurs est décrit dans la page Rattachement des tumeurs.

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 (pour le patient) et le rattachement des tumeurs (pour la tumeur) ont 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 en attente). 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 s’appliquent en aval : pas de tumeur sans comportement /2 ou /3, ni sur un dépistage dont le diagnostic final n’est pas « cancer ». Détail dans la page Rattachement des tumeurs.

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 du signalement en attente (un exclu peut porter un patient). L’exclusion à l’import se fait via une cellule excluded :

  • vide / 0 → 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 ;
  • toute autre valeur (oui, non, x, -1, 1.5, texte…) → ligne en erreur à la pré-validation : seuls des chiffres sont acceptés.

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 en attente : 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 en attente 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 signalements en attente (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, déduit d’une valeur fournie (structure résolue depuis le FINESS).
  • Calculé - dérivé par le pipeline (code caractérisant, CIM-O-3, groupes IARC). 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 (voir Pré-validation ci-dessous). À 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.

Dès le dépôt du fichier, chaque ligne est examinée contre l’ensemble des règles, et toutes ses fautes sont relevées - une ligne peut porter plusieurs anomalies. Six règles, communes aux six typologies :

AnomalieColonne concernéeCause
Champ obligatoire videun champ obligatoire à l’importcellule vide (ou ?)
Valeur illisibletoute colonne, obligatoire ou noncontenu que le format attendu ne permet pas de lire : date hors JJ/MM/AAAA, sexe hors M/F, can_create_* hors oui/non, nombre entier avec autre chose que des chiffres…
FINESS illisiblestructure_finessFINESS renseigné mais mal formé (un FINESS vide est accepté)
Établissement inconnustructure_finessFINESS bien formé mais absent du référentiel des structures
Motif d’exclusion inconnuexcludednombre ≥ 1 absent du catalogue d’exclusion du registre (0 = non exclu ; une valeur non numérique est une valeur illisible)
Date dans le futurpatient_birth_datedate de naissance postérieure au jour du dépôt du fichier

Une ligne portant au moins une anomalie est en erreur et ne sera pas intégrée ; les autres sont valides. Le verdict est figé au dépôt : corriger une ligne se fait en corrigeant le fichier puis en créant un nouvel import.

Pour cela, le fichier annoté reprend le fichier source à l’identique (mêmes colonnes, même séparateur) avec deux colonnes ajoutées en fin de chaque ligne :

  • statut - valide ou erreur ;
  • anomalies - la liste des anomalies de la ligne, sous la forme Colonne · Cause, séparées par ; (vide pour une ligne valide).

Le fichier annoté corrigé peut être redéposé tel quel : ses colonnes statut et anomalies sont ignorées à l’import et remplacées dans le fichier annoté suivant.

Il se télécharge depuis l’écran de pré-validation (« Exporter le tableau au format CSV » et, dans la fenêtre « Que souhaitez-vous faire ? », le parcours « Corriger les erreurs »). Le fichier est encodé en UTF-8 avec BOM, ce qui permet à Excel de l’ouvrir directement avec les accents.

Une valeur mal formée dans un champ facultatif n’est pas une anomalie : elle est ignorée à l’intégration (le champ reste vide).