Studio product · Android
lit
A campus-only social discovery app for university students, verified by school email. I built and run the backend — matching, real-time chat, ranking and the infrastructure.
- Role
- Backend & ML lead
- Year
- 2025–26
- Status
- Live on Google Play

- 370+
- backend commits, the large majority of the service
- UT-xxxx
- structured error catalog the app switches on
- 0
- managed services — self-hosted on Hetzner
Context
lit is a 4ourstack product: students sign up with their university email and discover people on their own campus. The mobile app is built by Uygar Çapar and the admin panel by Ramiz Kadayıfcı; I own the backend, the matching and the servers.
Rewriting matching for production
The first version stored every like and pass as JSON arrays inside the user profile, cached in a single node’s memory and computed distances in C# for every request. It worked for a demo and would not survive a semester. The v2 architecture I designed:
- Swipes in their own indexed table — one-row lookups instead of rewriting a growing profile on every swipe.
- Interests as a 64-bit flag field — shared-interest scoring becomes a bitwise
ANDand a popcount. - A Bloom filter per user in Redis so already-seen profiles don’t come back.
- A compatibility score instead of “premium > verified > everyone else”, and city-level geo with a seeded radius fallback for small campuses.
- An ONNX ranker trained offline in Python (two-tower + hobby embeddings) and served inside the .NET process.
Correctness under concurrency
The design went through a deliberate stress-test review. One real finding: two students liking each other at the same moment could both pass the “already matched?” check — the unique constraint saved the data, but one of them never got the match notification. The fix reads the existing match on conflict and still notifies over SignalR. Cold-start and race conditions got their own plan and tests.
An API the app can trust
Every expected failure returns a stable code (UT-1006), a localised message and a suggested action. The app switches on the code, never on text. Backend messages are translated server-side.
Infrastructure
Moved off a legacy Plesk box onto Hetzner Cloud with Docker Compose and a shared Caddy edge that also serves our other products. git push → GitHub Actions → GHCR → server → health check. Serilog to Seq, Sentry for errors, a written runbook for every migration.