new-site/docker-compose.yml
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

299 lines
10 KiB
YAML

services:
# ── Core Application ────────────────────────────────────────────────
site:
build: ./site
ports:
- "4322:80"
restart: unless-stopped
api:
build: ./api
ports:
- "3001:3001"
env_file: .env
environment:
- NODE_ENV=production
- PORT=3001
- DOMAIN=performancewest.net
- DATABASE_URL=postgresql://pw:${DB_PASSWORD:-pw_dev_2026}@api-postgres:5432/performancewest
- ERPNEXT_URL=http://erpnext:8000
- ERPNEXT_API_KEY=${ERPNEXT_API_KEY}
- ERPNEXT_API_SECRET=${ERPNEXT_API_SECRET}
- ERPNEXT_SITE_NAME=performancewest.net
- WORKER_URL=http://workers:8090
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
- STRIPE_TEST_SECRET_KEY=${STRIPE_TEST_SECRET_KEY}
- STRIPE_TEST_WEBHOOK_SECRET=${STRIPE_TEST_WEBHOOK_SECRET}
- STRIPE_TEST_IDENTITY_WEBHOOK_SECRET=${STRIPE_TEST_IDENTITY_WEBHOOK_SECRET}
- CUSTOMER_JWT_SECRET=${CUSTOMER_JWT_SECRET}
- ADMIN_JWT_SECRET=${ADMIN_JWT_SECRET}
- ADMIN_EMAIL=${ADMIN_EMAIL:-ops@performancewest.net}
- SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT}
- SMTP_USER=${SMTP_USER}
- SMTP_PASS=${SMTP_PASS}
- SMTP_FROM=${SMTP_FROM}
- MINIO_ENDPOINT=minio
- MINIO_PORT=9000
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
- PAYPAL_CLIENT_ID=${PAYPAL_CLIENT_ID}
- PAYPAL_CLIENT_SECRET=${PAYPAL_CLIENT_SECRET}
- PAYPAL_API_URL=https://api-m.paypal.com
- SHKEEPER_URL=${SHKEEPER_URL:-http://127.0.0.1:5000}
- SHKEEPER_API_KEY=${SHKEEPER_API_KEY}
- SHKEEPER_PUBLIC_URL=${SHKEEPER_PUBLIC_URL:-https://crypto.performancewest.net}
- WEBHOOK_SECRET=${WEBHOOK_SECRET}
- LISTMONK_URL=http://listmonk:9000
- LISTMONK_USER=${LISTMONK_USER:-admin}
- LISTMONK_PASSWORD=${LISTMONK_PASSWORD}
depends_on:
- api-postgres
restart: unless-stopped
api-postgres:
image: postgres:16-alpine
environment:
- POSTGRES_USER=pw
- POSTGRES_PASSWORD=${DB_PASSWORD:-pw_dev_2026}
- POSTGRES_DB=performancewest
ports:
- "5432:5432"
volumes:
- api-pgdata:/var/lib/postgresql/data
restart: unless-stopped
workers:
build:
context: .
dockerfile: scripts/Dockerfile
env_file: .env
environment:
- DATABASE_URL=postgresql://pw:${DB_PASSWORD:-pw_dev_2026}@api-postgres:5432/performancewest
- NODE_ENV=production
- DOMAIN=performancewest.net
- ERPNEXT_URL=http://erpnext:8000
- ERPNEXT_API_KEY=${ERPNEXT_API_KEY}
- ERPNEXT_API_SECRET=${ERPNEXT_API_SECRET}
- ERPNEXT_SITE_NAME=performancewest.net
- MINIO_ENDPOINT=minio
- MINIO_PORT=9000
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
- MINIO_BUCKET=performancewest
- MINIO_SECURE=false
- ADMIN_EMAIL=${ADMIN_EMAIL:-ops@performancewest.net}
- SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT}
- SMTP_USER=${SMTP_USER}
- SMTP_PASS=${SMTP_PASS}
- SMTP_FROM=${SMTP_FROM}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
- CUSTOMER_JWT_SECRET=${CUSTOMER_JWT_SECRET}
- OLLAMA_HOST=http://ollama:11434
- USE_DOCSERVER=true
- DOCSERVER_TIMEOUT=120
- FCC_CORES_USERNAME=${FCC_CORES_USERNAME}
- FCC_CORES_PASSWORD=${FCC_CORES_PASSWORD}
- OPS_IMAP_HOST=${OPS_IMAP_HOST:-mail.performancewest.net}
- OPS_IMAP_PORT=${OPS_IMAP_PORT:-993}
- OPS_IMAP_USER=${OPS_IMAP_USER}
- OPS_IMAP_PASS=${OPS_IMAP_PASS}
- FROM_EMAIL=Performance West <noreply@performancewest.net>
- CRYPTO_SWEEP_ADMIN_EMAIL=${ADMIN_EMAIL:-ops@performancewest.net}
- USAC_USERNAME=${USAC_USERNAME}
- USAC_PASSWORD=${USAC_PASSWORD}
- ANYTIME_MAILBOX_SIGNUP_EMAIL=${ANYTIME_MAILBOX_SIGNUP_EMAIL:-noreply@performancewest.net}
- ANYTIME_MAILBOX_SIGNUP_PHONE=${ANYTIME_MAILBOX_SIGNUP_PHONE}
- ANYTIME_MAILBOX_DEFAULT_PASSWORD=${ANYTIME_MAILBOX_DEFAULT_PASSWORD}
- ANYTIME_MAILBOX_IMAP_HOST=${ANYTIME_MAILBOX_IMAP_HOST:-co.carrierone.com}
- ANYTIME_MAILBOX_IMAP_PORT=${ANYTIME_MAILBOX_IMAP_PORT:-993}
- ANYTIME_MAILBOX_IMAP_USER=${ANYTIME_MAILBOX_IMAP_USER:-noreply@performancewest.net}
- ANYTIME_MAILBOX_IMAP_PASS=${ANYTIME_MAILBOX_IMAP_PASS}
- ANYTIME_MAILBOX_IMAP_SSL=${ANYTIME_MAILBOX_IMAP_SSL:-true}
- ANYTIME_MAILBOX_IMAP_FOLDER=${ANYTIME_MAILBOX_IMAP_FOLDER:-INBOX}
- ANYTIME_MAILBOX_OTP_SENDER_HINT=${ANYTIME_MAILBOX_OTP_SENDER_HINT:-anytimemailbox}
- ANYTIME_MAILBOX_OTP_CODE=${ANYTIME_MAILBOX_OTP_CODE}
- ANYTIME_MAILBOX_OTP_POLL_SECONDS=${ANYTIME_MAILBOX_OTP_POLL_SECONDS:-6}
- ANYTIME_MAILBOX_OTP_TIMEOUT_SECONDS=${ANYTIME_MAILBOX_OTP_TIMEOUT_SECONDS:-180}
volumes:
- worker-data:/app/data
depends_on:
- api-postgres
restart: unless-stopped
# ── ERPNext CRM ─────────────────────────────────────────────────────
erpnext:
image: performancewest-erpnext:latest
build:
context: ./erpnext
dockerfile: Dockerfile
ports:
- "8080:8000"
environment:
- DB_HOST=erpnext-mariadb
- DB_PORT=3306
- DB_NAME=erpnext
- DB_PASSWORD=${ERPNEXT_DB_PASSWORD:-d5Webu5n0LLW2GrmKDHCf5xPliVKO1Kd9XErpWRP}
- REDIS_CACHE=redis://erpnext-redis:6379/0
- REDIS_QUEUE=redis://erpnext-redis:6379/1
- REDIS_SOCKETIO=redis://erpnext-redis:6379/2
- SOCKETIO_PORT=9000
volumes:
- erpnext-frappe-public:/home/frappe/frappe-bench/apps/frappe/frappe/public
- erpnext-erpnext-public:/home/frappe/frappe-bench/apps/erpnext/erpnext/public
- erpnext-logs:/home/frappe/frappe-bench/logs
- erpnext-sites:/home/frappe/frappe-bench/sites
depends_on:
- erpnext-mariadb
- erpnext-redis
restart: unless-stopped
erpnext-mariadb:
image: mariadb:10.6
environment:
- MYSQL_ROOT_PASSWORD=${ERPNEXT_DB_PASSWORD:-d5Webu5n0LLW2GrmKDHCf5xPliVKO1Kd9XErpWRP}
volumes:
- erpnext-mariadb-data:/var/lib/mysql
restart: unless-stopped
erpnext-redis:
image: redis:7-alpine
restart: unless-stopped
erpnext-scheduler:
image: performancewest-erpnext:latest
command: bench schedule
volumes:
- erpnext-sites:/home/frappe/frappe-bench/sites
- erpnext-logs:/home/frappe/frappe-bench/logs
environment:
- DB_HOST=erpnext-mariadb
- DB_PORT=3306
- DB_NAME=erpnext
- DB_PASSWORD=${ERPNEXT_DB_PASSWORD:-d5Webu5n0LLW2GrmKDHCf5xPliVKO1Kd9XErpWRP}
- REDIS_CACHE=redis://erpnext-redis:6379/0
- REDIS_QUEUE=redis://erpnext-redis:6379/1
- REDIS_SOCKETIO=redis://erpnext-redis:6379/2
depends_on:
- erpnext-mariadb
- erpnext-redis
restart: unless-stopped
erpnext-worker-default:
image: performancewest-erpnext:latest
command: bench worker --queue default
volumes:
- erpnext-sites:/home/frappe/frappe-bench/sites
- erpnext-logs:/home/frappe/frappe-bench/logs
environment:
- DB_HOST=erpnext-mariadb
- DB_PORT=3306
- DB_NAME=erpnext
- DB_PASSWORD=${ERPNEXT_DB_PASSWORD:-d5Webu5n0LLW2GrmKDHCf5xPliVKO1Kd9XErpWRP}
- REDIS_CACHE=redis://erpnext-redis:6379/0
- REDIS_QUEUE=redis://erpnext-redis:6379/1
- REDIS_SOCKETIO=redis://erpnext-redis:6379/2
depends_on:
- erpnext-mariadb
- erpnext-redis
restart: unless-stopped
erpnext-worker-short:
image: performancewest-erpnext:latest
command: bench worker --queue short
volumes:
- erpnext-sites:/home/frappe/frappe-bench/sites
- erpnext-logs:/home/frappe/frappe-bench/logs
environment:
- DB_HOST=erpnext-mariadb
- DB_PORT=3306
- DB_NAME=erpnext
- DB_PASSWORD=${ERPNEXT_DB_PASSWORD:-d5Webu5n0LLW2GrmKDHCf5xPliVKO1Kd9XErpWRP}
- REDIS_CACHE=redis://erpnext-redis:6379/0
- REDIS_QUEUE=redis://erpnext-redis:6379/1
- REDIS_SOCKETIO=redis://erpnext-redis:6379/2
depends_on:
- erpnext-mariadb
- erpnext-redis
restart: unless-stopped
# ── Supporting Services ─────────────────────────────────────────────
ollama:
image: ollama/ollama:latest
volumes:
- ollama-data:/root/.ollama
restart: unless-stopped
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
ports:
- "127.0.0.1:9000:9000"
- "127.0.0.1:9001:9001"
environment:
- MINIO_ROOT_USER=${MINIO_ACCESS_KEY}
- MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}
volumes:
- minio-data:/data
restart: unless-stopped
listmonk:
image: listmonk/listmonk:latest
ports:
- "9100:9000"
environment:
- LISTMONK_app__address=0.0.0.0:9000
- LISTMONK_db__host=api-postgres
- LISTMONK_db__port=5432
- LISTMONK_db__user=pw
- LISTMONK_db__password=${DB_PASSWORD:-pw_dev_2026}
- LISTMONK_db__database=listmonk
- LISTMONK_db__ssl_mode=disable
- LISTMONK_db__max_open=25
- LISTMONK_db__max_idle=25
- LISTMONK_db__max_lifetime=300s
- LISTMONK_ADMIN_USER=${LISTMONK_USER:-admin}
- LISTMONK_ADMIN_PASSWORD=${LISTMONK_PASSWORD}
- TZ=America/New_York
volumes:
- listmonk-uploads:/listmonk/uploads
depends_on:
- api-postgres
restart: unless-stopped
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
ports:
- "3100:3000"
environment:
- DATABASE_URL=postgresql://umami:umami_dev@umami-postgres:5432/umami
- APP_SECRET=${UMAMI_APP_SECRET:-0MnMHB71wtSYMF33Pm0L+MWLKezVtLGNwbkg++PZi5c=}
depends_on:
- umami-postgres
restart: unless-stopped
umami-postgres:
image: postgres:16-alpine
environment:
- POSTGRES_USER=umami
- POSTGRES_PASSWORD=umami_dev
- POSTGRES_DB=umami
volumes:
- umami-pgdata:/var/lib/postgresql/data
restart: unless-stopped
volumes:
api-pgdata:
worker-data:
ollama-data:
minio-data:
erpnext-frappe-public:
erpnext-erpnext-public:
erpnext-logs:
erpnext-sites:
erpnext-mariadb-data:
listmonk-uploads:
umami-pgdata: