diff --git a/.env.prod.example b/.env.prod.example deleted file mode 100644 index 1b21644..0000000 --- a/.env.prod.example +++ /dev/null @@ -1,66 +0,0 @@ -# ============================================== -# Mosaic Stack Production Environment -# ============================================== -# Copy to .env and configure for production deployment - -# ====================== -# PostgreSQL Database -# ====================== -# CRITICAL: Use a strong, unique password -POSTGRES_USER=mosaic -POSTGRES_PASSWORD=REPLACE_WITH_SECURE_PASSWORD -POSTGRES_DB=mosaic -POSTGRES_SHARED_BUFFERS=256MB -POSTGRES_EFFECTIVE_CACHE_SIZE=1GB -POSTGRES_MAX_CONNECTIONS=100 - -# ====================== -# Valkey Cache -# ====================== -VALKEY_MAXMEMORY=256mb - -# ====================== -# API Configuration -# ====================== -API_PORT=3001 -API_HOST=0.0.0.0 - -# ====================== -# Web Configuration -# ====================== -WEB_PORT=3000 -NEXT_PUBLIC_API_URL=https://api.mosaicstack.dev - -# ====================== -# Authentication (Authentik OIDC) -# ====================== -OIDC_ISSUER=https://auth.diversecanvas.com/application/o/mosaic-stack/ -OIDC_CLIENT_ID=your-client-id -OIDC_CLIENT_SECRET=your-client-secret -OIDC_REDIRECT_URI=https://api.mosaicstack.dev/auth/callback/authentik - -# ====================== -# JWT Configuration -# ====================== -# CRITICAL: Generate a random secret (openssl rand -base64 32) -JWT_SECRET=REPLACE_WITH_RANDOM_SECRET -JWT_EXPIRATION=24h - -# ====================== -# Traefik Integration -# ====================== -# Set to true if using external Traefik -TRAEFIK_ENABLE=true -TRAEFIK_ENTRYPOINT=websecure -TRAEFIK_TLS_ENABLED=true -TRAEFIK_DOCKER_NETWORK=traefik-public -TRAEFIK_CERTRESOLVER=letsencrypt - -# Domain configuration -MOSAIC_API_DOMAIN=api.mosaicstack.dev -MOSAIC_WEB_DOMAIN=app.mosaicstack.dev - -# ====================== -# Optional: Ollama -# ====================== -# OLLAMA_ENDPOINT=http://ollama.diversecanvas.com:11434 diff --git a/.env.swarm.example b/.env.swarm.example deleted file mode 100644 index efa9d8a..0000000 --- a/.env.swarm.example +++ /dev/null @@ -1,161 +0,0 @@ -# ============================================== -# Mosaic Stack - Docker Swarm Configuration -# ============================================== -# Copy this file to .env for Docker Swarm deployment - -# ====================== -# Application Ports (Internal) -# ====================== -API_PORT=3001 -API_HOST=0.0.0.0 -WEB_PORT=3000 - -# ====================== -# Domain Configuration (Traefik) -# ====================== -# These domains must be configured in your DNS or /etc/hosts -MOSAIC_API_DOMAIN=api.mosaicstack.dev -MOSAIC_WEB_DOMAIN=mosaic.mosaicstack.dev -MOSAIC_AUTH_DOMAIN=auth.mosaicstack.dev - -# ====================== -# Web Configuration -# ====================== -# Use the Traefik domain for the API URL -NEXT_PUBLIC_APP_URL=http://mosaic.mosaicstack.dev -NEXT_PUBLIC_API_URL=http://api.mosaicstack.dev - -# ====================== -# PostgreSQL Database -# ====================== -DATABASE_URL=postgresql://mosaic:REPLACE_WITH_SECURE_PASSWORD@postgres:5432/mosaic -POSTGRES_USER=mosaic -POSTGRES_PASSWORD=REPLACE_WITH_SECURE_PASSWORD -POSTGRES_DB=mosaic -POSTGRES_PORT=5432 - -# PostgreSQL Performance Tuning -POSTGRES_SHARED_BUFFERS=256MB -POSTGRES_EFFECTIVE_CACHE_SIZE=1GB -POSTGRES_MAX_CONNECTIONS=100 - -# ====================== -# Valkey Cache -# ====================== -VALKEY_URL=redis://valkey:6379 -VALKEY_HOST=valkey -VALKEY_PORT=6379 -VALKEY_MAXMEMORY=256mb - -# Knowledge Module Cache Configuration -KNOWLEDGE_CACHE_ENABLED=true -KNOWLEDGE_CACHE_TTL=300 - -# ====================== -# Authentication (Authentik OIDC) -# ====================== -# NOTE: Authentik services are COMMENTED OUT in docker-compose.swarm.yml by default -# Uncomment those services if you want to run Authentik internally -# Otherwise, use external Authentik by configuring OIDC_* variables below - -# External Authentik Configuration (default) -OIDC_ENABLED=true -OIDC_ISSUER=https://auth.example.com/application/o/mosaic-stack/ -OIDC_CLIENT_ID=your-client-id-here -OIDC_CLIENT_SECRET=your-client-secret-here -OIDC_REDIRECT_URI=https://api.mosaicstack.dev/auth/callback/authentik - -# Internal Authentik Configuration (only needed if uncommenting Authentik services) -# Authentik PostgreSQL Database -AUTHENTIK_POSTGRES_USER=authentik -AUTHENTIK_POSTGRES_PASSWORD=REPLACE_WITH_SECURE_PASSWORD -AUTHENTIK_POSTGRES_DB=authentik - -# Authentik Server Configuration -AUTHENTIK_SECRET_KEY=REPLACE_WITH_RANDOM_SECRET_MINIMUM_50_CHARS -AUTHENTIK_ERROR_REPORTING=false -AUTHENTIK_BOOTSTRAP_PASSWORD=REPLACE_WITH_SECURE_PASSWORD -AUTHENTIK_BOOTSTRAP_EMAIL=admin@mosaicstack.dev -AUTHENTIK_COOKIE_DOMAIN=.mosaicstack.dev - -# ====================== -# JWT Configuration -# ====================== -JWT_SECRET=REPLACE_WITH_RANDOM_SECRET_MINIMUM_32_CHARS -JWT_EXPIRATION=24h - -# ====================== -# Encryption (Credential Security) -# ====================== -# Generate with: openssl rand -hex 32 -ENCRYPTION_KEY=REPLACE_WITH_64_CHAR_HEX_STRING_GENERATE_WITH_OPENSSL_RAND_HEX_32 - -# ====================== -# OpenBao Secrets Management -# ====================== -OPENBAO_ADDR=http://openbao:8200 -OPENBAO_PORT=8200 -# For development only - remove in production -OPENBAO_DEV_ROOT_TOKEN_ID=root - -# ====================== -# Ollama (Optional AI Service) -# ====================== -OLLAMA_ENDPOINT=http://ollama:11434 -OLLAMA_PORT=11434 -OLLAMA_EMBEDDING_MODEL=mxbai-embed-large - -# Semantic Search Configuration -SEMANTIC_SEARCH_SIMILARITY_THRESHOLD=0.5 - -# ====================== -# OpenAI API (Optional) -# ====================== -# OPENAI_API_KEY=sk-... - -# ====================== -# Application Environment -# ====================== -NODE_ENV=production - -# ====================== -# Gitea Integration (Coordinator) -# ====================== -GITEA_URL=https://git.mosaicstack.dev -GITEA_BOT_USERNAME=mosaic -GITEA_BOT_TOKEN=REPLACE_WITH_COORDINATOR_BOT_API_TOKEN -GITEA_BOT_PASSWORD=REPLACE_WITH_COORDINATOR_BOT_PASSWORD -GITEA_REPO_OWNER=mosaic -GITEA_REPO_NAME=stack -GITEA_WEBHOOK_SECRET=REPLACE_WITH_RANDOM_WEBHOOK_SECRET -COORDINATOR_API_KEY=REPLACE_WITH_RANDOM_API_KEY_MINIMUM_32_CHARS - -# ====================== -# Coordinator Service -# ====================== -ANTHROPIC_API_KEY=REPLACE_WITH_ANTHROPIC_API_KEY -COORDINATOR_POLL_INTERVAL=5.0 -COORDINATOR_MAX_CONCURRENT_AGENTS=10 -COORDINATOR_ENABLED=true - -# ====================== -# Rate Limiting -# ====================== -RATE_LIMIT_TTL=60 -RATE_LIMIT_GLOBAL_LIMIT=100 -RATE_LIMIT_WEBHOOK_LIMIT=60 -RATE_LIMIT_COORDINATOR_LIMIT=100 -RATE_LIMIT_HEALTH_LIMIT=300 -RATE_LIMIT_STORAGE=redis - -# ====================== -# Orchestrator Configuration -# ====================== -ORCHESTRATOR_API_KEY=REPLACE_WITH_RANDOM_API_KEY_MINIMUM_32_CHARS -CLAUDE_API_KEY=REPLACE_WITH_CLAUDE_API_KEY - -# ====================== -# Logging & Debugging -# ====================== -LOG_LEVEL=info -DEBUG=false diff --git a/docker-compose.portainer.yml b/docker-compose.portainer.yml deleted file mode 100644 index 54430b4..0000000 --- a/docker-compose.portainer.yml +++ /dev/null @@ -1,95 +0,0 @@ -# ============================================== -# OpenBao Standalone Deployment - Portainer Version -# ============================================== -# -# This file is optimized for Portainer deployment: -# - No env_file directive (define variables in Portainer's environment editor) -# - Port exposed on all interfaces (Portainer limitation) -# - All environment variables explicitly defined -# -# Usage in Portainer: -# 1. Stacks -> Add Stack -# 2. Name: mosaic-openbao -# 3. Paste this file content -# 4. Add environment variables in "Environment variables" section: -# - IMAGE_TAG=dev -# - OPENBAO_PORT=8200 -# 5. Deploy -# -# SECURITY NOTE: Port 8200 will be exposed on 0.0.0.0 (all interfaces) -# Use firewall rules to restrict access if needed. -# ============================================== - -services: - # ====================== - # OpenBao Secrets Vault - # ====================== - openbao: - image: git.mosaicstack.dev/mosaic/stack-openbao:${IMAGE_TAG:-dev} - container_name: mosaic-openbao - entrypoint: ["dumb-init", "--"] - command: ["bao", "server", "-config=/openbao/config/config.hcl"] - environment: - OPENBAO_ADDR: http://0.0.0.0:8200 - ports: - - "${OPENBAO_PORT:-8200}:8200" - volumes: - - openbao_data:/openbao/data - - openbao_logs:/openbao/logs - - openbao_init:/openbao/init - cap_add: - - IPC_LOCK - healthcheck: - test: - [ - "CMD-SHELL", - "wget --spider --quiet 'http://localhost:8200/v1/sys/health?standbyok=true&uninitcode=200&sealedcode=200'", - ] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - restart: unless-stopped - networks: - - mosaic_internal - - # ====================== - # OpenBao Init Sidecar - # ====================== - # Auto-initializes and unseals OpenBao on first run - openbao-init: - image: git.mosaicstack.dev/mosaic/stack-openbao:${IMAGE_TAG:-dev} - container_name: mosaic-openbao-init - command: /openbao/init.sh - environment: - OPENBAO_ADDR: http://openbao:8200 - volumes: - - openbao_init:/openbao/init - depends_on: - - openbao - restart: "no" - networks: - - mosaic_internal - -# ====================== -# Volumes -# ====================== -volumes: - openbao_data: - name: mosaic-openbao-data - driver: local - openbao_logs: - name: mosaic-openbao-logs - driver: local - openbao_init: - name: mosaic-openbao-init - driver: local - -# ====================== -# Networks -# ====================== -# Connect to the swarm stack's internal network -networks: - mosaic_internal: - external: true - name: mosaic_internal diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml deleted file mode 100644 index d248237..0000000 --- a/docker-compose.prod.yml +++ /dev/null @@ -1,180 +0,0 @@ -# Production Docker Compose - Uses pre-built images from Gitea Packages -# -# Prerequisites: -# - Images built and pushed to git.mosaicstack.dev/mosaic/* -# - .env file configured with production values -# -# Usage: -# docker compose -f docker-compose.prod.yml up -d -# -# For Portainer: -# - Stack → Add Stack → Repository -# - Compose file: docker-compose.prod.yml - -services: - # ====================== - # PostgreSQL Database - # ====================== - postgres: - image: git.mosaicstack.dev/mosaic/stack-postgres:${IMAGE_TAG:-latest} - container_name: mosaic-postgres - restart: unless-stopped - environment: - POSTGRES_USER: ${POSTGRES_USER:-mosaic} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB:-mosaic} - POSTGRES_SHARED_BUFFERS: ${POSTGRES_SHARED_BUFFERS:-256MB} - POSTGRES_EFFECTIVE_CACHE_SIZE: ${POSTGRES_EFFECTIVE_CACHE_SIZE:-1GB} - POSTGRES_MAX_CONNECTIONS: ${POSTGRES_MAX_CONNECTIONS:-100} - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-mosaic} -d ${POSTGRES_DB:-mosaic}"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - networks: - - mosaic-internal - labels: - - "com.mosaic.service=database" - - "com.mosaic.description=PostgreSQL 17 with pgvector" - - # ====================== - # Valkey Cache - # ====================== - valkey: - image: valkey/valkey:8-alpine - container_name: mosaic-valkey - restart: unless-stopped - command: - - valkey-server - - --maxmemory ${VALKEY_MAXMEMORY:-256mb} - - --maxmemory-policy noeviction - - --appendonly yes - volumes: - - valkey_data:/data - healthcheck: - test: ["CMD", "valkey-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - networks: - - mosaic-internal - labels: - - "com.mosaic.service=cache" - - "com.mosaic.description=Valkey Redis-compatible cache" - - # ====================== - # Mosaic API - # ====================== - api: - image: git.mosaicstack.dev/mosaic/stack-api:${IMAGE_TAG:-latest} - container_name: mosaic-api - restart: unless-stopped - environment: - NODE_ENV: production - PORT: ${API_PORT:-3001} - API_HOST: ${API_HOST:-0.0.0.0} - DATABASE_URL: postgresql://${POSTGRES_USER:-mosaic}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-mosaic} - VALKEY_URL: redis://valkey:6379 - OIDC_ISSUER: ${OIDC_ISSUER} - OIDC_CLIENT_ID: ${OIDC_CLIENT_ID} - OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET} - OIDC_REDIRECT_URI: ${OIDC_REDIRECT_URI} - JWT_SECRET: ${JWT_SECRET} - JWT_EXPIRATION: ${JWT_EXPIRATION:-24h} - BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET} - OLLAMA_ENDPOINT: ${OLLAMA_ENDPOINT:-http://ollama:11434} - ports: - - "${API_PORT:-3001}:${API_PORT:-3001}" - depends_on: - postgres: - condition: service_healthy - valkey: - condition: service_healthy - healthcheck: - test: - [ - "CMD-SHELL", - 'node -e "require(''http'').get(''http://localhost:${API_PORT:-3001}/health'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"', - ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - networks: - - mosaic-internal - - mosaic-public - labels: - - "com.mosaic.service=api" - - "com.mosaic.description=Mosaic NestJS API" - - "traefik.enable=${TRAEFIK_ENABLE:-false}" - - "traefik.http.routers.mosaic-api.rule=Host(`${MOSAIC_API_DOMAIN:-api.mosaicstack.dev}`)" - - "traefik.http.routers.mosaic-api.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - - "traefik.http.routers.mosaic-api.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.services.mosaic-api.loadbalancer.server.port=${API_PORT:-3001}" - - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}" - - "traefik.http.routers.mosaic-api.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - - # ====================== - # Mosaic Web - # ====================== - web: - image: git.mosaicstack.dev/mosaic/stack-web:${IMAGE_TAG:-latest} - container_name: mosaic-web - restart: unless-stopped - environment: - NODE_ENV: production - PORT: ${WEB_PORT:-3000} - NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-https://api.mosaicstack.dev} - ports: - - "${WEB_PORT:-3000}:${WEB_PORT:-3000}" - depends_on: - api: - condition: service_healthy - healthcheck: - test: - [ - "CMD-SHELL", - 'node -e "require(''http'').get(''http://localhost:${WEB_PORT:-3000}'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"', - ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - networks: - - mosaic-public - labels: - - "com.mosaic.service=web" - - "com.mosaic.description=Mosaic Next.js Web App" - - "traefik.enable=${TRAEFIK_ENABLE:-false}" - - "traefik.http.routers.mosaic-web.rule=Host(`${MOSAIC_WEB_DOMAIN:-app.mosaicstack.dev}`)" - - "traefik.http.routers.mosaic-web.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - - "traefik.http.routers.mosaic-web.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.services.mosaic-web.loadbalancer.server.port=${WEB_PORT:-3000}" - - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}" - - "traefik.http.routers.mosaic-web.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - -# ====================== -# Volumes -# ====================== -volumes: - postgres_data: - name: mosaic-postgres-data - driver: local - valkey_data: - name: mosaic-valkey-data - driver: local - -# ====================== -# Networks -# ====================== -networks: - mosaic-internal: - name: mosaic-internal - driver: bridge - mosaic-public: - name: mosaic-public - driver: bridge diff --git a/docker-compose.speech.yml b/docker-compose.speech.yml deleted file mode 100644 index 855a947..0000000 --- a/docker-compose.speech.yml +++ /dev/null @@ -1,113 +0,0 @@ -# ============================================== -# Speech Services - Docker Compose Dev Overlay -# ============================================== -# -# Adds STT and TTS services for local development. -# -# Usage: -# Basic (STT + default TTS): -# docker compose -f docker-compose.yml -f docker-compose.speech.yml up -d -# -# With premium TTS (requires GPU): -# docker compose -f docker-compose.yml -f docker-compose.speech.yml --profile premium-tts up -d -# -# Or use Makefile targets: -# make speech-up # Basic speech services -# make speech-down # Stop speech services -# make speech-logs # View speech service logs -# ============================================== - -services: - # ====================== - # Speaches (STT + basic TTS) - # ====================== - speaches: - image: ghcr.io/speaches-ai/speaches:latest - container_name: mosaic-speaches - restart: unless-stopped - environment: - WHISPER__MODEL: ${SPEACHES_WHISPER_MODEL:-Systran/faster-whisper-large-v3-turbo} - ports: - - "${SPEACHES_PORT:-8090}:8000" - volumes: - - speaches_models:/root/.cache/huggingface - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 120s - networks: - - mosaic-internal - labels: - - "com.mosaic.service=speech-stt" - - "com.mosaic.description=Speaches STT (Whisper) and basic TTS" - - # ====================== - # Kokoro TTS (Default TTS) - # ====================== - kokoro-tts: - image: ghcr.io/remsky/kokoro-fastapi:latest-cpu - container_name: mosaic-kokoro-tts - restart: unless-stopped - ports: - - "${KOKORO_TTS_PORT:-8880}:8880" - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8880/health || exit 1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 120s - networks: - - mosaic-internal - labels: - - "com.mosaic.service=speech-tts" - - "com.mosaic.description=Kokoro FastAPI TTS engine" - - # ====================== - # Chatterbox TTS (Premium TTS - Optional) - # ====================== - # Only starts with: --profile premium-tts - # Requires NVIDIA GPU with docker nvidia runtime - chatterbox-tts: - image: devnen/chatterbox-tts-server:latest - container_name: mosaic-chatterbox-tts - restart: unless-stopped - ports: - - "${CHATTERBOX_TTS_PORT:-8881}:8000" - profiles: - - premium-tts - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: 1 - capabilities: [gpu] - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 180s - networks: - - mosaic-internal - labels: - - "com.mosaic.service=speech-tts-premium" - - "com.mosaic.description=Chatterbox premium TTS with voice cloning (GPU)" - -# ====================== -# Volumes -# ====================== -volumes: - speaches_models: - name: mosaic-speaches-models - driver: local - -# ====================== -# Networks -# ====================== -networks: - mosaic-internal: - external: true - name: mosaic-internal diff --git a/docker-compose.swarm.yml b/docker-compose.swarm.yml deleted file mode 100644 index 1d3b1af..0000000 --- a/docker-compose.swarm.yml +++ /dev/null @@ -1,459 +0,0 @@ -# ============================================== -# Mosaic Stack - Docker Swarm Deployment -# ============================================== -# -# IMPORTANT: Docker Swarm does NOT support docker-compose profiles -# To disable services (e.g., for external alternatives), manually comment them out -# -# Current Configuration: -# - PostgreSQL: ENABLED (internal) -# - Valkey: ENABLED (internal) -# - Coordinator: ENABLED (internal) -# - OpenBao: DISABLED (must use standalone - see docker-compose.openbao.yml) -# - Authentik: DISABLED (commented out - using external OIDC) -# - Ollama: DISABLED (commented out - using external Ollama) -# -# For detailed deployment instructions, see: -# docs/SWARM-DEPLOYMENT.md -# -# Quick Start: -# 1. cp .env.swarm.example .env -# 2. nano .env # Configure environment -# 3. ./scripts/deploy-swarm.sh mosaic -# 4. Initialize OpenBao manually (see docs/SWARM-DEPLOYMENT.md) -# -# ============================================== - -services: - # ====================== - # PostgreSQL Database - # ====================== - postgres: - image: git.mosaicstack.dev/mosaic/stack-postgres:${IMAGE_TAG:-latest} - env_file: .env - environment: - POSTGRES_USER: ${POSTGRES_USER:-mosaic} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mosaic_dev_password} - POSTGRES_DB: ${POSTGRES_DB:-mosaic} - POSTGRES_SHARED_BUFFERS: ${POSTGRES_SHARED_BUFFERS:-256MB} - POSTGRES_EFFECTIVE_CACHE_SIZE: ${POSTGRES_EFFECTIVE_CACHE_SIZE:-1GB} - POSTGRES_MAX_CONNECTIONS: ${POSTGRES_MAX_CONNECTIONS:-100} - volumes: - - postgres_data:/var/lib/postgresql/data - # Note: init-scripts bind mount removed for Portainer compatibility - # Init scripts are baked into the postgres image at build time - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-mosaic} -d ${POSTGRES_DB:-mosaic}"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - networks: - - internal - deploy: - restart_policy: - condition: on-failure - - # ====================== - # Valkey Cache - # ====================== - valkey: - image: valkey/valkey:8-alpine - env_file: .env - command: - - valkey-server - - --maxmemory ${VALKEY_MAXMEMORY:-256mb} - - --maxmemory-policy noeviction - - --appendonly yes - volumes: - - valkey_data:/data - healthcheck: - test: ["CMD", "valkey-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - networks: - - internal - deploy: - restart_policy: - condition: on-failure - - # ====================== - # OpenBao Secrets Vault - # ====================== - openbao: - image: git.mosaicstack.dev/mosaic/stack-openbao:${IMAGE_TAG:-latest} - entrypoint: ["dumb-init", "--"] - command: ["bao", "server", "-config=/openbao/config/config.hcl"] - env_file: .env - environment: - OPENBAO_ADDR: http://0.0.0.0:8200 - volumes: - - openbao_data:/openbao/data - - openbao_logs:/openbao/logs - - openbao_init:/openbao/init - cap_add: - - IPC_LOCK - healthcheck: - test: - [ - "CMD-SHELL", - "wget --spider --quiet 'http://localhost:8200/v1/sys/health?standbyok=true&uninitcode=200&sealedcode=200'", - ] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - networks: - - internal - deploy: - restart_policy: - condition: on-failure - - # ====================== - # OpenBao Init Sidecar - # ====================== - # Auto-initializes and unseals OpenBao on first run. - # The init script has built-in retry logic (waits for OpenBao API). - openbao-init: - image: git.mosaicstack.dev/mosaic/stack-openbao:${IMAGE_TAG:-latest} - command: /openbao/init.sh - env_file: .env - environment: - VAULT_ADDR: http://openbao:8200 - volumes: - - openbao_init:/openbao/init - networks: - - internal - deploy: - restart_policy: - condition: on-failure - max_attempts: 5 - delay: 10s - - # ====================== - # Authentik - COMMENTED OUT (Using External Authentik) - # ====================== - # Uncomment these services if you want to run Authentik internally - # For external Authentik, configure OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET in .env - # - # authentik-postgres: - # image: postgres:17.7-alpine3.22 - # env_file: .env - # environment: - # POSTGRES_USER: ${AUTHENTIK_POSTGRES_USER:-authentik} - # POSTGRES_PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD:-authentik_password} - # POSTGRES_DB: ${AUTHENTIK_POSTGRES_DB:-authentik} - # volumes: - # - authentik_postgres_data:/var/lib/postgresql/data - # healthcheck: - # test: ["CMD-SHELL", "pg_isready -U ${AUTHENTIK_POSTGRES_USER:-authentik}"] - # interval: 10s - # timeout: 5s - # retries: 5 - # start_period: 20s - # networks: - # - internal - # deploy: - # restart_policy: - # condition: on-failure - # - # authentik-redis: - # image: valkey/valkey:8-alpine - # env_file: .env - # command: valkey-server --save 60 1 --loglevel warning - # volumes: - # - authentik_redis_data:/data - # healthcheck: - # test: ["CMD", "valkey-cli", "ping"] - # interval: 10s - # timeout: 5s - # retries: 5 - # start_period: 10s - # networks: - # - internal - # deploy: - # restart_policy: - # condition: on-failure - # - # authentik-server: - # image: ghcr.io/goauthentik/server:2024.12.1 - # env_file: .env - # command: server - # environment: - # AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-change-this-to-a-random-secret} - # AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING:-false} - # AUTHENTIK_POSTGRESQL__HOST: authentik-postgres - # AUTHENTIK_POSTGRESQL__PORT: 5432 - # AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRES_DB:-authentik} - # AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRES_USER:-authentik} - # AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD:-authentik_password} - # AUTHENTIK_REDIS__HOST: authentik-redis - # AUTHENTIK_REDIS__PORT: 6379 - # AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD:-admin} - # AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL:-admin@localhost} - # AUTHENTIK_COOKIE_DOMAIN: ${AUTHENTIK_COOKIE_DOMAIN:-.mosaicstack.dev} - # volumes: - # - authentik_media:/media - # - authentik_templates:/templates - # healthcheck: - # test: - # [ - # "CMD", - # "wget", - # "--no-verbose", - # "--tries=1", - # "--spider", - # "http://localhost:9000/-/health/live/", - # ] - # interval: 30s - # timeout: 10s - # retries: 3 - # start_period: 90s - # networks: - # - internal - # - traefik-public - # deploy: - # restart_policy: - # condition: on-failure - # labels: - # - "traefik.enable=true" - # - "traefik.http.routers.mosaic-auth.rule=Host(`${MOSAIC_AUTH_DOMAIN:-auth.mosaicstack.dev}`)" - # - "traefik.http.routers.mosaic-auth.entrypoints=web" - # - "traefik.http.services.mosaic-auth.loadbalancer.server.port=9000" - # - # authentik-worker: - # image: ghcr.io/goauthentik/server:2024.12.1 - # env_file: .env - # command: worker - # environment: - # AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-change-this-to-a-random-secret} - # AUTHENTIK_ERROR_REPORTING__ENABLED: ${AUTHENTIK_ERROR_REPORTING:-false} - # AUTHENTIK_POSTGRESQL__HOST: authentik-postgres - # AUTHENTIK_POSTGRESQL__PORT: 5432 - # AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRES_DB:-authentik} - # AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRES_USER:-authentik} - # AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD:-authentik_password} - # AUTHENTIK_REDIS__HOST: authentik-redis - # AUTHENTIK_REDIS__PORT: 6379 - # volumes: - # - authentik_media:/media - # - authentik_certs:/certs - # - authentik_templates:/templates - # networks: - # - internal - # deploy: - # restart_policy: - # condition: on-failure - - # ====================== - # Ollama (Optional AI Service) - # ====================== - # ollama: - # image: ollama/ollama:latest - # env_file: .env - # volumes: - # - ollama_data:/root/.ollama - # healthcheck: - # test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] - # interval: 30s - # timeout: 10s - # retries: 3 - # start_period: 60s - # networks: - # - internal - # deploy: - # restart_policy: - # condition: on-failure - - # ====================== - # Mosaic Coordinator - # ====================== - coordinator: - image: git.mosaicstack.dev/mosaic/stack-coordinator:${IMAGE_TAG:-latest} - env_file: .env - environment: - GITEA_WEBHOOK_SECRET: ${GITEA_WEBHOOK_SECRET} - GITEA_URL: ${GITEA_URL:-https://git.mosaicstack.dev} - ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} - LOG_LEVEL: ${LOG_LEVEL:-info} - HOST: 0.0.0.0 - PORT: 8000 - COORDINATOR_POLL_INTERVAL: ${COORDINATOR_POLL_INTERVAL:-5.0} - COORDINATOR_MAX_CONCURRENT_AGENTS: ${COORDINATOR_MAX_CONCURRENT_AGENTS:-10} - COORDINATOR_ENABLED: ${COORDINATOR_ENABLED:-true} - # Telemetry (task completion tracking & predictions) - MOSAIC_TELEMETRY_ENABLED: ${MOSAIC_TELEMETRY_ENABLED:-false} - MOSAIC_TELEMETRY_SERVER_URL: ${MOSAIC_TELEMETRY_SERVER_URL:-https://tel-api.mosaicstack.dev} - MOSAIC_TELEMETRY_API_KEY: ${MOSAIC_TELEMETRY_API_KEY:-} - MOSAIC_TELEMETRY_INSTANCE_ID: ${MOSAIC_TELEMETRY_INSTANCE_ID:-} - MOSAIC_TELEMETRY_DRY_RUN: ${MOSAIC_TELEMETRY_DRY_RUN:-false} - healthcheck: - test: - [ - "CMD", - "python", - "-c", - "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')", - ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 5s - networks: - - internal - deploy: - restart_policy: - condition: on-failure - - # ====================== - # Mosaic API - # ====================== - api: - image: git.mosaicstack.dev/mosaic/stack-api:${IMAGE_TAG:-latest} - env_file: .env - environment: - NODE_ENV: production - PORT: ${API_PORT:-3001} - API_HOST: ${API_HOST:-0.0.0.0} - DATABASE_URL: postgresql://${POSTGRES_USER:-mosaic}:${POSTGRES_PASSWORD:-mosaic_dev_password}@postgres:5432/${POSTGRES_DB:-mosaic} - VALKEY_URL: redis://valkey:6379 - OIDC_ISSUER: ${OIDC_ISSUER} - OIDC_CLIENT_ID: ${OIDC_CLIENT_ID} - OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET} - OIDC_REDIRECT_URI: ${OIDC_REDIRECT_URI:-http://localhost:3001/auth/callback} - JWT_SECRET: ${JWT_SECRET:-change-this-to-a-random-secret} - JWT_EXPIRATION: ${JWT_EXPIRATION:-24h} - BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET} - OLLAMA_ENDPOINT: ${OLLAMA_ENDPOINT:-http://ollama:11434} - OPENBAO_ADDR: ${OPENBAO_ADDR:-http://openbao:8200} - ORCHESTRATOR_URL: ${ORCHESTRATOR_URL:-http://orchestrator:3001} - ENCRYPTION_KEY: ${ENCRYPTION_KEY} - # Telemetry (task completion tracking & predictions) - MOSAIC_TELEMETRY_ENABLED: ${MOSAIC_TELEMETRY_ENABLED:-false} - MOSAIC_TELEMETRY_SERVER_URL: ${MOSAIC_TELEMETRY_SERVER_URL:-https://tel-api.mosaicstack.dev} - MOSAIC_TELEMETRY_API_KEY: ${MOSAIC_TELEMETRY_API_KEY:-} - MOSAIC_TELEMETRY_INSTANCE_ID: ${MOSAIC_TELEMETRY_INSTANCE_ID:-} - MOSAIC_TELEMETRY_DRY_RUN: ${MOSAIC_TELEMETRY_DRY_RUN:-false} - healthcheck: - test: - [ - "CMD-SHELL", - 'node -e "require(''http'').get(''http://localhost:${API_PORT:-3001}/health'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"', - ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - networks: - - internal - - traefik-public - deploy: - restart_policy: - condition: on-failure - labels: - - "traefik.enable=true" - - "traefik.http.routers.mosaic-api.rule=Host(`${MOSAIC_API_DOMAIN:-api.mosaicstack.dev}`)" - - "traefik.http.routers.mosaic-api.entrypoints=web" - - "traefik.http.services.mosaic-api.loadbalancer.server.port=${API_PORT:-3001}" - - # ====================== - # Mosaic Orchestrator - # ====================== - orchestrator: - image: git.mosaicstack.dev/mosaic/stack-orchestrator:${IMAGE_TAG:-latest} - env_file: .env - user: "1000:1000" - environment: - NODE_ENV: production - ORCHESTRATOR_PORT: 3001 - VALKEY_URL: redis://valkey:6379 - CLAUDE_API_KEY: ${CLAUDE_API_KEY} - DOCKER_SOCKET: /var/run/docker.sock - GIT_USER_NAME: "Mosaic Orchestrator" - GIT_USER_EMAIL: "orchestrator@mosaicstack.dev" - KILLSWITCH_ENABLED: "true" - SANDBOX_ENABLED: "true" - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - orchestrator_workspace:/workspace - healthcheck: - test: - ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - networks: - - internal - # Note: security_opt not supported in swarm mode - # Security hardening done via cap_drop/cap_add - cap_drop: - - ALL - cap_add: - - NET_BIND_SERVICE - tmpfs: - - /tmp:noexec,nosuid,size=100m - deploy: - restart_policy: - condition: on-failure - - # ====================== - # Mosaic Web - # ====================== - web: - image: git.mosaicstack.dev/mosaic/stack-web:${IMAGE_TAG:-latest} - env_file: .env - environment: - NODE_ENV: production - PORT: ${WEB_PORT:-3000} - NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001} - healthcheck: - test: - [ - "CMD-SHELL", - 'node -e "require(''http'').get(''http://localhost:${WEB_PORT:-3000}'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"', - ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - networks: - - traefik-public - deploy: - restart_policy: - condition: on-failure - labels: - - "traefik.enable=true" - - "traefik.http.routers.mosaic-web.rule=Host(`${MOSAIC_WEB_DOMAIN:-mosaic.mosaicstack.dev}`)" - - "traefik.http.routers.mosaic-web.entrypoints=web" - - "traefik.http.services.mosaic-web.loadbalancer.server.port=${WEB_PORT:-3000}" - -# ====================== -# Volumes -# ====================== -volumes: - postgres_data: - valkey_data: - openbao_data: - openbao_logs: - openbao_init: - # Authentik volumes - commented out (using external Authentik) - # authentik_postgres_data: - # authentik_redis_data: - # authentik_media: - # authentik_certs: - # authentik_templates: - # Ollama volume - commented out (using external Ollama) - # ollama_data: - orchestrator_workspace: - -# ====================== -# Networks -# ====================== -networks: - internal: - driver: overlay - traefik-public: - external: true diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml deleted file mode 100644 index af6dde7..0000000 --- a/docker/docker-compose.dev.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Development overrides for docker-compose.yml -# Usage: docker compose -f docker-compose.yml -f docker-compose.dev.yml up - -services: - postgres: - environment: - POSTGRES_USER: mosaic - POSTGRES_PASSWORD: mosaic_dev_password - POSTGRES_DB: mosaic - ports: - - "5432:5432" - # Enable query logging for development - command: - - "postgres" - - "-c" - - "log_statement=all" - - "-c" - - "log_duration=on" - - valkey: - ports: - - "6379:6379" diff --git a/docker/docker-compose.example.external.yml b/docker/docker-compose.example.external.yml deleted file mode 100644 index bbbb9e4..0000000 --- a/docker/docker-compose.example.external.yml +++ /dev/null @@ -1,126 +0,0 @@ -# ============================================== -# Mosaic Stack - External Services Deployment Example -# ============================================== -# This example shows a production deployment using external managed services. -# All infrastructure (database, cache, secrets, auth, AI) is managed externally. -# -# Usage: -# 1. Copy this file to docker-compose.override.yml -# 2. Set COMPOSE_PROFILES= (empty) in .env -# 3. Configure external service URLs in .env (see below) -# 4. Run: docker compose up -d -# -# Or run directly: -# docker compose -f docker-compose.yml -f docker-compose.example.external.yml up -d -# -# Services Included: -# - API (NestJS) - configured to use external services -# - Web (Next.js) -# - Orchestrator (Agent management) -# -# External Services (configured via .env): -# - PostgreSQL (e.g., AWS RDS, Google Cloud SQL, Azure Database) -# - Redis/Valkey (e.g., AWS ElastiCache, Google Memorystore, Azure Cache) -# - OpenBao/Vault (e.g., HashiCorp Vault Cloud, self-hosted) -# - OIDC Provider (e.g., Auth0, Okta, Google, Azure AD) -# - LLM Service (e.g., hosted Ollama, OpenAI, Anthropic) -# -# Required Environment Variables (.env): -# COMPOSE_PROFILES= # Empty - no bundled services -# IMAGE_TAG=latest -# -# # External Database -# DATABASE_URL=postgresql://user:password@rds.example.com:5432/mosaic -# -# # External Cache -# VALKEY_URL=redis://elasticache.example.com:6379 -# -# # External Secrets (OpenBao/Vault) -# OPENBAO_ADDR=https://vault.example.com:8200 -# OPENBAO_ROLE_ID=your-role-id -# OPENBAO_SECRET_ID=your-secret-id -# -# # External OIDC Authentication -# OIDC_ENABLED=true -# OIDC_ISSUER=https://auth.example.com/ -# OIDC_CLIENT_ID=your-client-id -# OIDC_CLIENT_SECRET=your-client-secret -# -# # External LLM Service -# OLLAMA_ENDPOINT=https://ollama.example.com:11434 -# # Or use OpenAI: -# # AI_PROVIDER=openai -# # OPENAI_API_KEY=sk-... -# -# ============================================== - -services: - # Disable all bundled infrastructure services - postgres: - profiles: - - disabled - - valkey: - profiles: - - disabled - - openbao: - profiles: - - disabled - - openbao-init: - profiles: - - disabled - - authentik-postgres: - profiles: - - disabled - - authentik-redis: - profiles: - - disabled - - authentik-server: - profiles: - - disabled - - authentik-worker: - profiles: - - disabled - - ollama: - profiles: - - disabled - - # Configure API to use external services - api: - environment: - # External database (e.g., AWS RDS) - DATABASE_URL: ${DATABASE_URL} - - # External cache (e.g., AWS ElastiCache) - VALKEY_URL: ${VALKEY_URL} - - # External secrets (e.g., HashiCorp Vault Cloud) - OPENBAO_ADDR: ${OPENBAO_ADDR} - OPENBAO_ROLE_ID: ${OPENBAO_ROLE_ID} - OPENBAO_SECRET_ID: ${OPENBAO_SECRET_ID} - - # External LLM (e.g., hosted Ollama or OpenAI) - OLLAMA_ENDPOINT: ${OLLAMA_ENDPOINT} - - # External OIDC (e.g., Auth0, Okta, Google) - OIDC_ENABLED: ${OIDC_ENABLED} - OIDC_ISSUER: ${OIDC_ISSUER} - OIDC_CLIENT_ID: ${OIDC_CLIENT_ID} - OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET} - - # Security - CSRF_SECRET: ${CSRF_SECRET} - ENCRYPTION_KEY: ${ENCRYPTION_KEY} - - # Web app remains unchanged - # web: (uses defaults from docker-compose.yml) - - # Orchestrator remains unchanged - # orchestrator: (uses defaults from docker-compose.yml) diff --git a/docker/docker-compose.example.hybrid.yml b/docker/docker-compose.example.hybrid.yml deleted file mode 100644 index 93de773..0000000 --- a/docker/docker-compose.example.hybrid.yml +++ /dev/null @@ -1,114 +0,0 @@ -# ============================================== -# Mosaic Stack - Hybrid Deployment Example -# ============================================== -# This example shows a hybrid deployment mixing bundled and external services. -# Common for staging environments: bundled database/cache, external auth/secrets. -# -# Usage: -# 1. Copy this file to docker-compose.override.yml -# 2. Set COMPOSE_PROFILES=database,cache,ollama in .env -# 3. Configure external service URLs in .env (see below) -# 4. Run: docker compose up -d -# -# Or run directly: -# docker compose -f docker-compose.yml -f docker-compose.example.hybrid.yml up -d -# -# Services Included (Bundled): -# - PostgreSQL 17 with pgvector -# - Valkey (Redis-compatible cache) -# - Ollama (local LLM) -# - API (NestJS) -# - Web (Next.js) -# - Orchestrator (Agent management) -# -# Services Included (External): -# - OpenBao/Vault (managed secrets) -# - Authentik/OIDC (managed authentication) -# -# Environment Variables (.env): -# COMPOSE_PROFILES=database,cache,ollama # Enable only these bundled services -# IMAGE_TAG=dev -# -# # Bundled Database (default from docker-compose.yml) -# DATABASE_URL=postgresql://mosaic:${POSTGRES_PASSWORD}@postgres:5432/mosaic -# -# # Bundled Cache (default from docker-compose.yml) -# VALKEY_URL=redis://valkey:6379 -# -# # Bundled Ollama (default from docker-compose.yml) -# OLLAMA_ENDPOINT=http://ollama:11434 -# -# # External Secrets (OpenBao/Vault) -# OPENBAO_ADDR=https://vault.example.com:8200 -# OPENBAO_ROLE_ID=your-role-id -# OPENBAO_SECRET_ID=your-secret-id -# -# # External OIDC Authentication -# OIDC_ENABLED=true -# OIDC_ISSUER=https://auth.example.com/ -# OIDC_CLIENT_ID=your-client-id -# OIDC_CLIENT_SECRET=your-client-secret -# -# ============================================== - -services: - # Use bundled PostgreSQL and Valkey (enabled via database,cache profiles) - # No overrides needed - profiles handle this - - # Disable bundled Authentik - use external OIDC - authentik-postgres: - profiles: - - disabled - - authentik-redis: - profiles: - - disabled - - authentik-server: - profiles: - - disabled - - authentik-worker: - profiles: - - disabled - - # Disable bundled OpenBao - use external vault - openbao: - profiles: - - disabled - - openbao-init: - profiles: - - disabled - - # Use bundled Ollama (enabled via ollama profile) - # No override needed - - # Configure API for hybrid deployment - api: - environment: - # Bundled database (default) - DATABASE_URL: postgresql://${POSTGRES_USER:-mosaic}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-mosaic} - - # Bundled cache (default) - VALKEY_URL: redis://valkey:6379 - - # External secrets - OPENBAO_ADDR: ${OPENBAO_ADDR} - OPENBAO_ROLE_ID: ${OPENBAO_ROLE_ID} - OPENBAO_SECRET_ID: ${OPENBAO_SECRET_ID} - - # Bundled Ollama (default) - OLLAMA_ENDPOINT: http://ollama:11434 - - # External OIDC - OIDC_ENABLED: ${OIDC_ENABLED} - OIDC_ISSUER: ${OIDC_ISSUER} - OIDC_CLIENT_ID: ${OIDC_CLIENT_ID} - OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET} - - # Security - CSRF_SECRET: ${CSRF_SECRET} - ENCRYPTION_KEY: ${ENCRYPTION_KEY} - - # Web and Orchestrator use defaults from docker-compose.yml diff --git a/docker/docker-compose.example.turnkey.yml b/docker/docker-compose.example.turnkey.yml deleted file mode 100644 index 9443c01..0000000 --- a/docker/docker-compose.example.turnkey.yml +++ /dev/null @@ -1,43 +0,0 @@ -# ============================================== -# Mosaic Stack - Turnkey Deployment Example -# ============================================== -# This example shows a complete all-in-one deployment with all services bundled. -# Ideal for local development, testing, and demo environments. -# -# Usage: -# 1. Copy this file to docker-compose.override.yml (optional) -# 2. Set COMPOSE_PROFILES=full in .env -# 3. Run: docker compose up -d -# -# Or run directly: -# docker compose -f docker-compose.yml -f docker-compose.example.turnkey.yml up -d -# -# Services Included: -# - PostgreSQL 17 with pgvector -# - Valkey (Redis-compatible cache) -# - OpenBao (secrets management) -# - Authentik (OIDC authentication) -# - Ollama (local LLM) -# - Traefik (reverse proxy) - optional, requires traefik-bundled profile -# - API (NestJS) -# - Web (Next.js) -# - Orchestrator (Agent management) -# -# Environment Variables (.env): -# COMPOSE_PROFILES=full -# IMAGE_TAG=dev # or latest -# -# All services run in Docker containers with no external dependencies. -# ============================================== - -services: - # No service overrides needed - the main docker-compose.yml handles everything - # This file serves as documentation for turnkey deployment - # Set COMPOSE_PROFILES=full in your .env file to enable all services - - # Placeholder to make the file valid YAML - # (Docker Compose requires at least one service definition) - _placeholder: - image: alpine:latest - profiles: - - never-used diff --git a/docker/docker-compose.matrix.yml b/docker/docker-compose.matrix.yml deleted file mode 100644 index 1062111..0000000 --- a/docker/docker-compose.matrix.yml +++ /dev/null @@ -1,123 +0,0 @@ -# ============================================== -# Matrix Dev Environment (Synapse + Element Web) -# ============================================== -# -# Development-only overlay for testing the Matrix bridge locally. -# NOT for production — use docker-compose.sample.matrix.yml for production. -# -# Usage: -# docker compose -f docker/docker-compose.yml -f docker/docker-compose.matrix.yml up -d -# -# Or with Makefile: -# make matrix-up -# -# This overlay: -# - Adds Synapse homeserver (localhost:8008) using shared PostgreSQL -# - Adds Element Web client (localhost:8501) -# - Creates a separate 'synapse' database in the shared PostgreSQL instance -# - Enables open registration for easy dev testing -# -# After first startup, create the bot account: -# docker/matrix/scripts/setup-bot.sh -# -# ============================================== - -services: - # ====================== - # Synapse Database Init - # ====================== - # Creates the 'synapse' database and user in the shared PostgreSQL instance. - # Runs once and exits — idempotent, safe to run repeatedly. - synapse-db-init: - image: postgres:17-alpine - container_name: mosaic-synapse-db-init - restart: "no" - environment: - PGHOST: postgres - PGPORT: 5432 - PGUSER: ${POSTGRES_USER:-mosaic} - PGPASSWORD: ${POSTGRES_PASSWORD:-mosaic_dev_password} - SYNAPSE_DB: ${SYNAPSE_POSTGRES_DB:-synapse} - SYNAPSE_USER: ${SYNAPSE_POSTGRES_USER:-synapse} - SYNAPSE_PASSWORD: ${SYNAPSE_POSTGRES_PASSWORD:-synapse_dev_password} - entrypoint: ["sh", "-c"] - command: - - | - until pg_isready -h postgres -p 5432 -U $${PGUSER}; do - echo "Waiting for PostgreSQL..." - sleep 2 - done - echo "PostgreSQL is ready. Creating Synapse database and user..." - - psql -h postgres -U $${PGUSER} -tc "SELECT 1 FROM pg_roles WHERE rolname='$${SYNAPSE_USER}'" | grep -q 1 || \ - psql -h postgres -U $${PGUSER} -c "CREATE USER $${SYNAPSE_USER} WITH PASSWORD '$${SYNAPSE_PASSWORD}';" - - psql -h postgres -U $${PGUSER} -tc "SELECT 1 FROM pg_database WHERE datname='$${SYNAPSE_DB}'" | grep -q 1 || \ - psql -h postgres -U $${PGUSER} -c "CREATE DATABASE $${SYNAPSE_DB} OWNER $${SYNAPSE_USER} ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0;" - - echo "Synapse database ready: $${SYNAPSE_DB}" - depends_on: - postgres: - condition: service_healthy - networks: - - mosaic-internal - - # ====================== - # Synapse (Matrix Homeserver) - # ====================== - synapse: - image: matrixdotorg/synapse:latest - container_name: mosaic-synapse - restart: unless-stopped - environment: - SYNAPSE_CONFIG_DIR: /data - SYNAPSE_CONFIG_PATH: /data/homeserver.yaml - ports: - - "${SYNAPSE_CLIENT_PORT:-8008}:8008" - - "${SYNAPSE_FEDERATION_PORT:-8448}:8448" - volumes: - - /opt/mosaic/synapse/homeserver.yaml:/data/homeserver.yaml:ro - - /opt/mosaic/synapse/media_store:/data/media_store - - /opt/mosaic/synapse/keys:/data/keys - depends_on: - postgres: - condition: service_healthy - synapse-db-init: - condition: service_completed_successfully - healthcheck: - test: ["CMD-SHELL", "curl -fSs http://localhost:8008/health || exit 1"] - interval: 15s - timeout: 5s - retries: 5 - start_period: 30s - networks: - - mosaic-internal - labels: - com.mosaic.service: "matrix-synapse" - com.mosaic.description: "Matrix homeserver (dev)" - - # ====================== - # Element Web (Matrix Client) - # ====================== - element-web: - image: vectorim/element-web:latest - container_name: mosaic-element-web - restart: unless-stopped - ports: - - "${ELEMENT_PORT:-8501}:80" - volumes: - - /opt/mosaic/synapse/element-config.json:/app/config.json:ro - depends_on: - synapse: - condition: service_healthy - healthcheck: - test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:80 || exit 1"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 10s - networks: - - mosaic-internal - labels: - com.mosaic.service: "matrix-element" - com.mosaic.description: "Element Web client (dev)" diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml deleted file mode 100644 index 01b637d..0000000 --- a/docker/docker-compose.prod.yml +++ /dev/null @@ -1,182 +0,0 @@ -# Production Docker Compose - Uses pre-built images from Gitea Packages -# -# Prerequisites: -# - Images built and pushed to git.mosaicstack.dev/mosaic/* -# - .env file configured with production values -# -# Usage: -# docker compose -f docker-compose.prod.yml up -d -# -# For Portainer: -# - Stack → Add Stack → Repository -# - Compose file: docker-compose.prod.yml - -services: - # ====================== - # PostgreSQL Database - # ====================== - postgres: - image: git.mosaicstack.dev/mosaic/postgres:latest - container_name: mosaic-postgres - restart: unless-stopped - environment: - POSTGRES_USER: ${POSTGRES_USER:-mosaic} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB:-mosaic} - POSTGRES_SHARED_BUFFERS: ${POSTGRES_SHARED_BUFFERS:-256MB} - POSTGRES_EFFECTIVE_CACHE_SIZE: ${POSTGRES_EFFECTIVE_CACHE_SIZE:-1GB} - POSTGRES_MAX_CONNECTIONS: ${POSTGRES_MAX_CONNECTIONS:-100} - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-mosaic} -d ${POSTGRES_DB:-mosaic}"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - networks: - - mosaic-internal - labels: - - "com.mosaic.service=database" - - "com.mosaic.description=PostgreSQL 17 with pgvector" - - # ====================== - # Valkey Cache - # ====================== - valkey: - image: valkey/valkey:8-alpine - container_name: mosaic-valkey - restart: unless-stopped - command: - - valkey-server - - --maxmemory ${VALKEY_MAXMEMORY:-256mb} - - --maxmemory-policy noeviction - - --appendonly yes - volumes: - - valkey_data:/data - healthcheck: - test: ["CMD", "valkey-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - networks: - - mosaic-internal - labels: - - "com.mosaic.service=cache" - - "com.mosaic.description=Valkey Redis-compatible cache" - - # ====================== - # Mosaic API - # ====================== - api: - image: git.mosaicstack.dev/mosaic/api:latest - container_name: mosaic-api - restart: unless-stopped - environment: - NODE_ENV: production - PORT: ${API_PORT:-3001} - API_HOST: ${API_HOST:-0.0.0.0} - DATABASE_URL: postgresql://${POSTGRES_USER:-mosaic}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-mosaic} - VALKEY_URL: redis://valkey:6379 - OIDC_ISSUER: ${OIDC_ISSUER} - OIDC_CLIENT_ID: ${OIDC_CLIENT_ID} - OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET} - OIDC_REDIRECT_URI: ${OIDC_REDIRECT_URI} - JWT_SECRET: ${JWT_SECRET} - JWT_EXPIRATION: ${JWT_EXPIRATION:-24h} - BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET} - CSRF_SECRET: ${CSRF_SECRET} - ENCRYPTION_KEY: ${ENCRYPTION_KEY} - OLLAMA_ENDPOINT: ${OLLAMA_ENDPOINT:-http://ollama:11434} - ports: - - "${API_PORT:-3001}:${API_PORT:-3001}" - depends_on: - postgres: - condition: service_healthy - valkey: - condition: service_healthy - healthcheck: - test: - [ - "CMD-SHELL", - 'node -e "require(''http'').get(''http://localhost:${API_PORT:-3001}/health'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"', - ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - networks: - - mosaic-internal - - mosaic-public - labels: - - "com.mosaic.service=api" - - "com.mosaic.description=Mosaic NestJS API" - - "traefik.enable=${TRAEFIK_ENABLE:-false}" - - "traefik.http.routers.mosaic-api.rule=Host(`${MOSAIC_API_DOMAIN:-api.mosaicstack.dev}`)" - - "traefik.http.routers.mosaic-api.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - - "traefik.http.routers.mosaic-api.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.services.mosaic-api.loadbalancer.server.port=${API_PORT:-3001}" - - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}" - - "traefik.http.routers.mosaic-api.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - - # ====================== - # Mosaic Web - # ====================== - web: - image: git.mosaicstack.dev/mosaic/web:latest - container_name: mosaic-web - restart: unless-stopped - environment: - NODE_ENV: production - PORT: ${WEB_PORT:-3000} - NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-https://api.mosaicstack.dev} - ports: - - "${WEB_PORT:-3000}:${WEB_PORT:-3000}" - depends_on: - api: - condition: service_healthy - healthcheck: - test: - [ - "CMD-SHELL", - 'node -e "require(''http'').get(''http://localhost:${WEB_PORT:-3000}'', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"', - ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - networks: - - mosaic-public - labels: - - "com.mosaic.service=web" - - "com.mosaic.description=Mosaic Next.js Web App" - - "traefik.enable=${TRAEFIK_ENABLE:-false}" - - "traefik.http.routers.mosaic-web.rule=Host(`${MOSAIC_WEB_DOMAIN:-app.mosaicstack.dev}`)" - - "traefik.http.routers.mosaic-web.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - - "traefik.http.routers.mosaic-web.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.services.mosaic-web.loadbalancer.server.port=${WEB_PORT:-3000}" - - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-mosaic-public}" - - "traefik.http.routers.mosaic-web.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - -# ====================== -# Volumes -# ====================== -volumes: - postgres_data: - name: mosaic-postgres-data - driver: local - valkey_data: - name: mosaic-valkey-data - driver: local - -# ====================== -# Networks -# ====================== -networks: - mosaic-internal: - name: mosaic-internal - driver: bridge - mosaic-public: - name: mosaic-public - driver: bridge diff --git a/docker/docker-compose.sample.matrix.yml b/docker/docker-compose.sample.matrix.yml deleted file mode 100644 index 5f71d48..0000000 --- a/docker/docker-compose.sample.matrix.yml +++ /dev/null @@ -1,206 +0,0 @@ -# ============================================== -# Matrix (Synapse + Element) - Sample Swarm Deployment -# ============================================== -# -# Standalone Matrix homeserver deployment for use with Mosaic Stack. -# This is SEPARATE infrastructure — not part of the Mosaic Stack itself. -# Mosaic connects to it via MATRIX_HOMESERVER_URL environment variable. -# -# Also serves: personal communications, GoToSocial bridges, other projects. -# -# Usage (Docker Swarm via Portainer): -# 1. Create a new stack in Portainer -# 2. Paste this file or point to the repo -# 3. Set environment variables in Portainer's env var section -# 4. Deploy the stack -# -# Usage (Docker Swarm CLI): -# 1. cp docker-compose.sample.matrix.env .env -# 2. nano .env # Configure -# 3. docker stack deploy -c docker-compose.sample.matrix.yml matrix -# -# Post-Deploy Setup: -# 1. Generate Synapse config (first run only): -# docker exec python -m synapse.app.homeserver \ -# --server-name ${MATRIX_DOMAIN} --report-stats no \ -# --generate-config --config-path /data/homeserver.yaml -# -# 2. Create admin account: -# docker exec -it register_new_matrix_user \ -# -u admin -a -c /data/homeserver.yaml http://localhost:8008 -# -# 3. Create Mosaic bot account: -# docker exec -it register_new_matrix_user \ -# -u mosaic-bot -c /data/homeserver.yaml http://localhost:8008 -# -# 4. Generate bot access token: -# curl -X POST http://localhost:8008/_matrix/client/v3/login \ -# -d '{"type":"m.login.password","user":"mosaic-bot","password":""}' -# -# 5. Set MATRIX_ACCESS_TOKEN in Mosaic Stack .env -# -# Required Environment Variables: -# MATRIX_DOMAIN=matrix.example.com # Synapse server name (permanent!) -# ELEMENT_DOMAIN=chat.example.com # Element Web domain -# POSTGRES_PASSWORD= # Synapse database password -# -# Optional Environment Variables: -# SYNAPSE_IMAGE_TAG=latest # Synapse version -# ELEMENT_IMAGE_TAG=latest # Element Web version -# POSTGRES_IMAGE_TAG=16-alpine # PostgreSQL version -# TRAEFIK_ENTRYPOINT=websecure # Traefik entrypoint name -# TRAEFIK_CERTRESOLVER=letsencrypt # Traefik cert resolver -# TRAEFIK_DOCKER_NETWORK=traefik-public # Traefik network name -# SYNAPSE_ENABLE_REGISTRATION=false # Public registration -# SYNAPSE_REPORT_STATS=no # Anonymous stats reporting -# SYNAPSE_MAX_UPLOAD_SIZE=50M # Max file upload size -# -# Connecting to Mosaic Stack: -# Add to your Mosaic Stack .env: -# MATRIX_HOMESERVER_URL=http://synapse:8008 (if same Docker network) -# MATRIX_HOMESERVER_URL=https://matrix.example.com (if external) -# MATRIX_ACCESS_TOKEN= -# MATRIX_BOT_USER_ID=@mosaic-bot:matrix.example.com -# -# ============================================== - -services: - # ====================== - # Synapse (Matrix Homeserver) - # ====================== - synapse: - image: matrixdotorg/synapse:${SYNAPSE_IMAGE_TAG:-latest} - environment: - SYNAPSE_SERVER_NAME: ${MATRIX_DOMAIN} - SYNAPSE_REPORT_STATS: ${SYNAPSE_REPORT_STATS:-no} - SYNAPSE_CONFIG_DIR: /data - SYNAPSE_DATA_DIR: /data - SYNAPSE_LOG_LEVEL: ${SYNAPSE_LOG_LEVEL:-WARNING} - # Database connection (external PostgreSQL or bundled) - POSTGRES_HOST: synapse-postgres - POSTGRES_PORT: 5432 - POSTGRES_DB: ${SYNAPSE_POSTGRES_DB:-synapse} - POSTGRES_USER: ${SYNAPSE_POSTGRES_USER:-synapse} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - volumes: - - synapse-data:/data - - synapse-media:/data/media_store - depends_on: - synapse-postgres: - condition: service_healthy - healthcheck: - test: ["CMD-SHELL", "curl -fSs http://localhost:8008/health || exit 1"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 30s - networks: - - internal - - traefik-public - deploy: - restart_policy: - condition: on-failure - delay: 10s - labels: - - "traefik.enable=true" - - "traefik.http.routers.matrix.rule=Host(`${MATRIX_DOMAIN}`)" - - "traefik.http.routers.matrix.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - - "traefik.http.routers.matrix.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.routers.matrix.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - - "traefik.http.services.matrix.loadbalancer.server.port=8008" - - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-traefik-public}" - # Well-known delegation (optional — for .well-known/matrix/server) - # - "traefik.http.routers.matrix-wellknown.rule=Host(`${MATRIX_DOMAIN}`) && PathPrefix(`/.well-known/matrix`)" - - # ====================== - # Element Web (Matrix Client) - # ====================== - element-web: - image: vectorim/element-web:${ELEMENT_IMAGE_TAG:-latest} - volumes: - - element-config:/app/config - healthcheck: - test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:80 || exit 1"] - interval: 30s - timeout: 5s - retries: 3 - networks: - - internal - - traefik-public - deploy: - restart_policy: - condition: on-failure - labels: - - "traefik.enable=true" - - "traefik.http.routers.element.rule=Host(`${ELEMENT_DOMAIN}`)" - - "traefik.http.routers.element.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - - "traefik.http.routers.element.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.routers.element.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - - "traefik.http.services.element.loadbalancer.server.port=80" - - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-traefik-public}" - - # ====================== - # PostgreSQL (Synapse Database) - # ====================== - # Separate from Mosaic's PostgreSQL — Synapse manages its own schema. - # If you prefer a shared PostgreSQL instance, remove this service and - # point POSTGRES_HOST to your existing PostgreSQL with a separate database. - synapse-postgres: - image: postgres:${POSTGRES_IMAGE_TAG:-16-alpine} - environment: - POSTGRES_DB: ${SYNAPSE_POSTGRES_DB:-synapse} - POSTGRES_USER: ${SYNAPSE_POSTGRES_USER:-synapse} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" - volumes: - - synapse-postgres-data:/var/lib/postgresql/data - healthcheck: - test: - [ - "CMD-SHELL", - "pg_isready -U ${SYNAPSE_POSTGRES_USER:-synapse} -d ${SYNAPSE_POSTGRES_DB:-synapse}", - ] - interval: 10s - timeout: 5s - retries: 5 - networks: - - internal - deploy: - restart_policy: - condition: on-failure - - # ====================== - # coturn (TURN/STUN for VoIP) - Optional - # ====================== - # Uncomment if you need voice/video calls through NAT. - # Requires additional DNS and port configuration. - # - # coturn: - # image: coturn/coturn:latest - # environment: - # TURN_REALM: ${MATRIX_DOMAIN} - # TURN_SECRET: ${COTURN_SECRET} - # ports: - # - "3478:3478/tcp" - # - "3478:3478/udp" - # - "5349:5349/tcp" - # - "5349:5349/udp" - # - "49152-49200:49152-49200/udp" - # networks: - # - internal - # deploy: - # restart_policy: - # condition: on-failure - -volumes: - synapse-data: - synapse-media: - synapse-postgres-data: - element-config: - -networks: - internal: - driver: overlay - traefik-public: - external: true - name: ${TRAEFIK_DOCKER_NETWORK:-traefik-public} diff --git a/docker/docker-compose.sample.speech.yml b/docker/docker-compose.sample.speech.yml deleted file mode 100644 index 983fb37..0000000 --- a/docker/docker-compose.sample.speech.yml +++ /dev/null @@ -1,164 +0,0 @@ -# ============================================== -# Speech Services - Sample Swarm Deployment -# ============================================== -# -# Standalone speech services deployment for use with Mosaic Stack. -# This is SEPARATE infrastructure — not part of the Mosaic Stack itself. -# Mosaic connects to it via SPEACHES_URL and TTS_URL environment variables. -# -# Provides: -# - Speaches: Speech-to-Text (Whisper) + basic TTS fallback -# - Kokoro TTS: Default high-quality text-to-speech -# - Chatterbox TTS: Premium TTS with voice cloning (optional, requires GPU) -# -# Usage (Docker Swarm via Portainer): -# 1. Create a new stack in Portainer -# 2. Paste this file or point to the repo -# 3. Set environment variables in Portainer's env var section -# 4. Deploy the stack -# -# Usage (Docker Swarm CLI): -# 1. Create .env file with variables below -# 2. docker stack deploy -c docker-compose.sample.speech.yml speech -# -# Required Environment Variables: -# STT_DOMAIN=stt.example.com # Domain for Speaches (STT + basic TTS) -# TTS_DOMAIN=tts.example.com # Domain for Kokoro TTS (default TTS) -# -# Optional Environment Variables: -# WHISPER_MODEL=Systran/faster-whisper-large-v3-turbo # Whisper model for STT -# CHATTERBOX_TTS_DOMAIN=tts-premium.example.com # Domain for Chatterbox (premium TTS) -# TRAEFIK_ENTRYPOINT=websecure # Traefik entrypoint name -# TRAEFIK_CERTRESOLVER=letsencrypt # Traefik cert resolver -# TRAEFIK_DOCKER_NETWORK=traefik-public # Traefik network name -# TRAEFIK_TLS_ENABLED=true # Enable TLS on Traefik routers -# -# Connecting to Mosaic Stack: -# Add to your Mosaic Stack .env: -# SPEACHES_URL=http://speaches:8000 (if same Docker network) -# SPEACHES_URL=https://stt.example.com (if external) -# TTS_URL=http://kokoro-tts:8880 (if same Docker network) -# TTS_URL=https://tts.example.com (if external) -# -# GPU Requirements (Chatterbox only): -# - NVIDIA GPU with CUDA support -# - nvidia-container-toolkit installed on Docker host -# - Docker runtime configured for GPU access -# - Note: Docker Swarm requires "generic resources" for GPU scheduling. -# See: https://docs.docker.com/engine/daemon/nvidia-gpu/#configure-gpus-for-docker-swarm -# -# ============================================== - -services: - # ====================== - # Speaches (STT + basic TTS) - # ====================== - # Primary speech-to-text service using Whisper. - # Also provides basic TTS as a fallback. - speaches: - image: ghcr.io/speaches-ai/speaches:latest - environment: - WHISPER__MODEL: ${WHISPER_MODEL:-Systran/faster-whisper-large-v3-turbo} - volumes: - - speaches-models:/root/.cache/huggingface - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 120s - networks: - - internal - - traefik-public - deploy: - restart_policy: - condition: on-failure - delay: 10s - labels: - - "traefik.enable=true" - - "traefik.http.routers.speech-stt.rule=Host(`${STT_DOMAIN}`)" - - "traefik.http.routers.speech-stt.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - - "traefik.http.routers.speech-stt.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.routers.speech-stt.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - - "traefik.http.services.speech-stt.loadbalancer.server.port=8000" - - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-traefik-public}" - - # ====================== - # Kokoro TTS (Default TTS) - # ====================== - # High-quality text-to-speech engine. Always deployed alongside Speaches. - kokoro-tts: - image: ghcr.io/remsky/kokoro-fastapi:latest-cpu - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8880/health || exit 1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 120s - networks: - - internal - - traefik-public - deploy: - restart_policy: - condition: on-failure - delay: 10s - labels: - - "traefik.enable=true" - - "traefik.http.routers.speech-tts.rule=Host(`${TTS_DOMAIN}`)" - - "traefik.http.routers.speech-tts.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - - "traefik.http.routers.speech-tts.tls=${TRAEFIK_TLS_ENABLED:-true}" - - "traefik.http.routers.speech-tts.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - - "traefik.http.services.speech-tts.loadbalancer.server.port=8880" - - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-traefik-public}" - - # ====================== - # Chatterbox TTS (Premium TTS - Optional) - # ====================== - # Premium TTS with voice cloning capabilities. Requires NVIDIA GPU. - # - # To enable: Uncomment this service and set CHATTERBOX_TTS_DOMAIN. - # - # For Docker Swarm GPU scheduling, configure generic resources on the node: - # /etc/docker/daemon.json: - # { "runtimes": { "nvidia": { ... } }, - # "node-generic-resources": ["NVIDIA-GPU=0"] } - # - # chatterbox-tts: - # image: devnen/chatterbox-tts-server:latest - # healthcheck: - # test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"] - # interval: 30s - # timeout: 10s - # retries: 5 - # start_period: 180s - # networks: - # - internal - # - traefik-public - # deploy: - # restart_policy: - # condition: on-failure - # delay: 10s - # resources: - # reservations: - # generic_resources: - # - discrete_resource_spec: - # kind: "NVIDIA-GPU" - # value: 1 - # labels: - # - "traefik.enable=true" - # - "traefik.http.routers.speech-tts-premium.rule=Host(`${CHATTERBOX_TTS_DOMAIN}`)" - # - "traefik.http.routers.speech-tts-premium.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" - # - "traefik.http.routers.speech-tts-premium.tls=${TRAEFIK_TLS_ENABLED:-true}" - # - "traefik.http.routers.speech-tts-premium.tls.certresolver=${TRAEFIK_CERTRESOLVER:-}" - # - "traefik.http.services.speech-tts-premium.loadbalancer.server.port=8000" - # - "traefik.docker.network=${TRAEFIK_DOCKER_NETWORK:-traefik-public}" - -volumes: - speaches-models: - -networks: - internal: - driver: overlay - traefik-public: - external: true - name: ${TRAEFIK_DOCKER_NETWORK:-traefik-public} diff --git a/docker/matrix/element/config.json b/docker/matrix/element/config.json index 509f013..1cdbfbe 100644 --- a/docker/matrix/element/config.json +++ b/docker/matrix/element/config.json @@ -1,30 +1,34 @@ { "default_server_config": { "m.homeserver": { - "base_url": "http://localhost:8008", - "server_name": "localhost" + "base_url": "https://matrix.mosaicstack.dev", + "server_name": "matrix.mosaicstack.dev" + }, + "m.identity_server": { + "base_url": "https://vector.im" } }, - "brand": "Mosaic Stack Dev", + "brand": "Mosaic Chat", + "integrations_ui_url": "https://scalar.vector.im/", + "integrations_rest_url": "https://scalar.vector.im/api", + "integrations_widgets_urls": [ + "https://scalar.vector.im/_matrix/integrations/v1", + "https://scalar.vector.im/api", + "https://scalar-staging.vector.im/_matrix/integrations/v1", + "https://scalar-staging.vector.im/api", + "https://scalar-staging.riot.im/scalar/api" + ], + "disable_custom_urls": false, + "disable_guests": true, + "disable_login_language_selector": false, + "disable_3pid_login": false, + "default_country_code": "US", + "show_labs_settings": false, "default_theme": "dark", "room_directory": { - "servers": ["localhost"] + "servers": ["matrix.mosaicstack.dev"] }, - "features": { - "feature_video_rooms": false, - "feature_group_calls": false - }, - "show_labs_settings": true, - "piwik": false, - "posthog": { - "enabled": false - }, - "privacy_policy_url": null, - "terms_and_conditions_links": [], "setting_defaults": { - "breadcrumbs": true, - "custom_themes": [] - }, - "disable_guests": true, - "disable_3pid_login": true + "breadcrumbs": true + } } diff --git a/docker/matrix/synapse/homeserver.yaml b/docker/matrix/synapse/homeserver.yaml index 304387c..35e09e5 100644 --- a/docker/matrix/synapse/homeserver.yaml +++ b/docker/matrix/synapse/homeserver.yaml @@ -1,27 +1,31 @@ # ============================================== -# Synapse Homeserver Configuration — Development Only +# Synapse Homeserver Configuration — Production # ============================================== # -# This config is for LOCAL DEVELOPMENT with the Mosaic Stack docker-compose overlay. -# Do NOT use this in production. See docker-compose.sample.matrix.yml for production. +# Deploy to /opt/mosaic/synapse/homeserver.yaml on the Docker host. # -# Server name is set to 'localhost' — this is permanent and cannot be changed -# after the database has been initialized. +# IMPORTANT: server_name is PERMANENT. It becomes part of every user ID +# (@user:server_name) and room alias. It cannot be changed after the +# database has been initialized without losing all data. +# +# Before first deploy, replace ALL placeholders marked REPLACE_*. # # ============================================== -server_name: "localhost" +# REPLACE with your Matrix domain (e.g. matrix.mosaicstack.dev) +# This is permanent — cannot be changed after first startup. +server_name: "REPLACE_MATRIX_DOMAIN" pid_file: /data/homeserver.pid -public_baseurl: "http://localhost:8008/" +public_baseurl: "https://REPLACE_MATRIX_DOMAIN/" # ====================== # Network Listeners # ====================== listeners: - # Client API (used by Element Web, Mosaic bridge, etc.) - port: 8008 tls: false type: http + # Traefik terminates TLS and forwards via X-Forwarded-For x_forwarded: true bind_addresses: ["0.0.0.0"] resources: @@ -35,9 +39,11 @@ database: name: psycopg2 txn_limit: 10000 args: - user: "synapse" - password: "synapse_dev_password" - database: "synapse" + # Must match SYNAPSE_POSTGRES_USER / SYNAPSE_POSTGRES_PASSWORD + # from your Portainer environment variables + user: "REPLACE_SYNAPSE_DB_USER" + password: "REPLACE_SYNAPSE_DB_PASSWORD" + database: "REPLACE_SYNAPSE_DB_NAME" host: "postgres" port: 5432 cp_min: 5 @@ -66,20 +72,25 @@ url_preview_ip_range_blacklist: - "fec0::/10" # ====================== -# Registration (Dev Only) +# Registration # ====================== -enable_registration: true -enable_registration_without_verification: true +# Public registration disabled. Create accounts via the admin API or CLI: +# docker exec -it register_new_matrix_user \ +# -u username -c /data/homeserver.yaml http://localhost:8008 +enable_registration: false # ====================== # Signing Keys # ====================== -# Auto-generated on first startup and persisted in the signing_key volume -signing_key_path: "/data/keys/localhost.signing.key" +# Auto-generated on first startup and persisted in /opt/mosaic/synapse/keys/ +signing_key_path: "/data/keys/signing.key" -# Suppress warning about trusted key servers in dev -suppress_key_server_warning: true -trusted_key_servers: [] +# ====================== +# Trusted Key Servers +# ====================== +# matrix.org is the default. Set to [] to disable federation key trust. +trusted_key_servers: + - server_name: "matrix.org" # ====================== # Room Configuration @@ -88,44 +99,46 @@ enable_room_list_search: true allow_public_rooms_over_federation: false # ====================== -# Rate Limiting (Relaxed for Dev) +# Rate Limiting # ====================== rc_message: - per_second: 100 - burst_count: 200 - -rc_registration: per_second: 10 burst_count: 50 +rc_registration: + per_second: 1 + burst_count: 5 + rc_login: address: - per_second: 10 - burst_count: 50 + per_second: 3 + burst_count: 10 account: - per_second: 10 - burst_count: 50 + per_second: 3 + burst_count: 10 # ====================== # Logging # ====================== -log_config: "/data/localhost.log.config" - -# Inline log config — write to stdout for docker logs -# Synapse falls back to a basic console logger if the log_config file is missing, -# so we leave log_config pointing to a non-existent file intentionally. -# Override: mount a custom log config file at /data/localhost.log.config +# Synapse falls back to a basic console logger (stdout) when this file +# does not exist, which is ideal for Docker log collection. +log_config: "/data/log.config" # ====================== -# Miscellaneous +# Secrets # ====================== +# Generate with: python3 -c 'import secrets; print(secrets.token_hex(32))' report_stats: false -macaroon_secret_key: "dev-macaroon-secret-change-in-production" -form_secret: "dev-form-secret-change-in-production" +macaroon_secret_key: "REPLACE_MACAROON_SECRET" +form_secret: "REPLACE_FORM_SECRET" -# Enable presence for dev +# ====================== +# Presence & Retention +# ====================== use_presence: true -# Retention policy (optional, keep messages for 180 days in dev) retention: - enabled: false + enabled: true + default_policy: + min_lifetime: 1d + max_lifetime: 365d diff --git a/docker/openbao/config.hcl b/docker/openbao/config.hcl index d9f578c..ea42bbe 100644 --- a/docker/openbao/config.hcl +++ b/docker/openbao/config.hcl @@ -11,9 +11,6 @@ listener "tcp" { tls_disable = 1 } -# Disable memory locking for Docker compatibility -disable_mlock = true - # API address for cluster communication api_addr = "http://0.0.0.0:8200"