SnapShot
Case study

SnapShot: guests find their own event photos with one selfie

SnapShot is an event photo platform I designed and built end to end. Organizers bulk-upload the photos from a wedding, a conference or a match; each guest takes one selfie and gets a personal album of every photo they appear in — no scrolling through two thousand pictures.

The problem

After an event, the photos end up in one huge shared folder. Guests scroll for ages looking for themselves, and the organizer answers the same “can you send me my photos?” message for weeks.

What I built

  • For organizers — events with an access code, a share link and a QR code; drag-and-drop bulk upload with live processing status; a featured album; dashboard statistics; photo credits, with a watermark on the free tier.
  • For guests, no account needed — open the event link, take a selfie in the browser, and get a personal album you can come back to. An email arrives when new photos of you are uploaded — grouped, so a bulk upload sends one message, not a dozen.
  • Across the platform — English, French and Arabic (right to left), light and dark themes, and an admin view of the whole platform.

Technical decisions

Face matching lives in PostgreSQL. Face embeddings are stored with pgvector next to the rest of the data and matched with a cosine-distance query on an HNSW index — no separate vector database to run and keep in sync.

The AI service is stateless. A FastAPI service (YuNet detection, SFace embeddings) takes image bytes and returns vectors. The Spring Boot backend owns every write, so the AI side holds no credentials.

Uploads never wait on the model. The upload returns immediately; faces are processed in the background, and a photo that fails is recorded with its reason instead of silently disappearing.

Models picked for their licence. YuNet and SFace are Apache-2.0, so the product can be sold — unlike the non-commercial model weights the first prototype used.

Originals are never exposed. Downloads go through the backend, which adds the watermark when needed, and the public endpoints that trigger face processing are rate-limited.

Stack

  • Java 25
  • Spring Boot 4.1
  • PostgreSQL 16 + pgvector
  • Python · FastAPI
  • OpenCV YuNet + SFace
  • Angular 22
  • MinIO (S3)
  • Docker
  • GitHub Actions

Everything runs as Docker containers behind Caddy, deployed automatically when a change is merged.

See it live

Building a product that processes images, relies on search, or serves many customers from one platform? Tell me what you have in mind.