# Deployment-controlled reading hours and quiz The reader enforces reading hours on both `GET /api/chapter` and chapter page-image requests under `/lib/` (HTTP 423 outside hours). The dashboard, manga metadata, covers, progress, reading-time summaries, scraper and administrator pages remain available. A reader tab already open when a window ends checks access every 15 seconds and returns to the gate. Chapter images use `Cache-Control: no-store` when the limiter is configured. Already downloaded images in a browser or files available directly on disk cannot be recalled; this is a self-imposed server access rule, not DRM. There is no schedule-changing API or UI. Signed-in readers and admins can view the effective weekly schedule and timezone under **Settings → Reading hours**; that page is read-only. ## Docker configuration Set these deployment variables in the Compose `.env` file next to `docker-compose.yml`, then recreate **only the reader**. The `reader` service passes them through to the container. `READER_IMAGE` selects a reader-only release while `APP_IMAGE` continues to select the scraper and Sentinel image. Leaving `READING_WINDOWS_JSON` empty disables the limiter. Day keys are `0` Sunday through `6` Saturday. Each day has any number of `[start,end]` intervals; an end earlier than its start carries into the next day. `24:00` is valid only as an end. Intervals are start-inclusive and end-exclusive, resolved using the IANA timezone, including daylight-saving changes. ```dotenv READING_WINDOWS_JSON='{"0":[["08:00","01:00"]],"1":[["07:00","12:00"],["13:00","24:00"]],"2":[["07:00","24:00"]],"3":[["07:00","24:00"]],"4":[["07:00","24:00"]],"5":[["07:00","24:00"]],"6":[["08:00","01:00"]]}' READING_TIMEZONE=Europe/Berlin READING_QUIZ_UNLOCK_MINUTES=60 READING_QUIZ_CATALOG_PATH=/data/reading-quiz.json ``` The Monday split above illustrates multiple on/off periods; replace it with `[["07:00","24:00"]]` for an uninterrupted weekday. The Saturday and Sunday windows extend to 01:00 on the following mornings. A malformed timezone, schedule, unlock length or catalog stops the reader at startup rather than silently removing the restriction. `READING_QUIZ_UNLOCK_MINUTES` accepts 1–1440. The scraper is independent and must not be restarted for this configuration. Until a reviewed catalog is installed at `READING_QUIZ_CATALOG_PATH`, the outside-hours gate cannot offer a quiz. It does not relax the schedule. ## Question bank and progress watermark The bank is a deployment-managed JSON file, separate from `manga.json` and from the scraper. See [`config/reading-quiz.example.json`](../config/reading-quiz.example.json). Its `manga` keys are **exact library folder IDs**. Each question has a stable ID, prompt, accepted answer variants, an evidence citation, and at least one `requires` chapter ID. The chapter IDs are the reader's IDs (for example `1/12`, not the on-disk `v01/c0012`). Every required chapter must be marked completed for that user before the question enters their pool. This supports a single watermark or a set of specific sections. Five eligible questions are needed to offer a quiz; an empty bank simply leaves outside-hours reading locked. A question's answers and evidence never go to the browser. The challenge randomly samples five progress-eligible questions across *all* library manga, not only the one being opened. It asks them sequentially, accepts unlimited retries, and has no answer timer. Accepted variants are normalized for case, punctuation and accents; one typo is tolerated for answers of five or more characters, two for answers of eleven or more. Starting a new visit invalidates the previous challenge, and leaving the page abandons it. Passing all five grants that user reading access across manga for the configured number of minutes, persisted in `db.json` across reader restarts. Questions are not shown before their watermark; this depends on the reader's existing self-reported completion records. Validate a proposed file with `node tools/validate-reading-quiz.js ` before pointing the reader at it. For an eventual research agent: write **drafts** with source citations, aliases and proposed chapter watermarks, then have a human verify identity, answer and spoiler boundary. Only a reviewed catalog should be copied to the configured path and loaded by restarting the reader. No wiki or transcript fetching is performed by the reader itself. ## Testing and rollback `node tools/test-compose.js --reading-limit-ui` creates a disposable Compose fixture with two progress-qualified sample manga, tests chapter and image denial, quiz flow and the one-hour unlock, then tears it down. Add `--keep` to leave an isolated playable instance locked for manual review; its printed URL and fixture path identify it. Main data and the running main scraper are not mounted. To roll back a future main deployment, restore the previous reader image and configuration, recreate only the reader, and preserve current `db.json` and library. The additional `readingAccess` field is backward-safe.