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.