A1Connect est la source de vérité du référentiel des établissements (lycées + supérieur), alimenté depuis ONISEP chaque mois. Dema1n et Inspire gardent chacun une copie locale rafraîchie sur notification.
[ONISEP] →(mensuel)→ [A1C] →(webhook POST)→ [Dema1n] copie locale
→(webhook POST)→ [Inspire] copie locale
Pour consommer les données déjà construites (auth, endpoints, format), voir api.md.
Source de données — ONISEP Idéo
ONISEP est la seule source. Elle couvre lycées + supérieur sans primaire ni maternelle, déjà filtrés pour l'orientation scolaire.
Pourquoi ONISEP et pas RAMSESE : RAMSESE ne couvre pas le supérieur et inclut primaire/maternelle (~30K établissements inutiles). ONISEP couvre les deux en un seul outil.
| Dataset | ID | Volume |
|---|---|---|
| Structures secondaire | 5fa5816ac6a6e |
~15 283 |
| Structures supérieur | 5fa586da5c4b6 |
~9 024 |
Auth : Bearer token JWT 24h + Application-ID statique. OnisepAuthService gère le cache mémoire du token (TTL 23h, renouvellement automatique). Env vars : ONISEP_APP_ID, ONISEP_EMAIL, ONISEP_PASSWORD.
Synchronisation
Cron
Un seul cron NestJS : @Cron('0 3 1 * *') dans EtablissementSyncService (1er du mois à 3h). Pas de CronJob K8s nécessaire — le scheduling est géré par l'application.
Le sync ONISEP se termine dès que l'upsert est fini. Le calcul des flags tourne ensuite en arrière-plan (non-bloquant). État accessible en temps réel via GET /api/v1/etablissements/sync/status.
Post-sync : message etablissements___synced publié sur RabbitMQ + email de rapport Brevo à tech@article-1.eu (succès ou échec).
Flow complet
1. Pull ONISEP — 2 datasets (~26 appels paginés)
2. Upsert ~24K records par codeUai (idempotent, relançable)
3. Résolution codes INSEE
→ si index absent : chargement automatique depuis geo.api.gouv.fr (~35K communes)
→ chaque établissement : codePostal + ville → codeInseeCommune
4. Calcul des flags (en parallèle)
├─ ZRR → Excel FRR (collectivites-locales.gouv.fr) + codeInseeCommune
├─ QPV → SIGVille API X,Y (latitude/longitude) — 50 requêtes concurrentes
└─ IPS + IEL → datasets data.education.gouv.fr (match par UAI)
5. Webhook POST vers Dema1n + Inspire (non actif — à décommenter dans notifyPlatforms()
quand les plateformes auront leur endpoint POST /etablissements/sync)
Tout est idempotent. En cas d'erreur mi-parcours, relancer POST /api/v1/etablissements/sync suffit.
Calcul des flags — ZRR / QPV / IPS / IEL
Quatre indicateurs de vulnérabilité territoriale et socio-économique, calculés par EtablissementFlagsService. Description des champs exposés : voir api.md.
Sources
| Flag | Source | Détail |
|---|---|---|
| ZRR | collectivites-locales.gouv.fr — fichier Excel FRR |
Colonne Code_insee. URL dans la constante FRR_EXCEL_URL de etablissement-flags.service.ts — à mettre à jour si le fichier est republié après une révision législative (~3–5 ans). |
| QPV | SIGVille ANCT — wsa.sig.ville.gouv.fr/api/xy.json |
Géoréférencement inverse : POST {type_quartier: 'QP', x: longitude, y: latitude} → OUI/NON. Auth HTTP Basic : SIGVILLE_USERNAME / SIGVILLE_PASSWORD. |
| IPS | data.education.gouv.fr — dataset fr-en-ips_lycees |
Champ ips_ensemble_gt_pro. Mis à jour à chaque rentrée scolaire. Fournit aussi code_insee_de_la_commune, renseigné en bonus sur les ~4 300 lycées couverts. |
| IEL | dataeducation.opendatasoft.com — dataset fr-en-indice_eloignement_lycee_ap2020 |
Champ indice_eloignement. Mis à jour à chaque rentrée scolaire. |
Résolution code INSEE
ZRR et QPV requièrent le codeInseeCommune (code INSEE 5 chars), différent du codePostal ONISEP.
Résolution via un index mémoire construit depuis geo.api.gouv.fr/communes (Map<codePostal, {code, nom}[]>, ~35K communes). syncAll le charge automatiquement en début de traitement s'il n'est pas déjà en mémoire. Aucun appel réseau par établissement — tout se fait en mémoire.
Si ambiguïté (plusieurs communes pour un code postal) : match sur le nom de ville (exact, puis préfixe pour les arrondissements Paris/Lyon/Marseille). Si non résolu, fallback sur la première entrée.
Sentinel NOT_FOUND
codeInseeCommune a trois états :
| Valeur | Signification |
|---|---|
null |
Pas encore résolu |
"01234" |
Résolu |
"NOT_FOUND" |
Résolution tentée, aucune commune trouvée |
Le sentinel distingue "pas encore traité" de "traité sans résultat" — évite de retenter à chaque sync. Arrive pour des codes postaux CEDEX ou des établissements à l'étranger. Si le code postal est corrigé dans ONISEP, relançable via POST /v1/admin/etablissements/sync/insee/not-found.
Formations
Source : deux datasets ONISEP dédiés, distincts des structures (OnisepAdapter.fetchFormationsIndex).
| Dataset | ID |
|---|---|
| Formations lycée | 605340ddc19a9 |
| Formations supérieur | 605344579a7d7 |
Deux champs sont stockés à partir de ces datasets :
- formations — intitulé détaillé (formation_for_libelle, ex: "BTS gestion de la PME")
- formationsTypes — catégorie brute (for_type, ex: "brevet de technicien supérieur")
Sync indépendante du sync principal, non-bloquante : POST /admin/etablissements/sync/formations (EtablissementSyncService.syncFormations), aussi déclenchée automatiquement en arrière-plan après chaque sync mensuel.
Cordée de la Réussite & établissements sélectifs
Cordées — seule donnée du référentiel obtenue par scraping (pas de dataset opendata dédié) : CordeePortailAdapter parcourt portail.onisep.fr/cordeesdelareussite.onisep.fr académie par académie. Déclenché via POST /admin/etablissements/sync/cordees.
Établissements sélectifs — liste statique SELECTIF_UAIS, pas de source externe — reset puis ré-application complète à chaque sync.
Notes et limites
Fallback établissement libre — ONISEP ne couvre pas les CFA hors contrat, privés hors contrat, établissements étrangers. Le champ texte libre etablissementNom dans inspire-v2 reste nécessaire.
codeAcademie et etatEtablissement — non fournis par ONISEP, restent null dans A1C.
sigle — champ sigle du dataset ONISEP (secondaire et supérieur), souvent vide côté secondaire. Réécrit à chaque sync mensuel comme les autres champs ONISEP ; correction manuelle possible en admin mais non protégée d'un futur resync.