KPSS Düello
Realtime quiz duels with server-verified scoring.
- Role
- Product, backend and mobile engineering
- Year
- 2026
- Links
- Watch the trailer
Overview
- Flutter
- Dart
- Firebase Realtime DB
- Firestore
- Cloud Functions
- Node.js
- Pub/Sub
- GitHub Actions
A mobile app where candidates for KPSS, Türkiye's civil service exam, challenge a friend or a random opponent to a 10-question duel. I designed and built all of it: the Flutter app, the realtime game protocol, the Cloud Functions backend, payments and the release pipeline.
Studying for KPSS is long and lonely. The idea was to make practice social: the same questions, a real opponent, and the one who knows more wins. That only works if nobody can fake a score, and if a duel survives flaky mobile connections.
How a duel is played
- 1Flutter appjoins the queue or opens a friend room through a callable function
- 2Cloud Functionsmatch players in a transaction, pick the questions and create the room
- 3Realtime Databaseplayers write only their pick and a server timestamp per question
- 4Scoring functionchecks answers against the published question bank and times the answers
- 5Firestoreresult, profile stats, duel history and league points are written by the server
Making scores impossible to fake
The first version let each device compute its own score, which meant a modified client could send any number. I moved to a second room protocol: the server creates every room and chooses the questions, and a player can write only two things per question, the chosen answer and a server-generated timestamp.
When both players finish, or one leaves, a function reads the published question bank, checks each answer and computes speed points from the server times. Security rules make every other field read-only for clients, and old app versions keep working in a restricted legacy mode during the migration.
Realtime that survives real phones
- Disconnect handlers mark a player who drops as having left; a stalled opponent ends the duel after 45 seconds instead of hanging it.
- When one player finishes, the other's clock runs twice as fast, so nobody waits forever.
- If no opponent turns up, a bot is offered after 10 seconds and joins on its own at 20; it plays on the server, its answers are validated like a human's and it never touches league points.
Everything around the game
- Weekly leagues of 30 players with promotion and relegation, a daily challenge, streaks with freezes, a gold economy and cosmetics, all written only by the server.
- Mock exams with KPSS subject weights and an estimated score; a mistakes notebook with spaced repetition.
- Map questions drawn from Natural Earth data, and a separate map-duel queue.
- Question bank and subject catalog edited in a web portal and published to Firestore; the app syncs only the topics that changed.
- Subscriptions and one-time purchases verified with the Google Play Developer API; renewals, cancellations and refunds arrive through Pub/Sub.
Testing and release
- About 3,000 Flutter tests, including every question type rendered at two screen sizes to catch overflow.
- Node tests for answer checking and scoring, plus security-rules and integration tests that run against the Firebase emulators in CI.
- Pushing a version tag builds the app bundle in GitHub Actions and uploads it to the Play testing track.
- App Check with Play Integrity is rolled out in monitor mode before enforcement.
What I took away
- Put the trust boundary on the server from day one; migrating a live protocol is much harder than designing it right.
- Emulator-backed rules tests are cheap insurance for a Firebase backend.


