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_USER=eventsnap
|
||||||
POSTGRES_PASSWORD=CHANGE_ME_use_a_strong_password
|
POSTGRES_PASSWORD=CHANGE_ME_use_a_strong_password
|
||||||
POSTGRES_DB=eventsnap
|
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 ────────────────────────────────────────────────────────────
|
# ── Authentication ────────────────────────────────────────────────────────────
|
||||||
# Generate with: openssl rand -hex 64
|
# 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.
|
# /media is publicly served, so exports here would be downloadable without auth.
|
||||||
EXPORT_PATH=/exports
|
EXPORT_PATH=/exports
|
||||||
|
|
||||||
# ── Upload limits ─────────────────────────────────────────────────────────────
|
# ── Runtime settings (upload limits, rate limits, capacity) ───────────────────
|
||||||
DEFAULT_MAX_IMAGE_SIZE_MB=20
|
# NOTE: These are NOT environment variables. Upload size caps, rate limits, guest
|
||||||
DEFAULT_MAX_VIDEO_SIZE_MB=500
|
# 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
|
||||||
# ── Rate limiting ─────────────────────────────────────────────────────────────
|
# not read them from .env. Setting them here has no effect. Current seeded defaults:
|
||||||
DEFAULT_UPLOAD_RATE_PER_HOUR=10
|
# upload rate 100 / hour / guest (raised from 10 by migration 015)
|
||||||
DEFAULT_FEED_RATE_PER_MIN=60
|
# feed rate 60 / minute
|
||||||
DEFAULT_EXPORT_RATE_PER_DAY=3
|
# export rate 3 / day
|
||||||
|
# max image size 20 MB
|
||||||
# ── Capacity ──────────────────────────────────────────────────────────────────
|
# max video size 500 MB
|
||||||
DEFAULT_ESTIMATED_GUEST_COUNT=100
|
# estimated guests 100
|
||||||
# Fraction of total storage that triggers the "low storage" warning (0.0–1.0)
|
# quota tolerance 0.75 (fraction of disk that triggers the low-storage warning)
|
||||||
DEFAULT_QUOTA_TOLERANCE=0.75
|
# Adjust these in the admin UI before the event if needed.
|
||||||
|
|
||||||
# ── Workers ───────────────────────────────────────────────────────────────────
|
# ── 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
|
COMPRESSION_WORKER_CONCURRENCY=2
|
||||||
|
|||||||
@@ -46,7 +46,11 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- "3000"
|
- "3000"
|
||||||
healthcheck:
|
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
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
@@ -73,7 +77,9 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- "3001"
|
- "3001"
|
||||||
healthcheck:
|
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
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
@@ -86,6 +92,12 @@ services:
|
|||||||
caddy:
|
caddy:
|
||||||
image: caddy:2-alpine
|
image: caddy:2-alpine
|
||||||
restart: unless-stopped
|
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:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
- "443:443"
|
- "443:443"
|
||||||
|
|||||||
Reference in New Issue
Block a user