Personal project, built solo · 2025
SparkleQuiz
Solo and multiplayer quiz app, in production on the web, Android and iOS.
- platforms: web, Android, iOS
- 3
- releases shipped
- 210+
- PHPUnit tests
- ~6 000
- downtime per deploy
- 0
Designed, built and operated on my own: Symfony API, Vue 3 front end, Capacitor mobile apps, real-time matches, leaderboards and player-made quizzes.
My role. Sole developer: design, back end, front end, mobile apps, infrastructure and store releases.
What I did
- Full progression system: levels, XP, daily quests, 68 trophies and 4 leaderboards synced with Game Center.
- Eight GitHub Actions pipelines: tests, Docker production deploys, store publishing, store listing updates.
- End-to-end tests with Playwright on the web and Maestro on mobile, Lighthouse audits.
Starting point
I wanted a project that forced me to do everything a company does, without a safety net: product, architecture, database, front end, mobile apps, then run it in production and keep it alive.
Architecture
A Symfony 7 API on MariaDB serves both the website and the apps. The Vue 3 TypeScript front end is the same code everywhere: Capacitor wraps it for Android and iOS. Redis handles caching and the message queue, Mercure pushes real-time events.
A deliberate choice: a well-structured monolith rather than microservices. For a team of one, it is the fastest thing to deploy, test and debug.
Vue 3 + TypeScript · Capacitor
Real time
Multiplayer matches run on Mercure (Server-Sent Events) rather than custom WebSockets: less server code, reconnection handled by the browser, and channel authorization stays in Symfony.
Quality and CI
Every change goes through the same gate: PHPStan, PHP-CS-Fixer, PHPUnit, front-end lint and type checks, Vitest, translation parity and a CSS budget. Playwright replays critical journeys every night.
On the API side, one simple rule: every predictable error returns a clear 4xx, a 5xx means a real bug and reaches monitoring.
Deployment
A push to main deploys the site to my server through GitHub Actions, blue/green behind Caddy: the new version boots next to the old one and only takes traffic once healthy. A version tag publishes the app to Google Play and submits it to Apple. Urgent fixes ship as live updates, without going through the stores.
What it taught me
The hard part is not writing the feature, it is keeping it standing in production: zero-downtime migrations, compatibility with older app versions still installed, performance on low-end phones, and tests reliable enough to ship often without fear.