Merge branch 'fix/prod-readiness-healthcheck-domain'
Some checks failed
Checks / Backend — cargo test + clippy + fmt (push) Failing after 1m14s
Checks / Frontend — vitest + svelte-check (push) Failing after 5m50s
Checks / E2E — typecheck + lint (push) Failing after 48s
E2E / Playwright E2E (chromium-desktop) (push) Failing after 6m44s
E2E / Cross-UA smoke matrix (push) Failing after 4m32s
Audit / cargo audit (backend) (push) Failing after 8m43s
Audit / npm audit (frontend) (push) Successful in 37s
Some checks failed
Checks / Backend — cargo test + clippy + fmt (push) Failing after 1m14s
Checks / Frontend — vitest + svelte-check (push) Failing after 5m50s
Checks / E2E — typecheck + lint (push) Failing after 48s
E2E / Playwright E2E (chromium-desktop) (push) Failing after 6m44s
E2E / Cross-UA smoke matrix (push) Failing after 4m32s
Audit / cargo audit (backend) (push) Failing after 8m43s
Audit / npm audit (frontend) (push) Successful in 37s
This commit is contained in:
35
.env.example
35
.env.example
@@ -16,6 +16,9 @@ DATABASE_URL=postgres://eventsnap:CHANGE_ME_use_a_strong_password@db:5432/events
|
||||
POSTGRES_USER=eventsnap
|
||||
POSTGRES_PASSWORD=CHANGE_ME_use_a_strong_password
|
||||
POSTGRES_DB=eventsnap
|
||||
# Connection pool size. Default 10. For a busy event (~100 guests polling the feed
|
||||
# + SSE + uploads at once) raise to ~30 so requests don't queue on a pool permit.
|
||||
DATABASE_MAX_CONNECTIONS=30
|
||||
|
||||
# ── Authentication ────────────────────────────────────────────────────────────
|
||||
# Generate with: openssl rand -hex 64
|
||||
@@ -40,19 +43,25 @@ MEDIA_PATH=/media
|
||||
# /media is publicly served, so exports here would be downloadable without auth.
|
||||
EXPORT_PATH=/exports
|
||||
|
||||
# ── Upload limits ─────────────────────────────────────────────────────────────
|
||||
DEFAULT_MAX_IMAGE_SIZE_MB=20
|
||||
DEFAULT_MAX_VIDEO_SIZE_MB=500
|
||||
|
||||
# ── Rate limiting ─────────────────────────────────────────────────────────────
|
||||
DEFAULT_UPLOAD_RATE_PER_HOUR=10
|
||||
DEFAULT_FEED_RATE_PER_MIN=60
|
||||
DEFAULT_EXPORT_RATE_PER_DAY=3
|
||||
|
||||
# ── Capacity ──────────────────────────────────────────────────────────────────
|
||||
DEFAULT_ESTIMATED_GUEST_COUNT=100
|
||||
# Fraction of total storage that triggers the "low storage" warning (0.0–1.0)
|
||||
DEFAULT_QUOTA_TOLERANCE=0.75
|
||||
# ── Runtime settings (upload limits, rate limits, capacity) ───────────────────
|
||||
# NOTE: These are NOT environment variables. Upload size caps, rate limits, guest
|
||||
# count and quota tolerance are stored in the database `config` table (seeded once
|
||||
# at first boot) and changed at runtime from the ADMIN DASHBOARD — the backend does
|
||||
# not read them from .env. Setting them here has no effect. Current seeded defaults:
|
||||
# upload rate 100 / hour / guest (raised from 10 by migration 015)
|
||||
# feed rate 60 / minute
|
||||
# export rate 3 / day
|
||||
# max image size 20 MB
|
||||
# max video size 500 MB
|
||||
# estimated guests 100
|
||||
# quota tolerance 0.75 (fraction of disk that triggers the low-storage warning)
|
||||
# Adjust these in the admin UI before the event if needed.
|
||||
|
||||
# ── Workers ───────────────────────────────────────────────────────────────────
|
||||
# Number of parallel image/video compression workers. Default 2. This is the main
|
||||
# throughput bottleneck: with 2 workers a burst of uploads can take ~5s to appear.
|
||||
# For a large event (100+ guests) 4 is a good target — but each worker can run an
|
||||
# ffmpeg transcode, so if you raise this ALSO raise the app container's memory limit
|
||||
# in docker-compose.yml (`app.deploy.resources.limits.memory`) from 1G to ~2G, or a
|
||||
# burst of large videos can OOM the box and take Postgres down with it.
|
||||
COMPRESSION_WORKER_CONCURRENCY=2
|
||||
|
||||
@@ -46,7 +46,11 @@ services:
|
||||
expose:
|
||||
- "3000"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q -O- http://localhost:3000/health || exit 1"]
|
||||
# Use 127.0.0.1, NOT localhost: the app binds IPv4 (0.0.0.0) but `localhost`
|
||||
# resolves to ::1 (IPv6) first inside the container, so a localhost probe gets
|
||||
# "connection refused" and the container never turns healthy — which would leave
|
||||
# Caddy (gated on `condition: service_healthy` below) blocked forever on boot.
|
||||
test: ["CMD-SHELL", "wget -q -O- http://127.0.0.1:3000/health || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
@@ -73,7 +77,9 @@ services:
|
||||
expose:
|
||||
- "3001"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q -O- http://localhost:3001/ >/dev/null 2>&1 || exit 1"]
|
||||
# 127.0.0.1, not localhost — see the app healthcheck note above (IPv4 bind vs
|
||||
# ::1 resolution would leave this container permanently unhealthy).
|
||||
test: ["CMD-SHELL", "wget -q -O- http://127.0.0.1:3001/ >/dev/null 2>&1 || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
@@ -86,6 +92,12 @@ services:
|
||||
caddy:
|
||||
image: caddy:2-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# The Caddyfile's site address is `{$DOMAIN}`, read from THIS container's env.
|
||||
# Without it, `{$DOMAIN}` expands to empty, the site block collapses, and Caddy
|
||||
# serves nothing / fails to obtain a TLS cert. `env_file` alone wouldn't help —
|
||||
# Caddy needs it in `environment`, and this keeps the Caddyfile the single source.
|
||||
DOMAIN: ${DOMAIN}
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
|
||||
Reference in New Issue
Block a user