Architecture
Overview
Quizzz runs on GKE with three main components:
┌─────────────────┐
│ Cloudflare │
│ (DNS + CDN) │
└────────┬────────┘
│
┌────────┴────────┐
│ Traefik │
│ (Ingress) │
└────────┬────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌────────┴───┐ ┌──────┴─────┐ ┌─────┴──────┐
│ Next.js │ │ PostgREST │ │ Worker │
│ Web │ │ (API) │ │ (BullMQ) │
└────────┬───┘ └──────┬─────┘ └─────┬──────┘
│ │ │
│ ┌──────┴──────┐ │
│ │ PostgreSQL │ │
│ └─────────────┘ │
│ │
└──────────┬──────────────────┘
│
┌────┴────┐
│ Redis │
└─────────┘Multi-Tenancy
All data tables are isolated by teacher_id. The middleware performs host-based routing:
- Main domain (
quizzz.techtranslab.com) — Marketing landing page - Custom domains — Tenant-specific landing pages
- Admin paths on custom domains redirect to main app host
Provider Pattern
Pluggable adapters for external services:
| Concern | Interface | Implementations |
|---|---|---|
| Auth | src/lib/auth/types.ts | postgres-*, authjs-* |
| Storage | src/lib/storage/types.ts | gcs-storage |
| Domains | src/lib/domains/types.ts | cloudflare |
| AI | src/lib/ai/types.ts | gemini, openai, anthropic, openrouter |
AI Gateway
src/lib/ai/gateway.ts resolves whether a teacher uses managed credits (pro plan) or BYOK (bring-your-own-key):
- Pro teachers with credits → platform-managed provider key
- Otherwise → teacher's stored keys in preference order
Background Worker
Batch quiz generation uses BullMQ with Redis:
- Web enqueues job via
POST /api/admin/quizzes/batches/{id}/run - Worker picks up job, runs AI generation with concurrency control
- Frontend polls
GET /api/admin/quizzes/batches/{id}/statusevery 3 seconds