Pilote Orléans · configuration, pas un fork · aucun lieu inventé

Livrable 17

Cartographie

Rôle

La carte est une interface de décision (quoi est actif dans le cadre), pas un clone de carte généraliste.

Couches : venues · events · offers · live_updates · zones. Transport : off tant que donnée ouverte utilisable non intégrée (EXTERNAL DATA REQUIRED).

Marqueurs par catégorie, pas par enseigne. Clustering quand le zoom dépasse un seuil de densité de points réels. Sélection liste ↔ marqueur. Mini-carte : nom, catégorie, distance si connue, statut temporel, prochain event s'il existe, prix si connu, CTA fiche.

Filtres : ouvert maintenant, commence bientôt, ce soir, gratuit (prix 0 connu), terrasse (attribut sourcé), réservation (URL présente), ouvert tard (horaire), distance, budget, genre musical (attribut ou event), ambiance (attribut sourcé seulement), zone.

Déplacement carte → nouveau bbox, debounce, requête viewport plafonnée. Pas de chargement « ville entière » si la bbox est large : à un zoom faible, clusters ou comptages par zone.

Moteur

Décision — MapLibre + fournisseur de tuiles interchangeable

OptionPourContre
MapLibre GL JS + tuilesRendu open, style propre, peu de lock-in sur le moteurLes tuiles restent un fournisseur
PMTiles (fichier tuiles hébergé chez nous, UE)Coût prévisible, pas d'appel par geste, style contrôléIl faut produire ou licencier le jeu de tuiles
MapboxQualité, routing/geocoding intégrésLock-in, clé, coût à l'usage — chiffres non estimés ici
Google MapsHabitude, POIContredit le positionnement, licence, POI qui ne sont pas notre graphe, lock-in

Retenu : MapLibre comme renderer. Tuiles via interface MapsProvider.

Préférence produit pour la prod : PMTiles (ou tuiles vector self-hosted en UE) une fois un jeu de tuiles légalement détenu. Ce jeu n'est pas dans le dépôt. THIRD-PARTY ou travail data EXTERNAL.

Interdit : hotlink « en douce » d'un serveur de tuiles public dont les conditions l'interdisent. Tant qu'aucun fournisseur n'est accepté, le pilote montre :

  • liste synchronisée (source de vérité) ;
  • schéma de zones (polygones que nous avons) dessinés en SVG/canvas, sans fond mondial prétendu.

Ce n'est pas une carte live de navigation. Le libellé ne dit pas « carte temps réel » s'il n'y a pas de tuile ni de flux.

Geocoding et routing : interfaces séparées (GeocodingProvider, RoutingProvider). Aucune implémentation prétendument active. Repli : pas de geocoding (la recherche de zone/lieu est la nôtre) ; distance directe libellée.

Géo en base

CoucheCible productionCet environnement
Pointgeography(Point,4326), ST_DWithinlat/lng + haversine
Zonegeography(Polygon/MultiPolygon) ST_ContainsGeoJSON + point-in-polygon en JS si géométrie présente
IndexGISTB-tree lat/lng insuffisant pour le rayon ; bbox grossière puis filtre haversine
ExtensionPostGISNon garantie sur Neon ici ; absente de PGLite

Choix : ne pas bloquer le schéma métier sur PostGIS. Vérifier SELECT postgis_version() au boot. Si oui, utiliser geog. Si non, chemin haversine. Les deux derrière GeoStore. Le jour où PostGIS manque, on ne documente pas les requêtes comme si ST_Contains tournait.

Risque haversine : mauvais près des pôles (hors sujet) et incapable des polygones. Les zones sans géométrie ne filtrent pas par containment ; elles filtrent par zone_id saisi sur le lieu.

Perf

  • Requête viewport uniquement.
  • Plafond de points par réponse.
  • Clustering côté serveur par cellule geohash simple si pas de PostGIS ; ST_Cluster plus tard.
  • Debounce ~200 ms (paramètre UI).
  • Liste virtualisée.
  • Tuiles : cache CDN du fournisseur, pas notre DB.

Aucun objectif Core Web Vitals chiffré inventé. Cible qualitative : la liste est utile même si WebGL échoue.

Accessibilité

La carte n'est pas la seule sortie. La liste est complète, focusable, ordre logique. Les marqueurs ont un nom accessible. prefers-reduced-motion : pas d'animation de clustering.

Multi-ville

Même composant. Bbox initiale = bbox publiée de la ville ou de la zone. Style commun. Pas de token Mapbox par ville.

Flags

  • Jeu de tuiles, clé, quota : THIRD-PARTY DEPENDENCY non souscrit.
  • Contours : EXTERNAL DATA REQUIRED.
  • Transport : off.