Rackd
A fitness app that hands you a workout in three taps
A cross-platform fitness app built and run end to end — Flutter client, TypeScript Cloud Functions, Firestore with tested security rules, subscriptions, analytics, and a keyless release pipeline. Five releases shipped and live on the App Store.
- Workout catalog, hand-built
- 425
- Releases shipped to the App Store
- 5
- Deploy keys to leak or rotate
- 0
The problem
Why the app existsMost people do not skip workouts because they are lazy. They skip because they do not know what to do, and every fitness app answers that question with a library to scroll and a program to build. The friction is where the workout dies.
The product bet was that removing the deciding is the whole product: answer two or three prompts — focus, equipment, time — and get something you can start now. That bet only pays if the app is fast, honest about the equipment you actually own, and trustworthy enough to log against for months. All three of those are engineering problems, not design problems.
What it looks like
Shipped screens, not mockups
How it was built
The decisions that mattered-
Ownership-scoped data from the first commit
Workout logs and personal forks are private by default, and the Firestore collection layout is shaped so an ownership-scoped read is the natural query rather than the careful one. Security rules are version controlled and every rule change ships with a rules test — the tests are what make it safe to keep changing the data model after launch.
-
Trust boundaries on the server, not the client
Anything security-sensitive runs in Cloud Functions or in rules, never in the client. Authenticated operations resolve the user from the Firebase Auth context instead of trusting an id the client sent, and App Check gates the callable surface. It is the difference between an app that is private and an app that merely looks private.
-
Dark launches behind flags
A full AI coaching surface — its own route, prompt entry, and loading experience — ships inside the binary but disabled by a remote flag, and no store metadata references it. Features land in production dormant and get switched on when the product is ready, which decouples shipping from launching. When the flag platform moved from Remote Config to PostHog, it moved as a seeded config rather than a code change.
-
A release pipeline with no keys in it
GitHub Actions builds and deploys through Workload Identity Federation: GitHub mints an OIDC token and Google exchanges it for short-lived credentials. There is no service-account JSON in a secret store, so there is nothing to leak and nothing to rotate — which is also what let the same pattern be reused, unchanged, for the marketing site and for this one.
-
Cost treated as a design constraint
Functions carry explicit instance caps, the workout catalog is fetched as a one-shot read rather than a live subscription, and the read pattern was revisited as the catalog grew past 400 documents. Serverless bills for carelessness, and the cheapest time to notice is before the invoice.
-
A social surface built to clear review
Teams and contact-based discovery shipped alongside a full moderation stack — reporting, blocking, and content filtering — specifically to satisfy App Review guideline 1.2. Building the moderation with the feature rather than after a rejection is the difference between one submission and three.
The stack
All of it, in one placeClient
- Flutter (Dart)
- Riverpod
- go_router
- freezed
Backend
- Cloud Functions (TypeScript, 2nd gen)
- Firestore
- Cloud Storage
- FCM
- App Check
- Remote Config
Platform
- GCP / Firebase
- GitHub Actions
- Workload Identity Federation
Product
- RevenueCat subscriptions
- PostHog analytics + flags
- Crashlytics
- Performance Monitoring
Want this run on your product instead of ours?
Send over the shape of the problem and we will come back with an honest read on scope, timeline, and cost — before anyone signs anything.


