252 lines
8.2 KiB
YAML
252 lines
8.2 KiB
YAML
name: crm-new
|
||
|
||
# 全新一套:LibreDesk(平台 + 内置 AI)+ Twenty(CRM)+ bridge(业务工具/集成)
|
||
# 与旧栈 crm/crm-ai-demo 完全隔离:独立 PG/Redis/端口/数据卷。
|
||
#
|
||
# 对外端口:
|
||
# LibreDesk http://localhost:9000
|
||
# Twenty http://localhost:3100
|
||
# bridge http://localhost:4100
|
||
# Postgres(宿主机) 127.0.0.1:5440
|
||
# Redis(宿主机) 127.0.0.1:6390
|
||
|
||
services:
|
||
postgres:
|
||
image: ${POSTGRES_IMAGE:-pgvector/pgvector:pg18}
|
||
container_name: crmnew-postgres
|
||
restart: unless-stopped
|
||
ports:
|
||
- "127.0.0.1:5440:5432"
|
||
environment:
|
||
POSTGRES_USER: ${POSTGRES_USER:-crmnew}
|
||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||
volumes:
|
||
# PG18 官方镜像要求挂载 /var/lib/postgresql(数据在子目录)
|
||
- pg-data:/var/lib/postgresql
|
||
- ./infra/init-databases.sql:/docker-entrypoint-initdb.d/01-init-databases.sql:ro
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-crmnew} -d postgres"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 20
|
||
|
||
redis:
|
||
image: ${REDIS_IMAGE:-redis:8.8-alpine}
|
||
container_name: crmnew-redis
|
||
restart: unless-stopped
|
||
command: ["redis-server", "--appendonly", "yes"]
|
||
ports:
|
||
- "127.0.0.1:6390:6379"
|
||
volumes:
|
||
- redis-data:/data
|
||
healthcheck:
|
||
test: ["CMD", "redis-cli", "ping"]
|
||
interval: 5s
|
||
timeout: 3s
|
||
retries: 20
|
||
|
||
# ---------------------------------------------------------------- LibreDesk
|
||
libredesk:
|
||
image: ${LIBREDESK_IMAGE:-libredesk/libredesk:v2.9.0-rc.10}
|
||
container_name: crmnew-libredesk
|
||
restart: unless-stopped
|
||
ports:
|
||
- "9000:9000"
|
||
environment:
|
||
LIBREDESK_SYSTEM_USER_PASSWORD: ${LIBREDESK_SYSTEM_USER_PASSWORD}
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
volumes:
|
||
- ./libredesk/uploads:/libredesk/uploads:rw
|
||
- ./libredesk/config/config.toml:/libredesk/config.toml:ro
|
||
command:
|
||
- sh
|
||
- -c
|
||
- >-
|
||
./libredesk --install --idempotent-install --yes --config /libredesk/config.toml &&
|
||
./libredesk --upgrade --yes --config /libredesk/config.toml &&
|
||
./libredesk --config /libredesk/config.toml
|
||
|
||
# ------------------------------------------------------------------- Twenty
|
||
twenty-server:
|
||
image: twentycrm/twenty:${TWENTY_TAG:-v2.30.1}
|
||
container_name: crmnew-twenty-server
|
||
restart: unless-stopped
|
||
ports:
|
||
- "3100:3000"
|
||
environment:
|
||
NODE_PORT: 3000
|
||
PG_DATABASE_URL: postgres://${POSTGRES_USER:-crmnew}:${POSTGRES_PASSWORD}@postgres:5432/twenty
|
||
SERVER_URL: ${TWENTY_SERVER_URL:-http://localhost:3100}
|
||
REDIS_URL: redis://redis:6379/1
|
||
DISABLE_DB_MIGRATIONS: "false"
|
||
DISABLE_CRON_JOBS_REGISTRATION: "false"
|
||
STORAGE_TYPE: local
|
||
ENCRYPTION_KEY: ${TWENTY_ENCRYPTION_KEY}
|
||
FALLBACK_ENCRYPTION_KEY: ${TWENTY_FALLBACK_ENCRYPTION_KEY}
|
||
APP_SECRET: ${TWENTY_APP_SECRET}
|
||
IS_BILLING_ENABLED: "false"
|
||
SIGN_IN_PREFILLED: "false"
|
||
EMAIL_DRIVER: logger
|
||
volumes:
|
||
- twenty-data:/app/packages/twenty-server/.local-storage
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
healthcheck:
|
||
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/healthz"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 30
|
||
start_period: 90s
|
||
|
||
twenty-worker:
|
||
image: twentycrm/twenty:${TWENTY_TAG:-v2.30.1}
|
||
container_name: crmnew-twenty-worker
|
||
restart: unless-stopped
|
||
command: ["yarn", "worker:prod"]
|
||
environment:
|
||
PG_DATABASE_URL: postgres://${POSTGRES_USER:-crmnew}:${POSTGRES_PASSWORD}@postgres:5432/twenty
|
||
SERVER_URL: ${TWENTY_SERVER_URL:-http://localhost:3100}
|
||
REDIS_URL: redis://redis:6379/1
|
||
DISABLE_DB_MIGRATIONS: "true"
|
||
DISABLE_CRON_JOBS_REGISTRATION: "true"
|
||
STORAGE_TYPE: local
|
||
ENCRYPTION_KEY: ${TWENTY_ENCRYPTION_KEY}
|
||
FALLBACK_ENCRYPTION_KEY: ${TWENTY_FALLBACK_ENCRYPTION_KEY}
|
||
APP_SECRET: ${TWENTY_APP_SECRET}
|
||
volumes:
|
||
- twenty-data:/app/packages/twenty-server/.local-storage
|
||
depends_on:
|
||
twenty-server:
|
||
condition: service_healthy
|
||
|
||
# IMAP ID 注入代理:LibreDesk 客户端不发 ID,163 会拒绝 SELECT
|
||
imap-proxy:
|
||
image: node:24-alpine
|
||
container_name: crmnew-imap-proxy
|
||
restart: unless-stopped
|
||
command: ["node", "/app/server.js"]
|
||
environment:
|
||
LISTEN_PORT: 1993
|
||
UPSTREAM_HOST: imap.163.com
|
||
UPSTREAM_PORT: 993
|
||
ports:
|
||
- "127.0.0.1:1993:1993"
|
||
volumes:
|
||
- ./services/imap-id-proxy:/app:ro
|
||
depends_on:
|
||
- libredesk
|
||
|
||
# 公网网关:仅暴露 WhatsApp webhook + 帮助中心,其余 404
|
||
public-gateway:
|
||
image: node:24-alpine
|
||
container_name: crmnew-public-gateway
|
||
restart: unless-stopped
|
||
command: ["node", "/app/server.js"]
|
||
environment:
|
||
PORT: 9001
|
||
UPSTREAM: http://libredesk:9000
|
||
volumes:
|
||
- ./services/public-gateway:/app:ro
|
||
depends_on:
|
||
- libredesk
|
||
|
||
# Cloudflare 临时隧道:给 Meta 一个公网 HTTPS 回调地址
|
||
cloudflared:
|
||
image: cloudflare/cloudflared:latest
|
||
container_name: crmnew-cloudflared
|
||
restart: unless-stopped
|
||
command: tunnel --no-autoupdate --url http://public-gateway:9001
|
||
depends_on:
|
||
- public-gateway
|
||
|
||
# ------------------------------------------------------------------- bridge
|
||
bridge:
|
||
build:
|
||
context: ./bridge
|
||
container_name: crmnew-bridge
|
||
restart: unless-stopped
|
||
extra_hosts:
|
||
- "host.docker.internal:host-gateway"
|
||
ports:
|
||
- "4100:4100"
|
||
environment:
|
||
TOOLS_PORT: 4100
|
||
TOOLS_SHARED_KEY: ${TOOLS_SHARED_KEY}
|
||
TOOLS_PUBLIC_BASE_URL: http://bridge:4100
|
||
TOOLS_DEV_BYPASS: ${TOOLS_DEV_BYPASS:-false}
|
||
RECOMMEND_URL: ${RECOMMEND_URL}
|
||
ORDER_API_URL: ${ORDER_API_URL}
|
||
INVENTORY_API_URL: ${INVENTORY_API_URL}
|
||
MEMBER_RPC_URL: ${MEMBER_RPC_URL}
|
||
RPC_TIMEOUT_MS: ${RPC_TIMEOUT_MS:-8000}
|
||
PRODUCT_TIMEOUT_MS: ${PRODUCT_TIMEOUT_MS:-15000}
|
||
SITE_SEARCH_URL: ${SITE_SEARCH_URL}
|
||
TWENTY_BASE_URL: http://twenty-server:3000
|
||
TWENTY_GRAPHQL_PATH: /graphql
|
||
TWENTY_WORKSPACE_ID: ${TWENTY_WORKSPACE_ID:-}
|
||
TWENTY_API_KEY: ${TWENTY_API_KEY:-}
|
||
LIBREDESK_BASE_URL: ${LIBREDESK_BASE_URL}
|
||
LIBREDESK_API_KEY: ${LIBREDESK_API_KEY:-}
|
||
LIBREDESK_API_SECRET: ${LIBREDESK_API_SECRET:-}
|
||
LIBREDESK_WEBHOOK_SECRET: ${LIBREDESK_WEBHOOK_SECRET:-}
|
||
LIBREDESK_WEBHOOK_INBOX_IDS: ${LIBREDESK_WEBHOOK_INBOX_IDS:-1}
|
||
LLM_BASE_URL: ${LLM_BASE_URL:-}
|
||
LLM_API_KEY: ${LLM_API_KEY:-}
|
||
LLM_MODEL: ${LLM_MODEL:-qwen-plus-latest}
|
||
LLM_TIMEOUT_MS: ${LLM_TIMEOUT_MS:-30000}
|
||
TRACE_ENABLED: ${TRACE_ENABLED:-false}
|
||
SMTP_HOST: ${SMTP_HOST:-}
|
||
SMTP_PORT: ${SMTP_PORT:-465}
|
||
SMTP_USER: ${SMTP_USER:-}
|
||
SMTP_PASS: ${SMTP_PASS:-}
|
||
SMTP_FROM: ${SMTP_FROM:-}
|
||
RAG_PG_URL: ${RAG_PG_URL:-}
|
||
EMB_BASE_URL: ${EMB_BASE_URL:-}
|
||
EMB_API_KEY: ${EMB_API_KEY:-}
|
||
EMB_MODEL: ${EMB_MODEL:-text-embedding-v4}
|
||
EMB_DIM: ${EMB_DIM:-1024}
|
||
EMB_TRANSLATE_MODEL: ${EMB_TRANSLATE_MODEL:-qwen-turbo}
|
||
LIBREDESK_INBOX_UUID: ${LIBREDESK_INBOX_UUID:-}
|
||
LIBREDESK_INBOX_SECRET: ${LIBREDESK_INBOX_SECRET:-}
|
||
SITE_JWT_SECRET: ${SITE_JWT_SECRET:-}
|
||
IDENTITY_DEV_MODE: ${IDENTITY_DEV_MODE:-false}
|
||
IDENTITY_CORS_ORIGIN: ${IDENTITY_CORS_ORIGIN:-}
|
||
IDENTITY_TTL_SEC: ${IDENTITY_TTL_SEC:-3600}
|
||
REDIS_URL: redis://redis:6379/3
|
||
DEFAULT_TENANT_ID: ${DEFAULT_TENANT_ID:-2}
|
||
DEFAULT_LANGUAGE_ID: ${DEFAULT_LANGUAGE_ID:-1}
|
||
PG_URL: postgres://${POSTGRES_USER:-crmnew}:${POSTGRES_PASSWORD}@postgres:5432/bridge
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
redis:
|
||
condition: service_healthy
|
||
networks:
|
||
- default
|
||
- spug-net
|
||
healthcheck:
|
||
test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:4100/healthz"]
|
||
interval: 10s
|
||
timeout: 3s
|
||
retries: 10
|
||
|
||
networks:
|
||
default:
|
||
name: crm-new_default
|
||
# 与本工作区的 wangliang-dev 同网络,bridge 可直接按容器名调用 9503/9505/9506/9509
|
||
spug-net:
|
||
external: true
|
||
|
||
volumes:
|
||
pg-data:
|
||
redis-data:
|
||
twenty-data:
|