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:
56
.env.example
56
.env.example
@@ -69,6 +69,27 @@ CORS_ALLOWED_ORIGINS=
|
||||
# value the browser uses.
|
||||
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 -----
|
||||
# Per-request body cap. axum rejects oversized requests with 413 before
|
||||
# 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,
|
||||
# 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):
|
||||
# ANALYSIS_TEMPERATURE Sampling temperature. Default 0 (deterministic).
|
||||
# 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,
|
||||
# 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) -----
|
||||
# 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
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -8,6 +8,10 @@
|
||||
/frontend/build
|
||||
/frontend/test-results
|
||||
/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
|
||||
# compose volume mounts at; `/backend/data` is where the dev backend
|
||||
|
||||
2
backend/Cargo.lock
generated
2
backend/Cargo.lock
generated
@@ -1517,7 +1517,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||
|
||||
[[package]]
|
||||
name = "mangalord"
|
||||
version = "0.87.0"
|
||||
version = "0.87.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mangalord"
|
||||
version = "0.87.0"
|
||||
version = "0.87.1"
|
||||
edition = "2021"
|
||||
default-run = "mangalord"
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@ services:
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
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:
|
||||
# SOCKS5 proxy for the crawler, plus a control port so the backend
|
||||
@@ -106,6 +111,7 @@ services:
|
||||
# development).
|
||||
expose:
|
||||
- "8080"
|
||||
restart: unless-stopped
|
||||
|
||||
frontend:
|
||||
build: ./frontend
|
||||
@@ -115,8 +121,12 @@ services:
|
||||
# SvelteKit's hooks.server.ts proxies /api/* to this URL so the
|
||||
# browser only ever talks to :3000 and cookies stay same-origin.
|
||||
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:
|
||||
- "3000:3000"
|
||||
restart: unless-stopped
|
||||
|
||||
# ----- Vision autoscaling (profile: ai) -----------------------------------
|
||||
# Two extra containers that idle-stop the mangalord-vision (llama.cpp)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mangalord-frontend",
|
||||
"version": "0.87.0",
|
||||
"version": "0.87.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user