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>
293 lines
8.5 KiB
YAML
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
|