fix(backend): bind session key to both secrets and guard no-op chapter saves

Final-review fix wave over the web UI branch.

- sessionKey now derives from API_TOKEN and WEB_PASSWORD with a \x00
  separator, so rotating the password logs every browser out too.
- uiChapter only clears last_chapter_url when the number actually
  changes. The form is pre-filled, so a bare tap of Save resubmits the
  same value; that used to destroy the chapter URL silently while
  updated_at stayed put, degrading Continue to the series index page.
- MANGA_WEB_HOST is now required by the prod override rather than
  falling back to manga.example.com, matching MANGA_API_HOST.
- Comment fixes: static cache rationale, pruneLocked aliasing
  invariant, and the stale "3 routes" line in CLAUDE.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 03:18:00 +07:00
parent aac00ec01c
commit 22bf68f12f
8 changed files with 88 additions and 28 deletions
+7 -2
View File
@@ -93,8 +93,13 @@ The browser UI is served by the same container on a second hostname.
Leaving `WEB_PASSWORD` unset is safe: the web routes are not registered and `/`
returns 404. The userscript's API on `MANGA_API_HOST` is unaffected either way.
Sessions are signed with a key derived from `API_TOKEN`, so rotating the token
logs every browser out. The session cookie lasts 60 days.
`MANGA_WEB_HOST` itself is required by the prod override regardless — like
`MANGA_API_HOST`, its Traefik label has no fallback, so `docker compose up`
refuses to start without it even if `WEB_PASSWORD` is unset and the web UI is
otherwise dormant.
Sessions are signed with a key derived from `API_TOKEN` and `WEB_PASSWORD`, so
rotating either one logs every browser out. The session cookie lasts 60 days.
---