Case study · Self-directed, fully owned

The game platform

A shared backend and content pipeline serving several daily puzzle games — live on the App Store and Play Store as Decode Daily.

Nobody asked for this one. I built it to carry a complete product lifecycle end to end, on my own terms: platform design, daily content generation, store review, and a full monetization stack.

  • Backend Laravel 12 · Elastic Beanstalk
  • Client Flutter · Riverpod
  • Targets iOS 14+ · Android 21+
  • Monetization AdMob
  • Live Decode Daily — App Store & Play Store

The game platform — one backend, many games

Built so that shipping another game means writing a client, not another backend. Daily content is generated ahead of time rather than on request.

Content pipeline — runs on a schedule, ahead of demand

  1. Scheduled generator

    An artisan command generates seven days of challenges at a time, targetable per game.

  2. Validated & stored

    Each challenge is checked for solvability before it is persisted — a broken daily puzzle is a broken day.

  3. Served as "today"

    Clients fetch the current challenge; nothing is generated during a user's request.

Shared backend

Laravel 12 REST API on Elastic Beanstalk

  • Challenge scheduling
  • Player profiles & streaks
  • Achievements
  • Leaderboards & stats
  • Categories
  • RDS MySQL

Game clients

  • Decode Daily

    Flutter cryptogram game, live on the App Store and Play Store. iOS 14+ / Android 21+, Riverpod state, AdMob monetization.

  • Stack & Sort

    Second game on the same platform contract.

  • Number Crunch

    Third game. Adding one is a client and a seeder, not a new system.

This is the self-directed work — fully owned, built to keep the craft sharp and to carry a full monetization stack end to end: ads, in-app purchase, store review, and the release cadence that comes with a daily game.

A platform, not a game

The straightforward way to ship a daily puzzle game is to build the game. The backend follows from whatever that one game needs, and the second game — if there ever is one — gets its own backend, its own accounts, and its own analytics.

I built the platform first instead. Challenges, player profiles, streaks, achievements, leaderboards, and categories are game-agnostic; the game identifier is a parameter, not a fork. Adding a game means writing a client and a seeder. That is why three of them sit on one contract rather than in three codebases.

Generate the content before anyone asks for it

A daily game has an unforgiving property: at midnight, in every timezone, a specific puzzle must exist and must be solvable. Generating it when the first player opens the app puts a content generator on the critical path of a cold start.

So generation is a scheduled command that produces seven days of challenges ahead of time, targetable per game, with solvability checked before anything is stored. By the time a player asks for today's puzzle, it has existed for a week and has already been validated.

A slow generator or an unlucky seed becomes an operational problem days before it could ever become a player-facing one.

The parts that are actually hard

The puzzle logic was the easy half. What takes the time is everything around it: store listings, age ratings, privacy declarations, an ads SDK and its consent requirements, the app-ads.txt file that has to resolve at a stable URL for ad serving to work at all, and the review cycles.

That is the reason this project exists. A developer who has only ever shipped backends will confidently underestimate all of it. Having carried the full monetization stack — ads here, in-app purchase and subscription billing elsewhere — means I can give a straight answer about what a mobile launch actually costs, rather than a hopeful one.


More work — a regulated clinical product, and a legacy system modernized in place.

All work →