Le modèle de données
Chaque table, son volume, et la nature exacte de ce qui la relie aux autres.
La distinction qui compte n’est pas de savoir si deux tables sont liées, mais par quoi. Un trait plein est une clé étrangère : la base en garantit la validité. Un trait pointillé est un rapprochement par nom : une déduction, exposée comme telle plutôt que présentée comme un fait.
24 M
Entités françaises
INSEE SIRENE, tout le répertoire
Explorer →800 k
Comptes publics
DGFiP, communes et collectivités, 25 ans
Explorer →663 k
Subventions et aides
PLF Jaune + aides d’État européennes
Explorer →643 k
Mandats électifs
526 624 élus, mandats en cours et passés
Explorer →527 k
Élus
Répertoire national, toutes fonctions
Explorer →12 k
Déclarations HATVP
6 148 responsables publics
Explorer →10 k
Volets financiers
Revenus, patrimoine, mandats déclarés
Explorer →4 k
Représentants d’intérêts
92 % rattachés à une entité
Explorer →Clé étrangère
Contrainte garantie par la base : la ligne référencée existe.
Rattachement par identifiant
Jointure sur le SIREN ou l’uid, sans contrainte — les deux bases sont distinctes. La couverture indique la part réellement rattachée.
Rapprochement par nom
Aucun identifiant commun : on rapproche sur (nom, prénom) normalisés. C’est une déduction, pas une preuve — les homonymes restent possibles.
Dérivation
Table ou vue recalculée à partir d’une autre. Ne contient aucune donnée propre.
Molette pour zoomer, glisser pour déplacer, clic sur une table pour le détail. Au clavier : + − 0 et les flèches.
Les 21 tables, en clair
Volumes exacts, clés primaires et sources. Chaque ligne mène à la page qui explore la donnée.
| Table | Domaine | Lignes | Clé primaire | Source | Explorer |
|---|---|---|---|---|---|
| Référentiel | 24 377 820 | siren (char 9) | INSEE SIRENE | Ouvrir → | |
| Référentiel | 101 | code (char 3) | Modèle Prisma | ||
| Argent public | 663 219 | id (cuid) | PLF Jaune + EU Transparency | Ouvrir → | |
| Argent public | 799 508 | id (cuid) | DGFiP / OFGL | Ouvrir → | |
| Personnes | 526 624 | id | Répertoire national des élus (DGCL) | Ouvrir → | |
| Personnes | 642 925 | id | Répertoire national des élus (DGCL) | Ouvrir → | |
| Personnes | 11 951 | id | HATVP | Ouvrir → | |
| Personnes | 10 207 | id | HATVP (XML) | Ouvrir → | |
| Personnes | 3 926 | id | HATVP — représentants d’intérêts | Ouvrir → | |
| Couche dérivée | 10 | category | Agrégat de entities | Ouvrir → | |
| Couche dérivée | 190 | (category, subType) | Agrégat de entities | Ouvrir → | |
| Couche dérivée | 21 000 | id | Agrégat de subsidies | Ouvrir → | |
| Couche dérivée | 24 000 | — | Vues matérialisées sur subsidies | Ouvrir → | |
| Application | — | uid (Firebase Auth) | Firestore | Ouvrir → | |
| Application | — | id | Firestore | Ouvrir → | |
| Application | — | id | Firestore | Ouvrir → | |
| Application | — | siren_urlHash | Firestore | Ouvrir → | |
| Application | — | id | Firestore + Cloud Storage | Ouvrir → | |
| Application | — | uid_domain | Firestore | Ouvrir → | |
| Application | — | uid_origin | Firestore | ||
| Application | — | id Stripe | Firestore (webhook Stripe) | Ouvrir → | |
| Total (hors couche dérivée) | 27 036 281 | ||||
Les 25 liens, et ce qu’ils valent
Une clé étrangère est garantie par la base. Un rapprochement par nom est une déduction.
| De | Vers | Nature | Clé | Couverture |
|---|---|---|---|---|
| subsidies | entities | Clé étrangère · N–1 | beneficiaryId → siren | 100 % |
| subsidies | entities | Clé étrangère · N–1 | grantorId → siren | facultatif |
| public_finances | entities | Rattachement par identifiant · N–1 | siren | 81 % |
| public_finances | entities | Rapprochement par nom · N–1 | UPPER("entityName") ↔ nom d’entité nettoyé | repli des 19 % restants |
| elus_mandats | elus | Clé étrangère · N–1 | elu_id → id | 100 % |
| elus_mandats | entities | Rattachement par identifiant · N–1 | siren | 84,8 % |
| elus_mandats | public_finances | Rattachement par identifiant · N–N | siren | situe un mandat dans un budget |
| lobbyists | entities | Rattachement par identifiant · 1–1 | siren | 92 % |
| official_declarations | public_officials | Rapprochement par nom · N–N | (lastName, firstName) sans accents | approximatif |
| public_officials | elus | Rapprochement par nom · N–N | (nom, prénom) en majuscules | approximatif |
| entities | departments | Rattachement par identifiant · N–1 | hqDepartment → code | jamais interrogé |
| category_stats | entities | Dérivation · 1–N | GROUP BY category | — |
| category_subtype_stats | entities | Dérivation · 1–N | GROUP BY (category, subType) | — |
| purpose_stats | subsidies | Dérivation · 1–N | GROUP BY purposeNorm | — |
| mv_* (9 vues) | subsidies | Dérivation · 1–N | vues matérialisées | — |
| subsidies | purpose_stats | Rattachement par identifiant · N–1 | purposeSlug / purposeNorm | résolution d’un objectif |
| reports | users | Rattachement par identifiant · N–1 | uid | — |
| articles | users | Rattachement par identifiant · N–1 | uid | — |
| entitySites | users | Rattachement par identifiant · N–1 | uid | — |
| captures | users | Rattachement par identifiant · N–1 | uid | — |
| sites | users | Rattachement par identifiant · N–1 | uid | — |
| sessions | users | Rattachement par identifiant · N–1 | uid | — |
| stripe_* (5 collections) | users | Rattachement par identifiant · N–1 | userId | — |
| entitySites | entities | Rattachement par identifiant · N–1 | siren | inter-base |
| users | entities | Rattachement par identifiant · N–N | following.{siren} | inter-base |
Quel point d’API lit quelle table
Une page vide se diagnostique en partant de l’appel qu’elle fait. 38 points d’entrée recensés.
| Point d’API | Tables lues |
|---|---|
| /addEntitySiteFromExtension | entitySites |
| /adminArticleQueue | articlesentitySites |
| /adminStats | users |
| /api/auth-bridge | sessions |
| /api/stripe/subscription-status | stripe_* (5 collections) |
| /api/stripe/webhook | stripe_* (5 collections) |
| /api/v1/captures | captures |
| /api/v1/media | captures |
| /api/v1/sites | sites |
| /api/v1/sites/** | sites |
| /askData | users |
| /generateReport | users |
| /getActorDetails | entities |
| /getActorsByCategory | entitiescategory_statscategory_subtype_stats |
| /getActorsOverview | entitiescategory_stats |
| /getArticles | articles |
| /getEluDetail | eluselus_mandats |
| /getEntityElus | public_financeseluselus_mandats |
| /getLobbyists | lobbyists |
| /getOfficialDetail | public_officialsofficial_declarations |
| /getOfficials | public_officials |
| /getPublicFinances | entitiespublic_finances |
| /getSubsidies | subsidies |
| /getSubsidiesByActor | subsidies |
| /getSubsidiesByPurpose | entitiessubsidiespurpose_statsmv_* (9 vues) |
| /getSubsidiesOverview | subsidiesmv_* (9 vues) |
| /getTopBeneficiaries | subsidiesmv_* (9 vues) |
| /getTopOfficials | official_declarations |
| /getTopRankings | public_finances |
| /getUserProfile | users |
| /reports | reports |
| /reports/confirm | reports |
| /reports/resolve | reports |
| /reports/submit | reports |
| /searchElus | eluselus_mandatspublic_officials |
| /searchEntities | entitiespublic_finances |
| /searchSubsidies | subsidies |
| /submitArticleFromExtension | articles |
24 points d’attention, table par table
Ce qui est connu, imparfait ou en attente. Une limite tue n’en est pas une de moins.
- Code mort
Table DÉCLARÉE dans le schéma mais interrogée par AUCUN point d’API. Elle est pourtant annoncée à l’assistant IA comme disponible : il peut donc la citer alors que rien ne l’alimente ni ne la lit.
- À surveiller
Reclassification des catégories juridiques en attente : les lignes chargées avant la correction portent encore l’ancienne catégorie.
- À surveiller
18,6 M d’entités privées ne sont pas indexées pour la recherche par nom (la recherche par SIREN fonctionne).
- À surveiller
Exercices 2013, 2014 et 2016 partiels : les fichiers PLF correspondants manquent à la source.
- À surveiller
EPCI : 0 ligne importée — les champs de la source sont incompatibles avec le lecteur actuel.
- À surveiller
19 % des exercices n’ont pas de SIREN exploitable ; le rattachement retombe alors sur une comparaison de NOMS en majuscules.
- À surveiller
15,2 % des mandats n’ont pas de SIREN exploitable : ils ne peuvent pas être rapprochés d’une commune ni d’un budget.
- À surveiller
Aucun identifiant commun avec le répertoire des élus : le rapprochement se fait sur (nom, prénom), avec un risque d’homonymie.
- À surveiller
Montants aberrants dans la source (jusqu’à 61,5 M€ pour un mandat parlementaire) : affichés tels quels, documentés dans le rapport sur les données.
- À surveiller
Reconstruit à l’import : tant que la reclassification n’a pas tourné, ces compteurs reflètent l’ancienne répartition.
- À surveiller
Rafraîchies uniquement à l’import : entre deux imports, elles peuvent diverger de la table source.
- À surveiller
Contient des jetons de session de sites TIERS. Chiffrés au repos et jamais lisibles par un client, avec expiration à 30 jours — mais aucune tâche planifiée ne purge encore les documents expirés.
- Bon à savoir
Ni code postal ni département pour la majorité des entités : le champ est absent du fichier importé.
- Bon à savoir
Espaces insécables dans certains objectifs — nettoyés à la lecture, d’où la colonne purposeNorm.
- Bon à savoir
Montants stockés en milliers d’euros, convertis en euros par l’API.
- Bon à savoir
Mandats antérieurs à 2020 non encore intégrés (2014 et 2008 à venir).
- Bon à savoir
47 déclarations de patrimoine seulement, contre 10 166 déclarations d’intérêts.
- Bon à savoir
Existe parce qu’un GROUP BY direct sur la catégorie SECTEUR_PRIVE (19,1 M de lignes) dépassait le délai maximal de requête.
- Bon à savoir
Ne couvre que les subventions aux associations : les objectifs des aides d’État vivent dans mv_purposes_stateaid, d’où l’union à la résolution d’un objectif.
- Bon à savoir
Les champs qui portent des droits ou de la facturation sont écrits par le serveur uniquement — les règles Firestore les refusent au client depuis le 3 août 2026.
- Bon à savoir
cityCode porte un code INSEE mais n’est rattaché à aucune table : la commune d’un signalement n’est pas jointe au référentiel.
- Bon à savoir
Seul pont entre l’application et le socle analytique. Le SIREN n’est contraint par rien : les deux bases sont distinctes.
- Bon à savoir
Les médias sont privés et servis après vérification de propriété. Les captures déposées avant le 3 août 2026 restent publiques au niveau du stockage : une purge des anciennes autorisations est à faire.
- Bon à savoir
stripeEvents sert de verrou d’idempotence : un même événement livré deux fois n’est traité qu’une fois.
D’où viennent ces données
Toutes publiques et ouvertes. Les liens pointent chez le producteur.
INSEE SIRENE
Répertoire des entreprises et établissements
DGFiP — data.economie.gouv.fr
Comptes individuels des collectivités
OFGL
Observatoire des finances et de la gestion publique locales
PLF Jaune — Budget
Subventions de l’État aux associations
EU Transparency Award
Aides d’État aux entreprises
HATVP
Déclarations d’intérêts, patrimoine, lobbyistes
Répertoire national des élus
DGCL — ministère de l’Intérieur
Nomenclature des catégories juridiques
INSEE — la table qui classe chaque entité
Le détail source par source — volumes, périodes couvertes, limites connues — est dans le rapport sur les données.
Ce que cette carte ne dit pas
Les volumes sont un relevé du 2 août 2026, pas un compteur temps réel. Les rattachements par SIREN ne sont jamais complets : 81 % des comptes publics et 84,8 % des mandats trouvent leur entité, le reste n’a pas de SIREN exploitable dans la source. Enfin, la catégorie juridique des entités fait l’objet d’une reclassification en cours — voir le rapport sur les données.