Skip to main contentSkip to footer
    Back to Case Studies
    The CornerFighter Cut for gyms and coaches
    Web AppiOS AppIn-House Product

    The Corner

    Your fight team, one glance. The coaching side of Fighter Cut: every fighter's last weigh-in, the week's load and the work you set them, shown only because the fighter chose to share it.

    Project Preview

    Live website preview - corner.fightercut.com

    3
    Event types a coach can see: weigh-in, session, assignment done
    0
    Food-log fields readable by a coach, by schema
    5
    Founding gyms on the Team plan free, enforced server-side
    8 days
    From first commit to a live web app and TestFlight

    Roster

    Every fighter at a glance: last weigh-in and the change across the week, sessions, minutes on the mat, roadwork, and assignments done against assigned.

    Assigned work

    Set work for the roster with a due date and watch completion counts climb without chasing anyone. Per-fighter assignments are modelled in the schema.

    Invite codes

    Mint a short team code. A fighter types it into their own app and lands on the roster in seconds.

    Claim, create or join

    Claim a gym a fighter already named, create a new one, or join an existing gym as staff. Claiming comes first, because a duplicate gym orphans everyone who was waiting.

    Staff roles

    Owner and coach are distinct roles in the database. Staff codes bring coaches in; only the owner can remove them or spend the gym's founding spot.

    Consent, not access

    A fighter flips sharing on in their app and can flip it off, which deletes the shared stream. What crosses over is weigh-ins, sessions and completed assignments. Never a food log.

    The problem

    A fight coach with a dozen athletes in camp spends Sunday evening texting. How is the weight? Did you run? Did you do the work I set? The answers come back late, partial and in twelve different formats, and by the time a problem shows up on the scale it is a week old. The fighter, meanwhile, is already logging all of it in Fighter Cut, the athlete app we built to plan a safe weight cut. The data existed. It just had no window for the person in the corner.

    The obvious answer is a coach login to the athlete app. We rejected it. A fighter's food log is private in a way a weigh-in is not, and once a coach can see calories, the athlete app's whole pitch, that this is your data and nobody else's, is gone. So The Corner is a separate product, in a separate repository, that can only see what a fighter chooses to send it.

    The rules we wrote before the first screen

    • Nothing from the athlete app: No cut planning, no food logging, no macro maths, no onboarding questionnaire. A feature request that sounds like one of those is aimed at the wrong app.
    • The fighter holds the switch: Sharing is opt-in from the fighter's side and revocable with one toggle, which deletes the shared stream.
    • Food logs never cross over: Not in a summary, not in a total, not ever. If a coach-side feature seems to need diet detail, the answer is no.
    • Server-owned, not local-first: The athlete app works offline on IndexedDB. A roster cannot, and pretending otherwise would let a stale cache impersonate a live team.

    What we built

    Five screens, one question

    Every screen answers "how is my fight team doing?" for someone who is not the fighter. Signed out, a coach sees a marketing page with a live count of founding spots and a sign-in. Signed in without a gym, they land in one-time setup. After that, four tabs.

    Roster: last weigh-in and weekly change, sessions, minutes, roadwork and assignment completion for every fighter attached to the club
    Fighter detail: recent weigh-ins, the week's load and what they still owe you
    Assigned: create work for the whole roster with a due date and see how many have finished it
    Invite: mint a team code fighters type into their own app
    Settings: gym details, coaching staff (invite and remove), the founding-gym code, sign out
    Password reset and signup confirmation pages that live outside the app shell, because both arrive carrying a valid session

    Getting a gym

    1. Claim: When a fighter names a gym in their app and nothing matches, the server creates an unclaimed club and files the request against it. The Corner's setup search finds those clubs, shows how many fighters are waiting, and hands the claimant ownership with every waiting fighter attached.
    2. Create: A new club, with the creator inserted as its owner in the same step. A club whose creator is not a member looks like success and then reads back empty forever, so that insert failing is surfaced, not swallowed.
    3. Join with a staff code: Redeems an owner's invite and joins as a coach, not an owner. Coaches see the roster; they cannot remove staff or spend the founding spot.

    How it works

    Shared backend, split ownership

    The Corner has no SQL of its own. Every table and function it calls, clubs, org members, fighter profiles, progress events, assignments, roster invites, staff invites, join requests and the founding-code pieces, is a migration in the athlete repository. A schema change for a coach feature is written over there and consumed here. Several of those functions have exactly one caller, this app, by design.

    Consent as a data shape

    What reaches a coach is a stream of progress events, three types only: weigh-in, session and assignment done, for fighters whose profile is attached to the club. The food log lives in a different table the coach role has no policy on. The privacy promise is enforced by what the schema exposes, not by a checkbox in the UI.

    Row-level security that does not recurse

    Membership checks run through SECURITY DEFINER helpers rather than inline subqueries against the membership table. The inline form produced a genuine infinite-recursion error in Postgres once; the helpers are now a rule, and a source-grep test keeps the fix from being reverted.

    Founding gyms, enforced in one place

    The first five gyms to redeem a founding code get the Team plan free, permanently. The remaining count is a live database read, the redemption is a single atomic function, and the client cannot fake it. The redeem function checks membership, not ownership, so the UI gates the offer to owner paths.

    Timeline

    1. 17 August 2026: Clubs and fighter profiles land in the athlete app's schema.
    2. 23 August 2026: Org dashboard migration: members, progress events, assignments and roster invites. The Corner repo starts the next day.
    3. 25 August 2026: Emailed links fixed after both were silently landing coaches in the athlete app.
    4. 30 August to 1 September 2026: Founding codes, club claiming and staff management migrations. corner.fightercut.com live, iOS build in App Store Connect.

    Problems worth talking about

    Coaches waking up in the wrong app

    Supabase does not reject an unlisted redirect target; it silently substitutes the project's site URL, which is the athlete app. Both of The Corner's emailed links did exactly that: a coach clicked confirm and landed in a fighter's onboarding questionnaire holding a valid session, with no error anywhere. Both links now build from one origin helper, and a new link type means checking the allow-list first.

    A deploy that says yes and does nothing

    Deploying from a worktree or detached HEAD makes the Pages CLI infer the branch, ship a preview, and print success while production is untouched. The rule now is an explicit branch flag and verifying the live bundle by fetching the chunk and grepping for what was shipped.

    Duplicates that orphan fighters

    Creating a gym under a new slug when a fighter already named it leaves those fighters attached to an unclaimed row nobody will ever own. Setup searches unclaimed clubs first and shows the waiting count, so claiming is the path of least resistance.

    Tests without a DOM

    The test runner deliberately has no DOM. The convention is source-grep: read a file's text and assert the wiring is still there, after stripping comments, because these files explain a fix by naming the construct it replaced and a naive match passes on a reverted file.

    Where it stands

    Beta, reported honestly

    The Corner is live on the web and in TestFlight as Fight Corner, alongside the Fighter Cut athlete app, with public release gated to October 2026. The numbers on this page are counts from the code and schema: event types, roles, founding spots, dates from the migration files. Known gaps are documented too: no in-app billing beyond the founding code, and no referral capture yet. We do not publish gyms, coaches or fighters on a roster for a product that has not launched.

    Food logs. Not in a summary, not in a total, not ever. What a fighter eats is between them and their own app.

    Fight Corner App Store listing

    What This Project Does Well

    Two apps, one Supabase project, one auth table: coaches and fighters sign in against the same store through different screens
    Not local-first, on purpose: a roster is server-owned, so every screen is a live read and there is no persistence layer to lie with
    Demo data appears only when there are no backend keys at all, never on a failed request, so an outage can never look like a working roster
    Access control lives in Postgres row-level security through SECURITY DEFINER helpers, after an inline membership check caused a real infinite-recursion failure
    The founding-gym programme is atomic in a single database function; the client call is the whole story and the code is never printed on the landing page
    No chart or component libraries: hand-built SVG and a small set of in-house primitives, sharing the athlete app's paper-and-ink design language
    Capacitor 8 on Swift Package Manager, its own bundle id under the Fighter Cut root, so both apps sit on one Apple Developer team

    Technologies Used

    React 19, Vite, TypeScript, Tailwind CSS 4, Zustand, Framer Motion springs, hand-built SVG, Supabase (Postgres, Auth, row-level security, SQL functions) shared with the Fighter Cut athlete app, Capacitor 8 for iOS with Swift Package Manager, Vitest, Cloudflare Pages, App Store Connect

    Ready to Build Something Similar?

    Let's discuss how we can help transform your business with a custom digital solution.