Files
quiz/README.md
ameer 7001a51803 deploy: add bootstrap.sh + Caddyfile + systemd unit + demo pool
One-shot deploy for fresh Ubuntu 24.04 root SSH:
  curl -fsSL https://gitea.ahkhan.me/apps/quiz/raw/branch/master/deploy/bootstrap.sh | bash

bootstrap.sh: idempotent stage-by-stage installer for Caddy, Python venv,
quiz system user, repo clone to /opt/quiz, env-var prompts, systemd unit,
Caddyfile, and a healthz check. Reattaches /dev/tty so curl|bash can read
the admin password interactively.

quiz.service: uvicorn under the quiz system user (no shell, no SSH),
ProtectSystem=full, ProtectHome=true, PrivateTmp=true, NoNewPrivileges=true.

Caddyfile.tpl: reverse_proxy 127.0.0.1:8001 with auto Let's Encrypt;
DOMAIN substituted at install time.

examples/pool_example.json: generic demo pool, schema reference only.

README rewritten around the deploy flow + class-day lifecycle.
2026-05-02 20:13:40 +08:00

78 lines
2.3 KiB
Markdown

# 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@<ip>:/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).