Skip to content
bpm.
Menu

How it’s built

One app, three front doors.

For the curious. BPM is a single Next.js deployment. The iPhone and Android apps are native shells around it, so every release reaches every device at once.

The shape of it

From your phone to the database.

iPhoneCapacitor shell · widgets · push
AndroidCapacitor shell · widgets · push
BrowserInstallable web app · Web Push
BPM web appNext.js · React · TypeScript · Azure App Service
  • Server-rendered pages, gated by sign-in and club
  • API routes, members-only and rate-limited
  • Every read scoped to one club
  • English and 简体中文 throughout
DatabaseAzure Cosmos DB
AIAnthropic Claude
PushFirebase · Web Push
EmailSMTP
Three clients, one deployment, four supporting services.

Decisions worth knowing

Why it’s built this way.

One deployment

Every change ships to everyone at once. Unfinished work stays behind feature flags, so there’s no separate “stable” version to drift.

Native shells, live web

The phone apps load the live app, so web, iPhone and Android never fall out of step. The shells add widgets, the app badge, shortcuts and push.

Clubs kept apart

Many clubs share one deployment, but every read goes through a single club-scoped path, so one club never sees another’s roster or money.

Honest failures

If something can’t load, the app says so. It never shows a confident zero in place of data it couldn’t fetch, because people rely on the numbers.

AI with a human in the loop

Claude helps draft announcements and summarise your stats. An organiser always sees an announcement before players do.

Fast first paint

Fonts and icons are self-hosted and trimmed, so the first screen doesn’t wait on anyone else’s servers.