* **Recherche** de formations par mots-clés (via l'API OpenData)
* **Visualisation cartographique** des établissements avec Leaflet
* **Consultation détaillée** d'une formation (taux d'accès, profil des admis, évolution multi-années)
* **Graphiques statistiques** intégrés avec Charts.css
* **Comparateur de sélection** pour estimer ses chances d'admission
* **Espace utilisateur** connecté avec Firebase Auth et Firestore (persistance avancée)
---
## Architecture et Composants (Riot.js)
L'application est construite de façon déclarative et modulaire avec le framework **Riot.js (v9)** et utilise le routeur officiel **@riotjs/route** pour la navigation SPA (Single Page Application).
***État (State) :** Stocke les résultats de recherche (`state.results`), la formation active (`state.selected`), la sélection pour comparaison (`state.selectedFormations`), et l'utilisateur connecté (`state.user`).
*`formation` : l'objet complet de la formation courante.
* **Sorties (Events) :**
*`onback()` : Demande de retour à l'écran de recherche principal.
* **Interactions :** Fait un appel API supplémentaire (via `window.chargerHistoriqueFormation`) pour récupérer l'historique sur 6 ans depuis l'API Parcoursup.
### 5. `components/map-view.riot`
* **Fonction :** Affiche une carte interactive Leaflet.
*`results` : La liste courante des formations de la vue recherche.
* **Interactions :** Instancie Leaflet dans `onMounted`, place les marqueurs sur carte selon les coordonnées latitude/longitude récupérées, et se redessine automatiquement avec `onUpdated()`. Fournit également une API window globale (`window.mapFocus`) que `result-list` utilise pour recentrer la carte.
### 6. `components/auth-panel.riot`
* **Fonction :** Panneau de connexion / inscription de l'utilisateur (Bonus Firebase).
*`onauth()` et `onlogout()` pour notifier `<app>` des changements de session, ce qui déclenche la synchronisation de la sélection `localStorage` <-> `Firestore`.
* **Fonction :** Comparateur de formations permettant à l'utilisateur d'estimer ses chances d'admission selon son profil (note, série de bac).
* **Props :**
*`formations` : le tableau des formations sélectionnées (passé par `<app>`).
*`onretirer(id)` : callback pour retirer une formation de la sélection.
*`onvider()` : callback pour vider toute la sélection.
* **État interne (State) :** Gère `note`, `serie` et `sortBy` — paramètres propres à l'affichage du comparateur, sans impacter le reste de l'app.
* **Logique :** Calcule un score sur 100 pour chaque formation (taux d'accès + note + proportion de la série) via `calculerScore()`, puis retourne une estimation textuelle (`"Favorable"`, `"Possible"`, etc.).
*`chargerFormations()` : Requete paginée avec filtres croisés vers l'API Data ESR.
*`chargerHistoriqueFormation()` : Requete intelligente multi-datasets (2020-2025) ciblant le code UAI d'un établissement précis pour en extraire l'historique d'admission.
### `formation.js` (Modèle Métier)
* **Fonction :** Isoler et abstraire la complexité du schéma JSON renvoyé par l'API Parcoursup.
* Transforme `brut.acc_tot` ou `brut.lib_for_voe_ins` en un objet lisible clair pour les composants (ex: `formation.admis` ou `formation.nom`), et y précalcule certains champs de base (comme le `tauxAcces`).
### `firebase.js` (Service Backend As a Service)
* Gère l'authentification (Emai/Password) avec `firebase-auth`.
* Gère la persistance cloud de la sélection de vœux dans `users/{uid}` via `firebase-firestore`.
this.map=L.map(element).setView([46.8,2.5],6)// crée la carte Leaflet
L.tileLayer('https://...').addTo(this.map)// ajoute les tuiles OpenStreetMap
}
```
**Étape 9 — L'application est prête, elle attend l'utilisateur**
À ce stade le navigateur affiche la page avec la barre de recherche, la carte vide centrée sur la France, et aucun résultat. Tout est en mémoire, prêt à réagir.
**Étape 10 — L'utilisateur interagit**
```
L'utilisateur tape "BUT informatique" et clique Rechercher
→ le navigateur déclenche l'événement onclick sur le bouton
→ Riot appelle submitSearch() dans search-bar.riot
→ qui appelle props.onsearch(requete, filtres)
→ qui appelle lancerRecherche() dans app.riot
→ qui appelle chargerPage(1)
→ qui appelle fetch() vers l'API
→ l'API retourne le JSON
→ app.riot fait this.update({ resultats: formations })