Case study · Baseline Tennis Academy
From a no-code app to a platform the business can grow on.
Baseline Tennis Academy coaches children and adults across clubs in Harare. Bookings, families, coaches, schedules and attendance all ran through a Bubble.io app that had grown to around 800 active users. We rebuilt it as a proper platform, a member app and a staff portal on one typed backend, and moved every record across without losing one.



The problem
No-code tools are a brilliant way to start a business and a painful way to run one at scale. By the time BTA had hundreds of families, thousands of bookings and a team relying on the admin screens every day, the Bubble app had become slow, hard to change and impossible to test. Every business rule lived inside visual workflows that only the original builder understood.
The academy needed the speed and reliability of real software without the disruption of starting again. Members had to keep their history. Staff had to keep working. And if anything went wrong, there had to be a way back.
The approach
We treated it as an ERP migration, not an app redesign. Rule one was parity: reproduce exactly how the business works before improving anything. Bubble's screens, workflows and data were the specification, and anything unclear was raised as a question rather than guessed.
The new platform was built alongside the live app, fed by a repeatable migration that could be run again and again until the numbers reconciled. Bubble stayed the source of truth until the day of cutover, so rollback was always one step away.
What we built
Two products, one backend. The member app and the staff portal share a single domain model, validation and database schema, so they can't drift apart.
A member app built around the family
Parents hold the account and book for their children. The home screen puts every kind of booking one tap away: private coaching, group sessions, court hire and school programmes. Each flow asks only what it needs, in order: who's playing, which club, which day and time.
- Family accounts with children's profiles and ages, so the right programmes appear
- Court booking across five clubs with live availability by the hour
- Private coaching built by club, programme and coach, from Red Ball to Adult Advanced
- Works offline for viewing, with biometric sign-in on supported phones


Returning members just log in
Passwords can't be moved from one system to another, so we didn't try. A returning member enters the email BTA already has for them, receives a one-time code, and claims their family with its full history. No pre-created accounts, no password resets, no support tickets. The customer experience of the migration is download the new app, log in, carry on.
- Email one-time codes instead of passwords
- Every migrated family, member and booking keeps its original record ID for traceability
- Account deletion built in from day one to meet App Store and Play Store policy

A staff portal that runs the day
Administrators and reception manage families, coaches, the programme catalogue, schedules, bookings and attendance from a web portal designed for a desk and a busy counter. Court and coach time is locked at the moment of booking, so two staff members can't double-book the same slot from different screens.
- Role-based permissions enforced in the API, not just hidden in the interface
- Archive instead of delete, with an audit trail on every change
- Paginated, indexed list views that stay fast as the data grows

The migration
The part nobody sees is the part that mattered most. Moving a live business off Bubble without losing a booking or a cent took a pipeline, not a copy-and-paste.
- ExtractImmutable, timestamped snapshots of every Bubble data type, never edited
- TransformVersioned field mappings from Bubble's shape to the new schema, validated before load
- LoadIdempotent upserts keyed on the original record ID, so a re-run is safe and a failed run rolls back whole
- ValidateRow counts, integrity, identity coverage and money reconciled to the cent before anyone is switched
Dual-run, then cutover
The new platform ran in parallel with the live app on scheduled delta syncs while staff trialled the portal against a faithful copy of real data. Cutover was gated on parity sign-off, a passing validation report, a load test and a rehearsed rollback.
The website came too
BTA's public site was also hosted on Bubble. We captured it pixel-for-pixel as a static site on Cloudflare, with a working contact form and the legal and support pages the app stores require, so the domain could leave Bubble on the same day.
How it's built and run
A single TypeScript codebase for web, mobile and server, so a change to the shape of a booking is checked across all three at compile time.
- Expo + React NativeOne codebase for iOS and Android, with over-the-air updates
- Next.js admin portalServer-rendered screens for data-heavy admin work
- tRPC API on NodeEnd-to-end type safety between every client and the server
- PostgreSQL on SupabaseManaged Postgres, auth and storage with point-in-time recovery
Tested like it matters
Integration tests run against a real database, browser tests cover the portal, and a mobile release gate runs on every build. Code reviews and a secret scan sit in front of every merge.
Ready for the stores
Universal iPhone and iPad layouts, dedicated support and privacy pages, in-app account deletion and Data Safety declarations were all handled before submission, drawing on what we learned shipping 4DWW Golf through both stores earlier in the year.
Outgrown your no-code app?
Keep the business. Replace the software.
If a Bubble, Glide or Airtable app has become the thing holding you back, we can rebuild it properly without losing your data or your customers.