Skip to content

Architecture

RankHub is a full-stack application deployed on Cloudflare's edge network. This page describes the high-level architecture and data flow.

System Overview

                    +------------------+
                    |   Cloudflare CDN |
                    +--------+---------+
                             |
              +--------------+--------------+
              |                             |
     +--------v--------+         +----------v-----------+
     |  SolidStart App  |         |  Durable Objects     |
     |  (Cloudflare     |<------->|  - LeaderboardDO     |
     |   Pages/SSR)     |  WS     |  - RateLimitDO       |
     +--------+---------+         |  - TokenTrackingDO   |
              |                   +----------+-----------+
              |                              |
     +--------v---------+         +----------v-----------+
     |   PostgreSQL     |         |  Cloudflare Storage  |
     |   (Supabase)     |<------->|  (DO state + alarms)|
     +------------------+         +----------------------+

Components

Web App (apps/web/)

SolidStart application with server-side rendering, file-based routing, and TailwindCSS v4.

  • Handles HTTP requests, serves HTML, and provides the REST API via Hono.
  • Runs on Cloudflare Pages with SSR enabled.
  • File-based routing: /category/[slug], /leaderboard/[slug], /vote, /submit, etc.
  • API routes under apps/web/src/routes/api/.

Durable Object Worker (apps/do-worker/)

Cloudflare Durable Objects worker that provides stateful, per-subcategory leaderboard management.

  • LeaderboardDO -- One instance per subcategory. Maintains an in-memory Map<string, ItemRating> for sub-100ms vote processing. Processes votes using the Glicko-2 engine, syncs to PostgreSQL every 30 seconds or every 100 votes via write-back caching. Supports WebSocket connections for real-time leaderboard updates.
  • RateLimitDO -- Distributed rate limiting with sliding window counters. One instance per rate limit scope (e.g., "vote", "api"). Auto-cleans expired entries every 5 minutes.
  • TokenTrackingDO -- Tracks token usage for authenticated users.

Rating Engine (packages/engine/)

Pure TypeScript implementation of the Glicko-2 algorithm using integer storage format.

  • glicko.ts -- Core rating computation: volatility update (Illinois algorithm), rating/RD update.
  • matchup.ts -- Matchup selection algorithm that considers rating uncertainty and recent matchup history to provide informative pairings.
  • Uses TypeBox schemas for runtime validation of all data structures.

Database Layer (packages/db/)

Drizzle ORM layer over PostgreSQL (hosted on Supabase).

  • Schema definitions with TypeScript inference.
  • Migration system: Drizzle auto-migrations plus manual SQL migrations for complex changes.
  • Manual migrations live in packages/db/migrations/manual_*.sql with idempotency tracking.

Data Flow: Vote Processing

  1. Client requests a matchup via GET /api/v1/matchup?subcategory=<slug>.
  2. Server fetches items from Supabase, selects a matchup using the engine's selectMatchup().
  3. Client submits a vote to POST /api/v1/vote with a Turnstile token.
  4. Vote routes to the LeaderboardDO instance for that subcategory.
  5. DO processes the vote with Glicko-2 via processVote(), updating in-memory state.
  6. DO syncs to Supabase on a 30-second alarm or after 100 accumulated votes.
  7. WebSocket-connected clients receive real-time rating updates.

Deployment

  • Web app: Cloudflare Pages with SSR (SolidStart preset).
  • DO worker: Cloudflare Workers with Durable Objects binding.
  • Database: Supabase managed PostgreSQL with transaction pooler for edge connections.
  • CI/CD: Forgejo Actions (.forgejo/workflows/) -- runs migrations, builds, and deploys on push.