# Swipenor: if the client computes the score, what does the server trust?

> A swipe-based true/false trivia game; the real subject is not the game but making a client-computed score verifiable through a signature.

- What it does today: The swipe-based true/false quiz runs end to end in its core loop as a mobile app; the score is produced on the client but verified server-side with a server_nonce and an HMAC signature. swipenor.com is the app's landing page, not the game itself.
- Form: Mobile app
- Maturity: Beta
- State: In development
- Focus: Security & verifiability
- Started: 2026-07-18
- Technologies: Laravel, PHP, PostgreSQL, Redis, React Native, Expo, TypeScript, Filament, Astro
- Tags: #mobile, #game, #api
- Website: https://swipenor.com
- Source: https://www.muhammetsafak.com.tr/en/labs/swipenor/
- Language: en-US
- Author: Muhammet Şafak

---
The mechanic is simple: a card arrives, swipe right for "True", left for
"False". Content is tailored by age group (4–9, 10–17, 18+), correct answers
score, streaks earn a bonus, and results land on global and per-age
leaderboards. The part that is not simple is who owns the score.

## If the client computes the score, what can the server check

The game loop runs on the client at 60fps (reanimated worklets plus
gesture-handler), so the client naturally computes the score. A server that
believes that number blindly turns the leaderboard into garbage on day one.

The model under test is **signed-client**: the server issues a `server_nonce`
per session, the client HMACs the score with it, and the API both sanity-checks
the value and verifies the signature. The scoring constants are not baked into
the client either — 100 points per correct answer, a streak threshold of 3, a
+25 streak bonus — and they all come from `GET /config`, so client and server
never drift apart.

## Four repositories, one schema owner

Four separate repositories in one workspace: `game` (Expo SDK 57, React Native,
TypeScript), `api` (Laravel 13, PostgreSQL 16, Redis), `admin` (Filament,
running against the **shared** database but never migrating it — the API owns
the schema) and a fourth holding the marketing page built with Astro. The core loop works end to
end: swiping, scoring, streak bonus, global and per-age leaderboards.

Schema ownership stays in one place. The admin panel is written with Filament
and looks at the same database as the API, but it never runs a migration: only
the API changes the schema. In a setup where both applications can migrate, it
at the first collision it becomes unclear which release defined which table,
and in production that ambiguity cannot be undone. So the panel was never given
write access to the schema.

## The signature model gets tested in production

The open ends are around the game rather than in it: ad integration and the
one-time "remove ads" purchase, store assets, and the release process. How well
the signature model holds up against real users is something only shipping will
tell.
