Spider Gym: React SPA Frontend
Migrated a 67-template Django 5.2 monolith into a typed React SPA with 68 routes across 10 domains for a live gym client. Mock-API-first workflow, role-based routing, CSRF-safe client, Vitest coverage.
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 real DRF /api/v2/ backend could ship in parallel. Lesson: a typed API client plus Vitest coverage turns a big migration into reviewable, mergeable work.
Context
Spider Gym started as a Django 5.2 monolith with 67 server-rendered templates. The job was to turn that into a typed React SPA without losing the operational surface the gym staff already depended on: member CRUD, memberships, payments, QR-based check-ins, a receptionist dashboard, and an admin reporting suite.
Architecture
The SPA shipped with 68 routes across 10 functional domains (auth, members, memberships, payments, QR check-ins, reports, admin utilities, and more). The stack is React 19, TypeScript 6, Vite 8, Tailwind CSS v4, and React Router v7, with a typed API client that handles CSRF and role-based route protection.
The approach was mock-API-first. The frontend consumed a json-server mock mirroring the planned DRF contract, which let the React SPA be developed end-to-end while the backend team built the real /api/v2/ endpoints against the same shapes. Cutover was swapping the base URL.
RBAC lives 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 check-in
The gym's original check-in flow scanned QR codes server-side with pyzbar and NumPy. In the SPA it moved to html5-qrcode running in the browser, which took the backend out of the scan loop and gave operators instant member status on screen.
Frontend
60+ typed React components and feature pages, covering member management, receptionist workflows, membership lifecycle, payment tracking, QR scanning, and admin dashboards. Loading states, skeleton screens, error boundaries, and responsive layouts across every route; the React Compiler (babel-plugin-react-compiler) handles memoization automatically.
Testing
Vitest and React Testing Library cover the migration-critical flows: login, check-in, membership renewal, payment. TypeScript strict mode across the codebase; ESLint on the frontend, Ruff on the Python side.
What I took from it
Frontend contracts unblock backend work. A typed API client that exists early gives the backend team a concrete target, and parallel delivery becomes possible once that shape is pinned down. A Vitest layer over the most painful flows is cheap insurance during a long migration.