Skip to content
back to projects

// project ·

Spider Gym: React SPA Frontend

Rebuilt a gym app so old Django templates stop owning the frontend. Stack: React, TypeScript, Vite, Django, Vitest.

React 19 / TypeScript 6 / Vite / Tailwind CSS v4 / React Router v7 / Vitest / Django 5.2 / DRF

Role: Freelance · frontend migration · Year: 2024 - 2025 · Status: shipped

tldr: Migrated a live gym’s 67-template Django 5.2 monolith into a typed React SPA with 68 routes across 10 domains. Building against a json-server mock first meant the frontend and the DRF /api/v2/ backend could ship in parallel. Lesson: a typed API client plus Vitest coverage turns a big migration into reviewable, mergeable work.

Problem

Spider Gym ran on a Django 5.2 monolith with 67 server-rendered templates. The job was to turn it into a typed React SPA without losing any of the operational surface the staff depended on: member CRUD, memberships, payments, QR check-ins, a receptionist dashboard, and admin reporting.

Constraints

  • The gym stays open. Staff use the system every day, so the migration couldn’t take the front desk offline.
  • The backend wasn’t ready. The DRF /api/v2/ endpoints were being built at the same time as the frontend.
  • Three staff roles (admin, receptionist, cashier) see different parts of the app.

Decisions

  • Mock API first. The SPA consumed a json-server mock that mirrored the planned DRF contract, so frontend and backend shipped in parallel. Cutover was swapping the base URL.
  • A typed API client, written early, handles CSRF and the shared response shapes and gave the backend team a concrete target.
  • RBAC on both sides. Django permissions and custom decorators on the server; a React auth context with isAdmin, isReceptionist, and isCashier flags plus protected route wrappers on the client.
  • QR scanning moved to the browser. The old flow decoded codes server-side with pyzbar and NumPy. html5-qrcode in the browser took the backend out of the scan loop and shows member status on screen immediately.
  • React 19, TypeScript 6, Vite 8, Tailwind CSS v4, and React Router v7, with the React Compiler handling memoization.

Outcome

The SPA shipped with 68 routes across 10 domains and 60+ typed components, with loading states, skeleton screens, error boundaries, and responsive layouts on every route. Vitest and React Testing Library cover the migration-critical flows: login, check-in, membership renewal, and payment. The lesson: a frontend contract that exists early unblocks the backend, and a thin test layer over the painful flows is cheap insurance on a long migration.