IA.
Back to projects

Photography product

Case study

Photorunning

A multi-tenant photography platform capable of ingesting up to 400,000 images per event and retrieving them by race bib or face.

Type Digital productFocus UX & architectureYear 2026
Photorunning demo

A walkthrough of the product’s core journey.

Context

Race and triathlon photographers upload massive image sets that participants need to search quickly.

Challenge

Absorb upload spikes, orchestrate multiple AI workloads, and enforce strict tenant data isolation.

Solution

An asynchronous, idempotent AWS architecture using S3, SQS, Lambda, Rekognition, PostgreSQL, and a decoupled RF-DETR GPU pipeline.

Contribution

Designed an end-to-end journey connecting ingestion, AI processing, observability, and delivery through a coherent product experience.

System design · ingestion pipeline

Massive, asynchronous, observable ingestion.

The critical path absorbs uploads, then distributes OCR, face, and preview workloads. GPU object detection scales independently.

Architecture verified in code
AWSASYNCMULTI-TENANT
50K–400K images / event
01Upload pathSynchronous
ClientAdmin uploader

Compute deterministicId

tRPC
SYNC
Next.js APIPresigned URL

Tenant + flag validation

POST / PUT
Object storageAmazon S3 · raw

Original + metadata

ObjectCreated
ASYNC
Message brokerSQS ingestion

Retry · DLQ · at-least-once

Event source mapping
02IngestionLambda fan-out
Lambda image-processingGROUP BY tenant · event · category
HeadObject metadata Upsert idempotent Extraction statuses
parallel branches
AWS RekognitionBib OCR

DetectText · confidence ≥ 90

AWS RekognitionFace indexing

Collection per category

SharpPreview pipeline

Resize · watermark · JPEG

OptionalLogo overlay

Runs after Rekognition

Durable results + per-photo status
03PersistenceSource of truth
ACID
PostgreSQL · PrismaPhotoProcessing

Photo · BibDetection · Face

ON CONFLICTdeterministicIdtenantId scope
Amazon S3 + CDNPreview assets

preview-wm · private originals

CloudWatchlogs · metrics · alarms
Decoupled pipeline — ON_LANDING or ON_DEMAND scheduling
04Object detectionGPU pull model
Durable statePhotoProcessing

requested_objdet

tick + claim
GPU
ECS · EC2 GPURF-DETR worker

People + bicycles

JSON → SQS
Lambda pull-ingestCompletion ingest

Fencing token + status

PostgreSQLBounding boxes

PersonBbox · BicycleBbox

Synchronous call Asynchronous event Idempotent & observable Durable PostgreSQL state
Cost constraint

Only pay for GPU compute while it is working.

A permanent RF-DETR fleet would sit idle between events. Capacity therefore follows durable workload state and is recalculated periodically.

EventBridgeTick · 60 sSingle scaling authority
BacklogCapacity per category⌈pending / 1,000⌉ · bounded capacity
ASG GPU0 → N → 0SetDesiredCapacity idempotent
Empty queueScale to zero0 instances · no idle GPU cost
Accepted cold start 3–5 min to wake upAnti-thrash floor of 1 during active uploadsCost guardrail alarm if an instance runs while desired = 0

Product architecture · bib-face resolution

A better gallery, without requiring a selfie.

OCR alone fails as soon as a race bib is hidden. Combining visible numbers with faces retrieves more relevant photos without adding friction to discovery and purchase.

BIB + FACE RESOLUTION
NO SELFIEBATCHEDHIGH VOLUME
Product relevance first
Product goalThe most complete runner gallery

Return relevant photos even when the bib is not visible in every image.

Friction avoidedNo mandatory selfie

Removing an extra action keeps the discovery and purchase journey fluid.

OCR limitationBibs are often obstructed

A hand, posture, or another runner can hide the number and pollute OCR-only galleries.

Available signals

Bib OCRVisible numbers

Face embeddingsVisual similarity

Person detectionRF-DETR bounding boxes

partitioned input
Fargate 01MEMORY-BOUND
Phase 1Clustering

Group photos that likely contain the same runner.

durable clusters
Fargate 02RESTARTABLE
Phase 2Scoring

Link each face cluster to the most credible bib.

Phase 3Materialization

Persist the associations used by the gallery.

assignments

Key outcomes

  • 50K–400K photos per event
  • Bib OCR and face indexing
  • Asynchronous GPU object detection
  • Scale-to-zero with controlled costs
  • Idempotent and observable pipeline

Technologies

Next.js · tRPCAWS S3 · SQS · LambdaRekognitionPostgreSQL · PrismaECS GPU · RF-DETRDatadog RUM