seepuls/infrastructure/docker-compose.production.yml
2026-06-06 18:48:31 +02:00

138 lines
6 KiB
YAML

# Production-Stack für Seepuls auf dem Mac Mini (mana-server).
#
# Lebt unter ~/projects/seepuls/ auf mana-server (Forgejo-Klon von
# git.mana.how/till/seepuls).
#
# Ports auf dem Mac Mini (mit mana/docs/PORTS.md abgestimmt):
# seepuls-postgres: 5441 (host-bind, container-intern 5432)
# seepuls-api: 3095 → api.seepuls.com
# seepuls-web: 3096 → seepuls.com
#
# Start (von ~/projects/seepuls/ auf mana-server):
# docker compose -f infrastructure/docker-compose.production.yml \
# --env-file infrastructure/.env.production up -d --build
#
# Stop:
# docker compose -f infrastructure/docker-compose.production.yml down
#
# Daten persistieren in /Volumes/ManaData/seepuls/postgres/.
#
# Aggregator-App, gilt mana/docs/AGGREGATOR_POLICY.md.
# Bilder sind Hot-Link (kein MinIO/Storage-Container).
services:
seepuls-postgres:
image: postgres:16-alpine
container_name: seepuls-postgres
restart: always
environment:
POSTGRES_USER: seepuls
POSTGRES_PASSWORD: ${SEEPULS_DB_PASSWORD:?missing SEEPULS_DB_PASSWORD}
POSTGRES_DB: seepuls
ports:
- '127.0.0.1:5441:5432'
volumes:
- /Volumes/ManaData/seepuls/postgres:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U seepuls -d seepuls']
interval: 5s
timeout: 3s
retries: 20
seepuls-api:
image: seepuls-api:local
container_name: seepuls-api
build:
context: ../
dockerfile: apps/api/Dockerfile
restart: unless-stopped
# `default` = seepuls_default (DB-Netz). `mana-net` (extern, geteilt)
# bringt Container-DNS zum Plattform-Kern — nötig, weil mana-notify
# KEINE Public-Route hat (notify.mana.how = NXDOMAIN). Siehe
# mana/docs/playbooks/CORE_ISOLATION.md §5c-C (mana-net-Migration).
networks:
- default
- mana-net
depends_on:
seepuls-postgres:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3095
DATABASE_URL: 'postgresql://seepuls:${SEEPULS_DB_PASSWORD}@seepuls-postgres:5432/seepuls'
SEEPULS_PUBLIC_URL: ${SEEPULS_PUBLIC_URL:-https://seepuls.com}
# Plattform-Services (prod-Defaults; lokal überschreibbar)
MANA_AUTH_URL: ${MANA_AUTH_URL:-https://auth.mana.how}
MANA_RESEARCH_URL: ${MANA_RESEARCH_URL:-https://research.mana.how}
MANA_LLM_URL: ${MANA_LLM_URL:-https://llm.mana.how}
MANA_GEOCODING_URL: ${MANA_GEOCODING_URL:-https://geocoding.mana.how}
MANA_MEDIA_URL: ${MANA_MEDIA_URL:-https://media.mana.how}
# Intern über mana-net — mana-notify hat keine Public-Route.
# Container heißt mana-core-notify, per Netz-Alias als mana-notify
# erreichbar (mana/infrastructure/core/docker-compose.core.yml).
MANA_NOTIFY_URL: ${MANA_NOTIFY_URL:-http://mana-notify:3013}
# Service-Key bei mana-auth registrieren (POST /admin/apps);
# ohne den schlagen DSGVO + admin-route fehl, public Read-API
# + Take-Down funktionieren auch ohne.
MANA_SERVICE_KEY: ${MANA_SERVICE_KEY:-}
# Aura-Vergabe gegen mana-admin (onboarding.first_use)
MANA_ADMIN_URL: ${MANA_ADMIN_URL:-http://mana-admin:3071}
# Crawl-Politeness (AGGREGATOR_POLICY §1)
SEEPULS_CRAWL_USER_AGENT: ${SEEPULS_CRAWL_USER_AGENT:-seepuls/0.0.1 (+https://seepuls.com; kontakt@mana.how)}
SEEPULS_CRAWL_INTERVAL_MS: ${SEEPULS_CRAWL_INTERVAL_MS:-1100}
# Re-Crawl-Scheduler: off bis Sources existieren + Stack
# validiert ist. Aktivieren mit SEEPULS_SCHEDULER=on.
SEEPULS_SCHEDULER: ${SEEPULS_SCHEDULER:-off}
SEEPULS_API_VERSION: ${SEEPULS_API_VERSION:-0.0.1}
# CORS — wer darf direkt aufs API
CORS_ORIGINS: ${CORS_ORIGINS:-https://seepuls.com}
# Drizzle-Migrations beim Container-Start automatisch
# anwenden (idempotent über `drizzle.__drizzle_migrations`).
# Siehe mana/docs/playbooks/MIGRATIONS_BOOTSTRAP.md
SEEPULS_RUN_MIGRATIONS: 'true'
# Web Push (Folgen → Benachrichtigung). Werte aus secrets.enc.env;
# ohne sie bleibt der Push-Worker idle. Doku: docs/NOTIFICATIONS.md
SEEPULS_VAPID_PUBLIC_KEY: ${SEEPULS_VAPID_PUBLIC_KEY:-}
SEEPULS_VAPID_PRIVATE_KEY: ${SEEPULS_VAPID_PRIVATE_KEY:-}
SEEPULS_VAPID_SUBJECT: ${SEEPULS_VAPID_SUBJECT:-mailto:kontakt@mana.how}
SEEPULS_NOTIFICATIONS: ${SEEPULS_NOTIFICATIONS:-on}
ports:
- '127.0.0.1:3095:3095'
healthcheck:
test: ['CMD-SHELL', 'wget --quiet --tries=1 --spider http://localhost:3095/healthz || exit 1']
interval: 10s
timeout: 3s
retries: 10
seepuls-web:
image: seepuls-web:local
container_name: seepuls-web
build:
context: ../
dockerfile: apps/web/Dockerfile
args:
NPM_AUTH_TOKEN: ${NPM_AUTH_TOKEN}
restart: unless-stopped
depends_on:
seepuls-api:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3096
HOST: 0.0.0.0
# SSR-Client gegen prod-API; lokal überschreiben für staging
SEEPULS_API_URL: ${SEEPULS_API_URL:-https://api.seepuls.com}
ports:
- '127.0.0.1:3096:3096'
healthcheck:
test: ['CMD-SHELL', 'wget -qO- http://127.0.0.1:3096/ >/dev/null 2>&1 || exit 1']
interval: 30s
timeout: 3s
retries: 3
networks:
# Geteiltes Plattform-Netz (extern angelegt: `docker network create mana-net`).
# Nur seepuls-api hängt dran (Kern-Erreichbarkeit). seepuls-postgres/-web
# bleiben implizit auf `default` (seepuls_default).
mana-net:
external: true