Add deployment reading windows and progress-aware quiz unlock

This commit is contained in:
Codex committed 2026-10-14 15:34:55 +02:00
1 parent edbc9c6056
commit d8eba9169f
15 files changed
+471 -5

No files matched your search

+76
View File
@@ -0,0 +1,76 @@
# 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.
## Docker configuration
Set these deployment variables on the reader service, then recreate **only the
reader**. 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.
## 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 <catalog.json>` 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.