Appearance
System Architecture
High-level shape
rendering diagram…
drag to pan · ctrl / ⌘ + scroll to zoom
Three properties define the design:
- No dedicated backend service. Everything a backend would own is covered by a managed piece: persistence and authorization by Firestore + security rules, request/response endpoints by Pages Functions, scheduled work by Workers, code execution by Judge0. The tradeoff (authorization logic in rules instead of API code) is discussed in Challenges #4.
- Content is data, not code. Markdown never enters the Vite module graph — see Question Bank & Content Runtime.
- Secrets live server-side only. AI keys, the Judge0 auth token, the GitHub token for Docy, and the Firebase service-account key exist only in Cloudflare env vars / Wrangler secrets. The browser holds nothing sensitive; the public Firebase config is guarded by rules, not secrecy.
Request lifecycles
A DSA submission (Run / Submit)
rendering diagram…
drag to pan · ctrl / ⌘ + scroll to zoom
Concurrency to Judge0 is capped at 1 — measured empirically as optimal for the single-core free-tier VM (see Code Execution).
An AI-graded concept answer
rendering diagram…
drag to pan · ctrl / ⌘ + scroll to zoom
Lecture notes (Docy) into the learning workspace
SubjectLayout → /list-notes (directory listing) → /get-notes?path=… per lecture → markdown rendered with KaTeX + annotations layered on top (Notes System). The GitHub token authorizing access to the private Docy repo never leaves the Function.
Where state lives
| State | Home | Why |
|---|---|---|
| Identity/session | Firebase Auth (indexedDB persistence) | Survives refresh mid-exam; no cookie plumbing |
| User data (events, submissions, drafts, annotations, revisions, OA attempts/templates) | users/{uid}/… subcollections | Owner-only rules are trivial to state and audit |
| Solve progress per section | progress/{uid} | One doc per user, cheap snapshot |
| Community percentile data | problemStats/{slug} | Public-read aggregate, bucketed |
| Shared OA templates | publicOAs/{templateId} | Public-read, owner-write |
| Question metadata | Static JSON shards (/content-index/*.json) | CDN-cached, no DB reads for browsing |
| Question bodies | Static .md (+ .tests.json sidecars) / jsDelivr for CP | Fetched on demand, cache-friendly |
| UI state (theme, sidebar) | React contexts + localStorage | Not worth a network round-trip |
Full schema: Database Schema & Rules.
Failure & resilience posture
- AI: a 9-provider fallback chain — an outage or 429 on one provider falls through to the next; the echo stub keeps the UI honest when no key is configured (AI Pipeline).
- Judging: browser-driven judging survives tab closure via the OA Worker, which claims jobs with Firestore
updateTimepreconditions so it can never double-judge against a live tab (Workers). - Reminders: per-minute Cloudflare cron with optimistic-lock claims and delivered flags; the retired GitHub Actions cron remains only as a manual backstop (Scheduling).
- Deploys: stale-SPA issues are prevented by
_headerscache-control (HTML never cached, hashed assets immutable) — see Build & Deployment.