The Approach
The first decision was where to draw the line between app and server. The Flutter app records and displays; the backend decides what counts. The compute-heavy geo math — areas, polygons, intersections — runs in a Go service on Google Cloud Run that scales automatically under load. The map therefore rests on a single source of truth, leaderboards and team scores stay comparable, and the computation does not sit on a device that is already busy logging positions for the length of an entire ride.
Go suits this kind of work because polygon operations are CPU-bound rather than waiting on I/O: compiled code, fast startup, a small memory footprint, concurrency without much ceremony. Cloud Run adds load-based autoscaling on top — fewer instances during quiet periods, more when demand arrives. The load profile of a leisure app is predictably uneven (after work, weekends, good weather), and request-based autoscaling is built for exactly that. The flip side: the service has to be stateless, and any state belongs in the data layer.
On the map, claimed territories are drawn through custom Mapbox layers rather than as individual overlay objects placed on top of the map. The difference is in the rendering: areas expressed as layers are drawn and styled by the map renderer itself and remain part of the map while panning and zooming, instead of floating above it as an ever-growing set of separate elements. The live map, the leaderboards and the team views all read from the same server-side state.
Anything that is not the core was integrated rather than built: subscriptions run cross-platform through RevenueCat, so there is one subscription status instead of two separate state machines for the App Store and the Play Store; fitness data comes in via the Garmin API, so riders can keep using the recording hardware they already own. The guiding principle: build what makes the product what it is — geo logic, game mechanics, map rendering — and use established services for the rest. Architecture, backend and the launch in both stores were all in one pair of hands.