Rakuteam: a platform for running a sports club
A multi-tenant SaaS that brings a sports club's membership, billing and attendance into one place. A GraphQL API on Cloudflare Workers serves three separate SPAs.
- Period
- In development and production use
- Stack
- Cloudflare Workers Cloudflare D1 (SQLite) Cloudflare Pages Hono GraphQL Yoga / Pothos React + Vite Relay Stripe Connect TypeScript
- Multi-tenant by design, so one platform runs many clubs
- Three SPAs for admins, members and our own operators, all generated type-safely from one GraphQL schema
- Membership fees collected through Stripe Connect direct charges and subscriptions
- The business-logic layer is held at 100% test coverage
The problem it solves
Running a sports club means keeping a member list, collecting monthly fees, chasing attendance and passing messages to parents, and that work tends to end up spread across paper, spreadsheets and someone’s personal LINE account. Rakuteam pulls all of it into one platform so that whoever runs the club can spend their time coaching rather than collecting money and maintaining a roster.
Architecture
The server is Hono with GraphQL Yoga and Pothos, running on Cloudflare Workers. The
database is Cloudflare D1 (SQLite), always reached through the env.DB binding.
Production, a local wrangler dev, and the test runner (vitest) all take that same path,
so the class of difference where something passes locally and fails in production cannot
arise in the first place.
The front end is split into three SPAs, one per audience.
| App | Audience | Data fetching |
|---|---|---|
web | Club administrators | Relay |
player | Members and their parents | Relay |
ops | Our own operators (behind Cloudflare Access) | graphql-codegen |
The club-facing schema and the operator-facing schema are served from separate endpoints, so operator-only mutations cannot leak into the schema a club can see.
Authentication and payments
Sign-in verifies a Google or LINE id_token and then issues our own HS256 session JWT.
Parents log in with an account they already use every day, and we pay no monthly fee to an
authentication service to make that happen. Only ops sits behind Cloudflare Access, which
stops requests before they reach the application at all.
Fees are collected with Stripe Connect direct charges and subscriptions. The money lands in each club’s own account, and our part is limited to building and running the payment flow.
How quality is kept
The business logic under services/ is held at 100% test coverage, and the results of the
unit, integration and end-to-end suites are always visible as badges in the README.
Specifications and design decisions are written down under docs/, and the conventions for
AI coding agents are collected in CLAUDE.md. The design document a human reads is the same
document that instructs the agent.