Case study · RunLink · 2025-2026

RunLink

Live on the iOS App Store with a web dashboard for club admins: club discovery, events with mapped routes and RSVPs, a member roster with roles, and in-app chat.

RunLink hero
Fig. 01 · RunLink

Role

Studio · build + ship

Status

Live

Year

2025-2026

Surfaces

Web + iOS

Live

In production

The problem

A running club is usually run by one founder on the side, out of a spreadsheet, a group text, and a social account. Members miss the route change, new runners cannot find the club, and everything the club knows lives in one person’s phone. Generic group apps and event tools were not built for how a running club actually operates. RunLink gives the person who runs the club one place to do it: a public club page so runners can find it, events with RSVPs and mapped routes, a member roster with roles, and group chat. Club admins manage it from a web dashboard, and members use a native iOS app that is free to download.

What we built

  • Public club pages and club discovery on a map
  • Events with RSVPs, recurring schedules, and mapped routes with auto-calculated distance
  • Route drawing on the club admin dashboard by dropping waypoints, with the route shown to members beside the RSVP
  • Member roster with roles for platform admins, club admins, and runners
  • Club chat and direct messages in real time
  • Invites from phone contacts, matched by email only, with nothing stored
  • Apple Health opt-in that fills in weekly mileage and longest run
  • Native SwiftUI app on the App Store, plus a web dashboard for club admins

Three clients, one backend

RunLink is a FastAPI backend on Cloud Run with Postgres and Redis, a Next.js dashboard for club admins and platform admins, and a native SwiftUI app for iOS 16 and up. The backend is the source of truth: the dashboard generates its API types from the backend’s OpenAPI spec, and the iOS app decodes exactly what the API returns rather than what a client assumes.

Three roles, platform admin, club admin, and runner, gate every surface, and the iOS app gives runners and club admins visibly different experiences. Chat runs in real time over WebSockets with messages persisted, and the dashboard opens its socket with a short-lived ticket from the backend. What a club admin actually gets from all of this is laid out on RunLink for running clubs.

What was hard

Routes were where the clients disagreed. The dashboard and the iOS app each had a reasonable way to store coordinates, and a route drawn on the web either rendered nothing on the phone or a straight line. We settled on one wire shape, typed waypoints plus the resolved walking path as points, applied on both create and update, and iOS now draws the saved points directly instead of re-routing the run as a car trip. When an organizer moves an event, the backend re-pins each route’s start to the new meeting point.

The first App Store submission was rejected on three items: Terms and Privacy links that were not tappable, no way to delete an account in the app, and a background location mode the app did not actually use. The fix was making the binary match what the app does, with real links, account deletion on both profile screens, and When-In-Use location only. The next build was approved.

Inviting from phone contacts had to be useful without becoming a privacy problem. Matching is by email address only, nothing about the submitted list is stored, and requests are batched, capped, and rate limited per user so the endpoint is not an easy way to test which addresses have accounts.

Apple Health is opt-in. Once a runner connects it, the app fills in weekly mileage and longest run from their recent running workouts, and keeps them fresh with a daily background refresh instead of waiting for the runner to reopen their profile.

Numbers that matter

Status

Live

iOS App Store

Built for

Club founders

owners and admins

Surfaces

iOS + web

runner and club admin

Roles

3

admin, club admin, runner

Stack

Frontend
Next.js 16SwiftUI iOS 16+TailwindTanStack Query
Backend
FastAPIPython 3.11SQLAlchemyWebSockets
Data
Cloud SQL PostgresRedisGeospatial search
Infra
Cloud RunVercelMapboxFirebaseApple HealthKit

What we learned

Agree on the wire shape before the second client ships. Our route bug was two reasonable data shapes and no single contract between the web and the phone.

App Review rewards a binary that tells the truth. Every permission and background mode has to match what the app really does.

Availability is not adoption. The app is live and free to download, so we describe what it does, never how many clubs use it.

Have something that looks like this?

Tell us what is broken. We’ll tell you what the first week looks like.

Next case study →

Copiara