Skip to content

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.

zrr vaut true si la commune est en FRR, null sinon. Il n'y a jamais de false explicite.


Notes et limites

Flags métierisPrioritaire, 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.