# Praxis — Docker Compose service definition (v0.2 + v0.4 Postgres). # Runs the praxis server + a Postgres 16 service inside a Docker-in-LXC CT. # Per ARCHITECTURE.md §v0.2 Deployment + §v0.4 Operator-Tier Architecture. services: praxis: build: . image: praxis:latest restart: unless-stopped ports: - "8789:8789" volumes: # SQLite DB persistence — survives container recreation (G-102). - praxis-data:/app/data environment: PRAXIS_HOST: "0.0.0.0" PRAXIS_PORT: "8789" PRAXIS_DB_PATH: "/app/data/praxis.db" PRAXIS_SCENARIOS_DIR: "/app/scenarios" PRAXIS_TTS: "${PRAXIS_TTS:-cartesia}" PRAXIS_SCENARIO: "${PRAXIS_SCENARIO:-customer_service_refund_ca_v01}" # Voice-service keys (empty if unprovisioned — server degrades gracefully) DEEPGRAM_API_KEY: "${DEEPGRAM_API_KEY:-}" CARTESIA_API_KEY: "${CARTESIA_API_KEY:-}" OLLAMA_API_KEY: "${OLLAMA_API_KEY:-}" # Ollama Cloud endpoints (D-020) OLLAMA_BASE_URL: "${OLLAMA_BASE_URL:-https://ollama.com/v1}" OLLAMA_CHAT_URL: "${OLLAMA_CHAT_URL:-https://ollama.com/api/chat}" OLLAMA_ROLEPLAY_MODEL: "${OLLAMA_ROLEPLAY_MODEL:-gemma4:cloud}" OLLAMA_DEBRIEF_MODEL: "${OLLAMA_DEBRIEF_MODEL:-deepseek-v4-flash:cloud}" # Deepgram (D-013) DEEPGRAM_MODEL: "${DEEPGRAM_MODEL:-nova-3}" DEEPGRAM_LANGUAGE: "${DEEPGRAM_LANGUAGE:-en}" DEEPGRAM_REGION: "${DEEPGRAM_REGION:-na}" # Cartesia (D-014) CARTESIA_VOICE_ID: "${CARTESIA_VOICE_ID:-a3536a36-1d18-4efb-a95a-7c44b7b5e384}" # v0.4 operator tier — Postgres DSN (D-050). Empty → graceful no-pool mode. PRAXIS_PG_DSN: "${PRAXIS_PG_DSN:-}" # v0.4 auth (D-041, D-056). Empty → server generates ephemeral secret (dev only). PRAXIS_COOKIE_SECRET: "${PRAXIS_COOKIE_SECRET:-}" PRAXIS_COOKIE_SECURE: "${PRAXIS_COOKIE_SECURE:-true}" PRAXIS_VC_ISSUER_KEY: "${PRAXIS_VC_ISSUER_KEY:-}" PRAXIS_ISSUER_URL: "${PRAXIS_ISSUER_URL:-https://praxis.example/issuers/v0.4}" env_file: # /etc/praxis/server.env is written by install-service.sh with # secrets injected via lxc.environment (G-101 fix: GITEA_TOKEN baked # into the snippet; voice keys from lxc.environment). # required: false so `docker compose config` validates in dev without # the file; install-service.sh ALWAYS creates it before # `docker compose up` in production (so secrets are present at runtime). - path: /etc/praxis/server.env required: false depends_on: postgres: condition: service_healthy networks: - praxis-net postgres: image: postgres:16-slim restart: unless-stopped environment: POSTGRES_USER: praxis POSTGRES_PASSWORD: "${PRAXIS_PG_PASSWORD:-}" POSTGRES_DB: praxis PGDATA: /var/lib/postgresql/data/pgdata env_file: - path: /etc/praxis/server.env required: false volumes: - pgdata:/var/lib/postgresql/data - pgbackups:/backups healthcheck: test: ["CMD-SHELL", "pg_isready -U praxis -d praxis"] interval: 10s timeout: 5s retries: 5 networks: - praxis-net # No `ports:` — Postgres is NOT exposed to the LXC host bridge (D-040). # The praxis service reaches it via the praxis-net bridge using the # service-DNS name `postgres`. volumes: praxis-data: driver: local pgdata: driver: local pgbackups: driver: local networks: praxis-net: driver: bridge