Référentiel Établissements — A1Connect
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
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.
Flags — ZRR / QPV / IPS / IEL
Quatre indicateurs de vulnérabilité territoriale et socio-économique, calculés par EtablissementFlagsService.
Champs
| Champ | Type | Description |
|---|---|---|
zrr |
boolean? | Zone France Ruralités Revitalisation (ex-ZRR). null si commune non résolue. |
qpv |
boolean? | Quartier Prioritaire de la Ville. null si commune non résolue. |
ips |
decimal? | Indice de Position Sociale (DEPP) — niveau socio-éco moyen des élèves. Lycées uniquement. |
iel |
decimal? | Indice d'Éloignement des Lycées (Éducation Nationale) — score ~0–100+. Lycées uniquement. |
codeInseeCommune |
string? | Code INSEE commune (5 chars) — clef de jointure pour ZRR et QPV. |
flagsSyncedAt |
datetime? | Date du dernier calcul. |
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.
zrrvauttruesi la commune est en FRR,nullsinon. Il n'y a jamais defalseexplicite.
Notes et limites
Flags métier — isPrioritaire, isPartenaire sont de la logique métier Article1, pas des données ONISEP. Ils restent dans chaque plateforme, pas dans A1C. A1C expose uniquement le référentiel brut + les indicateurs territoriaux/socio-éco (ZRR, QPV, IPS, IEL).
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.