Case study
JB Karting
A race site for a junior kart racer in the UK, with an admin the family publish from themselves, now becoming a platform for karting families.
- Client
- JB Karting
- Dates
- 2026 to now
- Live
- jb-karting.com
- merged PRs
- 202
- Terraform files
- 25
- React
- TypeScript
- Nx
- Hono
- AWS Lambda
- DynamoDB
- Cognito
- Terraform
The problem
A junior kart racer in the UK needs sponsors, and sponsors want to see results. The family needed a site that shows a season properly: every round, every session, wins and podiums, the circuits and the news, with the sponsors’ logos where people will see them.
Keeping it current was the hard part. Every change to the driver’s profile, from a new sponsor to an updated bio, went through me, and the family had to be able to edit it without a developer.
My role
I built all of it, alone: the public site, the admin, the API, the AWS infrastructure in Terraform, and the CI that deploys it. The family supply the content and the decisions: the results spreadsheet, sponsors, and feedback from their phones.
What I built
- The public site. A React app with results, races, circuits, teams, news and videos. Results show two sets of figures side by side, championship races and every competitive session, and a round’s headline is the final the driver raced, with its tier: “B Final · P8”.
- The admin. Cognito sign-in, then editing for circuits, championships, races, results, news, videos, sponsors and the driver’s profile, with a rich-text editor. Results can be entered by hand or imported from a CSV.
- Publish to website. The profile used to live in the code. Now it’s a record the family edit, and the admin’s publish button writes its public version to the site’s bucket as JSON and clears the CDN’s copy. The site reads that file when it loads, checks its shape, and falls back to a snapshot built into the app.
- Results. Updated every race weekend.
- Operations. Terraform manages the infrastructure, in three roots. CI plans every change on the pull request, refuses a destroy unless it’s labelled, and deploys on merge through GitHub OIDC, so CI holds no AWS keys.
Architecture
The site and the admin are static builds on S3 behind CloudFront. One Hono API on Lambda serves both, over the app’s DynamoDB table. Publishing writes the driver’s public profile into the site’s own bucket, so the site reads it from its own origin.
The hard part
Handing the site to the family
The driver’s profile, from the bio to the sponsors, started life in the code, so every change went through me. Moving it into the admin was the easy half. The hard half was letting the family press “Publish to website” without a developer watching, and making sure a bad moment could never take the site down or publish something it shouldn’t.
- One list of what is public. The published copy is built from a named list of fields, not the record minus a few. A field added to the profile tomorrow stays private until it is listed, so the phone number never reaches the site by accident.
- Every failure says what happened. If the write fails, the site keeps the last publish and the admin says the site is unchanged. If the write succeeds but recording it fails, the admin says the site already has the new copy and that publishing again is safe.
- No waiting on the cache. The file carries a one-minute cache lifetime and the publish clears the CDN’s copy. If clearing fails, the new profile is still live within a minute.
- Releases don’t undo it. Deploys sync the site’s bucket with deletes, so they skip the published profile; a release never wipes what the family published.
- The site never breaks on a bad file. It renders a snapshot built into the app straight away, then swaps in the published profile once it has checked its shape, and only if it is newer. A missing, slow or malformed file changes nothing.
What's next: a platform for karting families
JB Karting and I are turning the site into a platform. A karting family, coach or team picks a template, fills in a profile and has a sponsor-ready site of their own. It starts in the UK, and the original site stays on as the first tenant and the demo, working throughout.
It’s the same move I made with getMickled in 2026, from one storefront to a platform with an operator console and a tenanted admin, and it follows that order:
- The driver as data. Largely done: the driver is a record rather than code, results are keyed to the driver who raced them, and the admin edits the profile, teams and sponsors. Live since September 2026.
- Tenants. Tenant-scoped data and sign-in, and each site found by its hostname.
- Templated sites. One web app with a few templates, on subdomains first and the family’s own domain later.
- The admin and an operator console for onboarding and support, then billing.
- Posts that write themselves. A result becomes a social post tagged with the sponsors, waiting for the family’s approval, and each sponsor gets a report of the exposure they got.
Outcome
- Live at jb-karting.com since March 2026, with the family editing and publishing the profile themselves since September.
- Results are updated every race weekend.
- The platform is in build, starting from a data model that no longer assumes one driver.