docs(komodo): complete env reference — every server/vision var + defaults

The Stack example only listed the required set; expand it to the FULL reference so
an operator can see (and tweak) every env without digging through code. Grouped:
- IMAGE SELECTION (REGISTRY, TAG)
- REQUIRED (JWT_SECRET, EVENT_SIGNING_KEY, COOKIE_SECURE — no safe default)
- COMMONLY SET (VISION_ENABLED, WS_ALLOWED_ORIGINS)
- SET BY COMPOSE — don't put in the Stack (VISION_URL, DATABASE_URL, VISION_RECOGNIZER)
- OPTIONAL TUNABLES with code defaults: ports, logging/retention, device+printer poll
  intervals, lane/capture TTLs, and the ANPR knobs incl. this session's new
  ANPR_POLL_MS=1000 / ANPR_POLL_WINDOW_MS=8000 (raise the window for a slow barrier)
- VISION CONTAINER env (the Python service's own VISION_* vars)
All defaults pulled from the code (process.env.X ?? default). Documentation only.
This commit is contained in:
2026-06-27 23:23:11 +02:00
parent 96fd97efa9
commit a888125eca
+87 -14
View File
@@ -1,24 +1,97 @@
# Komodo Stack environment — reference of what a booth Stack needs and WHERE it comes # Komodo Stack environment — the COMPLETE reference of every env the booth stack reads:
# from. Under Komodo, plain env lives in the Stack definition (komodo/resources.toml); # required, image-selection, set-by-compose (don't override), and the optional tunables
# the two SECRETS come from Komodo Core's secret store, PER BOOTH and UNIQUE. This file # with their code defaults. Under Komodo, plain env lives in the Stack definition
# is documentation only — do NOT fill in real secrets here (it would be the same leak # (komodo/resources.toml); the two SECRETS come from Core's secret store, PER BOOTH and
# we're avoiding). See wiki/decisions/fleet-deployment-komodo.md. # UNIQUE. This file is DOCUMENTATION — never fill in real secrets here. See
# wiki/decisions/fleet-deployment-komodo.md.
#
# A minimal working Stack only needs: REGISTRY, TAG, the two secrets, COOKIE_SECURE=0,
# VISION_ENABLED=1, WS_ALLOWED_ORIGINS. Everything under "OPTIONAL TUNABLES" has a safe
# default in code — set one only to override it.
# --- plain Stack env (lives in resources.toml; safe in git) ------------------- # ════════════════════════════════════════════════════════════════════════════
# IMAGE SELECTION (picks which container image to pull — not server runtime env)
# ════════════════════════════════════════════════════════════════════════════
REGISTRY=git.infra.msai.al/mca/parking_solution REGISTRY=git.infra.msai.al/mca/parking_solution
# IMMUTABLE per-commit tag. Manual + pinned. Bump per deploy. Never the moving `dev` # IMMUTABLE per-commit tag. Manual + pinned. Bump per deploy. Never the moving `dev`
# on a production booth. # on a PRODUCTION booth (a staging booth may track `dev`).
TAG=dev-830993b TAG=dev-830993b
# ════════════════════════════════════════════════════════════════════════════
# REQUIRED (no safe default — the server refuses to boot / login breaks without)
# ════════════════════════════════════════════════════════════════════════════
# Login signing secret (>=32 chars, no change-me/insecure/dev-only). openssl rand -hex 32.
JWT_SECRET=[[booth_<name>_jwt_secret]]
# Ledger-signing HMAC key — the anti-fraud root. DISTINCT per booth; never reuse. If unset
# it falls back to JWT_SECRET (warned). openssl rand -hex 32.
EVENT_SIGNING_KEY=[[booth_<name>_event_signing_key]]
# CRITICAL on the plain-HTTP booth LAN: cookies are Secure (HTTPS-only) by DEFAULT, so
# without =0 the auth cookie never sends and operators CANNOT log in. Set 1 only behind TLS.
COOKIE_SECURE=0 COOKIE_SECURE=0
# ════════════════════════════════════════════════════════════════════════════
# COMMONLY SET (have defaults, but you usually want these explicit on a booth)
# ════════════════════════════════════════════════════════════════════════════
# Turn the ANPR/vision call on. Default "" (off-ish). Set 1 to enable. (Prod compose also
# forces VISION_RECOGNIZER=fast_alpr on the vision container.)
VISION_ENABLED=1 VISION_ENABLED=1
# Extra origins the booth WebSocket (/api/ws) accepts beyond same-origin. Comma-separated,
# e.g. http://parksystems.msai.al. Blank = only the same-origin booth URL. Default "".
WS_ALLOWED_ORIGINS= WS_ALLOWED_ORIGINS=
# --- secrets (Core secret store, referenced by name in resources.toml) -------- # ════════════════════════════════════════════════════════════════════════════
# Generated PER BOOTH (openssl rand -hex 32), registered in Core under booth-scoped # SET BY COMPOSE — do NOT put these in the Stack (the compose files own them)
# names, never reused across sites. The user generates these; they are never typed on # ════════════════════════════════════════════════════════════════════════════
# a CLI or committed. # VISION_URL=http://127.0.0.1:8089 # prod override (host-net server → loopback vision)
# DATABASE_URL=/data/parking.sqlite # the mounted volume (the signed ledger)
# VISION_RECOGNIZER=fast_alpr # prod override on the vision container
# ════════════════════════════════════════════════════════════════════════════
# OPTIONAL TUNABLES — all have code defaults; set only to override. (defaults shown)
# ════════════════════════════════════════════════════════════════════════════
# --- networking / process ---
# PORT=3000 # server listen port
# HOST=0.0.0.0 # bind interface (127.0.0.1 = loopback only)
# BACKEND_HOST_IP= # override the auto-picked IP devices push back to
# # (multi-NIC hosts; usually auto-detected fine)
# WEB_DIST_DIR= # where the built SPA lives (the image sets it)
# --- logging ---
# LOG_LEVEL=info # debug|info|warn|error
# LOG_RETENTION_DAYS=30 # app_logs auto-purge age
# LOG_RETENTION_MAX_ROWS=50000 # app_logs row cap
# RECYCLE_BIN_RETENTION_DAYS=30 # soft-deleted items auto-purge age (0 = keep forever)
# --- device monitor / lane ---
# DEVICE_POLL_MS=8000 # device health poll interval
# PRINTER_POLL_MS=5000 # printer status poll interval
# LANE_BUSY_TTL_MS=30000 # how long a lane stays "busy" after a vehicle push
# CAPTURE_TTL_MS=30000 # snapshot evidence cache TTL
# --- ANPR / vision (server side) ---
# VISION_URL is compose-set (above). These are the knobs you may tweak per booth:
# VISION_TIMEOUT_MS=1500 # per /analyze call timeout
# VISION_MIN_CONFIDENCE=0.5 # advisory floor (telemetry/lane); below = low_confidence
# VISION_ENTRY_MIN_CONFIDENCE=0.85 # STRICT barrier-driving floor (auto entry/exit). A
# # read below this is ignored (falls back to card/QR).
# ANPR_DEBOUNCE_MS=12000 # same plate/camera within this = one presentation
# ANPR_POLL_MS=1000 # poll-until-confident: re-pull a fresh frame every N ms
# ANPR_POLL_WINDOW_MS=8000 # ...for up to this long while the car sits at the
# # barrier. RAISE if a slow barrier means the car
# # waits >8s before the plate reads clean.
# ════════════════════════════════════════════════════════════════════════════
# VISION CONTAINER env (the Python ANPR service — its OWN process, prefix VISION_)
# Mostly compose-set; documented here for completeness. (defaults shown)
# ════════════════════════════════════════════════════════════════════════════
# VISION_RECOGNIZER=fast_alpr # stub | fast_alpr (prod compose forces fast_alpr)
# VISION_HOST=0.0.0.0 # bind (prod publishes 127.0.0.1 only — see compose)
# VISION_PORT=8089
# VISION_DETECTOR_MODEL=yolo-v9-t-384-license-plate-end2end
# VISION_OCR_MODEL=cct-xs-v2-global-model
# VISION_MIN_CONFIDENCE=0.5 # the Python service's own floor (keep ~in sync w/ server)
# ════════════════════════════════════════════════════════════════════════════
# SECRETS — referenced by name in resources.toml, stored in Core (never inline here)
# ════════════════════════════════════════════════════════════════════════════
# JWT_SECRET -> [[booth_<name>_jwt_secret]] (login) # JWT_SECRET -> [[booth_<name>_jwt_secret]] (login)
# EVENT_SIGNING_KEY -> [[booth_<name>_event_signing_key]] (ledger signing — fraud root) # EVENT_SIGNING_KEY -> [[booth_<name>_event_signing_key]] (ledger signing — fraud root)
# Periphery/registry auth also live in Core: # periphery passkey -> [[periphery_passkey_booth_<name>]] (agent onboarding)
# periphery passkey -> [[periphery_passkey_booth_<name>]] # registry account -> [[gitea_registry_account]] (image pull)
# registry account -> [[gitea_registry_account]]