CLAIR DocsCLAIR Docs
  • clair.vote
  • GitHub
  • Nous soutenir
Nous soutenir
  • Accueil
  • Plateforme & Guide
  • Données & Base de Données
  • Explorateur API
CLAIR

Plateforme citoyenne de transparence politique. Données 100% publiques, 0% d'opinion.

Explorer

  • Députés
  • Sénateurs
  • Groupes politiques
  • Sujets
  • Dossiers législatifs
  • Scrutins
  • Agenda
  • Lobbying

Ressources

  • Nous soutenir
  • À propos
  • Méthodologie
  • Contact
  • Comprendre
  • Guide pratique
  • API ouverte

Légal

  • Mentions légales
  • Confidentialité
  • CGU

© 2026 CLAIR. Sources : Assemblée nationale · Sénat · HATVP · Ministère de l'Intérieur · DILA

Vue d'ensembleCommandes CLIEnrichissement IAModèle PrismaOrchestrateur d'IngestionQualité des DonnéesSchémas ERDSources Open DataSuivi des Modifications
Données & Base de Données

L'Orchestrateur d'Ingestion

L'ingestion est une CLI Node.js (services/ingestion/src/cli.ts, bâtie sur commander) qui télécharge les sources publiques, les transforme et les écrit dans PostgreSQL, puis relie les entités entre elles, calcule les statistiques et génère les résumés IA. Il n'y a ni file de messages ni worker permanent : chaque commande s'exécute puis rend la main, avec une concurrence bornée par p-limit.


⏱️ Deux passages planifiés en production

Service RailwayPlanification (UTC)Heure de ParisCommande
Ingestion nightly0 3 * * *5 h en heure d'été, 4 h en heure d'hivernode --max-old-space-size=6144 services/ingestion/dist/cli.js smart-sync --all
Ingestion intraday0 6-21/2 * * *toutes les deux heures, de 8 h à 22 h en été (de 7 h à 21 h en hiver)node services/ingestion/dist/cli.js sync-intraday

Railway exprime ses crons en UTC : l'heure locale glisse donc d'une heure au changement d'heure. Les deux services sont construits depuis services/ingestion/Dockerfile, seul à installer pdftotext.

Le passage intraday ne rafraîchit que ce qui change dans la journée : l'agenda du Sénat (de J-2 à J+2), les vidéos du Sénat (séances et commissions) et celles de l'Assemblée. Il ne touche ni aux scrutins, ni aux amendements, ni aux dossiers, ni aux statistiques.


🔄 Le batch nocturne : smart-sync --all

Déroulé du batch nocturne

1. Événements institutionnels

La liste des repères de l'agenda (élections, bornes de session, suspensions, échéances budgétaires) est écrite en dur dans workers/evenements.ts et poussée par un upsert idempotent sur son slug. Aucun appel réseau.

2. Les sources, dans cet ordre

L'ordre suit les dépendances : les commissions avant les députés (dont les mandats pointent vers les commissions), les parlementaires avant les votes, les anciens sénateurs avant les scrutins (les votes historiques ont besoin de l'annuaire), les gouvernements après les parlementaires (un ministre est rattaché à sa fiche), les candidatures en dernier (le rattachement d'un candidat à sa fiche lit le corpus).

  1. assemblee_nationale:commissions
  2. assemblee_nationale:deputes
  3. senat:senateurs
  4. senat:senateurs_histo
  5. senat:fonctions
  6. assemblee_nationale:gouvernements
  7. assemblee_nationale:scrutins
  8. senat:scrutins
  9. assemblee_nationale:amendements
  10. senat:amendements
  11. assemblee_nationale:dossiers
  12. senat:dossiers
  13. assemblee_nationale:interventions
  14. senat:interventions
  15. hatvp:lobbyistes
  16. assemblee_nationale:reunions
  17. assemblee_nationale:seances_odj
  18. senat:agenda
  19. senat:reunions
  20. senat:dossier_commissions
  21. senat:videos
  22. assemblee_nationale:videos
  23. interieur:candidatures

Le détail de chaque source est sur la page Sources de données. Les résultats des élections et les mandats locaux des candidats ne sont dans aucun des deux batchs : ils se lancent à la main (voir Commandes CLI).

Fraîcheur. Avant de télécharger, le batch compare l'ETag et le Last-Modified de la ressource à ceux enregistrés dans source_states. S'ils sont identiques, la source est ignorée (sauf avec --force). Les sources sans en-tête exploitable sont marquées « toujours » et relues à chaque passage.

Échecs. Une source en échec est journalisée (sync_logs.statut = 'failed') et n'arrête pas le batch : elle est retirée des sources « changées », ce qui empêche les étapes qui en dépendent de tourner sur une lecture ratée. Le processus ne sort en erreur que si au moins une source a échoué et qu'aucune n'a été synchronisée avec succès. Un échec partiel se lit dans le récapitulatif et dans les logs d'erreur ; rejouer un batch entier pour une seule source resolliciterait toutes les autres.

3. Rattachements

Chaque étape ne tourne que si une source concernée a changé, et son échec n'est pas bloquant.

ConditionÉtape
interventions ou scrutinsSeconde lecture des comptes rendus de l'Assemblée (sans effet si rien n'a bougé), puis rattachement des débats de l'Assemblée aux scrutins qu'ils précèdent (table intervention_scrutin), puis de ceux du Sénat
interventions ou amendementsRattachement des prises de parole à leur dossier, par le numéro de texte en discussion
réunionsDébats de commission de l'Assemblée et avis de commission sur les amendements, pour les réunions des 60 derniers jours
amendements ou scrutinsRetrait des liens vers un amendement déposé après le vote, puis lecture des pages des scrutins encore sans amendement (Assemblée : 30 derniers jours ; Sénat : nouveaux scrutins)
dossiers ou scrutinsScrutins → dossiers : retrait des liens vers un dossier d'une autre législature (AN) ou d'une procédure sans vote (rapport, mission d'information, 49.3 hors motion de censure), rattachement au dossier que la source désigne (voteRefs), puis, pour les scrutins restés sans dossier : rattachement Sénat, TF-IDF sur les titres, titre (Assemblée), numéro de texte, titre de la loi promulguée
amendements, scrutins ou dossiersScrutins ↔ amendements (table de jointure), puis dossier des amendements : retrait des dossiers d'une autre législature, dossier du texte (texte_ref), propagation par leurs scrutins et entre amendements d'un même texte ; correction des liens dont l'article contredit le libellé du scrutin ; alignement du dossier des scrutins sur celui de leurs amendements
amendementsTexte des articles des nouvelles versions de textes de l'Assemblée (textes_articles). Une version déjà ingérée n'est pas retéléchargée ; seuls les textes que la source ne sert pas, ou dont le gabarit n'est pas couvert (budgets), sont retentés
toujoursIndex de la base LEGI (legi_textes, legi_articles) : les incréments publiés par la DILA depuis la dernière archive appliquée, quelques secondes. Ne charge jamais le dump global : un index vide ou décroché des archives publiées fait échouer l'étape, à relancer à la main avec sync-index-legi. Son échec apparaît dans le récapitulatif des sources en échec ; sa réussite ne compte pas comme un changement et ne déclenche donc pas les étapes suivantes
toujoursRenvois au droit en vigueur dans le dispositif des amendements (amendements_renvois) : amendements nouveaux, modifiés, ou déposés depuis moins de 45 jours (la DILA consolide une loi nouvelle avec quelques jours ou semaines de retard). Vient après les amendements, le texte des articles (qui donne le code modifié quand le dispositif ne le nomme pas) et l'index LEGI. Un échec est journalisé sans bloquer la suite ; check-quality le signale
scrutinsClassement de la nature des scrutins encore non classés (nature_vote)

L'ordre compte : le rattachement scrutin → dossier précède le rattachement scrutin → amendement, qui s'appuie sur le dossier pour éviter les faux positifs. Le texte des articles vient après le rattachement aux dossiers, dont il recopie le dossier_id, et avant l'IA, qui met l'article dans le prompt des scrutins.

4. Étapes exécutées dès qu'au moins une source a changé

Avec --all, les événements institutionnels et les sources « toujours » comptent comme changés : ces étapes tournent donc chaque nuit.

  1. Statistiques (sauf --skip-stats) : réalignement de parlementaires.actif sur « a un mandat en cours », statistiques des parlementaires, des groupes, alliances entre groupes, positions par thématique.
  2. Sujets : génération incrémentale (regroupement des dossiers AN et Sénat), liens « construction » (documents officiels), liens « contexte » (vie-publique.fr et Wikipédia, en incrémental).
  3. Compteurs dénormalisés des sujets (dossier_count, scrutin_count, date_dernier_vote).
  4. VACUUM ANALYZE sur scrutins, amendements, dossiers_legislatifs, parlementaires, votes, interventions.
  5. Déclarations HATVP des parlementaires.
  6. Statut des sujets, recalculé à partir de l'état de leurs dossiers.
  7. Enrichissement IA, en cascade : scrutins, dossiers, sujets, descriptions d'amendements par groupe, puis les fiches parlementaires en trois temps : les fiches encore absentes des parlementaires en exercice, jusqu'à 200 fiches devenues périmées (un fait qu'elles affirment a changé, ou le prompt a changé de version), et 25 fiches tirées au hasard parmi celles non rafraîchies depuis 25 jours, anciens parlementaires compris (ce que nos données ignorent, un ancien député devenu maire par exemple, ne périme aucune empreinte). Voir Enrichissement IA.

5. Cache de la page d'accueil

En fin de batch, la CLI attend 120 s, puis appelle POST /api/v1/homepage/warm (invalidation) et GET /api/v1/homepage (reconstruction), authentifiée par CLAIR_INTERNAL_SECRET ; chaque appel est borné à 120 s. Sans ce secret, l'étape est sautée. Les autres entrées du cache Redis de l'API ne sont pas invalidées : elles expirent selon leur durée de vie (voir Limites & Cache).


🧾 Traçabilité

  • source_states : une ligne par source, avec l'URL de la ressource, le dernier ETag, le dernier Last-Modified, la date de dernière synchronisation réussie et celle de dernière vérification.
  • sync_logs : une ligne par source et par passage, avec le statut (started, completed, failed, skipped), les compteurs (traités, créés, mis à jour, erreurs) et l'erreur éventuelle.
  • pnpm ingestion:status affiche la fraîcheur de toutes les sources.

🧩 Modules principaux (services/ingestion/src/workers/)

FichierRôle
sync.tsSynchronisation de chaque source, rattachements, orchestration smartSync et syncIntraday
stats-calculator.tsPrésence, loyauté, participation, alliances, thématiques
mandats.ts, backfill-mandats.ts, senat-histo.ts, mandats-an-sortants.tsMandats parlementaires multi-législatures, anciens sénateurs, clôture des mandats des députés sortants et de leurs mandats d'organe
changement-chambre.tsUn député élu sénateur garde sa fiche, qui passe au Sénat ; son identifiant de l'Assemblée est conservé dans parlementaires_identifiants
interventions-syceron.ts, interventions-commission.ts, avis-commission.tsDébats de séance et de commission de l'Assemblée, avis de commission
link-debats-scrutins.ts, link-debats-scrutins-senat.ts, link-interventions-dossiers.ts, link-interventions-ordre-du-jour.ts, segmenter-debats-senat.tsRattachement des débats aux scrutins et aux dossiers
liens-amendements-discordants.tsCorrection des liens scrutin ↔ amendement dont l'article contredit le libellé du scrutin
parents-amendements.ts, metadonnees-amendements-senat.ts, article-vise-senat.tsSous-amendements, discussions et article visé des amendements
sujet-generator.ts, sujet-links-generator.tsSujets et leurs liens sortants
ia-enrichment.ts, parlementaire-enrichment.tsEnrichissement IA
declarations-sync.tsDéclarations HATVP
senat-fonctions.ts, senat-dossier-commissions.tsFonctions datées des sénateurs (bureau, commissions, groupes) et saisines des commissions du Sénat
gouvernements.tsGouvernements, postes ministériels, présidences de la République et de l'Assemblée (archive AMO30), rattachement à la fiche
textes-articles.tsTexte des articles des textes de l'Assemblée
index-legi.tsIndex de la base LEGI de la DILA (textes et articles de loi, pour les liens vers Légifrance)
renvois-legi.tsRenvois au droit en vigueur dans le dispositif des amendements, rattachés à l'index LEGI (grammaire de @tricoteuses/tisseuse)
evenements.tsListe curée des événements institutionnels

La commande schedule (fichier src/scheduler.ts) lance un planificateur node-cron dans le processus. Elle n'est pas utilisée en production, où la planification est confiée à Railway.

Modèle PrismaQualité des Données
On this page
  • ⏱️ Deux passages planifiés en production
  • 🔄 Le batch nocturne : smart-sync --all
    • 1. Événements institutionnels
    • 2. Les sources, dans cet ordre
    • 3. Rattachements
    • 4. Étapes exécutées dès qu'au moins une source a changé
    • 5. Cache de la page d'accueil
  • 🧾 Traçabilité
  • 🧩 Modules principaux (services/ingestion/src/workers/)