SB
projects
Production · 2024-2026 Greenfield

SLAM Mapping Back-office

SLAM mapping back-office for an accessible indoor navigation product. Async pipeline from 360° video to navigable map, with a C++ SLAM engine driven remotely, interactive Sim(2) georeferencing, 2D/3D visualisation and operator curation. Greenfield, end-to-end.

The pipeline

From 360° video to a usable map

Field operators capture buildings as equirectangular 360° video. The back-office then orchestrates the full pipeline: 3D reconstruction, interactive georeferencing, operator curation, export. At the scale of large public venues — airports, train stations, museums, industrial sites.

1
Capture
2
Upload
3
SLAM
4
Parsing
5
Georef
6
Curation
7
Export
1 — Capture

Equirectangular 360° MP4 (handheld camera), several segments per site, walked at a steady pace.

2 — Upload

GCS signed URL (15 min, scoped) — the client uploads straight to the bucket, the backend never proxies the file.

3 — SLAM

C++ engine driven remotely on a dedicated external host. Adaptive YAML config (indoor / outdoor). Output: a binary MSG (msgpack) + trajectory.txt.

4 — Parsing

msgpack → keyframes serialised as JSON in the jobs table. Sub-second for a typical trajectory. Map points stay on GCS for debug.

5 — Georef

The operator pins GPS constraints on keyframes. Sim(2) solved via SVD / Umeyama as soon as ≥ 2 constraints. Solve is instant, even with a couple dozen points.

6 — Curation

Manual validation: only trajectories flagged as "validated" reach the production map. Avoids pollution by tests and A/B retries.

7 — Export

GeoJSON (FeatureCollection LineString + keyframe Points) is downloadable. Consumed by the downstream mobile app.

What I built

From scratch, end-to-end

01

SLAM driven remotely

FastAPI invokes the C++ SLAM engine over HTTPS on a dedicated external host (native deps, GPU for bundle adjustment). Three modes: remote prod, Docker dev, mock CI. Status tracking, clean retries, HTTP threads never block.

02

Synchronised 2D & 3D viewers

Mapbox GL for the floor plan with trajectories as LineStrings, keyframes as Points and draggable GPS constraints. Three.js for camera frustums, a filterable point cloud and the 3D trajectory. Selection and hover propagated across both views.

03

Interactive Sim(2) georeferencing

1 constraint → translation only. ≥ 2 constraints → Umeyama solve (SVD on the centred covariance matrix, det forced to +1 to avoid flips). Level override when all constraints live on the same floor. Solve is instant.

04

Large-file friendly upload

GCS signed URL (PUT, 15 min, scoped to the exact path) — the client uploads its video straight to the bucket via XHR with progress. No file transits through the backend pod, which stays lean on RAM.

05

Operator curation

A trajectory only reaches the production map after manual validation. Avoids pollution by retries and A/B comparisons. Reversible via a confirm dialog.

06

"Calm / loud" server dashboard

Infra monitoring with a simple rule: a quiet one-liner when healthy, a full panel when something is off. Covers uptime, DB, disk, RAM, SSL certs, GCP billing. Avoids Grafana fatigue.

07

Auth & audit

Keycloak OIDC, three roles (admin / operator / reader), full audit trail grouped by day, RFC 4180 CSV export with UTF-8 BOM (Excel FR friendly).

08

In-house design system

CSS tokens, systematic dark mode, shared components (EmptyState, UserChip, ConfirmDialog, Escape-to-close), unit + Playwright E2E coverage per scenario.

Stack

How it is built

Backend
Python 3.11 FastAPI SQLAlchemy 2.0 Pydantic 2 Alembic PostgreSQL 15 slowapi
Frontend
React 18 TypeScript Vite Zustand TanStack Query sonner
2D / 3D
Mapbox GL Three.js OpenCV msgpack
SLAM
moteur SLAM C++ g2o Eigen 3 OpenCV 4 FBoW CMake
Ops
GCP (GKE) GCS Cloud Build dedicated SLAM host Keycloak OIDC GitLab CI
Trade-offs

A few technical calls

SLAM off-GKE, on a dedicated external host

The C++ engine has heavy native dependencies and benefits from a GPU for bundle adjustment. A GKE GPU node would have cost more than a dedicated external server. Three fallback modes (remote / Docker / mock) make it testable without depending on the prod host.

FastAPI over Spring Boot

The SLAM ecosystem (open-source C++ engine, OpenCV, msgpack) is Python-native. A JNI bridge to Java would have doubled the technical surface for no gain.

Plain Three.js, not React Three Fiber

Need fine control over the scene and per-frame perf (thousands of frustums). RTF adds a React cost per frame we cannot afford.

Zustand + TanStack Query, not Redux

Limited client state, simpler API. TanStack Query handles cache, invalidation and refetch on its own — no reason to re-implement that.

Direct upload to GCS, not via a backend proxy

Videos weigh several gigabytes. Streaming a file that size through the backend pod would OOM it. A scoped signed URL + client-side XHR keeps the backend lean and lets the bucket handle throughput.

No DB mocks in integration tests

A divergent mock masked a broken migration in prod. Now: Testcontainers / ephemeral DBs, and that class of bug cannot ship again.