{
  "version": "0.3-proposition",
  "date": "2026-10-06",
  "scope": "Ambition maximale demandée par Pierre ; pas un engagement de charge ni une validation client.",
  "epics": [
    {
      "id": "E01",
      "title": "Accès et espaces habilités",
      "goal": "Retrouver le bon périmètre, sans fuite entre communes."
    },
    {
      "id": "E02",
      "title": "Atlas cartographique",
      "goal": "Relier territoire, sélection et couches de données."
    },
    {
      "id": "E03",
      "title": "Fiches, provenance et confiance",
      "goal": "Donner les limites nécessaires à une décision."
    },
    {
      "id": "E04",
      "title": "Exploration temporelle et dataviz",
      "goal": "Faire de la dataviz une interface de lecture, pas une image."
    },
    {
      "id": "E05",
      "title": "Comparaison et contexte partagé",
      "goal": "Conserver un contexte unique entre toutes les vues."
    },
    {
      "id": "E06",
      "title": "Demandes et collaboration",
      "goal": "Faire circuler une question avec son contexte."
    },
    {
      "id": "E07",
      "title": "Rapports IA sous contrôle humain",
      "goal": "Diffuser uniquement un document vérifié et traçable."
    },
    {
      "id": "E08",
      "title": "Exports et présentation",
      "goal": "Emporter les données sans perdre leur sens."
    },
    {
      "id": "E09",
      "title": "Administration des données",
      "goal": "Observer, corriger et reprendre les traitements."
    },
    {
      "id": "E10",
      "title": "Interface exigeante et accessible",
      "goal": "Faire de la qualité d’intégration un résultat vérifiable."
    },
    {
      "id": "E11",
      "title": "Consultation citoyenne",
      "goal": "Ouvrir des agrégats lorsque les règles de diffusion sont validées."
    },
    {
      "id": "E12",
      "title": "OPAH et rénovation",
      "goal": "Ajouter un suivi opérationnel sans confondre observation et gestion."
    },
    {
      "id": "E13",
      "title": "Trajectoire ZAN et foncier",
      "goal": "Documenter un périmètre foncier distinct du marché immobilier."
    },
    {
      "id": "E14",
      "title": "Recherche et expérience de travail",
      "goal": "Réduire le coût des déplacements entre vues."
    },
    {
      "id": "E15",
      "title": "Tableaux de bord et indicateurs du service",
      "goal": "Piloter l’observatoire et le travail du service."
    },
    {
      "id": "E16",
      "title": "Recette, exploitation et transmission",
      "goal": "Livrer un service qu’un tiers peut reprendre."
    },
    {
      "id": "E17",
      "title": "Quartiers délimités et rues sélectionnables",
      "goal": "Explorer Croix à partir de référentiels géographiques traçables, du quartier à la rue."
    }
  ],
  "stories": [
    {
      "id": "US-001",
      "epic": "E01",
      "title": "Entrer dans mon espace",
      "story": "En tant que maire, je veux me connecter à mon espace communal afin de consulter les informations qui me concernent.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front espaces + Back API",
      "dependencies": [
        "EN-01",
        "EN-02"
      ],
      "criteria": [
        "Identifiants valides : ouverture de la commune autorisée ; retour à la vue demandée si elle est autorisée.",
        "Échec : message générique, champs conservés sauf mot de passe, nouvelle tentative possible.",
        "Le chargement, l’expiration et le refus sont distingués ; le focus revient au message utile."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-002",
      "epic": "E01",
      "title": "Retrouver ma session",
      "story": "En tant que utilisateur habilité, je veux reprendre ma consultation après une interruption afin de éviter de perdre mon contexte.",
      "priority": "P0",
      "sprint": "S3",
      "team": "Front espaces + Back API",
      "dependencies": [
        "US-001"
      ],
      "criteria": [
        "Une session expirée demande une reconnexion avant de recharger les données.",
        "Un retour sur une URL restaure une vue autorisée sans afficher fugitivement des données interdites.",
        "La déconnexion révoque la session serveur et retire les données sensibles des caches du navigateur."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-003",
      "epic": "E01",
      "title": "Attribuer un périmètre",
      "story": "En tant que agent Habitat habilité, je veux attribuer un rôle et une commune à un utilisateur afin de maintenir des accès cohérents avec ses fonctions.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front espaces + Back API",
      "dependencies": [
        "US-001",
        "EN-14"
      ],
      "criteria": [
        "Rôles maire, élu communautaire et agent Habitat distingués ; aucune auto-attribution de privilège.",
        "Modification enregistrée, journalisée et prise en compte sur la prochaine requête.",
        "Un utilisateur non habilité reçoit un refus côté serveur, même en appelant directement la route."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-004",
      "epic": "E01",
      "title": "Consulter sans modifier",
      "story": "En tant que élu communautaire, je veux consulter le territoire sans pouvoir publier ni changer les accès afin de m’informer dans mon rôle de consultation.",
      "priority": "P0",
      "sprint": "S3",
      "team": "Front espaces + Back API",
      "dependencies": [
        "US-001",
        "EN-14"
      ],
      "criteria": [
        "Les 32 communes autorisées sont consultables.",
        "Les actions d’administration et de publication ne sont pas disponibles.",
        "Toute tentative directe de mutation reçoit 403 ; un brouillon de rapport non diffusé n’est pas exposé."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-005",
      "epic": "E02",
      "title": "Explorer les communes",
      "story": "En tant que agent Habitat, je veux repérer une commune sur la carte et ouvrir sa fiche afin de répondre à une question territoriale sans chercher dans plusieurs outils.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front cartographie + Back API",
      "dependencies": [
        "EN-01",
        "EN-03"
      ],
      "criteria": [
        "Carte, liste et fiche partagent le même identifiant communal ; sélectionner sur l’une actualise les autres.",
        "Une géométrie absente n’empêche pas l’accès à la fiche depuis la liste.",
        "Carte utilisable au clavier avec alternative tabulaire ; le périmètre provient du serveur."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-006",
      "epic": "E02",
      "title": "Changer de couche",
      "story": "En tant que agent Habitat, je veux passer des prix aux DPE et aux risques afin de croiser plusieurs lectures du même territoire.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back données",
      "dependencies": [
        "US-005",
        "EN-08",
        "EN-09",
        "EN-10"
      ],
      "criteria": [
        "Le changement conserve commune, zoom et période ; légende, unité et date suivent la couche.",
        "Classes documentées, trames ou valeurs en complément de la couleur ; sans donnée distinct du zéro.",
        "Un résultat tardif de l’ancienne couche ne peut pas écraser la couche active."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-007",
      "epic": "E02",
      "title": "Naviguer à plusieurs échelles",
      "story": "En tant que agent Habitat, je veux zoomer et déplacer la carte vers la zone étudiée afin de examiner le contexte sans perdre ma sélection.",
      "priority": "P1",
      "sprint": "S2",
      "team": "Front cartographie",
      "dependencies": [
        "US-005"
      ],
      "criteria": [
        "Zoom et déplacement à la souris, au tactile et par commandes clavier ; bornes explicites.",
        "Recentrer retrouve le territoire entier sans annuler les filtres.",
        "Les libellés adaptent leur densité au zoom ; aucune valeur ne devient inaccessible sans survol."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-008",
      "epic": "E02",
      "title": "Explorer les quartiers et rues",
      "story": "En tant que maire, je veux naviguer dans les quartiers et rues de ma commune et consulter des indicateurs agrégés uniquement lorsque les données le permettent afin de préparer une action localisée.",
      "priority": "P1",
      "sprint": "S2",
      "team": "Front cartographie + Back données",
      "dependencies": [
        "US-006",
        "EN-18"
      ],
      "criteria": [
        "La maille est visible et ne contient aucune adresse dans la diffusion prévue.",
        "Le retour à la commune conserve indicateur et période.",
        "Les quartiers non couverts sont indiqués ; aucune interpolation silencieuse ne crée une valeur.",
        "Carte et liste permettent commune → quartier → rue, recherche, retour, recharge et lien partagé.",
        "Une rue est rattachée à sa commune et son quartier ; un maire ne sort jamais de son périmètre autorisé.",
        "Le quartier municipal ou IRIS est identifié ; aucun découpage inventé n’est présenté comme officiel.",
        "Une demande conserve le quartier ou la rue sélectionnée ; les données communales ne sont pas reportées à la rue."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-009",
      "epic": "E03",
      "title": "Lire une fiche communale",
      "story": "En tant que maire, je veux retrouver les indicateurs clés de ma commune afin de préparer mon conseil avec des chiffres compréhensibles.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front fiche + Back API",
      "dependencies": [
        "US-005"
      ],
      "criteria": [
        "Chaque indicateur expose valeur, unité, période, date d’import et source.",
        "Valeur absente, non diffusable et erreur de chargement ont des états et des explications distincts.",
        "Prix, DPE et risques ne sont pas mélangés dans un score composite non défini."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-010",
      "epic": "E03",
      "title": "Comprendre un taux DPE",
      "story": "En tant que élu, je veux connaître le dénominateur et la couverture du taux F+G afin de éviter de le présenter comme un recensement de tous les logements.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front fiche + Back DPE",
      "dependencies": [
        "US-009",
        "EN-09"
      ],
      "criteria": [
        "Le numérateur F+G et le total de DPE retenus sont consultables.",
        "Règles de déduplication, méthode et période sont affichées.",
        "Une couverture inconnue reste inconnue ; aucune multiplication par le parc n’est faite sans méthode validée."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-011",
      "epic": "E03",
      "title": "Voir la provenance",
      "story": "En tant que utilisateur habilité, je veux ouvrir la provenance d’un chiffre afin de savoir à quelle donnée je peux me fier.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front fiche + Back API",
      "dependencies": [
        "US-009"
      ],
      "criteria": [
        "Le panneau identifie producteur, jeu, période, date d’import et transformation utilisée.",
        "Ouverture et fermeture au clavier avec restitution du focus au déclencheur.",
        "Une source manquante bloque l’affirmation, sans inventer un nom de producteur."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-012",
      "epic": "E03",
      "title": "Comprendre une non-diffusion",
      "story": "En tant que utilisateur habilité, je veux comprendre pourquoi une valeur est absente afin de distinguer absence, confidentialité et indisponibilité technique.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front fiche + Back données",
      "dependencies": [
        "US-009",
        "EN-15"
      ],
      "criteria": [
        "Un code de qualité stable distingue missing, insufficient_sample, suppressed et source_error.",
        "L’explication propose une autre période ou une référence agrégée lorsqu’elles sont autorisées.",
        "Le seuil est versionné et présenté comme une règle validée du projet, pas comme une loi supposée."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-013",
      "epic": "E04",
      "title": "Explorer une année",
      "story": "En tant que agent Habitat, je veux changer l’année affichée sur la carte afin de observer une évolution sans perdre mon contexte.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front dataviz + Back API",
      "dependencies": [
        "US-006",
        "EN-12"
      ],
      "criteria": [
        "Carte, fiche, légende et source changent ensemble pour l’année sélectionnée.",
        "Lecture et pause de la chronologie ; fin sans boucle imposée ; contrôle toujours possible.",
        "Année sans données explicitée ; une animation ne fabrique pas de valeur intermédiaire interprétable comme réelle."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-014",
      "epic": "E04",
      "title": "Lire une courbe précisément",
      "story": "En tant que élu, je veux parcourir les points d’une série au pointeur et au clavier afin de lire une valeur exacte et sa période.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front dataviz",
      "dependencies": [
        "US-013"
      ],
      "criteria": [
        "Curseur commun entre séries, infobulle située sans sortir du viewport et tableau de valeurs équivalent.",
        "Flèches gauche/droite parcourent les années ; la lecture ne dépend pas du survol.",
        "Une lacune casse la courbe ; les points manquants ne sont pas reliés arbitrairement."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-015",
      "epic": "E04",
      "title": "Recadrer une période",
      "story": "En tant que agent Habitat, je veux réduire la période d’analyse afin de examiner un changement sur un intervalle choisi.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front dataviz + Back API",
      "dependencies": [
        "US-014"
      ],
      "criteria": [
        "Bornes ordonnées, manipulables au clavier et au tactile ; année unique autorisée.",
        "Courbes, écarts, tableau et export utilisent les mêmes bornes.",
        "Le recadrage conserve les communes sélectionnées et signale une période indisponible."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-016",
      "epic": "E04",
      "title": "Lire la relation marché-énergie",
      "story": "En tant que agent Habitat, je veux sélectionner une commune dans un nuage de points afin de comparer ses niveaux de prix et de passoires.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front dataviz",
      "dependencies": [
        "US-014",
        "US-010"
      ],
      "criteria": [
        "Axes, unités et période visibles ; sélection reliée à la fiche et à la comparaison.",
        "Les données manquantes sont exclues du nuage mais restent listées dans le tableau.",
        "Une relation visuelle n’est jamais présentée comme une causalité prouvée."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-017",
      "epic": "E05",
      "title": "Constituer une comparaison",
      "story": "En tant que agent Habitat, je veux sélectionner jusqu’à trois communes afin de les lire côte à côte sur une période identique.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front dataviz + Front cartographie",
      "dependencies": [
        "US-009",
        "US-014"
      ],
      "criteria": [
        "Ajout/retrait depuis carte et tableau ; limite visible ; sélection conservée en changeant de vue.",
        "Courbes identifiées par libellé et style de trait, pas seulement par couleur.",
        "Une commune hors périmètre est refusée et retirée de la sélection restaurée."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-018",
      "epic": "E05",
      "title": "Me situer dans le territoire",
      "story": "En tant que maire, je veux comparer ma commune à des références agrégées autorisées afin de contextualiser ses indicateurs.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front dataviz + Back données",
      "dependencies": [
        "US-010",
        "EN-12"
      ],
      "criteria": [
        "Commune, agglomération et département hors agglomération emploient la même définition et la même période.",
        "Le calcul de la référence et ses poids sont documentés ; ratios jamais moyennés sans méthode.",
        "Pas de nom ni de valeur d’une autre commune lorsque le périmètre du maire l’interdit."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-019",
      "epic": "E05",
      "title": "Partager une vue",
      "story": "En tant que utilisateur habilité, je veux partager un lien de ma consultation afin de retrouver les mêmes filtres avec un collègue autorisé.",
      "priority": "P1",
      "sprint": "S2",
      "team": "Front espaces",
      "dependencies": [
        "US-017"
      ],
      "criteria": [
        "URL encode commune, indicateur, année, période, sélection et couches actives.",
        "Lien ouvert dans un autre profil : contrôle des accès avant chargement ; identifiants inconnus normalisés.",
        "Retour navigateur et rechargement restaurent un état cohérent ; le lien ne contient aucun jeton."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-020",
      "epic": "E05",
      "title": "Filtrer par classe de valeur",
      "story": "En tant que agent Habitat, je veux sélectionner une classe dans une distribution afin de examiner les communes qui correspondent à mon analyse.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front dataviz",
      "dependencies": [
        "US-016",
        "US-017"
      ],
      "criteria": [
        "Classe sélectionnée filtre tableau, décompte et export ; action répétée retire le filtre.",
        "Les classes restent fixes entre années et les valeurs manquantes ont une classe distincte.",
        "Le focus reste utilisable après actualisation ; la classe active est annoncée."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-021",
      "epic": "E06",
      "title": "Transmettre une demande contextualisée",
      "story": "En tant que maire, je veux demander une synthèse depuis ma consultation afin de éviter de ressaisir les chiffres et le périmètre.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front rapports + Back API",
      "dependencies": [
        "US-009",
        "EN-13"
      ],
      "criteria": [
        "Objet obligatoire et précisions facultatives ; contexte joint : commune, indicateur, période, sources et filtre.",
        "Succès retourne une référence serveur ; erreur conserve la saisie et permet une reprise.",
        "Double clic ou retry ne créent pas deux demandes ; les délais affichés proviennent d’un engagement validé."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-022",
      "epic": "E06",
      "title": "Suivre mes demandes",
      "story": "En tant que maire, je veux retrouver l’état de mes demandes afin de savoir si une réponse est prête.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front rapports + Back API",
      "dependencies": [
        "US-021"
      ],
      "criteria": [
        "Nouvelle, en cours, en attente de précision, répondue et close distinguées.",
        "Liste paginée, triée et limitée au périmètre ; état vide avec action pertinente.",
        "Le brouillon interne n’est jamais inclus dans la réponse API destinée au maire."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-023",
      "epic": "E06",
      "title": "Traiter la file de demandes",
      "story": "En tant que agent Habitat, je veux affecter et prioriser les demandes afin de organiser le travail du service.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front rapports + Back API",
      "dependencies": [
        "US-021"
      ],
      "criteria": [
        "Filtres commune, thème, statut et responsable ; détail lié à la fiche.",
        "Changement de statut journalisé, conflit de modification signalé sans écraser le travail d’un collègue.",
        "Une demande sans données exploitables peut recevoir une réponse explicative."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-024",
      "epic": "E06",
      "title": "Être averti d’une réponse",
      "story": "En tant que maire, je veux recevoir un avis lorsqu’une synthèse est publiée afin de ne pas devoir vérifier chaque jour.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front rapports + Back API",
      "dependencies": [
        "US-022",
        "US-027"
      ],
      "criteria": [
        "Notification in-app avec lien vers la ressource autorisée.",
        "Lecture de la notification enregistrée sans modifier le rapport.",
        "Échec du canal externe journalisé ; publication conservée ; pas d’envoi à des utilisateurs hors périmètre."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-025",
      "epic": "E07",
      "title": "Préparer un brouillon sourcé",
      "story": "En tant que agent Habitat, je veux générer un brouillon depuis des indicateurs agrégés afin de préparer une synthèse sans ressaisir les valeurs.",
      "priority": "P0",
      "sprint": "S4",
      "team": "Front rapports + Back IA",
      "dependencies": [
        "EN-16",
        "US-010",
        "US-023"
      ],
      "criteria": [
        "Job asynchrone : queued, running, failed et ready ; pas de bouton qui prétend publier immédiatement.",
        "Chiffres liés aux snapshots utilisés ; texte sans chiffre non fourni ni causalité inventée.",
        "Prompt, modèle, version et horodatage tracés ; données au logement exclues du périmètre de génération retenu."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-026",
      "epic": "E07",
      "title": "Relire section par section",
      "story": "En tant que agent Habitat, je veux accepter, corriger ou exclure les sections du brouillon afin de garder la maîtrise de son contenu.",
      "priority": "P0",
      "sprint": "S4",
      "team": "Front rapports + Back IA",
      "dependencies": [
        "US-025"
      ],
      "criteria": [
        "Acceptation impossible sans source ; correction réelle du texte, source et auteur sauvegardés.",
        "Section exclue absente du document diffusé ; le brouillon conserve son historique.",
        "Retour ou rechargement conserve les décisions ; deux relecteurs ne peuvent pas s’écraser silencieusement."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-027",
      "epic": "E07",
      "title": "Publier une version validée",
      "story": "En tant que agent Habitat habilité, je veux publier une version entièrement relue afin de diffuser un document dont je peux justifier les chiffres.",
      "priority": "P0",
      "sprint": "S4",
      "team": "Front rapports + Back IA",
      "dependencies": [
        "US-026",
        "EN-14"
      ],
      "criteria": [
        "Le serveur vérifie les sections, les sources et l’habilitation ; le front seul ne peut pas lever le blocage.",
        "Version, auteur, date et empreinte des données enregistrés ; publiée et brouillon distingués.",
        "La publication ne modifie pas une version déjà diffusée ; une correction crée une nouvelle version."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-028",
      "epic": "E07",
      "title": "Consulter un rapport validé",
      "story": "En tant que élu, je veux lire un rapport publié pour mon périmètre afin de l’utiliser en réunion en connaissant ses limites.",
      "priority": "P0",
      "sprint": "S4",
      "team": "Front rapports + Back API",
      "dependencies": [
        "US-027"
      ],
      "criteria": [
        "Une version publiée expose texte, sources, auteur de validation, date et période.",
        "Brouillons, sections rejetées et commentaires internes absents de la réponse destinée aux élus.",
        "Rapport retiré signalé explicitement ; lien vers la version remplaçante si autorisé."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-029",
      "epic": "E08",
      "title": "Exporter un tableau",
      "story": "En tant que agent Habitat, je veux exporter les données de ma sélection afin de poursuivre une analyse avec les mêmes définitions.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front dataviz + Back API",
      "dependencies": [
        "US-015",
        "US-020"
      ],
      "criteria": [
        "Export CSV avec filtres, période, unités, sources et codes de qualité.",
        "Cellules texte protégées contre l’interprétation comme formules dans un tableur.",
        "Jeu trop volumineux traité par job et lien temporaire autorisé ; aucune fuite hors périmètre."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-030",
      "epic": "E08",
      "title": "Télécharger une synthèse PDF",
      "story": "En tant que élu, je veux télécharger la version publiée d’un rapport afin de la distribuer en réunion.",
      "priority": "P1",
      "sprint": "S4",
      "team": "Front rapports + Back IA",
      "dependencies": [
        "US-028"
      ],
      "criteria": [
        "PDF reproduit uniquement la version validée et ses sources ; date et numéro de version visibles.",
        "Pagination, graphiques et tables lisibles ; aucun contenu tronqué.",
        "Le téléchargement contrôle l’habilitation et explique une indisponibilité sans faux succès."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-031",
      "epic": "E08",
      "title": "Présenter en conseil",
      "story": "En tant que agent Habitat, je veux passer les visualisations en mode présentation afin de les lire clairement avec les élus.",
      "priority": "P2",
      "sprint": "S5",
      "team": "Front dataviz",
      "dependencies": [
        "US-014",
        "US-028"
      ],
      "criteria": [
        "Mode grand écran avec titre, unités, sources et période conservés.",
        "Navigation clavier, sortie explicite et restauration du contexte de travail.",
        "Les annotations ne masquent pas les données ; le mode ne crée aucun accès supplémentaire."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-032",
      "epic": "E08",
      "title": "Annoter une analyse",
      "story": "En tant que agent Habitat, je veux associer une note à une sélection et une période afin de préparer une discussion sans altérer la donnée.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front dataviz + Back API",
      "dependencies": [
        "US-019"
      ],
      "criteria": [
        "Annotation liée à des identifiants et à un snapshot ; auteur et date conservés.",
        "Texte éditable et supprimable selon les droits, sans modifier les valeurs.",
        "Changement de millésime signale que la note porte sur une autre version."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-033",
      "epic": "E09",
      "title": "Voir la fraîcheur des sources",
      "story": "En tant que agent Habitat, je veux consulter l’état de chaque alimentation afin de savoir si une donnée récente est réellement disponible.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front données + Back données",
      "dependencies": [
        "EN-08",
        "EN-09",
        "EN-10"
      ],
      "criteria": [
        "Période source, publication producteur et date d’import distinguées.",
        "Dernier import réussi, import en cours, retard et échec visibles.",
        "Le retard ne masque pas la dernière donnée valide ; la date reste attachée à sa valeur."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-034",
      "epic": "E09",
      "title": "Relancer un import",
      "story": "En tant que exploitant habilité, je veux relancer un traitement en échec afin de rétablir l’alimentation sans créer de doublons.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front données + Back données",
      "dependencies": [
        "US-033",
        "EN-11"
      ],
      "criteria": [
        "Reprise depuis le dernier point connu et idempotence vérifiées.",
        "Deux lancements concurrents contrôlés ; progression observable.",
        "Les erreurs détaillées restent dans l’espace d’exploitation, sans secrets dans le navigateur."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-035",
      "epic": "E09",
      "title": "Réconcilier les communes",
      "story": "En tant que agent Habitat, je veux résoudre les noms et codes ambigus de l’ancien fichier afin de rattacher correctement les données au territoire.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front données + Back données",
      "dependencies": [
        "EN-06"
      ],
      "criteria": [
        "Candidats, raisons et anomalies visibles ; aucune association silencieuse à partir d’un nom ambigu.",
        "Décision humaine conservée avec auteur et date ; le quartier gare n’est pas traité comme une commune.",
        "Doublons, codes réutilisés et anciens libellés restent consultables dans le journal de migration."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-036",
      "epic": "E09",
      "title": "Auditer un indicateur",
      "story": "En tant que agent Habitat, je veux retrouver les étapes de calcul d’une valeur afin de expliquer un écart entre deux millésimes.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front données + Back données",
      "dependencies": [
        "US-011",
        "EN-12"
      ],
      "criteria": [
        "Version de méthode, volume brut, exclusions et total retenu accessibles.",
        "Recalcul reproductible depuis les références enregistrées.",
        "Un changement de méthode marque une rupture et ne se présente pas comme une variation territoriale."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-037",
      "epic": "E10",
      "title": "Utiliser le service sur mobile",
      "story": "En tant que maire, je veux consulter puis demander un rapport sur mon téléphone afin de préparer une réunion en déplacement.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Tous les fronts",
      "dependencies": [
        "US-009",
        "EN-04"
      ],
      "criteria": [
        "À 390 px, carte et fiche se réorganisent sans réduire une page desktop en miniature.",
        "Actions tactiles de 44 px minimum, clavier virtuel et safe areas pris en compte.",
        "La consultation et le formulaire restent utilisables à 200 % de zoom, sans perte d’information."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-038",
      "epic": "E10",
      "title": "Tout parcourir au clavier",
      "story": "En tant que utilisateur au clavier, je veux naviguer dans les cartes, graphiques et dialogues afin de accéder à toutes les informations sans souris.",
      "priority": "P0",
      "sprint": "S3",
      "team": "Tous les fronts",
      "dependencies": [
        "US-014",
        "EN-04"
      ],
      "criteria": [
        "Ordre de tabulation, focus visible, liens d’évitement et restitution du focus dans chaque dialogue.",
        "Carte et graphiques disposent d’une lecture équivalente tabulaire.",
        "Changement de donnée annoncé de manière mesurée ; aucun piège clavier ni contenu exclusivement au survol."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-039",
      "epic": "E10",
      "title": "Comprendre les transitions visuelles",
      "story": "En tant que utilisateur, je veux voir les transitions entre données et contextes afin de comprendre ce qui a changé sans perdre mes repères.",
      "priority": "P1",
      "sprint": "S2",
      "team": "Front dataviz + Front cartographie",
      "dependencies": [
        "US-013",
        "EN-05"
      ],
      "criteria": [
        "Tracé des séries, morphing des points, changement de couche et panneau coordonnés selon la spécification motion.",
        "Animation annulable lors d’un nouvel événement ; seul le dernier état demandé est retenu.",
        "Réduction des mouvements : affichage immédiat et lisible ; les nombres intermédiaires ne sont pas annoncés comme des mesures."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-040",
      "epic": "E10",
      "title": "Reprendre après une erreur",
      "story": "En tant que utilisateur, je veux réessayer un chargement sans refaire ma sélection afin de continuer mon travail malgré une panne.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Tous les fronts + Back API",
      "dependencies": [
        "EN-03"
      ],
      "criteria": [
        "Chargement, vide, absent, non diffusable, refus et panne ont des états distincts.",
        "Nouvelle tentative conserve filtres et saisies ; aucun ancien résultat n’est affiché comme nouveau.",
        "Erreur persistante propose une sortie utile ; messages compréhensibles et corrélation de diagnostic côté service."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-041",
      "epic": "E11",
      "title": "Consulter des indicateurs publics",
      "story": "En tant que citoyen, je veux consulter les données territoriales publiées afin de comprendre l’habitat dans mon territoire.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front public + Back API",
      "dependencies": [
        "EN-17",
        "US-012"
      ],
      "criteria": [
        "Seuls les jeux explicitement autorisés au public sont exposés.",
        "Vue adaptée au grand public, avec définition, date et limites.",
        "Une route publique ne permet pas de déduire des données privées par ses filtres."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-042",
      "epic": "E11",
      "title": "Comprendre un indicateur public",
      "story": "En tant que citoyen, je veux ouvrir une explication simple des indicateurs afin de éviter de confondre aléa, sinistre et diagnostic.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front public",
      "dependencies": [
        "US-041",
        "US-010"
      ],
      "criteria": [
        "Définitions courtes complétées par la méthode détaillée.",
        "Les limites du parc diagnostiqué et des petits effectifs apparaissent près des valeurs.",
        "Vocabulaire factuel, aucune commune qualifiée de bonne ou mauvaise."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-043",
      "epic": "E11",
      "title": "Lire les rapports publics",
      "story": "En tant que citoyen, je veux lire les rapports explicitement ouverts au public afin de accéder à une information validée.",
      "priority": "P2",
      "sprint": "S5",
      "team": "Front public + Back API",
      "dependencies": [
        "US-041",
        "US-027"
      ],
      "criteria": [
        "Publication interne et publication publique sont deux décisions distinctes.",
        "Les versions publiques excluent annexes ou informations non autorisées.",
        "Retrait et remplacement d’une version visibles, sans effacer l’historique de validation interne."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-044",
      "epic": "E11",
      "title": "Rechercher une commune publique",
      "story": "En tant que citoyen, je veux retrouver une commune dans l’espace public afin de accéder rapidement aux données qui m’intéressent.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front public",
      "dependencies": [
        "US-041"
      ],
      "criteria": [
        "Recherche par nom, avec accents et aliases normalisés.",
        "Absence de résultat expliquée ; aucune suggestion d’un territoire non publié.",
        "URL publique stable et utilisable sur mobile."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-045",
      "epic": "E12",
      "title": "Voir les périmètres OPAH",
      "story": "En tant que agent Habitat, je veux superposer les périmètres des opérations de rénovation afin de situer les actions par rapport au parc étudié.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front cartographie + Back données",
      "dependencies": [
        "EN-19",
        "US-006"
      ],
      "criteria": [
        "Périmètre, dates et type d’opération documentés ; source jointe.",
        "Superposition activable sans modifier la classification des DPE.",
        "Aucun périmètre reconstitué à partir de notes incomplètes."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-046",
      "epic": "E12",
      "title": "Suivre les objectifs de rénovation",
      "story": "En tant que agent Habitat, je veux suivre objectifs et réalisations d’une opération afin de préparer un bilan opérationnel.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front données + Back données",
      "dependencies": [
        "US-045",
        "EN-19"
      ],
      "criteria": [
        "Objectifs, engagés et achevés distingués par période.",
        "Saisie avec preuve ou source, responsable et historique.",
        "Total et taux calculés avec dénominateur documenté ; absent différent de zéro."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-047",
      "epic": "E12",
      "title": "Comparer objectifs et résultats",
      "story": "En tant que élu, je veux voir l’évolution d’une opération par rapport à ses objectifs afin de identifier les écarts à discuter.",
      "priority": "P2",
      "sprint": "S5",
      "team": "Front dataviz",
      "dependencies": [
        "US-046"
      ],
      "criteria": [
        "Graphique objectifs/résultats accessible avec mêmes périodes et unités.",
        "Écart factuel, sans explication causale automatiquement inventée.",
        "Une opération terminée et une opération en cours restent distinguées."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-048",
      "epic": "E12",
      "title": "Joindre le bilan OPAH au rapport",
      "story": "En tant que agent Habitat, je veux intégrer un bilan validé d’opération à la synthèse afin de présenter une lecture observation et action.",
      "priority": "P2",
      "sprint": "S5",
      "team": "Front rapports + Back IA",
      "dependencies": [
        "US-046",
        "US-026"
      ],
      "criteria": [
        "Section rattachée au snapshot de l’opération et revue séparément.",
        "Objectifs futurs jamais présentés comme des réalisations.",
        "Même contrôle de publication que pour les autres sections."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-049",
      "epic": "E13",
      "title": "Consulter une trajectoire foncière",
      "story": "En tant que agent Habitat, je veux consulter une trajectoire de consommation d’espace documentée afin de préparer un échange avec les services d’aménagement.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front dataviz + Back données",
      "dependencies": [
        "EN-20"
      ],
      "criteria": [
        "Période de référence, unité, périmètre et source explicités.",
        "Objectifs et mesures observées distingués ; données SCOT absentes signalées.",
        "Aucun calcul ZAN déduit des seules ventes DVF."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-050",
      "epic": "E13",
      "title": "Explorer le foncier sur la carte",
      "story": "En tant que agent Habitat, je veux superposer des agrégats fonciers autorisés afin de situer les évolutions à l’échelle utile.",
      "priority": "P2",
      "sprint": "S5",
      "team": "Front cartographie + Back données",
      "dependencies": [
        "US-049",
        "EN-18"
      ],
      "criteria": [
        "Géométrie et unité de surface homogènes ; maille et source visibles.",
        "Surfaces cumulées sans double comptage ; couches compatibles clairement indiquées.",
        "Données cadastrales indisponibles ne sont pas remplacées par une géométrie inventée."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-051",
      "epic": "E13",
      "title": "Suivre un scénario de trajectoire",
      "story": "En tant que élu, je veux comparer une trajectoire observée à des hypothèses explicites afin de discuter une projection sans la confondre avec un résultat.",
      "priority": "P2",
      "sprint": "S5",
      "team": "Front dataviz + Back données",
      "dependencies": [
        "US-049"
      ],
      "criteria": [
        "Hypothèses éditables identifiées comme hypothèses et versionnées.",
        "Courbe observée et projection différenciées par style et libellé.",
        "Résultats invalides ou inputs absents explicités ; aucune certitude réglementaire implicite."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-052",
      "epic": "E13",
      "title": "Exporter une note foncière",
      "story": "En tant que agent Habitat, je veux exporter une note fondée sur les données foncières validées afin de partager une analyse avec le service d’aménagement.",
      "priority": "P2",
      "sprint": "S5",
      "team": "Front rapports + Back IA",
      "dependencies": [
        "US-049",
        "US-030"
      ],
      "criteria": [
        "Données, hypothèses et objectifs présentés séparément.",
        "Source, méthode et date de validation intégrées au document.",
        "Une note non validée reste un brouillon non diffusable."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-053",
      "epic": "E14",
      "title": "Rechercher rapidement",
      "story": "En tant que agent Habitat, je veux rechercher une commune depuis n’importe quelle vue afin de accéder à sa fiche sans revenir à la carte.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front espaces",
      "dependencies": [
        "US-005"
      ],
      "criteria": [
        "Recherche accessible depuis un bouton et un raccourci documenté.",
        "Résultats filtrés par droits, navigation clavier, recherche insensible aux accents.",
        "Dialogue fermé restaure le focus ; absence de résultat ne bloque pas la navigation."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-054",
      "epic": "E14",
      "title": "Retrouver une vue favorite",
      "story": "En tant que agent Habitat, je veux enregistrer une consultation favorite afin de reprendre mes analyses récurrentes.",
      "priority": "P2",
      "sprint": "S3",
      "team": "Front espaces + Back API",
      "dependencies": [
        "US-019"
      ],
      "criteria": [
        "Nom, périmètre et filtres stockés ; favoris propres au compte.",
        "Une commune devenue inaccessible est signalée puis retirée de la restauration.",
        "Modification et suppression n’altèrent pas les données consultées."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-055",
      "epic": "E14",
      "title": "Consulter deux périodes côte à côte",
      "story": "En tant que agent Habitat, je veux comparer visuellement deux périodes sur la carte afin de repérer les évolutions géographiques.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front cartographie + Front dataviz",
      "dependencies": [
        "US-013",
        "EN-12"
      ],
      "criteria": [
        "Deux cartes partagent zoom, centre et classification ; années identifiées.",
        "Séparateur déplaçable au clavier et au tactile, avec mode côte à côte équivalent.",
        "Différences de méthode ou couverture signalées avant une lecture des écarts."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-056",
      "epic": "E14",
      "title": "Conserver mes préférences de lecture",
      "story": "En tant que utilisateur, je veux conserver les couches et préférences de présentation afin de retrouver un environnement adapté à mes usages.",
      "priority": "P2",
      "sprint": "S3",
      "team": "Front espaces",
      "dependencies": [
        "US-019",
        "US-039"
      ],
      "criteria": [
        "Préférences non sensibles restaurées sans dépasser les droits actuels.",
        "Préférence système de réduction des mouvements respectée en priorité.",
        "Une sauvegarde impossible ne bloque pas la consultation ; reset disponible."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-057",
      "epic": "E15",
      "title": "Lire la synthèse territoriale",
      "story": "En tant que agent Habitat, je veux retrouver une synthèse du territoire afin de identifier les sujets à examiner en priorité.",
      "priority": "P1",
      "sprint": "S2",
      "team": "Front dataviz + Back données",
      "dependencies": [
        "EN-12",
        "US-033"
      ],
      "criteria": [
        "Indicateurs agrégés calculés par méthode documentée, avec leurs dates.",
        "Le tableau de bord dirige vers les communes ou sources concernées.",
        "Un sous-ensemble ne se présente pas comme un total des 32 communes."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-058",
      "epic": "E15",
      "title": "Repérer les données à vérifier",
      "story": "En tant que agent Habitat, je veux voir les anomalies prioritaires afin de concentrer les corrections sur les informations utiles.",
      "priority": "P1",
      "sprint": "S3",
      "team": "Front données + Back données",
      "dependencies": [
        "US-035",
        "US-036"
      ],
      "criteria": [
        "Anomalies filtrées par source, commune et gravité méthodologique.",
        "Résolution nécessite une action ou justification tracée.",
        "Les anomalies ne sont pas masquées par un indicateur global de succès."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-059",
      "epic": "E15",
      "title": "Suivre l’activité du service",
      "story": "En tant que responsable Habitat, je veux suivre les demandes et délais réellement observés afin de adapter l’organisation du travail.",
      "priority": "P2",
      "sprint": "S4",
      "team": "Front dataviz + Back API",
      "dependencies": [
        "US-023"
      ],
      "criteria": [
        "Volumes et délais fondés sur événements horodatés, avec règles de jours ouvrés définies.",
        "Demandes non répondues comptées séparément ; pas de moyenne qui les efface.",
        "Objectifs de délai validés et observés distingués."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-060",
      "epic": "E15",
      "title": "Préparer le conseil communautaire",
      "story": "En tant que agent Habitat, je veux assembler des sections validées pour un conseil afin de produire une synthèse au périmètre pertinent.",
      "priority": "P1",
      "sprint": "S5",
      "team": "Front rapports + Back IA",
      "dependencies": [
        "US-027",
        "US-059"
      ],
      "criteria": [
        "Sections choisies depuis des versions compatibles et validées.",
        "Périodes hétérogènes signalées ; références conservées pour chaque chiffre.",
        "L’assemblage final est relu et validé avant diffusion."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-061",
      "epic": "E16",
      "title": "Vérifier les parcours livrés",
      "story": "En tant que représentant du client, je veux recetter les parcours au regard des engagements afin de savoir ce qui est effectivement livré.",
      "priority": "P0",
      "sprint": "S5",
      "team": "Projet + tous les fronts",
      "dependencies": [
        "EN-07",
        "EN-21"
      ],
      "criteria": [
        "Scénarios nominaux, variantes, erreurs, droits et retours documentés.",
        "Recette exécutée sur l’environnement intégré avec données de test identifiées.",
        "Écart entre proposition, mock et intégré consigné sans prétendre qu’une maquette est une livraison."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-062",
      "epic": "E16",
      "title": "Reprendre l’outil",
      "story": "En tant que exploitant mutualisé, je veux redémarrer et alimenter l’application avec la documentation afin de assurer sa continuité après le projet.",
      "priority": "P0",
      "sprint": "S5",
      "team": "Plateforme + Back données",
      "dependencies": [
        "EN-22"
      ],
      "criteria": [
        "Un tiers démarre l’environnement en moins de 30 minutes selon une procédure testée.",
        "Documentation des sources, secrets, sauvegardes et procédures de reprise.",
        "Chaque décision structurante et contrat d’API est versionné."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-063",
      "epic": "E16",
      "title": "Diagnostiquer une panne",
      "story": "En tant que exploitant mutualisé, je veux retrouver les traces d’une requête ou d’un import afin de résoudre un incident sans reproduire toute la consultation.",
      "priority": "P0",
      "sprint": "S4",
      "team": "Plateforme + Back API",
      "dependencies": [
        "EN-23"
      ],
      "criteria": [
        "Identifiant de corrélation entre navigateur, API et job ; logs sans secrets ni données inutiles.",
        "Panne de source et panne applicative distinguées.",
        "Procédure permet rollback et reprise ; dernière donnée valide identifiable."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-064",
      "epic": "E16",
      "title": "Restaurer une sauvegarde",
      "story": "En tant que exploitant mutualisé, je veux restaurer les données et versions publiées afin de récupérer le service après un incident.",
      "priority": "P0",
      "sprint": "S5",
      "team": "Plateforme",
      "dependencies": [
        "EN-24"
      ],
      "criteria": [
        "Sauvegarde et restauration testées dans un environnement isolé.",
        "Rapports, validations et rattachements de sources conservés.",
        "Temps observés et pertes possibles documentés ; aucune promesse non mesurée."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-065",
      "epic": "E02",
      "title": "Voir les quartiers délimités",
      "story": "En tant que maire, je veux identifier les quartiers de ma commune sur la carte afin de situer les enjeux locaux.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back géospatial + Data",
      "dependencies": [],
      "criteria": [
        "Les quartiers publiés sont des polygones ou multipolygones nommés, avec source, date, version et nature du découpage consultables.",
        "Carte et liste sélectionnent le même quartier ; son contour reste distinct de la couleur de l’indicateur.",
        "Aucun rectangle de scénario ne porte le nom d’un quartier réel ; si le référentiel manque, l’état indique quartiers non alimentés."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-066",
      "epic": "E02",
      "title": "Explorer un quartier",
      "story": "En tant que maire, je veux ouvrir un quartier et retrouver ses rues afin de passer de la vue communale à un périmètre précis.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back géospatial + Data",
      "dependencies": [
        "US-065"
      ],
      "criteria": [
        "Le clic recadre le quartier, conserve couche et année et ouvre une fiche ; le fil Croix > quartier revient sans perdre le contexte.",
        "La liste contient les rues intersectant le quartier, dont les rues qui le traversent partiellement.",
        "L’animation de caméra est interruptible, réduite si demandé et ne déplace pas le focus clavier."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-067",
      "epic": "E02",
      "title": "Sélectionner une rue réelle",
      "story": "En tant que maire, je veux sélectionner une rue sur la carte ou dans une liste afin de la localiser et consulter les informations disponibles.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back géospatial + Data",
      "dependencies": [
        "US-066"
      ],
      "criteria": [
        "Le tracé réel de la rue est cliquable avec une zone de capture élargie ; survol, focus et sélection sont distincts.",
        "Les tronçons portent un identifiant de rue stable ; sélectionner la rue souligne ses tronçons autorisés, le tronçon cliqué restant identifiable.",
        "La fiche affiche nom, commune, quartiers traversés, source géographique et disponibilité des indicateurs ; aucun agrégat communal ne devient une valeur de rue."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-068",
      "epic": "E02",
      "title": "Rechercher une rue ou un quartier",
      "story": "En tant que maire, je veux retrouver un lieu par son nom afin de accéder directement à son contexte.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back géospatial + Data",
      "dependencies": [
        "US-067"
      ],
      "criteria": [
        "Recherche sans accents, catégories quartier/rue, gestion des homonymes ; résultats limités côté serveur à Croix pour le maire.",
        "La sélection d’un résultat synchronise carte, liste, fiche et fil de navigation.",
        "Chargement, absence de résultat, erreur et reprise sont distingués ; navigation complète au clavier."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-069",
      "epic": "E02",
      "title": "Comprendre les valeurs à chaque maille",
      "story": "En tant que élu communautaire, je veux connaître la disponibilité et la méthode des indicateurs du lieu sélectionné afin de éviter une interprétation trompeuse.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back géospatial + Data",
      "dependencies": [
        "US-065",
        "US-067"
      ],
      "criteria": [
        "Chaque valeur affiche maille, période, source, méthode, effectif et statut disponible/absent/non calculable/masqué.",
        "Un indicateur de rue nécessite une affectation géographique documentée ; sa disponibilité peut différer de celle du quartier.",
        "Seuils de diffusion configurés et validés par le responsable de données ; valeurs masquées absentes des API et exports, pas seulement du graphique."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-070",
      "epic": "E02",
      "title": "Partager et questionner un lieu",
      "story": "En tant que maire, je veux conserver quartier et rue dans un lien ou une demande afin de obtenir une réponse sur le même lieu.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back géospatial + Data",
      "dependencies": [
        "US-067"
      ],
      "criteria": [
        "URL et demande conservent communeId, quartierId facultatif, rueId facultatif, tronconId facultatif, version du référentiel, indicateur et année.",
        "Retour navigateur et rechargement rétablissent la sélection autorisée ; le service retrouve le contexte exact.",
        "Lieu retiré, version obsolète ou périmètre interdit : message explicite et retour à la commune, sans fuite de géométrie ni d’indicateur."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-071",
      "epic": "E17",
      "title": "Publier un référentiel de quartiers",
      "story": "En tant que agent Habitat habilité, je veux importer, vérifier puis publier un découpage géographique afin de maintenir une carte fiable.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back géospatial + Data",
      "dependencies": [],
      "criteria": [
        "Import GeoJSON avec identifiants, noms, source, licence et date ; contrôles de géométrie, projection, périmètre, doublons, recouvrements et lacunes.",
        "Aperçu en brouillon et liste des anomalies ; les lacunes et recouvrements doivent être corrigés ou explicitement justifiés avant publication.",
        "Publication crée une version atomique, trace auteur et date, préserve la version précédente et permet sa restauration ; aucun dessin manuel n’est présenté comme officiel."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-072",
      "epic": "E17",
      "title": "Contrôler le réseau de rues",
      "story": "En tant que agent Habitat habilité, je veux vérifier les rues et leurs relations avec les quartiers afin de fiabiliser la recherche et la navigation.",
      "priority": "P0",
      "sprint": "S2",
      "team": "Front cartographie + Back géospatial + Data",
      "dependencies": [
        "US-071"
      ],
      "criteria": [
        "Le réseau conserve identifiants de rue et de tronçon, nom, géométrie linéaire, source, licence, date et commune.",
        "Les intersections géographiques produisent une relation plusieurs-à-plusieurs quartier/rue ; les rues sans nom ou non affectées restent contrôlables.",
        "Un rapport compare versions, signale rues ajoutées/retirées/modifiées et permet de publier le réseau avec le découpage cohérent."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-073",
      "epic": "E01",
      "title": "Réinitialiser mon mot de passe",
      "story": "En tant qu’utilisateur, je veux réinitialiser mon mot de passe oublié afin de retrouver l’accès à mon espace.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front espaces + Back API",
      "dependencies": [
        "EN-01",
        "EN-02"
      ],
      "criteria": [
        "Le lien « Mot de passe oublié » est accessible depuis la connexion ; les écrans d’accès et de réinitialisation ne présentent aucune navigation métier.",
        "La saisie d’une adresse e-mail permet de demander un lien ; le message de confirmation reste identique que le compte existe ou non.",
        "Le lien de réinitialisation est à usage unique et sa durée de validité est contrôlée côté serveur.",
        "Le nouveau mot de passe et sa confirmation doivent correspondre et respecter la politique de sécurité retenue.",
        "Après confirmation, l’utilisateur revient à la connexion ; les anciennes sessions sont invalidées."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "US-074",
      "epic": "E02",
      "title": "Déplacer la carte",
      "story": "En tant qu’utilisateur de l’atlas, je veux déplacer la carte librement afin de explorer les rues et quartiers autour du lieu étudié.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front cartographie + Back géographie",
      "dependencies": [
        "US-005"
      ],
      "criteria": [
        "Le glisser-déposer déplace le fond, les limites, les rues et les valeurs ensemble, sans modifier le zoom.",
        "Le déplacement ne sélectionne pas involontairement une rue ou un quartier.",
        "La sélection, l’indicateur et la période restent conservés pendant le déplacement.",
        "Des commandes accessibles au clavier permettent le déplacement sans imposer la souris."
      ],
      "status": "Proposé · à estimer",
      "estimate": null,
      "roles": [
        "maire",
        "habitat",
        "elu"
      ],
      "persona": "utilisateur de l’atlas",
      "kind": "map",
      "steps": [
        "Ouvrir la carte du territoire",
        "Glisser pour explorer les alentours",
        "Conserver le lieu sélectionné et ses valeurs"
      ],
      "benefit": "Explorer les rues et quartiers autour du lieu étudié.",
      "captures": [],
      "visualStatus": "illustration cible",
      "functionalScope": "nominal",
      "videoTitle": "Déplacer la carte"
    },
    {
      "id": "US-075",
      "epic": "E02",
      "title": "Zoomer et dézoomer sur la carte",
      "story": "En tant qu’utilisateur de l’atlas, je veux régler le niveau de zoom afin de passer de la commune au détail des rues.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front cartographie + Back géographie",
      "dependencies": [
        "US-005"
      ],
      "criteria": [
        "Les boutons + et − et les gestes de zoom adaptent le niveau de détail de la carte.",
        "Le zoom conserve le point visé et la sélection ; il ne réinitialise pas les filtres.",
        "Les libellés, tracés de rues et limites sont adaptés au zoom et restent lisibles.",
        "Les commandes ont un libellé accessible et fonctionnent au clavier."
      ],
      "status": "Proposé · à estimer",
      "estimate": null,
      "roles": [
        "maire",
        "habitat",
        "elu"
      ],
      "persona": "utilisateur de l’atlas",
      "kind": "map",
      "steps": [
        "Repérer le quartier",
        "Zoomer sur les rues",
        "Dézoomer pour retrouver le contexte communal"
      ],
      "benefit": "Passer de la commune au détail des rues.",
      "captures": [],
      "visualStatus": "illustration cible",
      "functionalScope": "nominal",
      "videoTitle": "Zoomer et dézoomer sur la carte"
    },
    {
      "id": "US-076",
      "epic": "E02",
      "title": "Recentrer sur le territoire ou la sélection",
      "story": "En tant qu’utilisateur de l’atlas, je veux recentrer la carte en une action afin de retrouver rapidement mon territoire ou le lieu étudié.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front cartographie + Back géographie",
      "dependencies": [
        "US-005"
      ],
      "criteria": [
        "« Voir la commune » cadre la commune autorisée avec ses limites visibles.",
        "« Voir la sélection » cadre le quartier ou la rue sélectionnée sans masquer son tracé sous le panneau.",
        "Le recentrage conserve l’indicateur, la période et les couches activées."
      ],
      "status": "Proposé · à estimer",
      "estimate": null,
      "roles": [
        "maire",
        "habitat",
        "elu"
      ],
      "persona": "utilisateur de l’atlas",
      "kind": "map",
      "steps": [
        "Déplacer la carte hors du lieu étudié",
        "Choisir Voir la sélection",
        "Retrouver le quartier ou la rue cadrée"
      ],
      "benefit": "Retrouver rapidement mon territoire ou le lieu étudié.",
      "captures": [],
      "visualStatus": "illustration cible",
      "functionalScope": "nominal",
      "videoTitle": "Recentrer sur le territoire ou la sélection"
    },
    {
      "id": "US-077",
      "epic": "E02",
      "title": "Repérer une rue avant de la sélectionner",
      "story": "En tant qu’utilisateur de l’atlas, je veux repérer une rue sur la carte afin de choisir le bon tracé sans ambiguïté.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front cartographie + Back géographie",
      "dependencies": [
        "US-005"
      ],
      "criteria": [
        "Le survol met en évidence le tracé complet et affiche le nom de la rue.",
        "Au clavier, le focus d’un résultat de recherche permet de repérer la rue correspondante ; sur écran tactile, la sélection reste accessible.",
        "Une rue formée de plusieurs tronçons est présentée comme une seule voie.",
        "Le repérage temporaire ne remplace pas la sélection actuelle ni ses chiffres."
      ],
      "status": "Proposé · à estimer",
      "estimate": null,
      "roles": [
        "maire",
        "habitat",
        "elu"
      ],
      "persona": "utilisateur de l’atlas",
      "kind": "map",
      "steps": [
        "Explorer les rues visibles",
        "Repérer le nom et le tracé d’une voie",
        "Vérifier le lieu avant de le sélectionner"
      ],
      "benefit": "Choisir le bon tracé sans ambiguïté.",
      "captures": [],
      "visualStatus": "illustration cible",
      "functionalScope": "nominal",
      "videoTitle": "Repérer une rue avant de la sélectionner"
    },
    {
      "id": "US-078",
      "epic": "E02",
      "title": "Changer ou effacer la sélection cartographique",
      "story": "En tant qu’utilisateur de l’atlas, je veux changer de rue ou revenir à la commune afin de poursuivre mon analyse sans perdre les réglages.",
      "priority": "P0",
      "sprint": "S1",
      "team": "Front cartographie + Back géographie",
      "dependencies": [
        "US-005"
      ],
      "criteria": [
        "Sélectionner une autre rue remplace la sélection précédente et synchronise tracé, nom et fiche.",
        "La commande « Effacer la sélection » revient à la lecture communale.",
        "L’indicateur, l’année et les couches restent conservés.",
        "La sélection active se distingue visuellement du simple survol."
      ],
      "status": "Proposé · à estimer",
      "estimate": null,
      "roles": [
        "maire",
        "habitat",
        "elu"
      ],
      "persona": "utilisateur de l’atlas",
      "kind": "map",
      "steps": [
        "Sélectionner une première rue",
        "Choisir une autre rue",
        "Effacer la sélection pour revenir à la commune"
      ],
      "benefit": "Poursuivre mon analyse sans perdre les réglages.",
      "captures": [],
      "visualStatus": "illustration cible",
      "functionalScope": "nominal",
      "videoTitle": "Changer ou effacer la sélection cartographique"
    }
  ],
  "enablers": [
    {
      "id": "EN-01",
      "title": "Contrat API initial",
      "team": "Plateforme + Back + Front",
      "sprint": "S1",
      "dependencies": [],
      "goal": "Définir indicateurs, qualités, rôles, erreurs, pagination et exemples avant de brancher les vues.",
      "criteria": [
        "OpenAPI versionné, relu par Front et Back.",
        "Exemples normal, missing, suppressed, 403 et 503 valides contre le schéma.",
        "Changement cassant proposé et versionné avant implémentation."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-02",
      "title": "Session et identité mockées",
      "team": "Plateforme + Back API",
      "sprint": "S1",
      "dependencies": [
        "EN-01"
      ],
      "goal": "Fournir un utilisateur et ses périmètres par une route commune.",
      "criteria": [
        "GET /me cohérent avec les rôles.",
        "Mock séparé du contrôle réel serveur.",
        "Aucun secret ni mot de passe réel dans les fixtures."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-03",
      "title": "Adaptateur de données front",
      "team": "Front + Plateforme",
      "sprint": "S1",
      "dependencies": [
        "EN-01"
      ],
      "goal": "Brancher un même contrat sur fixtures puis API réelle.",
      "criteria": [
        "Mode fixture et mode API explicites.",
        "Annulation ou latest-wins en cas de changement rapide.",
        "Scénarios de panne reproductibles sans modifier les composants."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-04",
      "title": "Tokens et composants accessibles",
      "team": "Front",
      "sprint": "S1",
      "dependencies": [],
      "goal": "Extraire charte, états, focus, cibles et composants structurants.",
      "criteria": [
        "Inter et couleurs institutionnelles conservées.",
        "Navigation, dialogue, champ et états partagés.",
        "Documentation desktop/mobile avec variantes."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-05",
      "title": "Contrat de motion",
      "team": "Front dataviz",
      "sprint": "S1",
      "dependencies": [
        "EN-04"
      ],
      "goal": "Définir les transitions et règles d’annulation avant de multiplier les animations.",
      "criteria": [
        "Durées, easing, ordre et réduction des mouvements documentés.",
        "Animations interrompues sans écraser l’état courant.",
        "Budget de performance observé et rapporté sur un appareil de référence."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-06",
      "title": "Référentiel communal",
      "team": "Back données",
      "sprint": "S1",
      "dependencies": [],
      "goal": "Constituer un pivot communal unique et une table d’aliases.",
      "criteria": [
        "Les 32 libellés fictifs sont normalisés ; un territoire pilote réel est choisi pour tester les sources, sans correspondance géographique inventée.",
        "Codes du territoire pilote vérifiés et stockés en texte ; aliases pédagogiques, versions et périmètres explicités.",
        "Aucune assimilation quartier/commune."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-07",
      "title": "Squelette intégré et CI/CD",
      "team": "Plateforme",
      "sprint": "S1",
      "dependencies": [
        "EN-01"
      ],
      "goal": "Déployer une chaîne base → API → front.",
      "criteria": [
        "Lint, tests, contrat et build contrôlés.",
        "Une première donnée réelle traverse toutes les couches.",
        "CI rouge bloque la fusion ; démonstration sur l’environnement intégré."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-08",
      "title": "Ingestion DVF",
      "team": "Back ventes",
      "sprint": "S2",
      "dependencies": [
        "EN-06"
      ],
      "goal": "Charger, dédupliquer et normaliser les mutations.",
      "criteria": [
        "Brut conservé en staging et transformations traçables.",
        "Mutations multi-lots et dépendances traitées explicitement.",
        "Import rejouable sans doublon et millésimes corrigés supportés."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-09",
      "title": "Ingestion DPE",
      "team": "Back énergie",
      "sprint": "S2",
      "dependencies": [
        "EN-06"
      ],
      "goal": "Charger les diagnostics et définir le périmètre analytique.",
      "criteria": [
        "Méthode, dates et identifiants de déduplication documentés.",
        "Ruptures de méthode visibles dans les séries.",
        "Numérateur, dénominateur et couverture contrôlés."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-10",
      "title": "Ingestion risques",
      "team": "Back risques",
      "sprint": "S2",
      "dependencies": [
        "EN-06"
      ],
      "goal": "Récupérer les aléas et arrêtés par commune.",
      "criteria": [
        "Pagination, quotas, retry borné et absence de réponse traités.",
        "Aléa et sinistre séparés.",
        "Données et import horodatés, dernière version valide conservée."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-11",
      "title": "Orchestration des imports",
      "team": "Back + Plateforme",
      "sprint": "S2",
      "dependencies": [
        "EN-08",
        "EN-09",
        "EN-10"
      ],
      "goal": "Rendre les jobs idempotents, observables et reprenables.",
      "criteria": [
        "Point de reprise et verrous de concurrence.",
        "Échec partiel ne détruit pas les agrégats valides.",
        "État des jobs accessible à l’exploitation."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-12",
      "title": "Agrégats et séries",
      "team": "Back données",
      "sprint": "S2",
      "dependencies": [
        "EN-08",
        "EN-09",
        "EN-10"
      ],
      "goal": "Pré-agréger les mesures par maille et période.",
      "criteria": [
        "Méthodes de pondération documentées.",
        "Séries avec lacunes et codes de qualité.",
        "Département hors agglo calculé selon même définition, sans moyenne naïve de ratios."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-13",
      "title": "Persistance des demandes",
      "team": "Back API",
      "sprint": "S2",
      "dependencies": [
        "EN-01"
      ],
      "goal": "Stocker demandes, contextes et transitions.",
      "criteria": [
        "Clé d’idempotence et périmètres vérifiés.",
        "Transitions journalisées.",
        "Données minimales, pas de copie de chiffres sans version de source."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-14",
      "title": "Autorisations serveur",
      "team": "Back API",
      "sprint": "S3",
      "dependencies": [
        "EN-02"
      ],
      "goal": "Contrôler toutes les lectures et mutations par rôle et territoire.",
      "criteria": [
        "Tests de lecture d’une commune voisine refusée au maire.",
        "Élu en lecture seule ; brouillons non diffusés absents des réponses.",
        "Exports, liens et jobs contrôlés au même niveau."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-15",
      "title": "Politique de diffusion",
      "team": "Projet + client + Back",
      "sprint": "S2",
      "dependencies": [
        "EN-06"
      ],
      "goal": "Faire valider mailles, petits effectifs et périmètres.",
      "criteria": [
        "Décisions versionnées, propriétaire identifié.",
        "Seuils et exceptions justifiés, sans affirmation réglementaire non sourcée.",
        "Règles identiques dans API, carte, rapport et export."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-16",
      "title": "Génération IA et snapshots",
      "team": "Back IA",
      "sprint": "S4",
      "dependencies": [
        "EN-12",
        "EN-15"
      ],
      "goal": "Créer un pipeline de brouillons ancrés dans les données.",
      "criteria": [
        "Pas d’appel IA avec données brutes inutiles.",
        "Modèle, prompt, snapshot et génération tracés.",
        "Échec, timeout et retry contrôlés ; aucun brouillon diffusé."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-17",
      "title": "Politique de publication publique",
      "team": "Projet + client",
      "sprint": "S3",
      "dependencies": [
        "EN-15"
      ],
      "goal": "Résoudre la tension transparence / périmètre politique avant ouverture citoyenne.",
      "criteria": [
        "Liste des données publiables et responsables de validation.",
        "Règles stables et factuelles plutôt qu’une sélection opportuniste de chiffres.",
        "Diffusion publique distincte des droits internes."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-18",
      "title": "Géométries multi-mailles",
      "team": "Back données + Front cartographie",
      "sprint": "S3",
      "dependencies": [
        "EN-06"
      ],
      "goal": "Fournir géométries officielles adaptées au rendu et au zoom.",
      "criteria": [
        "Versions, projections et clés de jointure documentées.",
        "Simplification conserve la topologie utile.",
        "Géométries synthétiques de la maquette jamais publiées comme réelles."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-19",
      "title": "Données OPAH",
      "team": "Projet + Back données",
      "sprint": "S3",
      "dependencies": [
        "EN-15"
      ],
      "goal": "Identifier les données opérationnelles et leur propriétaire.",
      "criteria": [
        "Objectifs, réalisations, dates, périmètres et responsables disponibles.",
        "Accès et fréquence de mise à jour confirmés.",
        "Absence de source bloque le développement de mesures supposées."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-20",
      "title": "Données foncières / ZAN",
      "team": "Projet + Back données",
      "sprint": "S3",
      "dependencies": [
        "EN-15"
      ],
      "goal": "Obtenir un jeu et une méthode de trajectoire foncière validés.",
      "criteria": [
        "Source, période et définition du foncier confirmées.",
        "Lien avec SCOT/PLH documenté par propriétaire métier.",
        "Aucun proxy DVF pour une mesure ZAN."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-21",
      "title": "Tests de contrat et parcours",
      "team": "Plateforme + tous",
      "sprint": "S3",
      "dependencies": [
        "EN-07"
      ],
      "goal": "Vérifier les interfaces et scénarios critiques dans la CI.",
      "criteria": [
        "Tests consumer/provider et validation schéma.",
        "Tests réels auth, navigation, demande, relecture, publication et export.",
        "Erreurs, accès refusés, petits effectifs et rechargements couverts."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-22",
      "title": "Documentation de reprise",
      "team": "Tous + Plateforme",
      "sprint": "S5",
      "dependencies": [
        "EN-07",
        "EN-11"
      ],
      "goal": "Écrire et éprouver le guide de démarrage et d’exploitation.",
      "criteria": [
        "README, ADRs, OpenAPI, runbook d’import et diagnostic.",
        "Test de reprise par une personne extérieure.",
        "Écarts et éléments non livrés explicités."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-23",
      "title": "Performance et observabilité",
      "team": "Plateforme + tous",
      "sprint": "S4",
      "dependencies": [
        "EN-07",
        "EN-12"
      ],
      "goal": "Mesurer API, imports, carte et animation sur un contexte de référence.",
      "criteria": [
        "Appareil, navigateur, taille du jeu et réseau documentés.",
        "Temps p95, payloads et frames mesurés avant/après.",
        "Pagination, caches et réduction de géométrie justifiés par mesures."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    },
    {
      "id": "EN-24",
      "title": "Hébergement France et sauvegardes",
      "team": "Plateforme + Projet",
      "sprint": "S1",
      "dependencies": [],
      "goal": "Proposer une exploitation compatible avec la contrainte client.",
      "criteria": [
        "Localisation des données, sauvegardes et prestataires documentée.",
        "Restauration répétable et testée avant recette finale.",
        "Secrets hors dépôt et procédure de rotation."
      ],
      "status": "Proposé · à estimer",
      "estimate": null
    }
  ]
}
