TR
← All work

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
Links
A lecture hall full of students, one of them looking at her phone
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 AND and 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.

Contact

Tell me about
your problem.

A few lines are enough. I reply within one working day — with questions, a rough plan, or an honest “AI is not the answer here”.

Or reach me directlyhello@erenakay.com
WhatsApp ↗