A community based topic aggregation platform built on atproto
1version: '3.8'
2
3# Coves Local Development Stack
4# All-in-one setup: PDS + PostgreSQL + optional Relay
5#
6# Usage:
7# make dev-up # Start PDS + PostgreSQL
8# make dev-down # Stop everything
9# docker-compose up relay # Optional: start with relay
10#
11# Profiles:
12# - default: PDS + PostgreSQL (dev database on port 5433)
13# - test: PostgreSQL test database (port 5434)
14# - relay: BigSky relay (optional, will crawl entire network!)
15
16services:
17 # PostgreSQL Database (Port 5435)
18 # Used by Coves AppView for indexing data from firehose
19 postgres:
20 image: postgres:15
21 container_name: coves-dev-postgres
22 ports:
23 - "5435:5432"
24 environment:
25 POSTGRES_DB: ${POSTGRES_DB:-coves_dev}
26 POSTGRES_USER: ${POSTGRES_USER:-dev_user}
27 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-dev_password}
28 volumes:
29 - postgres-data:/var/lib/postgresql/data
30 networks:
31 - coves-dev
32 healthcheck:
33 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-dev_user} -d ${POSTGRES_DB:-coves_dev}"]
34 interval: 5s
35 timeout: 5s
36 retries: 5
37
38 # PostgreSQL Test Database (Port 5434) - Optional
39 # Use with: docker-compose --profile test up postgres-test
40 postgres-test:
41 image: postgres:15
42 container_name: coves-test-postgres
43 ports:
44 - "${POSTGRES_TEST_PORT:-5434}:5432"
45 environment:
46 POSTGRES_DB: ${POSTGRES_TEST_DB:-coves_test}
47 POSTGRES_USER: ${POSTGRES_TEST_USER:-test_user}
48 POSTGRES_PASSWORD: ${POSTGRES_TEST_PASSWORD:-test_password}
49 volumes:
50 - postgres-test-data:/var/lib/postgresql/data
51 networks:
52 - coves-dev
53 healthcheck:
54 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_TEST_USER:-test_user} -d ${POSTGRES_TEST_DB:-coves_test}"]
55 interval: 5s
56 timeout: 5s
57 retries: 5
58 profiles:
59 - test
60
61 # Bluesky Personal Data Server (PDS)
62 # Handles user repositories, DIDs, and CAR files
63 pds:
64 image: ghcr.io/bluesky-social/pds:latest
65 container_name: coves-dev-pds
66 ports:
67 - "3001:3000" # PDS XRPC API (avoiding production PDS on :3000)
68 environment:
69 # PDS Configuration
70 PDS_HOSTNAME: ${PDS_HOSTNAME:-localhost}
71 PDS_PORT: 3000
72 PDS_DATA_DIRECTORY: /pds
73 PDS_BLOBSTORE_DISK_LOCATION: /pds/blocks
74 PDS_DID_PLC_URL: ${PDS_DID_PLC_URL:-https://plc.directory}
75 # PDS_CRAWLERS not needed - we're not using a relay for local dev
76
77 # Note: PDS uses its own internal SQLite database and CAR file storage
78 # Our PostgreSQL database is only for the Coves AppView
79
80 # JWT secrets (for local dev only)
81 PDS_JWT_SECRET: ${PDS_JWT_SECRET:-local-dev-jwt-secret-change-in-production}
82 PDS_ADMIN_PASSWORD: ${PDS_ADMIN_PASSWORD:-admin}
83 PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX: ${PDS_PLC_ROTATION_KEY:-af514fb84c4356241deed29feb392d1ee359f99c05a7b8f7bff2e5f2614f64b2}
84
85 # Service endpoints
86 # Allow both user handles (.local.coves.dev) and community handles (.community.coves.social)
87 PDS_SERVICE_HANDLE_DOMAINS: ${PDS_SERVICE_HANDLE_DOMAINS:-.local.coves.dev,.community.coves.social}
88
89 # Dev mode settings (allows HTTP instead of HTTPS)
90 PDS_DEV_MODE: "true"
91
92 # Disable invite codes for testing
93 PDS_INVITE_REQUIRED: "false"
94
95 # Development settings
96 NODE_ENV: development
97 LOG_ENABLED: "true"
98 LOG_LEVEL: ${LOG_LEVEL:-debug}
99 volumes:
100 - pds-data:/pds
101 networks:
102 - coves-dev
103 healthcheck:
104 test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/xrpc/_health"]
105 interval: 10s
106 timeout: 5s
107 retries: 5
108
109 # Jetstream - Consumes PDS firehose and serves JSON WebSocket
110 # This is the RECOMMENDED approach for local E2E testing
111 # Jetstream converts raw atProto CBOR firehose to clean JSON events
112 #
113 # Flow: PDS firehose → Jetstream (CBOR→JSON) → Your AppView (JSON)
114 #
115 # Usage:
116 # docker-compose --profile jetstream up pds jetstream
117 # Your AppView connects to: ws://localhost:6008/subscribe
118 #
119 # Why use Jetstream instead of direct PDS firehose?
120 # - PDS emits raw CBOR (binary) - hard to parse
121 # - Jetstream converts to clean JSON - easy to consume
122 # - Same format as production Bluesky Jetstream
123 jetstream:
124 image: ghcr.io/bluesky-social/jetstream:sha-306e463693365e21a5ffd3ec051a5a7920000214
125 container_name: coves-dev-jetstream
126 ports:
127 - "6008:6008" # Jetstream WebSocket endpoint
128 - "6009:6009" # Metrics endpoint
129 environment:
130 # Point Jetstream at local PDS firehose
131 JETSTREAM_WS_URL: ws://pds:3000/xrpc/com.atproto.sync.subscribeRepos
132
133 # Server configuration
134 JETSTREAM_LISTEN_ADDR: ":6008"
135 JETSTREAM_METRICS_LISTEN_ADDR: ":6009"
136
137 # Data storage
138 JETSTREAM_DATA_DIR: /data
139 JETSTREAM_EVENT_TTL: 24h
140
141 # Set long liveness TTL for local dev (PDS may be quiet for long periods)
142 JETSTREAM_LIVENESS_TTL: 24h
143
144 # Performance tuning
145 JETSTREAM_WORKER_COUNT: 10
146 JETSTREAM_MAX_QUEUE_SIZE: 1000
147
148 # Development settings
149 LOG_LEVEL: ${LOG_LEVEL:-debug}
150 volumes:
151 - jetstream-data:/data
152 networks:
153 - coves-dev
154 depends_on:
155 pds:
156 condition: service_healthy
157 healthcheck:
158 test: ["CMD", "wget", "--spider", "-q", "http://localhost:6009/metrics"]
159 interval: 10s
160 timeout: 5s
161 retries: 5
162 profiles:
163 - jetstream
164
165 # PostgreSQL Database for PLC Directory (Port 5436)
166 # Separate database for local PLC directory to avoid conflicts
167 postgres-plc:
168 image: postgres:15
169 container_name: coves-dev-postgres-plc
170 ports:
171 - "5436:5432"
172 environment:
173 POSTGRES_DB: plc_dev
174 POSTGRES_USER: plc_user
175 POSTGRES_PASSWORD: plc_password
176 volumes:
177 - postgres-plc-data:/var/lib/postgresql/data
178 networks:
179 - coves-dev
180 healthcheck:
181 test: ["CMD-SHELL", "pg_isready -U plc_user -d plc_dev"]
182 interval: 5s
183 timeout: 5s
184 retries: 5
185 profiles:
186 - plc
187
188 # Local PLC Directory - For E2E testing without polluting production plc.directory
189 # This allows dev mode DID registration for testing community provisioning
190 #
191 # Usage:
192 # docker-compose --profile plc up postgres-plc plc-directory
193 # Or with all services: docker-compose --profile jetstream --profile plc up
194 #
195 # Configuration in your tests:
196 # PLC_DIRECTORY_URL=http://localhost:3002
197 # IS_DEV_ENV=false # Use production mode but point to local PLC
198 plc-directory:
199 image: node:18-alpine
200 container_name: coves-dev-plc
201 ports:
202 - "3002:3000" # PLC directory API
203 working_dir: /app
204 command: >
205 sh -c "
206 if [ ! -d '/app/.git' ]; then
207 echo 'First run: Installing PLC directory...' &&
208 apk add --no-cache git python3 make g++ yarn &&
209 git clone https://github.com/did-method-plc/did-method-plc.git . &&
210 yarn install --frozen-lockfile &&
211 yarn build &&
212 echo 'PLC directory installed successfully!'
213 fi &&
214 cd packages/server &&
215 yarn start
216 "
217 environment:
218 # Point to dedicated PLC PostgreSQL database
219 DATABASE_URL: postgresql://plc_user:plc_password@postgres-plc:5432/plc_dev?sslmode=disable
220
221 # Development settings
222 DEBUG_MODE: "1"
223 LOG_ENABLED: "true"
224 LOG_LEVEL: debug
225 LOG_DESTINATION: "1"
226 NODE_ENV: development
227
228 # API configuration
229 PORT: 3000
230 volumes:
231 # Persist the PLC repo so we don't rebuild every time
232 - plc-app-data:/app
233 networks:
234 - coves-dev
235 depends_on:
236 postgres-plc:
237 condition: service_healthy
238 healthcheck:
239 test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/"]
240 interval: 10s
241 timeout: 5s
242 retries: 10
243 start_period: 120s
244 profiles:
245 - plc
246
247 # Indigo Relay (BigSky) - OPTIONAL for local dev
248 # WARNING: BigSky is designed to crawl the entire atProto network!
249 # For local dev, consider using direct PDS firehose instead (see AppView config below)
250 #
251 # To use relay: docker-compose -f docker-compose.dev.yml up pds relay
252 # To skip relay: docker-compose -f docker-compose.dev.yml up pds
253 #
254 # If using relay, you MUST manually configure it to only watch local PDS:
255 # 1. Start relay
256 # 2. Use admin API to block all domains except localhost
257 # curl -X POST http://localhost:2471/admin/pds/requestCrawl \
258 # -H "Authorization: Bearer dev-admin-key" \
259 # -d '{"hostname": "localhost:3001"}'
260 relay:
261 image: ghcr.io/bluesky-social/indigo:bigsky-0a2d4173e6e89e49b448f6bb0a6e1ab58d12b385
262 container_name: coves-dev-relay
263 ports:
264 - "2471:2470" # Relay firehose WebSocket (avoiding conflicts)
265 environment:
266 # Relay Configuration
267 BGS_ADMIN_KEY: ${BGS_ADMIN_KEY:-dev-admin-key}
268 BGS_PORT: 2470
269
270 # IMPORTANT: Allow insecure WebSocket for local PDS (ws:// instead of wss://)
271 BGS_CRAWL_INSECURE_WS: "true"
272
273 # Database connection (uses PostgreSQL for relay state)
274 DATABASE_URL: postgresql://${POSTGRES_USER:-dev_user}:${POSTGRES_PASSWORD:-dev_password}@postgres:5432/${POSTGRES_DB:-coves_dev}?sslmode=disable
275
276 # Relay will discover PDSs automatically - use admin API to restrict!
277 # See comments above for how to configure allowlist
278
279 # Development settings
280 LOG_LEVEL: ${LOG_LEVEL:-debug}
281 networks:
282 - coves-dev
283 depends_on:
284 postgres:
285 condition: service_healthy
286 pds:
287 condition: service_healthy
288 healthcheck:
289 test: ["CMD", "wget", "--spider", "-q", "http://localhost:2470/xrpc/_health"]
290 interval: 10s
291 timeout: 5s
292 retries: 5
293 # Mark as optional - start with: docker-compose up pds relay
294 profiles:
295 - relay
296
297 # Coves AppView (Your Go Application)
298 # Subscribes to PDS firehose and indexes Coves-specific data
299 # Note: Uncomment when you have a Dockerfile for the AppView
300 # appview:
301 # build:
302 # context: .
303 # dockerfile: Dockerfile
304 # container_name: coves-dev-appview
305 # ports:
306 # - "8081:8080" # AppView API (avoiding conflicts)
307 # environment:
308 # # Database connection
309 # DATABASE_URL: postgresql://${POSTGRES_USER:-dev_user}:${POSTGRES_PASSWORD:-dev_password}@postgres:5432/${POSTGRES_DB:-coves_dev}?sslmode=disable
310 #
311 # # PDS Firehose subscription (direct, no relay)
312 # FIREHOSE_URL: ws://pds:3000/xrpc/com.atproto.sync.subscribeRepos
313 #
314 # # PDS connection (for XRPC calls)
315 # PDS_URL: http://pds:3000
316 #
317 # # Application settings
318 # PORT: 8080
319 # ENV: development
320 # LOG_LEVEL: ${LOG_LEVEL:-debug}
321 # networks:
322 # - coves-dev
323 # depends_on:
324 # postgres:
325 # condition: service_healthy
326 # pds:
327 # condition: service_healthy
328
329networks:
330 coves-dev:
331 driver: bridge
332 name: coves-dev-network
333
334volumes:
335 postgres-data:
336 name: coves-dev-postgres-data
337 postgres-test-data:
338 name: coves-test-postgres-data
339 postgres-plc-data:
340 name: coves-dev-postgres-plc-data
341 pds-data:
342 name: coves-dev-pds-data
343 jetstream-data:
344 name: coves-dev-jetstream-data
345 plc-app-data:
346 name: coves-dev-plc-app-data