Back-office cartographie SLAM
Back-office de cartographie SLAM pour un produit de navigation indoor accessible. Pipeline asynchrone vidéo 360° → trajectoire 3D → carte exploitable, avec moteur SLAM C++ piloté à distance, géoréférencement Sim(2) interactif, visualisation 2D/3D et curation opérateur. Greenfield, end-to-end.
De la vidéo 360° au plan exploitable
Les opérateurs terrain filment les bâtiments en vidéo 360° équirectangulaire. Le back-office orchestre ensuite tout le pipeline : reconstruction 3D, géoréférencement interactif, validation par l'opérateur, export. À l'échelle de grands ERP — aéroports, gares, musées, sites industriels.
Vidéo MP4 360° équirectangulaire (caméra portative), plusieurs segments par site, marche à vitesse constante.
Signed URL GCS (15 min, scopée) — le client uploade directement vers le bucket, le backend ne proxifie pas le fichier.
Moteur C++ piloté à distance sur un serveur dédié externe. Config YAML adaptative (indoor / outdoor). Output : binaire MSG msgpack + trajectory.txt.
msgpack → keyframes JSON sérialisés dans la table de jobs. Sous la seconde pour une trajectoire typique. Map points laissés sur GCS pour debug.
L'opérateur pose des contraintes GPS sur les keyframes. Sim(2) résolu via SVD / Umeyama dès ≥ 2 contraintes. Solve instantané, même avec une vingtaine de points.
Curation manuelle : seules les trajectoires marquées « validée » sont visibles côté carte production. Évite la pollution par les tests et A/B.
GeoJSON (FeatureCollection LineString + Points keyframes) téléchargeable. Format consommé par l’app mobile downstream.
From scratch, end-to-end
SLAM piloté à distance
Backend FastAPI déclenche le moteur SLAM C++ via HTTPS sur un serveur dédié externe (dépendances natives, GPU pour le bundle adjustment). Trois modes : remote prod, Docker dev, mock CI. Tracking d'état, retries propres, jamais de blocage du thread HTTP.
Visualisation 2D & 3D synchronisée
Mapbox GL pour le plan d’étage avec trajectoires en LineString, keyframes en Points et contraintes GPS draggables. Three.js pour frustums caméra, nuage de points filtrable et trajectoire 3D. Sélection et survol propagés entre les deux vues.
Géoréférencement Sim(2) interactif
1 contrainte → translation seule. ≥ 2 contraintes → solve Umeyama (SVD sur matrice de covariance centrée, force det = +1 pour éviter les flips). Override de niveau si toutes les contraintes sont sur le même étage. Solve instantané.
Upload résistant aux gros fichiers
Signed URL GCS (PUT, 15 min, scopée au path) — le client envoie sa vidéo directement au bucket via XHR avec progress. Aucun fichier ne transite par le pod backend, qui reste léger en RAM.
Curation opérateur
Une trajectoire n'apparaît sur la carte production qu'après validation manuelle. Évite la pollution par les retries et les comparaisons A/B. Réversible avec confirm dialog.
Dashboard serveur « calm / loud »
Monitoring infra avec une règle simple : 1-liner discret quand tout va bien, panneau détaillé quand anomalie. Couvre uptime, DB, disque, RAM, certs SSL, facturation GCP. Évite la fatigue Grafana.
Auth & audit
Keycloak OIDC, 3 rôles (admin / operator / reader), audit trail complet groupé par jour, export CSV RFC 4180 UTF-8 BOM (compatible Excel FR).
Design system maison
Tokens CSS, dark mode systémique, composants mutualisés (EmptyState, UserChip, ConfirmDialog, Escape-to-close), couverture unit + Playwright E2E par scenario.
Comment c’est fait
Quelques choix techniques
SLAM hors GKE, sur host dédié externe
Le moteur C++ a des dépendances natives lourdes et profite d'un GPU pour le bundle adjustment. Un GKE GPU aurait été plus cher qu'un serveur dédié externe. Trois modes de fallback (remote / Docker / mock) permettent de tester sans dépendre du host prod.
FastAPI plutôt que Spring Boot
L’écosystème SLAM (moteur C++ open-source, OpenCV, msgpack) est Python-natif. Un bridge JNI vers du Java aurait doublé la surface technique sans gain.
Three.js direct, pas React Three Fiber
Besoin de contrôle fin sur la scène et la perf (milliers de frustums). RTF rajoute un coût React par frame qu’on ne peut pas se permettre.
Zustand + TanStack Query, pas Redux
Volume de state client limité, API plus simple. TanStack Query gère seule le cache/invalidation/refetch — pas besoin de re-coder ce pattern.
Upload direct vers GCS, pas via proxy backend
Les vidéos pèsent plusieurs gigas. Recevoir le fichier dans le pod backend l'aurait fait crasher en RAM. Signed URL scopée + XHR direct côté client : le backend reste léger, le bucket gère le débit.
Pas de mock DB dans les tests d’intégration
Un mock divergent avait masqué une migration cassée en prod. Depuis : Testcontainers / DB éphémère, et le bug ne peut plus passer.