54121c1721
- SmtpConfig.bugReportRecipient (nullable, additive Migration 20260914170000), DTO @IsOptional @IsEmail, SAFE_SELECT, getBugReportRecipient gebunden - MailService: Versandkern deliver (wirft, Anhaenge), sendViaTenantTransport bleibt verschluckender Mantel (T-02-12), sendBugReport laesst Fehler durch - POST /bug-reports: Multipart 4 MiB je Route, alle angemeldeten Rollen, Drossel 5/10 min -> 429, PNG-Signatur -> 400, kein Empfaenger -> 409, Versandfehler -> 502, eine Protokollzeile - Falsifizierungen (a)-(d) als Specs; @Expose() im DTO, damit errors auch bei fehlendem Feld zu [] wird - Doku-Zeile fuer rls-access-inventory, TESSERA_BUGREPORT_TO in docker-compose.prod.yml Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
101 lines
3.4 KiB
YAML
101 lines
3.4 KiB
YAML
services:
|
|
web:
|
|
# IMAGE_TAG in .env selects the delivery channel: beta (alpha, all new
|
|
# changes) or live (released versions only). Defaults to beta.
|
|
image: git.vicolab.de/schalli/tessera-ctl/web:${IMAGE_TAG:-beta}
|
|
restart: unless-stopped
|
|
ports:
|
|
- "3000:3000"
|
|
environment:
|
|
HOSTNAME: "0.0.0.0"
|
|
# Read by the browser, not by the web container, so it must be an address
|
|
# that resolves outside Docker. http://api:3001 only exists on the compose
|
|
# network and leaves the UI unable to reach the API.
|
|
NEXT_PUBLIC_API_URL: ${APP_URL:-http://localhost:3001}
|
|
API_INTERNAL_URL: "http://api:3001"
|
|
JWT_SECRET: ${JWT_SECRET}
|
|
networks:
|
|
- frontend-net
|
|
- backend-net
|
|
depends_on:
|
|
api:
|
|
condition: service_healthy
|
|
|
|
api:
|
|
# Same channel as web, see IMAGE_TAG above.
|
|
image: git.vicolab.de/schalli/tessera-ctl/api:${IMAGE_TAG:-beta}
|
|
restart: unless-stopped
|
|
ports:
|
|
- "3001:3001"
|
|
networks:
|
|
- backend-net
|
|
- data-net
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
DATABASE_URL: ${DATABASE_URL}
|
|
TESSERA_MIGRATE_DATABASE_URL: ${TESSERA_MIGRATE_DATABASE_URL:-}
|
|
JWT_SECRET: ${JWT_SECRET}
|
|
TESSERA_ADMIN_USER: ${TESSERA_ADMIN_USER:-admin}
|
|
TESSERA_ADMIN_EMAIL: ${TESSERA_ADMIN_EMAIL}
|
|
TESSERA_ADMIN_PASSWORD: ${TESSERA_ADMIN_PASSWORD}
|
|
TESSERA_FORCE_CHANGE: ${TESSERA_FORCE_CHANGE:-true}
|
|
TESSERA_SMTP_HOST: ${TESSERA_SMTP_HOST:-}
|
|
TESSERA_SMTP_PORT: ${TESSERA_SMTP_PORT:-587}
|
|
TESSERA_SMTP_SECURE: ${TESSERA_SMTP_SECURE:-false}
|
|
TESSERA_SMTP_USER: ${TESSERA_SMTP_USER:-}
|
|
TESSERA_SMTP_PASSWORD: ${TESSERA_SMTP_PASSWORD:-}
|
|
TESSERA_SMTP_FROM: ${TESSERA_SMTP_FROM:-Tessera <noreply@tessera.local>}
|
|
# Fallback mailbox for the in-app bug report button. Empty = only the
|
|
# per-tenant setting in Administrator -> SMTP ("Fehlermeldungen an") applies.
|
|
TESSERA_BUGREPORT_TO: ${TESSERA_BUGREPORT_TO:-}
|
|
TESSERA_APP_URL: ${APP_URL:-http://localhost:3000}
|
|
# Unset used to resolve to an empty value and only fail later, inside the
|
|
# API, with a stack trace. Fail at compose level with a usable message
|
|
# instead. Generate with: openssl rand -hex 32
|
|
#
|
|
# CALENDAR_ENCRYPTION_KEY is the previous name and is still accepted, so
|
|
# an existing .env keeps working; the API logs a deprecation warning when
|
|
# it falls back to it.
|
|
TESSERA_ENCRYPTION_KEY: "${TESSERA_ENCRYPTION_KEY:-${CALENDAR_ENCRYPTION_KEY:?set TESSERA_ENCRYPTION_KEY in .env, generate one with openssl rand -hex 32}}"
|
|
CALENDAR_ENCRYPTION_KEY: "${CALENDAR_ENCRYPTION_KEY:-}"
|
|
volumes:
|
|
- user-files:/app/user-files
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 20s
|
|
|
|
db:
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
networks:
|
|
- data-net
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
environment:
|
|
POSTGRES_USER: tessera
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
|
POSTGRES_DB: tessera
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U tessera"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 5
|
|
|
|
networks:
|
|
frontend-net:
|
|
driver: bridge
|
|
backend-net:
|
|
driver: bridge
|
|
data-net:
|
|
driver: bridge
|
|
internal: true
|
|
|
|
volumes:
|
|
pgdata:
|
|
user-files:
|