A suite of business applications
Since August 2026 I have been the lead engineer on a suite of nine applications for a food and beverage company that runs concession stands inside two stadiums and is opening its first shop. Between them they run the business: the money, the production schedule, the crew on shift, and the people and their pay.
Built with TypeScript, React, Vite, Express, PostgreSQL, Supabase Auth, React Native (Expo), TanStack Query, Railway
I built every app below from scratch.
Sign-in and launcher
Nine apps, one sign-in, and access that can be taken away in a click.
The sign-in every app shares, the launcher they all open from, and the admin screen that decides who can open what.
Before
Each app had its own way in: one used a single shared passcode, another three hard-coded passwords. Removing someone meant changing a passcode everyone else used.
After
Everyone signs in once, with two-factor authentication, and sees only the apps they have been given. New staff register with a work address and an admin approves them.
- 1 sign-in
- for every app, replacing a shared passcode and hard-coded passwords
- Next click
- is when removed access takes effect, not when someone’s session expires
Financials
Closing a game day went from keying reports in by hand to uploading them.
The finance app the back office closes each game day with: reports read straight from PDFs and spreadsheets, every day reconciled, and dashboards for each venue.
Before
After every game, someone keyed the point-of-sale report, the vendor invoice and the settlement into spreadsheets by hand, and a weekly vendor invoice was being recorded as sales on top of the till’s own figure.
After
The reports are uploaded as they arrive and read automatically. Each day reconciles itself, and the dashboard shows per-cap spend, margin and trends for each venue.
- 10–15 min → under 2
- to process one supplier invoice, roughly 6× faster
- 100%
- revenue double-count found and removed: every game day had been counted twice
P&L model
The investor P&L now updates itself from the season’s real numbers.
A three-to-five-year profit and loss model with scenarios, the season’s actual results laid alongside, and a read-only view for investors.
Before
The three-to-five-year forecast ran on assumptions alone, kept apart from the finance records of how the season was actually going.
After
Scenarios sit on top of the current season’s actual results, which flow in from Financials. A commercial kitchen and a wholesale line are modelled alongside the stands, and investors get a read-only view.
- 0
- figures re-keyed: the season’s actual results come straight from Financials
- 3–5 years
- of profit and loss, by scenario, from one set of assumptions
Production
The production schedule is drafted automatically, then adjusted by the operations manager.
A production planner that drafts the schedule around games, batter kits, transport between venues and who is available, on a calendar the operations manager can adjust.
Before
The operations manager worked out every production day by hand: which days each stadium was free of games, whether the batter kits were ready, how stock would move between venues, and who was available and trained.
After
The planner reads both stadiums’ event calendars, finds the access windows, and drafts a schedule that respects kits, transport and staff skills. The manager adjusts it rather than building it.
- 2 stadiums
- scheduled from their live event calendars, so a new fixture moves the plan without anyone retyping it
- 4 checks
- on every production day: venue access, batter kits, transport and staff, all done automatically
Crew phone app
Shifts, clock-ins and end-of-shift counts now come from the crew’s phones.
A native iPhone and Android app for the people making the product, and the API behind it.
Before
Clock-ins lived in a third-party scheduling tool whose API can only be read, never written, so the company did not own its own timesheet.
After
Crew see their shifts on a native iPhone or Android app, get a notification when scheduled, clock in at the stand, and finish with a count that goes straight into the stock ledger.
- 1 ledger
- for stock: the end-of-shift count is the same record the office and the finance app read
- Owned
- timesheet: clock-ins are stored in the company’s own database, not a vendor’s
People
Pay is visible only to the people who should see it.
The roster, absences, hours and pay, in an app of their own.
Before
The roster, absences, hours and pay were four tabs inside the scheduling app, so anyone who could plan production could also see wages.
After
People is its own app. Pay is a separate permission, and the roster is kept in one place for every other app to read.
- 1 roster
- shared by scheduling, the crew app and payroll hours
- Pay
- is a permission of its own, so giving someone the scheduler no longer shows them wages
Website admin
The website’s inbox and newsletter moved behind the same sign-in.
The back office for the public website: its contact inbox and newsletter list.
Before
The marketing website had its own admin screen with its own accounts and passwords, and replies to enquiries went out from people’s own email with no record of who had answered.
After
Contact and catering enquiries and newsletter sign-ups are handled from one tile in the launcher. Every enquiry is tracked from new to replied, and replies are sent from the inbox and kept on record.
- 2 forms → 1 inbox
- contact and catering enquiries, each tracked from new to replied
- 1 fewer
- set of accounts and passwords to manage