Files
deploy/.env.example
T
julian 10c548b010 Add SPA service block, runtime config override, README updates
- compose.yaml: new spa service. Image trm/spa:${SPA_TAG:-main}.
  expose: 80 (internal-only; reverse proxy fronts it). Read-only
  volume mount ${SPA_CONFIG_FILE:-./spa-config.json} ->
  /usr/share/nginx/html/config.json for the runtime-config override.
  Healthcheck via wget against localhost.
- spa-config.example.json: dev-default-equivalent file with env=stage.
  Operators copy to spa-config.json and edit per environment.
- .gitignore: spa-config.json never committed (per-environment).
- .env.example: new spa section documenting SPA_TAG and
  SPA_CONFIG_FILE; reframes the directus internal-only note as a
  shared design (SPA also internal-only).
- README.md:
  - Services in the stack: SPA moved from Planned to Currently.
  - Step 8 in first-deploy checklist: "Verify the SPA loads".
  - Network model: spell out the four routes the proxy must wire
    (/api, /ws-business, /ws-live, default -> SPA). Same-origin
    non-negotiable callout.
  - New "Runtime config override (SPA)" section: copy/edit/mount
    workflow + when not to use absolute URLs.
2026-05-02 18:50:17 +02:00

145 lines
6.6 KiB
Bash

# Copy to `.env` for local docker-compose runs, OR enter these values in
# Portainer's Stack → Environment variables UI.
#
# All variables have defaults baked into compose.yaml — this file is the
# documentation of what's configurable, not a hard requirement.
# ---------------------------------------------------------------------
# tcp-ingestion
# ---------------------------------------------------------------------
# Image tag to pull. `main` auto-tracks the latest commit on the main branch.
# In production, pin to a specific commit SHA for reproducibility.
# Example: TCP_INGESTION_TAG=af06973
TCP_INGESTION_TAG=main
# Instance identifier — must be stable across the lifetime of the process.
# Phase 2's connection registry depends on this; keep it unique per deployed
# instance (e.g. `stage-1`, `stage-2`, `prod-eu-1`).
TCP_INGESTION_INSTANCE_ID=stage-1
# Host port that GPS devices connect to. The container always listens on 5027
# internally; this maps it to a host port. If multiple stacks run on one host,
# give each a distinct host port (e.g. 5028, 5029).
TCP_INGESTION_PORT=5027
# ---------------------------------------------------------------------
# postgres / TimescaleDB
# ---------------------------------------------------------------------
# Database superuser, password, and default database. Created on first
# boot of the postgres container; the volume persists them after that.
# IMPORTANT: change POSTGRES_PASSWORD before deploying to production.
# Changing it after first boot has no effect — the volume already has
# the password baked in. To rotate, ALTER USER inside psql.
POSTGRES_USER=trm
POSTGRES_PASSWORD=trm-pilot-change-me
POSTGRES_DB=trm
# ---------------------------------------------------------------------
# processor
# ---------------------------------------------------------------------
# Image tag to pull. `main` auto-tracks the latest commit on the main branch.
# In production, pin to a specific commit SHA for reproducibility.
# Example: PROCESSOR_TAG=9791620
PROCESSOR_TAG=main
# Instance identifier — must be stable across the lifetime of the process,
# AND unique per running instance (it's used as the Redis consumer-group
# member name; two instances with the same name will read from the same
# Pending Entries List, which is undefined behaviour).
PROCESSOR_INSTANCE_ID=processor-1
# ---------------------------------------------------------------------
# directus (business plane)
# ---------------------------------------------------------------------
# Image tag to pull. `main` auto-tracks the latest commit on the main branch.
# In production, pin to a specific commit SHA for reproducibility.
# Example: DIRECTUS_TAG=ef8bd91
DIRECTUS_TAG=main
# Note: directus is intentionally NOT host-published. The admin UI + API
# listen on port 8055 inside the `trm_default` Compose network only,
# reachable as `http://directus:8055` from a reverse proxy (Traefik /
# Caddy / nginx) on the host or attached to the same network. Wire your
# proxy to forward your public domain to that internal address; the
# proxy handles TLS, auth headers, and any WAF / rate-limit policy.
# For local dev (compose.dev.yaml in trm/directus) the dev compose
# host-publishes 8055 directly — this prod stack does not.
# REQUIRED. Instance identity key (any UUID) and JWT signing secret
# (long random string). Generate fresh values per environment:
# DIRECTUS_KEY=$(uuidgen)
# DIRECTUS_SECRET=$(openssl rand -hex 64)
# Two instances sharing these produce colliding tokens — never reuse
# stage's KEY/SECRET in production. The compose defaults are obvious
# placeholders and will fail on any meaningful KEY validation.
DIRECTUS_KEY=REPLACE-ME-WITH-A-UUID
DIRECTUS_SECRET=REPLACE-ME-WITH-A-LONG-RANDOM-STRING
# First-boot admin user. Created automatically when directus_users is
# empty at first boot; ignored on subsequent boots. Change the password
# via the admin UI after first login (the password env var is NOT a
# rotation mechanism — only the initial seed).
DIRECTUS_ADMIN_EMAIL=admin@example.com
DIRECTUS_ADMIN_PASSWORD=CHANGE-ON-FIRST-LOGIN
# Public-facing URL used in password-reset emails, OAuth redirects, and
# asset URLs. In real prod set to https://<your-domain>; the localhost
# default is for first-deploy smoke testing only.
DIRECTUS_PUBLIC_URL=http://localhost:8055
# Optional toggles. Defaults disable cache and CORS. Enable per env:
# DIRECTUS_CACHE_ENABLED=true (then configure CACHE_STORE etc. directly
# in compose.yaml — Directus has 20+
# cache-related env vars not exposed here)
# DIRECTUS_CORS_ENABLED=true
# DIRECTUS_CORS_ORIGIN=https://your-spa.example.com
DIRECTUS_CACHE_ENABLED=false
DIRECTUS_CORS_ENABLED=false
DIRECTUS_CORS_ORIGIN=false
# pino log style: json (structured, for log aggregators) | pretty (human-readable).
# Defaults to json in compose.yaml — production-friendly. Set to `pretty`
# for local debugging.
LOG_STYLE=json
# ---------------------------------------------------------------------
# spa (React front-end)
# ---------------------------------------------------------------------
# Image tag to pull. `main` auto-tracks the latest commit on the main branch.
# In production, pin to a specific commit SHA for reproducibility.
# Example: SPA_TAG=ab12cd3
SPA_TAG=main
# Path on the host to the runtime config file. Mounted read-only into the
# SPA container at /usr/share/nginx/html/config.json. Defaults to a sibling
# file in this repo; create it from spa-config.example.json before first
# deploy:
# cp spa-config.example.json spa-config.json
# # edit env to "stage" or "prod"; add googleMapsKey if operators have one
# In Portainer, mount via a host-path volume that points at the file.
SPA_CONFIG_FILE=./spa-config.json
# Note: the SPA is intentionally NOT host-published. nginx serves the
# bundle on port 80 inside the trm_default Compose network only,
# reachable as `http://spa:80` from the same reverse proxy that fronts
# directus. The proxy routes `/api` + `/ws-business` + `/ws-live` to the
# backends and everything else to the SPA — same-origin is required for
# the cookie-based auth flow to work end-to-end.
# ---------------------------------------------------------------------
# Shared
# ---------------------------------------------------------------------
# Redis Stream name carrying normalized Position records from
# tcp-ingestion to processor. Both services must use the same value.
# Override only if migrating to a new stream (e.g. for multi-vendor).
REDIS_TELEMETRY_STREAM=telemetry:teltonika
# pino log level: fatal | error | warn | info | debug | trace
LOG_LEVEL=info