chore: CRM-NEW baseline

This commit is contained in:
wangliang
2026-10-23 10:35:28 +08:00
commit aa499f6dbf
111 changed files with 15126 additions and 0 deletions
+243
View File
@@ -0,0 +1,243 @@
name: crm-new
# 全新一套:LibreDesk(平台 + 内置 AI)+ Twenty(CRM)+ bridge(业务工具/集成)
# 与旧栈 crm/crm-ai-demo 完全隔离:独立 PG/Redis/端口/数据卷。
#
# 对外端口:
# LibreDesk http://192.168.31.61:9000
# Twenty http://192.168.31.61:3100
# bridge http://192.168.31.61: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://192.168.31.61: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://192.168.31.61: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}
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}
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
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
volumes:
pg-data:
redis-data:
twenty-data: