diff --git a/.env.example b/.env.example index 9c50ffb..c764a42 100644 --- a/.env.example +++ b/.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 diff --git a/.gitignore b/.gitignore index a22c07f..bc6f749 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/backend/Cargo.lock b/backend/Cargo.lock index cb907d4..0bbae31 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -1517,7 +1517,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "mangalord" -version = "0.87.0" +version = "0.87.1" dependencies = [ "anyhow", "argon2", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index edc2e71..36cdf93 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mangalord" -version = "0.87.0" +version = "0.87.1" edition = "2021" default-run = "mangalord" diff --git a/docker-compose.yml b/docker-compose.yml index f995b43..6f02d2d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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) diff --git a/frontend/package.json b/frontend/package.json index 06d336f..20a8f02 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "mangalord-frontend", - "version": "0.87.0", + "version": "0.87.1", "private": true, "type": "module", "scripts": {