# Live in-lecture quiz portal FastAPI + WebSocket + SQLite quiz portal designed for ~40 students per class session. Single-process, in-memory room manager, vanilla HTML/JS front-end, Caddy in front for TLS. ## Quick local run ```bash python3 -m venv .venv . .venv/bin/activate pip install -e '.[dev]' cp .env.example .env # edit QUIZ_SECRET_KEY + QUIZ_ADMIN_PASSWORD uvicorn app.main:app --host 127.0.0.1 --port 8001 --reload ``` Open `http://127.0.0.1:8001/admin/`, log in, create a quiz pool from a JSON pool file (see `examples/pool_example.json` for the schema), create a session, and share the join URL. ## VPS deploy (one-shot) On a fresh Ubuntu 24.04 LTS root SSH: ```bash curl -fsSL https://gitea.ahkhan.me/apps/quiz/raw/branch/master/deploy/bootstrap.sh | bash ``` The bootstrap: 1. apt-installs Caddy + Python venv tooling 2. Creates a `quiz` system user (no shell, no SSH) 3. Clones this repo to `/opt/quiz` 4. Builds the venv and installs the app 5. Generates `QUIZ_SECRET_KEY`, prompts for `QUIZ_ADMIN_PASSWORD` 6. Drops the systemd unit and Caddyfile 7. Starts both services 8. Curl-checks `127.0.0.1:8001/healthz` After: `quiz.ahkhan.me` is live with auto-Let's-Encrypt cert. To override the domain or repo URL, set `DOMAIN=` or `REPO_URL=` in the environment before running the script. ## Class-day workflow 1. Provision Aliyun Intl HK ECS pay-as-you-go (`ecs.t6-c2m1.large`, Ubuntu 24.04 LTS). 2. Point DNS A-record `quiz.ahkhan.me` at the new IP. 3. SSH in as root, run the curl|bash one-liner above. 4. Open `quiz.ahkhan.me/admin/`, log in, upload the week's pool JSON, create a session. 5. Share the QR / join URL with the class. 6. After class: `scp root@:/opt/quiz/quiz.db ./backups/quiz-YYYY-MM-DD.db` 7. Destroy the instance. ## Quiz pool files Real pool JSON files contain answer keys and **must not be committed** to this repo. `.gitignore` excludes `examples/*_pool.json` (only `examples/pool_example.json` may be tracked). Author pools elsewhere (e.g., your course-material directory) and upload at runtime via the admin UI. ## Tests ```bash pytest -q pytest --cov=app ``` For the WebSocket adversarial stress harness (Node.js + Playwright, runs in a tmux loop), see `tests/stress/README.md`. ## Spec `SPEC.md` documents the locked v1.0 design (state machine, scoring, identity flow, all WS message types).