Architecture¶
Quicz runs as a single Node.js process on a single port. A custom HTTP server (server.ts) hosts both the Next.js request handler and a Socket.IO server, sharing the same listener. SQLite (via Drizzle ORM and better-sqlite3) is the single source of truth for session state; Socket.IO is used only as a broadcast mechanism.
High-level¶
flowchart LR
A[Admin browser] -- HTTP + WS --> S((server.ts))
P[Participant browser] -- HTTP + WS --> S
S --> N[Next.js App Router]
S --> IO[Socket.IO]
N <--> DB[(SQLite)]
IO <--> DB
Component diagram¶
flowchart LR
subgraph Clients
A[Admin browser<br/>/admin, /presenter]
P[Participant browser<br/>/join, /play/:code]
end
subgraph Server["Node.js process (server.ts)"]
direction TB
H[HTTP listener<br/>single port]
N[Next.js App Router<br/>pages + API routes]
S[Socket.IO<br/>rooms: session:CODE, admin:ID]
M[Drizzle migrations<br/>run at boot]
T[autoLockTimers<br/>in-memory map]
end
DB[(SQLite<br/>WAL, FK on)]
A -- HTTPS --> H
P -- HTTPS --> H
A -- WebSocket --> H
P -- WebSocket --> H
H --> N
H --> S
N <--> DB
S <--> DB
M --> DB
S -.uses.-> T
Session phase machine¶
stateDiagram-v2
[*] --> lobby
lobby --> question_open: admin:start / admin:next
question_open --> question_locked: admin:lock-voting<br/>(or time limit)
question_locked --> results: admin:show-results
results --> results: admin:reveal-correct<br/>(sets correctRevealed)
results --> question_open: admin:next (more questions)
results --> final: admin:show-final
final --> [*]
The full spec — data model, socket events, payload shapes — lives in DESIGN.md in the repo.