Skip to content
Club system guide

How the system works

How the website, API, Discord, email, storage, and scheduled jobs connect.

The short version

The website sends requests to the API, the service that checks rules and saves club data. The API then asks the other services to handle Discord, email, or scheduled work.

The API is the only service that changes club records. The website shows the interface, the Discord Worker handles Discord actions, the Email Worker reads receipts, and the Scheduler Worker starts timed jobs.

Each service has one job. A web page cannot change Discord directly. The Scheduler Worker cannot write to the database. The Email Worker cannot create a membership by itself.

System flow

How the services connect

The website, Email Worker, and scheduler call the API. The API owns D1 and R2, and it signs events for Discord. The wiki deploys separately.

A member uses the website

  1. Browser Shows pages, forms, and the dashboard
  2. Website Worker Runs Astro, React, and the same-origin API bridge
  3. API Worker Checks access, applies rules, and routes requests
  4. D1 + R2 Store records and media files

A change reaches Discord

  1. API Worker Signs a typed event for the Discord Worker
  2. Discord Worker Checks the event, claims its nonce, and runs it
  3. Discord REST Updates roles, DMs, posts, or channels

A purchase receipt arrives

  1. Email Routing Sends the purchase receipt to the Email Worker
  2. Email Worker Reads the receipt, removes duplicates, and retries failures
  3. API Worker Claims the purchase and records the result

Timed jobs run

  1. Cron Runs every thirty minutes
  2. Scheduler Worker Starts seven API jobs at the same time
  3. API Worker Claims a lease and runs each job

The wiki deploys

  1. GitHub Actions Builds the Starlight wiki
  2. Cloudflare Pages Hosts the static wiki files
  3. Reader Reads the wiki without calling the API
The API owns club data and rules. The other services display data, send requests, or complete outside work.

Website Worker

Website pages

Shows public pages and the dashboard. It sends API requests through a private link between Cloudflare Workers.

API Worker

Rules and records

Checks identity and permissions, applies limits, updates D1 and R2, and adds a digital signature to Discord events.

Discord Worker

Discord changes

Checks Discord interactions and signed messages, then updates roles, DMs, posts, and channels.

Discord Gateway

Live connection

Keeps Discord’s live connection on a VPS, a private server, and sends a small set of checked events to the Worker.

Email Worker

Receipts

Checks forwarded receipts, reads their PDF data, tracks retries in KV storage, and sends valid orders to the API.

Scheduler Worker

Scheduled jobs

Runs every thirty minutes and starts seven private API jobs. It cannot access D1 or Discord directly.

The wiki is separate from these services. Astro and Starlight build it as static HTML, Pagefind adds search, and Cloudflare Pages hosts it. You can read this guide even when the member API is unavailable.

The API can check a user’s identity, permissions, club records, and stored files. A request may start on the website, in Discord, from an email, or on a timer. The API still decides whether data can change.

The main rule is:

If club data changes, the request goes through the API.

This means Discord and the dashboard use the same equipment loan, membership, and request records.

The workspace uses several repositories. Each repository is deployed on its own.

RepositoryBuilt withRuns onConnects to
websiteAstro + React on WorkersCloudflare WorkerAPI Worker service binding
apiTypeScript WorkerCloudflare WorkerD1, three R2 buckets, Discord Worker, email providers and verification services
discordWorker + Node.js GatewayCloudflare Worker + VPSAPI Worker, Discord REST, Discord Gateway, VPC service
email-workerTypeScript WorkerCloudflare WorkerEmail Routing, KV, API Worker
scheduler-workerTypeScript WorkerCloudflare WorkerAPI Worker only
wikiAstro + StarlightCloudflare PagesNone; it works on its own

Service bindings are private links between Cloudflare Workers, so their traffic does not use a public address. The services still use shared secrets and signed messages. These checks tell the receiving service who sent a request and whether it changed on the way.

Technology

Tools used by the platform

Each service has a small, specific job.

Interface

Astro

Builds the website shell and the static wiki

Interface

React

Runs interactive parts of the public site and dashboard

Foundation

TypeScript

Provides one language for every Worker and web app

Interface

Tailwind CSS

Styles the pages and their responsive layouts

Interface

Starlight + Pagefind

Organizes the wiki and builds its search index

Cloudflare

Cloudflare Workers

Runs the website, API, Discord, email, and scheduler services

Cloudflare

Cloudflare Pages

Hosts and deploys this static wiki

Cloudflare

D1

Stores the club records used by the API

Cloudflare

R2

Stores gallery, competition, avatar, merchandise, and leadership media

Cloudflare

KV

Tracks receipt intake, leases, and retries

Cloudflare

Email Routing

Sends TooCOOL receipts to the Email Worker

Operations

Wrangler

Builds and deploys Workers, and manages bindings, migrations, and secrets

Identity

Better Auth

Manages sessions, accounts, passkeys, 2FA, and Discord links

Identity

Turnstile

Checks for bots on public account and request forms

Data

Drizzle ORM

Provides typed database access in the API Worker

Automation

Discord

Provides commands, roles, DMs, channels, and server events

Automation

discord.js

Keeps the Discord Gateway connection open on the VPS

Foundation

Node.js

Runs the VPS Gateway and local development tools

Data

postal-mime + unpdf

Reads email messages and extracts text from receipt PDFs

Communication

Resend

Sends membership and activation emails

Operations

GitHub Actions

Runs checks and deploys services to Cloudflare

This guide does not include secret values, private IDs, or credentials. Live routes and VPS settings may change before this page is updated.

Expanded photograph