managarten/docker-compose.macmini.yml
Till JS bb69f78e1e fix(auth): add missing trusted origins for cross-app SSO
Several apps (mukke, photos, planta, questions, todo, traces, context,
docs, manadeck, zitare) were missing from Better Auth's trustedOrigins,
causing SSO session cookie exchange to fail for those apps. Also synced
CORS_ORIGINS in docker-compose.macmini.yml.

Added 47 SSO contract tests to prevent regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:17:34 +01:00

1972 lines
62 KiB
YAML

# Mana Mac Mini Configuration
# Domain: mana.how (via Cloudflare Tunnel)
#
# Port Schema:
# 3000-3099: Core Services & Backends
# 4000-4099: Matrix Stack
# 5000-5099: Web Frontends
# 6000-6099: Automation & Workflows
# 8000-8099: Monitoring Dashboards
# 9000-9199: Infrastructure & Exporters
#
# Naming Convention: mana-{category}-{service}
# Categories: infra, core, app, matrix, mon, auto
services:
# ============================================
# Tier 0: Infrastructure Services
# ============================================
postgres:
image: postgres:16-alpine
container_name: mana-infra-postgres
restart: always
environment:
POSTGRES_DB: mana
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mana123}
volumes:
- /Volumes/ManaData/postgres:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: mana-infra-redis
restart: always
command: redis-server --requirepass ${REDIS_PASSWORD:-redis123}
volumes:
- redis_data:/data
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 10s
timeout: 5s
retries: 5
minio:
image: minio/minio:latest
container_name: mana-infra-minio
restart: always
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:-minioadmin}
volumes:
- /Volumes/ManaData/minio:/data
ports:
- "9000:9000"
- "9001:9001"
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 30s
timeout: 20s
retries: 3
# ============================================
# Tier 1: Core Auth Service (Port 3001)
# ============================================
mana-auth:
build:
context: .
dockerfile: services/mana-core-auth/Dockerfile
image: mana-core-auth:local
container_name: mana-core-auth
restart: always
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3001
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_auth
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
JWT_SECRET: ${JWT_SECRET:-your-jwt-secret-change-me}
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:-${JWT_SECRET:-your-jwt-secret-change-me}}
JWT_PUBLIC_KEY: ${JWT_PUBLIC_KEY:-}
JWT_PRIVATE_KEY: ${JWT_PRIVATE_KEY:-}
BASE_URL: https://auth.mana.how
# Cross-domain SSO: share session cookies across all *.mana.how subdomains
COOKIE_DOMAIN: .mana.how
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
SMTP_HOST: smtp-relay.brevo.com
SMTP_PORT: 587
SMTP_USER: ${SMTP_USER:-94cde5002@smtp-brevo.com}
SMTP_PASSWORD: ${SMTP_PASSWORD}
SMTP_FROM: Mana <noreply@mana.how>
CORS_ORIGINS: https://mana.how,https://calendar.mana.how,https://chat.mana.how,https://clock.mana.how,https://contacts.mana.how,https://context.mana.how,https://docs.mana.how,https://element.mana.how,https://link.mana.how,https://manadeck.mana.how,https://matrix.mana.how,https://mukke.mana.how,https://nutriphi.mana.how,https://photos.mana.how,https://picture.mana.how,https://planta.mana.how,https://playground.mana.how,https://presi.mana.how,https://questions.mana.how,https://skilltree.mana.how,https://storage.mana.how,https://todo.mana.how,https://traces.mana.how,https://zitare.mana.how
DUCKDB_PATH: /data/analytics/metrics.duckdb
SYNAPSE_OIDC_CLIENT_SECRET: ${SYNAPSE_OIDC_CLIENT_SECRET:-}
# Backend URLs for user data aggregation (GDPR self-service)
CHAT_BACKEND_URL: http://chat-backend:3030
TODO_BACKEND_URL: http://todo-backend:3031
CALENDAR_BACKEND_URL: http://calendar-backend:3032
CONTACTS_BACKEND_URL: http://contacts-backend:3034
PICTURE_BACKEND_URL: http://photos-backend:3039
PRESI_BACKEND_URL: http://presi-backend:3036
ZITARE_BACKEND_URL: http://zitare-backend:3007
PHOTOS_BACKEND_URL: http://photos-backend:3039
CLOCK_BACKEND_URL: http://clock-backend:3033
STORAGE_BACKEND_URL: http://storage-backend:3035
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
volumes:
- analytics_data:/data/analytics
ports:
- "3001:3001"
healthcheck:
test: ["CMD", "node", "-e", "const http = require('http'); http.get('http://127.0.0.1:3001/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# ============================================
# Tier 2: Gateway & Search Services (Ports 3010-3029)
# ============================================
# NOTE: api-gateway disabled - no GHCR image available, no Dockerfile exists
# To re-enable: create Dockerfile in services/api-gateway/ and build locally
api-gateway:
profiles: ["disabled"]
image: ghcr.io/memo-2023/api-gateway:latest
container_name: mana-core-gateway
restart: always
depends_on:
mana-auth:
condition: service_healthy
# Removed: postgres, redis, mana-search - lazy connect with retry
environment:
NODE_ENV: production
PORT: 3010
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
MANA_CORE_AUTH_URL: http://mana-auth:3001
SEARCH_SERVICE_URL: http://mana-search:3020
STT_SERVICE_URL: http://host.docker.internal:3021
TTS_SERVICE_URL: http://host.docker.internal:3022
IMAGE_GEN_SERVICE_URL: http://host.docker.internal:3025
CORS_ORIGINS: https://api.mana.how,https://mana.how
# Retry config for lazy dependencies
DB_RETRY_ATTEMPTS: 5
DB_RETRY_DELAY: 3000
ports:
- "3010:3010"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3010/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
searxng:
image: searxng/searxng:latest
container_name: mana-core-searxng
restart: always
volumes:
- ./services/mana-search/searxng/settings.yml:/etc/searxng/settings.yml:ro
- ./services/mana-search/searxng/limiter.toml:/etc/searxng/limiter.toml:ro
environment:
SEARXNG_BASE_URL: http://searxng:8080
SEARXNG_SECRET: ${SEARXNG_SECRET:-change-me-searxng-secret}
# Internal only - no external port mapping
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
mana-search:
build:
context: .
dockerfile: services/mana-search/Dockerfile
image: mana-search:local
container_name: mana-core-search
restart: always
depends_on:
searxng:
condition: service_healthy
# Removed: redis - lazy connect
environment:
NODE_ENV: production
PORT: 3020
SEARXNG_URL: http://searxng:8080
SEARXNG_TIMEOUT: 15000
SEARXNG_DEFAULT_LANGUAGE: de-DE
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
CACHE_SEARCH_TTL: 3600
CACHE_EXTRACT_TTL: 86400
EXTRACT_TIMEOUT: 10000
EXTRACT_MAX_LENGTH: 50000
ports:
- "3020:3020"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3020/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mana-media:
build:
context: .
dockerfile: services/mana-media/apps/api/Dockerfile
image: mana-media:local
container_name: mana-core-media
restart: always
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3015
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_media
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
S3_ENDPOINT: minio
S3_PORT: 9000
S3_USE_SSL: "false"
S3_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
S3_BUCKET: mana-media
S3_PUBLIC_URL: https://media.mana.how
MATRIX_HOMESERVER_URL: https://matrix.mana.how
PUBLIC_URL: https://media.mana.how/api/v1
CORS_ORIGINS: https://mana.how,https://nutriphi.mana.how,https://contacts.mana.how,https://chat.mana.how,https://storage.mana.how,https://photos.mana.how
ports:
- "3015:3015"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3015/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# ============================================
# Tier 3: App Backends (Ports 3030-3049)
# ============================================
chat-backend:
build:
context: .
dockerfile: apps/chat/apps/backend/Dockerfile
image: chat-backend:local
container_name: mana-app-chat-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
# Removed: postgres - lazy connect
environment:
NODE_ENV: production
PORT: 3030
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/chat
MANA_CORE_AUTH_URL: http://mana-auth:3001
OLLAMA_URL: http://host.docker.internal:11434
OLLAMA_TIMEOUT: 120000
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
SUPABASE_URL: ${SUPABASE_URL:-}
SUPABASE_SERVICE_KEY: ${SUPABASE_SERVICE_ROLE_KEY:-}
AZURE_OPENAI_ENDPOINT: ${AZURE_OPENAI_ENDPOINT:-}
AZURE_OPENAI_API_KEY: ${AZURE_OPENAI_API_KEY:-}
AZURE_OPENAI_API_VERSION: 2024-12-01-preview
CORS_ORIGINS: https://chat.mana.how,https://mana.how
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
ports:
- "3030:3030"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3030/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
todo-backend:
build:
context: .
dockerfile: apps/todo/apps/backend/Dockerfile
image: todo-backend:local
container_name: mana-app-todo-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3031
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/todo
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://todo.mana.how,https://mana.how
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
GLITCHTIP_DSN: https://c774433d212c473d9088542a84224488@glitchtip.mana.how/3
ports:
- "3031:3031"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3031/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
calendar-backend:
build:
context: .
dockerfile: apps/calendar/apps/backend/Dockerfile
image: calendar-backend:local
container_name: mana-app-calendar-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3032
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/calendar
DB_HOST: postgres
DB_PORT: 5432
DB_USER: postgres
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://calendar.mana.how,https://mana.how
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
ENCRYPTION_KEY: ${CALENDAR_ENCRYPTION_KEY:-}
GLITCHTIP_DSN: https://7dcf6e8648a04b85b2cb275921c059d5@glitchtip.mana.how/1
ports:
- "3032:3032"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3032/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
clock-backend:
build:
context: .
dockerfile: apps/clock/apps/backend/Dockerfile
image: clock-backend:local
container_name: mana-app-clock-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3033
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/clock
DB_HOST: postgres
DB_PORT: 5432
DB_USER: postgres
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://clock.mana.how,https://mana.how
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
ports:
- "3033:3033"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3033/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
contacts-backend:
build:
context: .
dockerfile: apps/contacts/apps/backend/Dockerfile
image: contacts-backend:local
container_name: mana-app-contacts-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
# Removed: minio - lazy connect
environment:
NODE_ENV: production
PORT: 3034
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/contacts
DB_HOST: postgres
DB_PORT: 5432
DB_USER: postgres
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://contacts.mana.how,https://mana.how,https://calendar.mana.how
S3_ENDPOINT: http://minio:9000
S3_REGION: us-east-1
S3_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
S3_BUCKET: contacts-photos
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
GLITCHTIP_DSN: https://a0d81e4b78694b57951a1a5de6d64ae7@glitchtip.mana.how/2
ports:
- "3034:3034"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3034/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
storage-backend:
build:
context: .
dockerfile: apps/storage/apps/backend/Dockerfile
image: storage-backend:local
container_name: mana-app-storage-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3035
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/storage
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://storage.mana.how,https://mana.how
S3_ENDPOINT: http://minio:9000
S3_REGION: us-east-1
S3_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
S3_BUCKET: storage-storage
STORAGE_S3_PUBLIC_URL: https://storage-files.mana.how
MAX_FILE_SIZE: 104857600
MAX_FILES_PER_UPLOAD: 10
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
ports:
- "3035:3035"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3035/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
presi-backend:
build:
context: .
dockerfile: apps/presi/apps/backend/Dockerfile
image: presi-backend:local
container_name: mana-app-presi-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3036
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/presi
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://presi.mana.how,https://mana.how
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
ports:
- "3036:3036"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3036/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
nutriphi-backend:
image: ghcr.io/memo-2023/nutriphi-backend:latest
container_name: mana-app-nutriphi-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3037
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/nutriphi
DB_HOST: postgres
DB_PORT: 5432
DB_USER: postgres
MANA_CORE_AUTH_URL: http://mana-auth:3001
GEMINI_API_KEY: ${GEMINI_API_KEY:-}
CORS_ORIGINS: https://nutriphi.mana.how,https://mana.how
ports:
- "3037:3037"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3037/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
skilltree-backend:
image: ghcr.io/memo-2023/skilltree-backend:latest
container_name: mana-app-skilltree-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3038
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/skilltree
DB_HOST: postgres
DB_PORT: 5432
DB_USER: postgres
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://skilltree.mana.how,https://mana.how
ports:
- "3038:3038"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3038/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
photos-backend:
build:
context: .
dockerfile: apps/photos/apps/backend/Dockerfile
image: photos-backend:local
container_name: mana-app-photos-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
mana-media:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3039
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/photos
DB_HOST: postgres
DB_PORT: 5432
DB_USER: postgres
MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_MEDIA_URL: http://mana-media:3015
CORS_ORIGINS: https://photos.mana.how,https://mana.how
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
ports:
- "3039:3039"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3039/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
zitare-backend:
build:
context: .
dockerfile: apps/zitare/apps/backend/Dockerfile
image: zitare-backend:local
container_name: mana-app-zitare-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3007
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/zitare
DB_HOST: postgres
DB_PORT: 5432
DB_USER: postgres
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://zitare.mana.how,https://mana.how
ADMIN_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
ports:
- "3007:3007"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3007/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mukke-backend:
build:
context: .
dockerfile: apps/mukke/apps/backend/Dockerfile
image: mukke-backend:local
container_name: mana-app-mukke-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3010
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mukke
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://mukke.mana.how,https://mana.how
S3_ENDPOINT: http://minio:9000
S3_PUBLIC_ENDPOINT: https://minio.mana.how
S3_REGION: us-east-1
S3_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
S3_BUCKET: mukke-storage
RUN_DB_PUSH: "true"
ports:
- "3010:3010"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3010/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
planta-backend:
build:
context: .
dockerfile: apps/planta/apps/backend/Dockerfile
image: planta-backend:local
container_name: mana-app-planta-backend
restart: always
depends_on:
mana-auth:
condition: service_healthy
minio:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3022
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/planta
DB_HOST: postgres
DB_PORT: 5432
DB_USER: postgres
MANA_CORE_AUTH_URL: http://mana-auth:3001
CORS_ORIGINS: https://planta.mana.how,https://mana.how
GOOGLE_GEMINI_API_KEY: ${GOOGLE_GEMINI_API_KEY}
S3_ENDPOINT: http://minio:9000
S3_PUBLIC_ENDPOINT: https://minio.mana.how
S3_REGION: us-east-1
S3_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
S3_BUCKET: planta-storage
ports:
- "3022:3022"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3022/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# ============================================
# Tier 4: Matrix Stack (Ports 4000-4099)
# ============================================
synapse:
image: matrixdotorg/synapse:latest
container_name: mana-matrix-synapse
restart: always
depends_on:
postgres:
condition: service_healthy
environment:
SYNAPSE_CONFIG_PATH: /config/homeserver.yaml
TZ: Europe/Berlin
SYNAPSE_DB_PASSWORD: ${SYNAPSE_DB_PASSWORD:-synapse-secure-password}
SYNAPSE_PASSWORD_PEPPER: ${SYNAPSE_PASSWORD_PEPPER:-change-me-pepper}
SYNAPSE_FORM_SECRET: ${SYNAPSE_FORM_SECRET:-change-me-form-secret}
SYNAPSE_MACAROON_SECRET: ${SYNAPSE_MACAROON_SECRET:-change-me-macaroon-secret}
SYNAPSE_REGISTRATION_SECRET: ${SYNAPSE_REGISTRATION_SECRET:-change-me-registration-secret}
SYNAPSE_OIDC_CLIENT_SECRET: ${SYNAPSE_OIDC_CLIENT_SECRET}
volumes:
- ./docker/matrix/homeserver.yaml:/config/homeserver.yaml:ro
- ./docker/matrix/log.config.yaml:/config/log.config.yaml:ro
- ./docker/matrix/appservices:/appservices:ro
- ./docker/matrix/data:/data
ports:
- "4000:8008"
- "9002:9002" # Metrics
healthcheck:
test: ["CMD", "curl", "-fSs", "http://localhost:8008/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
element-web:
image: vectorim/element-web:latest
container_name: mana-matrix-element
restart: always
depends_on:
synapse:
condition: service_healthy
volumes:
- ./docker/matrix/element-config.json:/app/config.json:ro
ports:
- "4080:80"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/"]
interval: 30s
timeout: 10s
retries: 3
matrix-web:
build:
context: .
dockerfile: apps/matrix/apps/web/Dockerfile
image: matrix-web:latest
container_name: mana-matrix-web
restart: always
depends_on:
synapse:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5180
PUBLIC_MANA_CORE_AUTH_URL: https://auth.mana.how
ports:
- "4090:5180"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5180/health"]
interval: 30s
timeout: 10s
retries: 3
# Matrix Bots (Ports 4010-4029)
matrix-mana-bot:
build:
context: .
dockerfile: services/matrix-mana-bot/Dockerfile
image: matrix-mana-bot:local
platform: linux/arm64
container_name: mana-matrix-bot-mana
restart: always
depends_on:
synapse:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4010
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_MANA_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_MANA_BOT_ROOMS:-}
MATRIX_STORAGE_PATH: /app/data/mana-bot-storage.json
OLLAMA_URL: http://host.docker.internal:11434
OLLAMA_MODEL: ${OLLAMA_MODEL:-gemma3:4b}
OLLAMA_TIMEOUT: 120000
CLOCK_API_URL: http://mana-matrix-bot-clock:4018/api/v1
TODO_STORAGE_PATH: /app/data/todos.json
CALENDAR_STORAGE_PATH: /app/data/calendar.json
STT_URL: http://host.docker.internal:3026
STT_API_KEY: ${STT_INTERNAL_API_KEY:-}
TTS_URL: http://host.docker.internal:3022
volumes:
- matrix_bots_data:/app/data
ports:
- "4010:4010"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4010/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-ollama-bot:
image: ghcr.io/memo-2023/matrix-ollama-bot:latest
platform: linux/amd64
container_name: mana-matrix-bot-ollama
restart: always
depends_on:
synapse:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4011
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_OLLAMA_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_OLLAMA_BOT_ROOMS:-}
OLLAMA_URL: http://host.docker.internal:11434
OLLAMA_MODEL: ${OLLAMA_MODEL:-gemma3:4b}
OLLAMA_TIMEOUT: 120000
volumes:
- matrix_bots_data:/app/data
ports:
- "4011:4011"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4011/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-stats-bot:
image: matrix-stats-bot:local
#platform: linux/amd64
container_name: mana-matrix-bot-stats
restart: always
depends_on:
synapse:
condition: service_healthy
victoriametrics:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4012
TZ: Europe/Berlin
# Redis for session storage (Matrix-SSO-Link)
REDIS_HOST: redis
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
# Mana Core Auth for Matrix-SSO-Link auto-login
MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_STATS_BOT_TOKEN}
MATRIX_REPORT_ROOM_ID: ${MATRIX_STATS_REPORT_ROOM:-}
UMAMI_API_URL: http://umami:3000
UMAMI_USERNAME: ${UMAMI_USERNAME:-admin}
UMAMI_PASSWORD: ${UMAMI_PASSWORD}
PROMETHEUS_URL: http://victoriametrics:9090
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_auth
volumes:
- matrix_bots_data:/app/data
ports:
- "4012:4012"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4012/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-project-doc-bot:
image: ghcr.io/memo-2023/matrix-project-doc-bot:latest
platform: linux/amd64
container_name: mana-matrix-bot-projectdoc
restart: always
depends_on:
synapse:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4013
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_PROJECT_DOC_BOT_TOKEN}
MATRIX_ALLOWED_USERS: ${MATRIX_PROJECT_DOC_ALLOWED_USERS:-}
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/project_doc_bot
S3_ENDPOINT: http://minio:9000
S3_REGION: us-east-1
S3_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
S3_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
S3_BUCKET: project-doc-bot
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
OPENAI_MODEL: gpt-4o-mini
volumes:
- matrix_bots_data:/app/data
ports:
- "4013:4013"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4013/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-todo-bot:
image: matrix-todo-bot:local
build:
context: .
dockerfile: services/matrix-todo-bot/Dockerfile
platform: linux/amd64
container_name: mana-matrix-bot-todo
restart: always
depends_on:
synapse:
condition: service_healthy
todo-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4014
TZ: Europe/Berlin
REDIS_HOST: redis
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
TODO_BACKEND_URL: http://todo-backend:3031
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_TODO_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_TODO_BOT_ROOMS:-}
volumes:
- matrix_bots_data:/app/data
ports:
- "4014:4014"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4014/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-calendar-bot:
image: matrix-calendar-bot:local
pull_policy: never
platform: linux/amd64
container_name: mana-matrix-bot-calendar
restart: always
depends_on:
synapse:
condition: service_healthy
calendar-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4015
TZ: Europe/Berlin
REDIS_HOST: redis
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
CALENDAR_BACKEND_URL: http://calendar-backend:3032
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_CALENDAR_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_CALENDAR_BOT_ROOMS:-}
volumes:
- matrix_bots_data:/app/data
ports:
- "4015:4015"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4015/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-nutriphi-bot:
image: ghcr.io/memo-2023/matrix-nutriphi-bot:latest
platform: linux/amd64
container_name: mana-matrix-bot-nutriphi
restart: always
depends_on:
synapse:
condition: service_healthy
mana-media:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4016
TZ: Europe/Berlin
REDIS_HOST: redis
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
MANA_CORE_AUTH_URL: http://mana-auth:3001
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_NUTRIPHI_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_NUTRIPHI_BOT_ROOMS:-}
NUTRIPHI_BACKEND_URL: http://nutriphi-backend:3037
MANA_MEDIA_URL: http://mana-media:3015
volumes:
- matrix_bots_data:/app/data
ports:
- "4016:4016"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4016/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-zitare-bot:
image: ghcr.io/memo-2023/matrix-zitare-bot:latest
platform: linux/amd64
container_name: mana-matrix-bot-zitare
restart: always
depends_on:
synapse:
condition: service_healthy
zitare-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4017
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_ZITARE_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_ZITARE_BOT_ROOMS:-}
ZITARE_BACKEND_URL: http://zitare-backend:3007
MANA_CORE_AUTH_URL: http://mana-auth:3001
volumes:
- matrix_bots_data:/app/data
ports:
- "4017:4017"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4017/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-clock-bot:
build:
context: .
dockerfile: services/matrix-clock-bot/Dockerfile
image: matrix-clock-bot:local
container_name: mana-matrix-bot-clock
restart: always
depends_on:
synapse:
condition: service_healthy
mana-auth:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4018
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_CLOCK_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_CLOCK_BOT_ROOMS:-}
CLOCK_API_URL: http://clock-backend:3033/api/v1
STT_URL: http://host.docker.internal:3026
STT_API_KEY: ${STT_INTERNAL_API_KEY:-}
MANA_CORE_AUTH_URL: http://mana-core-auth:3001
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
WIDGET_PUBLIC_URL: ${CLOCK_BOT_WIDGET_URL:-https://clock-bot.mana.how/widget}
volumes:
- matrix_bots_data:/app/data
ports:
- "4018:4018"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4018/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-tts-bot:
build:
context: .
dockerfile: services/matrix-tts-bot/Dockerfile
image: matrix-tts-bot:local
platform: linux/amd64
container_name: mana-matrix-bot-tts
restart: always
depends_on:
synapse:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4019
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_TTS_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_TTS_BOT_ROOMS:-}
TTS_URL: http://host.docker.internal:3022
TTS_API_KEY: ${TTS_INTERNAL_API_KEY:-}
DEFAULT_VOICE: de_kerstin
DEFAULT_SPEED: 1.0
MAX_TEXT_LENGTH: 500
volumes:
- matrix_bots_data:/app/data
ports:
- "4019:4019"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4019/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-stt-bot:
build:
context: .
dockerfile: services/matrix-stt-bot/Dockerfile
image: matrix-stt-bot:local
platform: linux/amd64
container_name: mana-matrix-bot-stt
restart: always
depends_on:
synapse:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4021
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_STT_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_STT_BOT_ROOMS:-}
STT_URL: http://host.docker.internal:3026
STT_API_KEY: ${STT_INTERNAL_API_KEY:-}
DEFAULT_LANGUAGE: de
DEFAULT_MODEL: whisper
volumes:
- matrix_bots_data:/app/data
ports:
- "4021:4021"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4021/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-onboarding-bot:
build:
context: .
dockerfile: services/matrix-onboarding-bot/Dockerfile
image: matrix-onboarding-bot:local
container_name: mana-matrix-bot-onboarding
restart: always
depends_on:
synapse:
condition: service_healthy
mana-auth:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4020
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_ONBOARDING_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_ONBOARDING_BOT_ROOMS:-}
MANA_CORE_AUTH_URL: http://mana-auth:3001
MANA_CORE_SERVICE_KEY: ${MANA_CORE_SERVICE_KEY}
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
volumes:
- matrix_bots_data:/app/data
ports:
- "4020:4020"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4020/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
matrix-planta-bot:
build:
context: .
dockerfile: services/matrix-planta-bot/Dockerfile
image: matrix-planta-bot:local
container_name: mana-matrix-bot-planta
restart: always
depends_on:
synapse:
condition: service_healthy
mana-auth:
condition: service_healthy
redis:
condition: service_healthy
planta-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 4022
TZ: Europe/Berlin
MATRIX_HOMESERVER_URL: http://synapse:8008
MATRIX_ACCESS_TOKEN: ${MATRIX_PLANTA_BOT_TOKEN}
MATRIX_ALLOWED_ROOMS: ${MATRIX_PLANTA_BOT_ROOMS:-}
PLANTA_BACKEND_URL: http://planta-backend:3022
PLANTA_API_PREFIX: /api
MANA_CORE_AUTH_URL: http://mana-auth:3001
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
volumes:
- matrix_bots_data:/app/data
ports:
- "4022:4022"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:4022/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# ============================================
# Tier 5: Web Frontends (Ports 5000-5099)
# ============================================
mana-web:
build:
context: .
dockerfile: apps/manacore/apps/web/Dockerfile
image: manacore-web:local
container_name: mana-app-web
restart: always
depends_on:
mana-auth:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5000
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
PUBLIC_TODO_API_URL: http://todo-backend:3031
PUBLIC_TODO_API_URL_CLIENT: https://todo-api.mana.how
PUBLIC_CALENDAR_API_URL: http://calendar-backend:3032
PUBLIC_CALENDAR_API_URL_CLIENT: https://calendar-api.mana.how
PUBLIC_CLOCK_API_URL: http://clock-backend:3033
PUBLIC_CLOCK_API_URL_CLIENT: https://clock-api.mana.how
PUBLIC_CONTACTS_API_URL: http://contacts-backend:3034
PUBLIC_CONTACTS_API_URL_CLIENT: https://contacts-api.mana.how
ports:
- "5000:5000"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
chat-web:
image: ghcr.io/memo-2023/chat-web:latest
container_name: mana-app-chat-web
restart: always
depends_on:
chat-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5010
PUBLIC_BACKEND_URL: http://chat-backend:3030
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://chat-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5010:5010"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5010/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
todo-web:
build:
context: .
dockerfile: apps/todo/apps/web/Dockerfile
image: todo-web:local
container_name: mana-app-todo-web
restart: always
depends_on:
todo-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5011
PUBLIC_BACKEND_URL: http://todo-backend:3031
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://todo-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5011:5011"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5011/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
zitare-web:
build:
context: .
dockerfile: apps/zitare/apps/web/Dockerfile
image: zitare-web:local
container_name: mana-app-zitare-web
restart: always
depends_on:
zitare-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5018
PUBLIC_ZITARE_API_URL: http://zitare-backend:3007
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_ZITARE_API_URL_CLIENT: https://zitare-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5018:5018"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5018/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
calendar-web:
image: ghcr.io/memo-2023/calendar-web:latest
container_name: mana-app-calendar-web
restart: always
depends_on:
calendar-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5012
PUBLIC_BACKEND_URL: http://calendar-backend:3032
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://calendar-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
PUBLIC_TODO_BACKEND_URL: https://todo-api.mana.how
PUBLIC_CONTACTS_API_URL: https://contacts-api.mana.how
ports:
- "5012:5012"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5012/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
clock-web:
image: ghcr.io/memo-2023/clock-web:latest
container_name: mana-app-clock-web
restart: always
depends_on:
clock-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5013
PUBLIC_BACKEND_URL: http://clock-backend:3033
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://clock-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5013:5013"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5013/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
contacts-web:
build:
context: .
dockerfile: apps/contacts/apps/web/Dockerfile
args:
PUBLIC_BACKEND_URL: http://contacts-backend:3034
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
image: contacts-web:local
container_name: mana-app-contacts-web
restart: always
depends_on:
contacts-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5014
PUBLIC_BACKEND_URL: http://contacts-backend:3034
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://contacts-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
PUBLIC_TODO_BACKEND_URL: https://todo-api.mana.how
ports:
- "5014:5014"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5014/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
storage-web:
image: ghcr.io/memo-2023/storage-web:latest
container_name: mana-app-storage-web
restart: always
depends_on:
storage-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5015
PUBLIC_BACKEND_URL: http://storage-backend:3035
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://storage-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5015:5015"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5015/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
presi-web:
image: ghcr.io/memo-2023/presi-web:latest
container_name: mana-app-presi-web
restart: always
depends_on:
presi-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5016
PUBLIC_BACKEND_URL: http://presi-backend:3036
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://presi-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5016:5016"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5016/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
nutriphi-web:
image: ghcr.io/memo-2023/nutriphi-web:latest
container_name: mana-app-nutriphi-web
restart: always
depends_on:
nutriphi-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5017
PUBLIC_BACKEND_URL: http://nutriphi-backend:3037
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://nutriphi-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5017:5017"
healthcheck:
test: ["CMD", "node", "-e", "const http = require('http'); http.get('http://127.0.0.1:5017/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
skilltree-web:
build:
context: .
dockerfile: apps/skilltree/apps/web/Dockerfile
args:
PUBLIC_BACKEND_URL: http://skilltree-backend:3038
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
image: skilltree-web:local
container_name: mana-app-skilltree-web
restart: always
depends_on:
skilltree-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5020
PUBLIC_BACKEND_URL: http://skilltree-backend:3038
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://skilltree-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5020:5020"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5020/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
photos-web:
build:
context: .
dockerfile: apps/photos/apps/web/Dockerfile
args:
PUBLIC_BACKEND_URL: http://photos-backend:3039
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_MANA_MEDIA_URL: http://mana-media:3015
image: photos-web:local
container_name: mana-app-photos-web
restart: always
depends_on:
photos-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5019
PUBLIC_BACKEND_URL: http://photos-backend:3039
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_MANA_MEDIA_URL: http://mana-media:3015
PUBLIC_BACKEND_URL_CLIENT: https://photos-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
PUBLIC_MANA_MEDIA_URL_CLIENT: https://media.mana.how
ports:
- "5019:5019"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5019/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mukke-web:
build:
context: .
dockerfile: apps/mukke/apps/web/Dockerfile
args:
PUBLIC_BACKEND_URL: http://mukke-backend:3010
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
image: mukke-web:local
container_name: mana-app-mukke-web
restart: always
depends_on:
mukke-backend:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5180
PUBLIC_BACKEND_URL: http://mukke-backend:3010
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_BACKEND_URL_CLIENT: https://mukke-api.mana.how
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
ports:
- "5180:5180"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5180/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mana-llm:
build:
context: ./services/mana-llm
dockerfile: Dockerfile
container_name: mana-service-llm
restart: unless-stopped
depends_on:
redis:
condition: service_healthy
environment:
PORT: 3025
LOG_LEVEL: info
OLLAMA_URL: http://host.docker.internal:11434
OLLAMA_DEFAULT_MODEL: gemma3:4b
OLLAMA_TIMEOUT: 120
REDIS_URL: redis://redis:6379
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
GROQ_API_KEY: ${GROQ_API_KEY:-}
TOGETHER_API_KEY: ${TOGETHER_API_KEY:-}
CORS_ORIGINS: https://playground.mana.how,https://mana.how,https://chat.mana.how
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- "3025:3025"
healthcheck:
test: ["CMD", "python", "-c", "import httpx; httpx.get('http://localhost:3025/health').raise_for_status()"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
llm-playground:
build:
context: .
dockerfile: services/llm-playground/Dockerfile
container_name: mana-app-llm-playground
restart: unless-stopped
depends_on:
mana-auth:
condition: service_healthy
mana-llm:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5090
PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
PUBLIC_MANA_LLM_URL: http://mana-llm:3025
PUBLIC_MANA_LLM_URL_CLIENT: https://llm.mana.how
ports:
- "5090:5090"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5090/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
labels:
- "com.centurylinklabs.watchtower.enable=true"
# ============================================
# Tier 6: Automation & Workflows (Ports 6000-6099)
# ============================================
n8n:
image: n8nio/n8n:latest
container_name: mana-auto-n8n
restart: always
depends_on:
postgres:
condition: service_healthy
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: postgres
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD:-mana123}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY:-change-me-n8n-encryption-key}
N8N_USER_MANAGEMENT_JWT_SECRET: ${N8N_JWT_SECRET:-change-me-n8n-jwt-secret}
N8N_HOST: n8n.mana.how
N8N_PROTOCOL: https
WEBHOOK_URL: https://n8n.mana.how/
N8N_BASIC_AUTH_ACTIVE: "false"
N8N_PORT: 6000
GENERIC_TIMEZONE: Europe/Berlin
TZ: Europe/Berlin
N8N_DIAGNOSTICS_ENABLED: "false"
N8N_VERSION_NOTIFICATIONS_ENABLED: "false"
volumes:
- n8n_data:/home/node/.n8n
ports:
- "6000:6000"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:6000/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# ============================================
# Tier 7: Monitoring Dashboards (Ports 8000-8099)
# ============================================
grafana:
image: grafana/grafana:10.4.1
container_name: mana-mon-grafana
restart: always
depends_on:
victoriametrics:
condition: service_healthy
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
GF_USERS_ALLOW_SIGN_UP: false
GF_AUTH_ANONYMOUS_ENABLED: true
GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer
GF_SERVER_ROOT_URL: https://grafana.mana.how
GF_SERVER_HTTP_PORT: 8000
GF_INSTALL_PLUGINS: yesoreyeram-infinity-datasource
GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH: /var/lib/grafana/dashboards/master-overview.json
volumes:
- ./docker/grafana/provisioning:/etc/grafana/provisioning:ro
- ./docker/grafana/dashboards:/var/lib/grafana/dashboards:ro
- grafana_data:/var/lib/grafana
ports:
- "8000:8000"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8000/api/health"]
interval: 30s
timeout: 10s
retries: 3
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
container_name: mana-mon-umami
restart: always
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/umami
DATABASE_TYPE: postgresql
APP_SECRET: ${UMAMI_APP_SECRET:-change-me-umami-secret}
DISABLE_TELEMETRY: 1
ports:
- "8010:3000"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/heartbeat"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# ============================================
# Tier 8: Metrics & Exporters (Ports 9000-9199)
# ============================================
victoriametrics:
image: victoriametrics/victoria-metrics:v1.99.0
container_name: mana-mon-victoria
restart: always
command:
- '-storageDataPath=/storage'
- '-retentionPeriod=2y'
- '-httpListenAddr=:9090'
- '-promscrape.config=/etc/prometheus/prometheus.yml'
- '-promscrape.config.strictParse=false'
- '-selfScrapeInterval=15s'
- '-search.latencyOffset=0s'
volumes:
- ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./docker/prometheus/alerts.yml:/etc/prometheus/alerts.yml:ro
- victoriametrics_data:/storage
ports:
- "9090:9090"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:9090/health"]
interval: 30s
timeout: 10s
retries: 3
pushgateway:
image: prom/pushgateway:v1.7.0
container_name: mana-mon-pushgateway
restart: always
ports:
- "9091:9091"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:9091/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
cadvisor:
image: gcr.io/cadvisor/cadvisor:v0.49.1
container_name: mana-mon-cadvisor
restart: always
privileged: true
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
ports:
- "9110:8080"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8080/healthz"]
interval: 30s
timeout: 10s
retries: 3
postgres-exporter:
image: prometheuscommunity/postgres-exporter:v0.15.0
container_name: mana-mon-postgres-exporter
restart: always
depends_on:
postgres:
condition: service_healthy
environment:
DATA_SOURCE_NAME: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/postgres?sslmode=disable
ports:
- "9187:9187"
redis-exporter:
image: oliver006/redis_exporter:v1.58.0
container_name: mana-mon-redis-exporter
restart: always
depends_on:
redis:
condition: service_healthy
environment:
REDIS_ADDR: redis://redis:6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
ports:
- "9121:9121"
node-exporter:
image: prom/node-exporter:v1.7.0
container_name: mana-mon-node-exporter
restart: always
# macOS Docker runs in a Linux VM, so we can only monitor the VM's metrics
# For full host metrics on macOS, install node_exporter natively
command:
- '--collector.disable-defaults'
- '--collector.cpu'
- '--collector.meminfo'
- '--collector.loadavg'
- '--collector.filesystem'
- '--collector.netdev'
- '--collector.time'
- '--collector.uname'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
ports:
- "9100:9100"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:9100/metrics"]
interval: 30s
timeout: 10s
retries: 3
# ============================================
# Alerting Stack (Ports 9093-9095)
# ============================================
vmalert:
image: victoriametrics/vmalert:v1.99.0
container_name: mana-mon-vmalert
restart: always
depends_on:
victoriametrics:
condition: service_healthy
alertmanager:
condition: service_healthy
command:
- '-datasource.url=http://victoriametrics:9090'
- '-notifier.url=http://alertmanager:9093'
- '-remoteWrite.url=http://victoriametrics:9090'
- '-remoteRead.url=http://victoriametrics:9090'
- '-rule=/etc/alerts/*.yml'
- '-evaluationInterval=30s'
- '-httpListenAddr=:8880'
volumes:
- ./docker/prometheus/alerts.yml:/etc/alerts/alerts.yml:ro
ports:
- "8880:8880"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8880/health"]
interval: 30s
timeout: 10s
retries: 3
alertmanager:
image: prom/alertmanager:v0.27.0
container_name: mana-mon-alertmanager
restart: always
depends_on:
alert-notifier:
condition: service_healthy
command:
- '--config.file=/etc/alertmanager/alertmanager.yml'
- '--storage.path=/alertmanager'
- '--web.listen-address=:9093'
volumes:
- ./docker/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
- alertmanager_data:/alertmanager
ports:
- "9093:9093"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:9093/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
alert-notifier:
build:
context: ./docker/alert-notifier
dockerfile: Dockerfile
image: alert-notifier:local
container_name: mana-mon-alert-notifier
restart: always
environment:
PORT: 8080
TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:-}
TELEGRAM_CHAT_ID: ${TELEGRAM_CHAT_ID:-}
NTFY_TOPIC: ${NTFY_TOPIC:-}
ports:
- "9095:8080"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8080/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 5s
# ============================================
# Auto-Update (Watchtower)
# ============================================
watchtower:
image: nickfedor/watchtower:latest
container_name: mana-auto-watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
TZ: Europe/Berlin
DOCKER_API_VERSION: 1.45
WATCHTOWER_POLL_INTERVAL: 300
WATCHTOWER_CLEANUP: "true"
WATCHTOWER_INCLUDE_STOPPED: "false"
# Notifications disabled - configure Matrix if needed
# ============================================
# Volumes (Naming: mana-{service}-data)
# ============================================
# ============================================
# GlitchTip Error Tracking (Sentry-compatible)
# ============================================
glitchtip:
image: glitchtip/glitchtip:latest
container_name: mana-mon-glitchtip
restart: always
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/glitchtip
REDIS_URL: redis://:${REDIS_PASSWORD:-redis123}@redis:6379/1
SECRET_KEY: ${GLITCHTIP_SECRET_KEY:-change-me-in-production}
PORT: "8020"
GLITCHTIP_DOMAIN: https://glitchtip.mana.how
DEFAULT_FROM_EMAIL: glitchtip@mana.how
CELERY_WORKER_AUTOSCALE: "1,3"
ENABLE_USER_REGISTRATION: "true"
ports:
- "8020:8020"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8020/_health/"]
interval: 30s
timeout: 10s
retries: 3
glitchtip-worker:
image: glitchtip/glitchtip:latest
container_name: mana-mon-glitchtip-worker
restart: always
command: ./bin/run-celery-with-beat.sh
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/glitchtip
REDIS_URL: redis://:${REDIS_PASSWORD:-redis123}@redis:6379/1
SECRET_KEY: ${GLITCHTIP_SECRET_KEY:-change-me-in-production}
GLITCHTIP_DOMAIN: https://glitchtip.mana.how
CELERY_WORKER_AUTOSCALE: "1,3"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
volumes:
redis_data:
name: mana-redis-data
victoriametrics_data:
name: mana-victoria-data
alertmanager_data:
name: mana-alertmanager-data
grafana_data:
name: mana-grafana-data
analytics_data:
name: mana-analytics-data
n8n_data:
name: mana-n8n-data
matrix_bots_data:
name: mana-matrix-bots-data