Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
139 lines (132 loc) · 4.57 KB
/
Copy pathdocker-compose.yml
File metadata and controls
139 lines (132 loc) · 4.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# LeadForge full stack.
#
# docker compose up --build
#
# Backend API http://localhost:8000 (docs: /docs, health: /health)
# Dashboard http://localhost:3000
#
# App ports (8000/3000) are open on every interface so the stack works on a
# LAN. Postgres/Redis bind to 127.0.0.1 only — they are implementation
# details and must never face your network.
#
# Before exposing the API beyond localhost, generate a real secret:
# SECRET_KEY=$(openssl rand -hex 32) docker compose up -d
# and set ENV=production + an explicit CORS_ORIGINS (see .env.example).
#
# The dashboard talks to the API through a same-origin Next.js rewrite, so the
# browser only ever calls localhost:3000. That is what makes the stack work
# from another machine on the LAN — the old build-time NEXT_PUBLIC_API_URL
# baked "localhost:8000" into the client bundle, so every visitor's browser
# tried to reach *their own* machine.
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_USER: leadforge
POSTGRES_PASSWORD: password
POSTGRES_DB: leadforge
ports:
- "127.0.0.1:5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U leadforge -d leadforge"]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:7-alpine
ports:
- "127.0.0.1:6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql+asyncpg://leadforge:password@postgres:5432/leadforge
- REDIS_URL=redis://redis:6379/0
- CELERY_BROKER_URL=redis://redis:6379/0
- CELERY_RESULT_BACKEND=redis://redis:6379/0
- SECRET_KEY=${SECRET_KEY:-leadforge-secret-key-production-change-me}
- ENV=${ENV:-dev}
- CORS_ORIGINS=${CORS_ORIGINS:-*}
- TRACKING_DOMAIN=${TRACKING_DOMAIN:-http://localhost:8000}
- USE_CELERY=true
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
# No --reload. The reload watcher restarts the process on any file write,
# which kills in-flight campaigns (the sender runs inside this process).
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8000/health', timeout=5).status == 200 else 1)"]
interval: 10s
timeout: 5s
retries: 12
start_period: 20s
celery-worker:
build:
context: ./backend
dockerfile: Dockerfile
environment:
- DATABASE_URL=postgresql+asyncpg://leadforge:password@postgres:5432/leadforge
- REDIS_URL=redis://redis:6379/0
- CELERY_BROKER_URL=redis://redis:6379/0
- CELERY_RESULT_BACKEND=redis://redis:6379/0
- SECRET_KEY=${SECRET_KEY:-leadforge-secret-key-production-change-me}
- ENV=${ENV:-dev}
- USE_CELERY=true
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
backend:
condition: service_healthy
command: celery -A app.workers.tasks worker --loglevel=info
# The beat scheduler. It was missing entirely, and because USE_CELERY=true
# disables the in-process reply poller in the API, reply detection NEVER ran
# in the Docker deployment. Multi-step sequences were not scheduled either.
celery-beat:
build:
context: ./backend
dockerfile: Dockerfile
environment:
- DATABASE_URL=postgresql+asyncpg://leadforge:password@postgres:5432/leadforge
- REDIS_URL=redis://redis:6379/0
- CELERY_BROKER_URL=redis://redis:6379/0
- CELERY_RESULT_BACKEND=redis://redis:6379/0
- SECRET_KEY=${SECRET_KEY:-leadforge-secret-key-production-change-me}
- ENV=${ENV:-dev}
- USE_CELERY=true
depends_on:
redis:
condition: service_healthy
backend:
condition: service_healthy
command: celery -A app.workers.tasks beat --loglevel=info
dashboard:
build:
context: ./dashboard
dockerfile: Dockerfile
args:
# Server-side only. The browser calls /api/* on its own origin and
# Next.js proxies to the backend, so nothing localhost-ish is baked
# into the client bundle.
API_PROXY_URL: ${API_PROXY_URL:-http://backend:8000/api}
ports:
- "3000:3000"
depends_on:
backend:
condition: service_healthy
volumes:
postgres_data: