5.6 KiB
5.6 KiB
TryMe Gaming App — System Architecture (SYSTEM.md)
1. High-Level Overview
TryMe is a web platform designed for students to author, share, vote on, favourite, and play multiple-choice and write-in quizzes (0–40 questions on the public free tier). It packages a React 19 + TypeScript single-page frontend and a FastAPI + SQLAlchemy 2.0 backend into a single multi-stage container image, backed by either PostgreSQL or SQLite.
graph TB
Student["Student / Moderator Browser (SPA)"]
CLI["Automation / Study Script (X-API-Key)"]
Auth0["Auth0 Federated IdP (OIDC / JWKS)"]
subgraph Container["TryMe Container (:8000)"]
FastAPI["FastAPI HTTP & Static Layer (app/main.py)"]
AuthLayer["Session, Auth0 JWKS & API Key Guard (app/auth.py)"]
QuizSvc["Quiz Grading & Leaderboard Service (app/services/quiz_service.py)"]
SPA["Compiled React + Vite Assets (frontend/dist)"]
end
DB[("PostgreSQL 16 or SQLite + PVC")]
Student -->|"HTTPS / Cookie or Bearer JWT"| FastAPI
CLI -->|"HTTPS + X-API-Key"| FastAPI
FastAPI --> SPA
FastAPI --> AuthLayer
AuthLayer -->|"Verify OIDC / JWKS"| Auth0
AuthLayer --> QuizSvc
QuizSvc --> DB
2. CoreSubsystems
2.1 Authentication, Consent & API Keys (app/auth.py, app/routers/auth_routes.py, app/routers/users.py)
- Auth0 Federated Login:
/api/v1/auth/logininitiates an OAuth2/OIDC Authorization Code flow with signed anti-CSRF state (itsdangerous)./api/v1/auth/callbackexchanges the code, fetches/userinfo, provisions or updates theUserrow, and issues anHttpOnlysession JWT cookie (tryme_session). Direct Auth0 RS256 Bearer tokens are also verified via cached/.well-known/jwks.json. - Player Onboarding & Privacy: Users select a stylized animal icon (
fox,owl,bear,otter,koala,tiger,frog,penguin) and colorway (avatar-1..8), set a uniquenickname,first_name,last_name, optional integerage(never storing a birthday), inclusivegender(woman,man,non_binary,agender,genderqueer,two_spirit,other,prefer_not_to_say), and explicitly confirm permission to use public websites (public_website_consent). - Personal API Keys: Users generate
tm_live_<token>keys stored strictly as SHA-256 hashes (key_hash) with configurable expiration and one-click revocation (POST /api/v1/users/me/api-keys/{id}/expire).
2.2 Quiz Engine, Leaderboards & Voting (app/routers/quizzes.py, app/services/quiz_service.py)
- Free Tier Guardrails: Validated via Pydantic (
max_length=40) and route checks (0 <= len(questions) <= 40). - Question Formats: Each question supports either
multiple_choice(2–6 options) orwrite_in(whitespace-normalized, case-insensitive matching againstcorrect_answerplus optionalaccepted_answerssynonyms). - Score Aggregation: Every quiz card and detail response computes three distinct metrics in bulk SQL queries:
- Global Best Score: Highest
score_percentacross all attempts, paired with the top holder'snicknameand animal icon (ties broken by earliest completion). - User Latest Score: The signed-in player's most chronological recent
QuizAttempt. - User All-Time Best Score: The signed-in player's highest
QuizAttempton that quiz.
- Global Best Score: Highest
- Thumbs Up / Down Voting: Stored in
quiz_voteswith aUNIQUE(quiz_id, user_id)constraint (+1or-1, toggleable back to0). - Shareable URLs: Every quiz receives a unique
share_slug(e.g.,/quiz/solar-system-quick-ch-a1b2c3) routable directly in the SPA and backend.
2.3 Right-Hand Favourites Pane & Recycle Bin (app/routers/favourites.py, FavouritesPane.tsx)
sequenceDiagram
participant Main as Explore Feed Card
participant Rail as Right Favourites Pane
participant Bin as Pop-up Recycle Bin
participant API as FastAPI /api/v1/favourites
Main->>Rail: Drag quiz card (application/x-tryme-quiz-id)
Rail->>API: POST /api/v1/favourites {quiz_id, position}
API-->>Rail: Ordered favourites list
Rail->>Rail: Drag existing favourite (summons Recycle Bin)
alt Reorder inside rail
Rail->>API: PUT /api/v1/favourites/reorder {quiz_ids}
else Drop onto Recycle Bin
Rail->>Bin: Drop favourite item
Bin->>API: DELETE /api/v1/favourites/{quiz_id}
Bin-->>Rail: Show 7-second Undo bar
end
2.4 Moderation (app/routers/admin.py, ModeratorView.tsx)
- Moderators can be designated via
ADMIN_USERcontainer env var (matched againstauth_sub,email, ornickname) or claimed once at initial launch (POST /api/v1/admin/claim) when no moderator exists. - Moderators can suspend/restore accounts (
is_banned = Trueblocks quiz creation, submissions, and voting with403 Forbidden) and remove quizzes (is_removed = Truehides the quiz from public feeds and cleans up dangling favourites).
3. UI Design System
The frontend uses the Hallmark Hum (playful genre, --scope app) design system in frontend/src/styles/tokens.css and frontend/src/styles/app.css:
- Primary Brand Colors: Warm festive orange
#fb723a(oklch(70.6% 0.178 41)) paired with deep slate-navy#253450(oklch(32.5% 0.058 258)) over warm cream card stock (oklch(97.2% 0.012 72)). - Typography:
Chillax(500,600) for headings, body, and controls;Geist Monoexclusively for API key tokens;tabular-numson all scores, counts, and votes. - Accessibility & Motion: Instant
:focus-visiblerings, 44px touch targets, native<dialog>modals, keyboard reorder/delete fallbacks alongside HTML5 drag-and-drop, andprefers-reduced-motion: reducesupport.