fix(infra): plug operational defaults — pg restart, proxy timeout, env template (0.87.1)

Three operational gaps tripped a recent review:

1. **Postgres had no `restart:` policy.** tor / docker-socket-proxy /
   vision-manager all set `unless-stopped`; pg was the lone exception.
   A transient OOM or panic left backend's `depends_on: service_healthy`
   blocking every future restart and took the stack offline. Add
   `unless-stopped` on postgres and on backend/frontend in the base
   compose so the prod overlay is the same shape.

2. **`BACKEND_PROXY_TIMEOUT_MS` was documented but silently a no-op.**
   `.env.example` carried it but `docker-compose.yml` never forwarded it
   into the frontend service env, so the value never reached
   `hooks.server.ts`. Wire it through.

3. **`.env.example` omitted required env vars.** Operators copying the
   template got no admin bootstrap, no boot-seed crawler URL, no
   analysis configuration. Add: `ADMIN_USERNAME`, `ADMIN_PASSWORD`,
   `PRIVATE_MODE`, `ALLOW_SELF_REGISTER`, `CRAWLER_START_URL`,
   `CRAWLER_CDN_HOST`, `ANALYSIS_ENABLED`, `ANALYSIS_VISION_URL`,
   `ANALYSIS_VISION_MODEL`, `ANALYSIS_WORKERS`,
   `ANALYSIS_JOB_TIMEOUT_SECS`, `ANALYSIS_API_KEY` — each with the
   comment block that explains seed-vs-runtime semantics.

Also adds `frontend/vite.config.ts.timestamp-*.mjs` to `.gitignore` — a
crashed dev server leaves these transient files behind otherwise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-22 20:23:56 +02:00
parent 9f7dfe4d4e
commit b14ed02670
6 changed files with 73 additions and 3 deletions

View File

@@ -69,6 +69,27 @@ CORS_ALLOWED_ORIGINS=
# value the browser uses. # value the browser uses.
ADMIN_ALLOWED_ORIGINS= ADMIN_ALLOWED_ORIGINS=
# ----- Admin bootstrap -----
# When BOTH are set and non-empty, the backend ensures a user with this
# username exists at startup, promotes it to admin, and (for a brand-new
# row only) sets the password. An existing user's password is NEVER
# overwritten by this — rotate via the dashboard or `/auth/me/password`.
# Leave BOTH empty in a fully provisioned deploy.
ADMIN_USERNAME=
ADMIN_PASSWORD=
# ----- Site-wide auth gates (env-ONLY) -----
# PRIVATE_MODE: when `true`, every endpoint except a small public allowlist
# (/health, /auth/config, /auth/login, /auth/logout) demands a valid
# session — anonymous reads return 401. Self-registration is also
# force-disabled regardless of ALLOW_SELF_REGISTER. Default `false`.
PRIVATE_MODE=false
# ALLOW_SELF_REGISTER: when `false`, /auth/register returns 403 and the
# frontend hides its register affordance. Admins can still mint accounts
# via /admin/users. Default `true` (open registration). Forced to `false`
# when PRIVATE_MODE=true.
ALLOW_SELF_REGISTER=true
# ----- Upload limits ----- # ----- Upload limits -----
# Per-request body cap. axum rejects oversized requests with 413 before # Per-request body cap. axum rejects oversized requests with 413 before
# our handlers run. Default 200 MiB. # our handlers run. Default 200 MiB.
@@ -182,6 +203,17 @@ BACKEND_PROXY_TIMEOUT_MS=300000
# analysis ANALYSIS_API_KEY. The important site levers (PRIVATE_MODE, # analysis ANALYSIS_API_KEY. The important site levers (PRIVATE_MODE,
# ALLOW_SELF_REGISTER) also remain env-only by design. # ALLOW_SELF_REGISTER) also remain env-only by design.
# #
# Crawler boot seeds (effective only on first boot, then editable from the
# dashboard):
# CRAWLER_START_URL The catalog listing URL the crawler walks. Without
# it, the cron is disabled (no daemon-driven sweeps;
# force-resync from the dashboard still works).
# CRAWLER_CDN_HOST Distinct host the source serves images from. Used to
# set a slower rate limit (CRAWLER_CDN_RATE_MS) and
# seed the download allowlist.
CRAWLER_START_URL=
CRAWLER_CDN_HOST=
#
# New analysis knobs (all optional, all seed defaults): # New analysis knobs (all optional, all seed defaults):
# ANALYSIS_TEMPERATURE Sampling temperature. Default 0 (deterministic). # ANALYSIS_TEMPERATURE Sampling temperature. Default 0 (deterministic).
# ANALYSIS_SYSTEM_PROMPT Override the single-call vision system prompt. # ANALYSIS_SYSTEM_PROMPT Override the single-call vision system prompt.
@@ -190,6 +222,30 @@ BACKEND_PROXY_TIMEOUT_MS=300000
# Leave the prompt vars unset to use the built-in defaults (also editable, # Leave the prompt vars unset to use the built-in defaults (also editable,
# with a per-prompt "reset to default", in the dashboard). # with a per-prompt "reset to default", in the dashboard).
# ----- Analysis (vision) — boot seeds + env-only secret -----
# The page-analysis worker (off by default) POSTs each page image at a
# Chat-Completions-compatible vision endpoint and persists OCR + tags.
# All fields except ANALYSIS_API_KEY are boot seeds for the app_settings
# row and switch to dashboard-editable once persisted.
#
# ANALYSIS_ENABLED Turn the worker on at first boot. Toggleable live in
# the dashboard. Default `false`.
ANALYSIS_ENABLED=false
# ANALYSIS_VISION_URL /v1/chat/completions endpoint. Required when enabled.
# For the bundled vision container, use
# http://mangalord-vision:8000/v1/chat/completions.
ANALYSIS_VISION_URL=
# ANALYSIS_VISION_MODEL Model id the endpoint expects (`model:` field).
ANALYSIS_VISION_MODEL=
# ANALYSIS_WORKERS Concurrent vision dispatches. Default 1.
ANALYSIS_WORKERS=1
# ANALYSIS_JOB_TIMEOUT_SECS Hard upper bound per vision call before the
# job is acked failed (backoff). Default 600.
ANALYSIS_JOB_TIMEOUT_SECS=600
# ANALYSIS_API_KEY env-ONLY. Bearer-attached to every vision call; never
# persisted, never logged.
ANALYSIS_API_KEY=
# ----- Vision autoscaling (the `ai` compose profile) ----- # ----- Vision autoscaling (the `ai` compose profile) -----
# The mangalord-vision (llama.cpp) container pins ~4.4 GiB and has no # The mangalord-vision (llama.cpp) container pins ~4.4 GiB and has no
# idle-unload, so the `vision-manager` sidecar starts it on demand and # idle-unload, so the `vision-manager` sidecar starts it on demand and

4
.gitignore vendored
View File

@@ -8,6 +8,10 @@
/frontend/build /frontend/build
/frontend/test-results /frontend/test-results
/frontend/playwright-report /frontend/playwright-report
# Vite writes these transient files next to vite.config.ts while the dev
# server is running, then deletes them on clean shutdown — but a crashed
# server leaves them behind. Keep them out of `git status` either way.
/frontend/vite.config.ts.timestamp-*.mjs
# Local storage volume (manga files). `/data` is the root path the # Local storage volume (manga files). `/data` is the root path the
# compose volume mounts at; `/backend/data` is where the dev backend # compose volume mounts at; `/backend/data` is where the dev backend

2
backend/Cargo.lock generated
View File

@@ -1517,7 +1517,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]] [[package]]
name = "mangalord" name = "mangalord"
version = "0.87.0" version = "0.87.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"argon2", "argon2",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "mangalord" name = "mangalord"
version = "0.87.0" version = "0.87.1"
edition = "2021" edition = "2021"
default-run = "mangalord" default-run = "mangalord"

View File

@@ -18,6 +18,11 @@ services:
interval: 5s interval: 5s
timeout: 5s timeout: 5s
retries: 10 retries: 10
# Without this, a single Postgres crash leaves backend's
# `depends_on: service_healthy` blocking every future restart and
# takes the whole stack offline. Match the policy already set on
# tor / docker-socket-proxy / vision-manager.
restart: unless-stopped
tor: tor:
# SOCKS5 proxy for the crawler, plus a control port so the backend # SOCKS5 proxy for the crawler, plus a control port so the backend
@@ -106,6 +111,7 @@ services:
# development). # development).
expose: expose:
- "8080" - "8080"
restart: unless-stopped
frontend: frontend:
build: ./frontend build: ./frontend
@@ -115,8 +121,12 @@ services:
# SvelteKit's hooks.server.ts proxies /api/* to this URL so the # SvelteKit's hooks.server.ts proxies /api/* to this URL so the
# browser only ever talks to :3000 and cookies stay same-origin. # browser only ever talks to :3000 and cookies stay same-origin.
BACKEND_URL: http://backend:8080 BACKEND_URL: http://backend:8080
# Per-request wall-clock cap for the /api/* reverse proxy. Defaults
# to 300000 (5 min) in hooks.server.ts; raise/lower via .env.
BACKEND_PROXY_TIMEOUT_MS: ${BACKEND_PROXY_TIMEOUT_MS:-300000}
ports: ports:
- "3000:3000" - "3000:3000"
restart: unless-stopped
# ----- Vision autoscaling (profile: ai) ----------------------------------- # ----- Vision autoscaling (profile: ai) -----------------------------------
# Two extra containers that idle-stop the mangalord-vision (llama.cpp) # Two extra containers that idle-stop the mangalord-vision (llama.cpp)

View File

@@ -1,6 +1,6 @@
{ {
"name": "mangalord-frontend", "name": "mangalord-frontend",
"version": "0.87.0", "version": "0.87.1",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {