Files
goodgo-platform/docker-compose.yml
Ho Ngoc Hai deb04989de feat(api): add industrial, transfer, and reports backend modules
Add three new NestJS modules following DDD/CQRS architecture:
- Industrial: KCN (industrial park) management with PostGIS geo queries, Typesense search, and market statistics
- Transfer: Furniture/premises transfer listings with AI-powered price estimation and depreciation modeling
- Reports: Async AI report generation via BullMQ with Claude narrative service, PDF generation, and macro data integration

Includes Prisma schema models, migrations, seed scripts, and app.module wiring with BullMQ Redis config.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 09:11:16 +07:00

293 lines
8.5 KiB
YAML

services:
postgres:
image: postgis/postgis:16-3.4
container_name: goodgo-postgres
restart: unless-stopped
ports:
- '${DB_PORT:-5432}:5432'
environment:
POSTGRES_DB: ${DB_NAME:-goodgo}
POSTGRES_USER: ${DB_USER:-goodgo}
POSTGRES_PASSWORD: ${DB_PASSWORD:-goodgo_secret}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${DB_USER:-goodgo} -d ${DB_NAME:-goodgo}']
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- goodgo-net
redis:
image: redis:7-alpine
container_name: goodgo-redis
restart: unless-stopped
ports:
- '${REDIS_PORT:-6379}:6379'
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru --requirepass ${REDIS_PASSWORD:-changeme}
volumes:
- redis_data:/data
healthcheck:
test: ['CMD', 'redis-cli', '-a', '${REDIS_PASSWORD:-changeme}', '--no-auth-warning', 'ping']
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
networks:
- goodgo-net
typesense:
image: typesense/typesense:27.1
container_name: goodgo-typesense
restart: unless-stopped
ports:
- '${TYPESENSE_PORT:-8108}:8108'
environment:
TYPESENSE_API_KEY: ${TYPESENSE_API_KEY:-ts_dev_key_change_me}
TYPESENSE_DATA_DIR: /data
TYPESENSE_ENABLE_CORS: 'true'
volumes:
- typesense_data:/data
healthcheck:
test: ['CMD-SHELL', 'bash -c "echo > /dev/tcp/localhost/8108"']
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
networks:
- goodgo-net
minio:
image: minio/minio:latest
container_name: goodgo-minio
restart: unless-stopped
ports:
- '${MINIO_API_PORT:-9000}:9000'
- '${MINIO_CONSOLE_PORT:-9001}:9001'
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:?MINIO_ACCESS_KEY is required}
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:?MINIO_SECRET_KEY is required}
MINIO_API_CORS_ALLOW_ORIGIN: 'http://localhost:3000,http://localhost:3001'
volumes:
- minio_data:/data
healthcheck:
test: ['CMD', 'curl', '-sf', 'http://localhost:9000/minio/health/live']
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
networks:
- goodgo-net
minio-init:
image: minio/mc:latest
container_name: goodgo-minio-init
restart: 'no'
depends_on:
minio:
condition: service_healthy
entrypoint: /bin/sh
command:
- -c
- |
mc alias set local http://minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}
mc mb --ignore-existing local/$${MINIO_BUCKET}
mc anonymous set download local/$${MINIO_BUCKET}
echo "MinIO init complete: bucket=$${MINIO_BUCKET}, public read enabled"
environment:
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:?MINIO_ACCESS_KEY is required}
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:?MINIO_SECRET_KEY is required}
MINIO_BUCKET: ${MINIO_BUCKET:-goodgo-media}
networks:
- goodgo-net
ai-services:
build:
context: ./libs/ai-services
dockerfile: Dockerfile
container_name: goodgo-ai-services
restart: unless-stopped
ports:
- '${AI_SERVICES_PORT:-8000}:8000'
environment:
AI_DEBUG: ${AI_DEBUG:-false}
AI_LOG_LEVEL: ${AI_LOG_LEVEL:-info}
healthcheck:
test: ['CMD', 'python', '-c', 'import httpx; httpx.get("http://localhost:8000/health").raise_for_status()']
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
networks:
- goodgo-net
# ── Database Backup ──
pg-backup:
image: postgis/postgis:16-3.4
container_name: goodgo-pg-backup
restart: unless-stopped
entrypoint: /bin/bash
command:
- -c
- |
apt-get update -qq && apt-get install -y -qq cron > /dev/null 2>&1
(echo "0 2 * * * PGHOST=postgres PGPORT=5432 PGUSER=${DB_USER:-goodgo} PGDATABASE=${DB_NAME:-goodgo} PGPASSWORD=${DB_PASSWORD:-goodgo_secret} BACKUP_DIR=/backups RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-7} /scripts/pg-backup.sh >> /var/log/pg-backup.log 2>&1"; echo "0 4 * * * PGHOST=postgres PGPORT=5432 PGUSER=${DB_USER:-goodgo} PGDATABASE=${DB_NAME:-goodgo} PGPASSWORD=${DB_PASSWORD:-goodgo_secret} BACKUP_DIR=/backups REPORT_FILE=/backups/verify-latest.json /scripts/pg-verify-backup.sh >> /var/log/pg-verify-backup.log 2>&1") | crontab -
/scripts/pg-backup.sh
cron -f
environment:
PGHOST: postgres
PGPORT: '5432'
PGUSER: ${DB_USER:-goodgo}
PGDATABASE: ${DB_NAME:-goodgo}
PGPASSWORD: ${DB_PASSWORD:-goodgo_secret}
BACKUP_DIR: /backups
RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-7}
volumes:
- ./scripts/backup:/scripts:ro
- pg_backups:/backups
depends_on:
postgres:
condition: service_healthy
networks:
- goodgo-net
# ── Backup Verification (on-demand) ──
# Run manually: docker compose run --rm pg-verify-backup
pg-verify-backup:
image: postgis/postgis:16-3.4
container_name: goodgo-pg-verify-backup
profiles:
- tools
entrypoint: /bin/bash
command:
- -c
- /scripts/pg-verify-backup.sh
environment:
PGHOST: postgres
PGPORT: '5432'
PGUSER: ${DB_USER:-goodgo}
PGDATABASE: ${DB_NAME:-goodgo}
PGPASSWORD: ${DB_PASSWORD:-goodgo_secret}
BACKUP_DIR: /backups
REPORT_FILE: /backups/verify-report.json
volumes:
- ./scripts/backup:/scripts:ro
- pg_backups:/backups
depends_on:
postgres:
condition: service_healthy
networks:
- goodgo-net
# ── Log Aggregation ──
loki:
image: grafana/loki:3.0.0
container_name: goodgo-loki
restart: unless-stopped
ports:
- '${LOKI_PORT:-3100}:3100'
command: -config.file=/etc/loki/loki-config.yml
volumes:
- ./monitoring/loki/loki-config.yml:/etc/loki/loki-config.yml:ro
- loki_data:/loki
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:3100/ready']
interval: 15s
timeout: 5s
retries: 5
start_period: 20s
networks:
- goodgo-net
promtail:
image: grafana/promtail:3.0.0
container_name: goodgo-promtail
restart: unless-stopped
command: -config.file=/etc/promtail/promtail-config.yml
volumes:
- ./monitoring/promtail/promtail-config.yml:/etc/promtail/promtail-config.yml:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
loki:
condition: service_healthy
networks:
- goodgo-net
prometheus:
image: prom/prometheus:v2.51.0
container_name: goodgo-prometheus
restart: unless-stopped
ports:
- '${PROMETHEUS_PORT:-9090}:9090'
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=15d'
- '--web.enable-lifecycle'
volumes:
- ./monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
extra_hosts:
- 'host.docker.internal:host-gateway'
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:9090/-/healthy']
interval: 15s
timeout: 5s
retries: 3
start_period: 10s
networks:
- goodgo-net
grafana:
image: grafana/grafana:10.4.1
container_name: goodgo-grafana
restart: unless-stopped
ports:
- '${GRAFANA_PORT:-3002}:3000'
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-admin}
GF_USERS_ALLOW_SIGN_UP: 'false'
volumes:
- ./monitoring/grafana/provisioning:/etc/grafana/provisioning:ro
- ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards:ro
- grafana_data:/var/lib/grafana
depends_on:
prometheus:
condition: service_healthy
loki:
condition: service_healthy
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:3000/api/health']
interval: 15s
timeout: 5s
retries: 3
start_period: 15s
networks:
- goodgo-net
volumes:
pgdata:
driver: local
redis_data:
driver: local
typesense_data:
driver: local
minio_data:
driver: local
pg_backups:
driver: local
loki_data:
driver: local
prometheus_data:
driver: local
grafana_data:
driver: local
networks:
goodgo-net:
driver: bridge
name: goodgo-net