Skip to content
All work

Geo-verified mediaValidated proof of concept

Showing where, when and which way a camera was pointing.

A mobile and web platform for capturing photos and video with GPS and a continuous compass log, uploading them with an integrity check, and burning where, when and which way the camera pointed into the frame itself.

Role
Sole engineer
Scope
Architecture to validated PoC
Platforms
iOS, Android, web
Status
Validated proof of concept

Context

Photos and video get cropped, re-shared and re-captioned until nobody can say where they came from. People who need to rely on footage need to know where it was captured, when, and in which direction, and that information has to survive the trip from the phone to whoever looks at it next.

Constraints

  • Mobile connections in the field drop constantly.
  • Location and bearing must survive upload and processing.
  • Private events must stay private, even from other users of the app.
  • Personal data must be erasable on request.
3DIN: from camera to map
  1. Captured in the fieldGPS position and a continuous compass log recorded with the video
  2. Uploaded in chunksResumable session survives a dropped mobile connection
  3. Checksum verifiedSHA-256 of the assembled file matches the one sent by the phone
  4. Context burned into the frameFFmpeg adds compass overlay, coordinates and timestamp
  5. Published to the event mapVisibility checked against the event's permission model
GPSVideo, 42 s, 1,218 bearings0 of 5

My responsibility

Sole engineer: architecture, backend, the mobile app and the web portal.

Architecture

Capture
A React Native app records photos and video with GPS coordinates and a continuous compass log.
Upload
Resumable, chunked upload sessions with a SHA-256 checksum of the whole file verified when the chunks are assembled.
Processing
FFmpeg burns a compass overlay, coordinates and timestamp into every photo and video and generates thumbnails, asynchronously and off the request path.
Identity and access
Keycloak as the identity provider with PKCE for the web; the backend is an OAuth2 resource server. Phone verification by one-time code, stored only as a hash. One permission model for public and private events, member roles and access requests.
Web portal
A Next.js portal with a MapLibre map of media and events, built with TanStack Query.

Critical decisions

Log the bearing continuously

A video records the compass bearing for every moment of the recording, so a pan shows up in the data.

Put the context in the frame

Coordinates, bearing and time are burned into the media itself, so they survive being downloaded and re-shared.

Identity only from the token

The backend never trusts a user id sent by the client; every request is attributed from the verified token.

Keep the map out of every other page

The map bundle is split from all non-map routes, taking their initial JavaScript from 996 KB to 84 KB.

When things go wrong

WhenWhat happens
The connection drops mid-uploadThe session resumes from the last received chunk.
The assembled file doesn't match the phone's checksumThe mismatch is caught at assembly, before the file is stored.
A client sends someone else's user idIt is ignored; identity comes from the token.
A user deletes their accountDatabase rows and stored media are removed together.

Result

The proof of concept passed validation.

996 → 84 KB

Initial JavaScript on non-map routes after splitting the map bundle

Photo and video captures during the pilot

Stack

Java 21 · Spring Boot 3 · PostgreSQL · Flyway · FFmpeg · S3 · Keycloak · React Native · Next.js · MapLibre

Next case study

An agent that completes visa filings

Need a system that holds up like this one?

Tell me what's at stake. You'll hear back within one business day, and the first call is 30 minutes, with no obligation.