services: web: build: context: . dockerfile: apps/web/Dockerfile ports: - "3000:3000" environment: HOSTNAME: "0.0.0.0" NEXT_PUBLIC_API_URL: "http://localhost:3001" API_INTERNAL_URL: "http://api:3001" JWT_SECRET: ${JWT_SECRET:-tessera-dev-jwt-secret-change-in-production} networks: - frontend-net - backend-net depends_on: api: condition: service_healthy api: build: context: . dockerfile: apps/api/Dockerfile ports: - "3001:3001" networks: - backend-net - data-net depends_on: db: condition: service_healthy environment: DATABASE_URL: ${DATABASE_URL:-postgresql://tessera:tessera_dev@db:5432/tessera} JWT_SECRET: ${JWT_SECRET:-tessera-dev-jwt-secret-change-in-production} TESSERA_ADMIN_USER: ${TESSERA_ADMIN_USER:-admin} TESSERA_ADMIN_EMAIL: ${TESSERA_ADMIN_EMAIL:-admin@tessera.local} TESSERA_ADMIN_PASSWORD: ${TESSERA_ADMIN_PASSWORD:-admin123} TESSERA_FORCE_CHANGE: ${TESSERA_FORCE_CHANGE:-false} TESSERA_SMTP_HOST: ${TESSERA_SMTP_HOST:-mailhog} TESSERA_SMTP_PORT: ${TESSERA_SMTP_PORT:-1025} 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 } TESSERA_APP_URL: ${TESSERA_APP_URL:-http://localhost:3000} # No default on purpose: this key decrypts every stored credential # (LDAP bind, calendar, SMTP, DKV and tender mailboxes). A built-in # fallback would let a stack start and encrypt everything with a value # that is public in this repository -- encryption that looks present and # protects nothing. Failing to start is the honest outcome. # Generate one with: openssl rand -hex 32 # Keep it with your backups but stored separately from the database dump; # losing it means re-entering every stored credential by hand. CALENDAR_ENCRYPTION_KEY: "${CALENDAR_ENCRYPTION_KEY:?set CALENDAR_ENCRYPTION_KEY in .env, generate one with openssl rand -hex 32}" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"] interval: 10s timeout: 5s retries: 3 start_period: 10s db: image: postgres:16-alpine networks: - data-net volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_USER: tessera POSTGRES_PASSWORD: ${DB_PASSWORD:-tessera_dev} 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: