Files
ad/molodetz/templates/docs/prose/operator.md
T
retoor 9fb4d65787 Member invites, gallery resync, content and operator docs
- Invite flow: admin issue/revoke on join requests, public single-use
  claim links (hash-only tokens, 7-day expiry, no state reveal), claim
  creates the Member account and marks the request accepted
- Gallery: admin status page plus resync endpoint; sync refreshes
  thumbnails whose content changed; tools/gallery contract and checker
- Docs: public content page, admin-only operator runbook, api.md
  invite/gallery sections, all routes in the live API docs, docs
  reachability gate test
- Screenshots cover the new pages; version 1.0.18
2026-10-06 02:56:08 +02:00

3.6 KiB

Operator runbook

This page is only visible to administrators. It covers the flows that move people and content through the system: invites, gallery updates, trash, caches and the environment rules.

Member invites

Join requests end in membership through an invite link. The full flow:

  1. Read the request under Admin, Join requests. Check link fetches the linked work once and stores the outcome on the request.
  2. Move the status to contacted while talking, declined to refuse. A declined request cannot receive an invite.
  3. Press Issue invite. The claim link is shown once on the confirmation page: copy it and send it to the person yourself. There is no email sending.
  4. The person opens the link, picks a name and password and accepts the house rules. Claiming creates a Member account, logs them in and flips the request to accepted.

Rules the code enforces:

  • One open invite per request. Issuing a new one revokes the previous.
  • Single use, 7 day expiry by default (invite_expiry_days setting).
  • Only a hash of the token is stored; a database read never yields a usable link.
  • Unknown, used, revoked and expired links all answer identically (404, same message), so links cannot be probed for state.
  • If the contact looked like an email address, the claim must use that same address. Handle-style contacts leave the email free for the claimer to fill in.
  • Revoke invite kills the open link without touching the request.

API: POST /admin/joins/{uid}/invite returns {"claim_url", "expires_at"} in data (JSON only; the HTML form renders the one-time page instead). POST /admin/joins/{uid}/invite/revoke returns {"revoked": n}. Public claim is GET and POST /invite/{token}.

Source files plus catalogue entries arrive through deploy. After deploy, press Resync under Admin, Gallery (or POST /admin/gallery/resync). The status page shows live flyer and meme counts and lists catalogued files missing from disk. Resync refreshes thumbnails whose content changed and retires removed entries. Boot runs the same sync, so a production rebuild never needs the button.

Trash

Soft-deleted rows carry a deleted_at stamp (UTC ISO). Restore and purge match the exact stamp across every soft-delete table, so one trash event restores or purges as a unit. Purge is permanent; there is no undo.

Sessions and suspension

Login resolution order is session cookie, X-API-KEY, Bearer, Basic; see API and authentication. Sessions live 7 days, 30 with remember me (session_max_age_days, session_remember_days). A suspended account (suspended_until in the future) is refused on every mutating route outside /auth with 403. Users whose terms_version lags behind the setting are sent to /terms on mutating routes (redirect for browsers, 403 with a redirect target for JSON) until they accept.

Caches

Short TTLs everywhere; defaults below, environment variables may override per deploy:

Cache Default
landing page 30 s
settings 60 s
version 1 s
unread counts 10 s
sitemap 3600 s
auth user lookups 300 s

Docs prose is additionally cached in the process for its lifetime: doc text changes need a staging restart or a production rebuild to show.

Environments and data

All runtime data lives under ./data/[env] (database, blobs, backups, logs). Never anything outside it. Production data is holy: copies flow production to staging only, never back. Staging runs the dev server, so file changes show without restart except for the process-lifetime caches above. Production is a baked image and needs a rebuild for code, prose and media changes.