Challenges.API

Roadmap

Sequenced by what blocks what.

The north star: be the competition layer small teams reach for — not by outspending anyone, but through care for detail, closeness to the people using it, and pricing nobody can undercut without losing money.

Everything in the first block is built and tested. Everything after it is not, and the order is honest about dependencies rather than about what would be fun to build.

Built

  • Identity across apps
  • Four aggregations
  • Qualifications
  • Regional leaderboards
  • Async challenges
  • Head-to-head + Glicko-2
  • Geographic titles
  • Badge rule engine
  • Collections
  • Daily seeds
  • Event stream
  • Profiles
  • Rivals and friend boards
  • Blocks
  • Reports and moderation
  • Invites
  • Self-opening waitlists
  • GDPR export and deletion
  • Retention limits
  • Sign in with GitHub or email link
  • Key rotation, expiry, revocation
  • Self-service apps
  • Audit trail
  • 220 tests at 97 % coverage

Phase 1

Actually online

Nothing below matters until this is done.

Done when the live smoke test passes against the public URL.

Remote D1 in the EU, worker deployed, custom domain, admin key as a secret

A real migration runner instead of hand-applied files

Cron triggers: retention sweep daily, season close on schedule

Static site and dashboard on Cloudflare Pages

Phase 1b

The rest of the key story

Sign-in and key lifecycle are built. Three pieces need somebody outside us.

Done when a key pushed to a public repository is dead before anyone reads it.

Register chapi_sk_ with GitHub secret scanning, so a leaked key is revoked before anyone reads it

Scoped keys — allowed to submit entries but not to create disciplines

Phase 2

SDKs, so integrating takes five minutes

The whole thesis is that nobody should build this twice. That only holds if integration is trivial in the languages small teams actually use.

Done when somebody who is not us integrates without asking a question.

JavaScript/TypeScript package, typed, browser and worker

Godot plugin in the Asset Library — the most underserved channel

Flutter/Dart package on pub.dev

A drop-in leaderboard widget: one script tag, claim the account later

Two of our own games wired end to end, in public, as the reference

Phase 3

An identity that survives a lost phone

Today, losing the device without an open link code loses the account. Acceptable for a pilot, unacceptable for titles people care about.

Done when a player can move to a new phone with no support contact.

Passkey and email upgrade on top of the anonymous account

Session listing and revocation

Recovery that does not require storing more than we do now

Phase 4

A read path that survives a real population

Ranks are computed in memory from the full standing. Correct, tested, fine for thousands — not for hundreds of thousands.

Done when a district with 100,000 entries answers as fast as one with ten.

Materialised standings per competition key, rebuildable from the ledger

Rank and neighbourhood without loading the whole board

Pagination and cursors on every list endpoint

A load test that is part of the suite, not a one-off

Phase 5

Live

Everything so far works asynchronously on purpose. This is where simultaneity arrives.

Done when two strangers in one city get matched and play without either client claiming a result.

SSE on the event stream, replacing polling

Presence and a matchmaking queue with parties and region hints

Server-issued join tickets so a match server can trust who joined

Signed webhooks with retries

Phase 6

Verification — the part nobody copies in a weekend

The moat is not the code, the code is CC0. It is that a title from here is believable. That needs a machine which can check a claim.

Done when a tier-1 discipline can prove a run instead of trusting it.

Developers upload a deterministic simulation core as a WASM module

We re-run the submitted input trace in a sandbox and compare the state hash

Metered per verified run, because it is real CPU

Verified results carry a mark; unverified ones say so

Phase 7

Ceremony, because a title needs a moment

A season that simply ends is a season nobody remembers.

Done when winning a district title produces something a person wants to post.

Tournaments: brackets, swiss, scheduled finals

Replays and ghosts — race the district champion while they sleep

Season ceremony, permanent title archive, shareable images per title

City clubs and team standings aggregated from individual results

Phase 8

Community surface

We do not win on budget. We win on care and closeness.

Done when the first city final happens with real humans in one room.

OpenAPI specification and generated typed clients

Docs with a live console against a sandbox app

Public changelog, status page, and a place to talk that we actually read

A city-by-city rollout, starting with Hamburg

Phase 9

Billing, and not a day earlier

Metering, invoicing and quotas get built when an outside developer actually needs them — not to have a pricing page.

Done when somebody outside pays for verification or a world-level title.

Usage metering per app

Payment and invoices

Quotas and honest overage behaviour

Out of scope, permanently

What will never be built here.

Every one of these is a place where the big platforms became large, expensive and slow. Staying out of them is the plan, not an oversight.

Inventory and in-game currency

Cloud saves and player storage

Remote config and feature flags

Analytics

Push delivery

Chat

Chat deserves its own sentence: it is where a small competition layer turns into a moderation company. What exists here is challenges, rivals and reports. Conversations belong in your app.