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:3001" # PDS XRPC API (avoiding production PDS on :3000)
68 environment:
69 # PDS Configuration
70 PDS_HOSTNAME: ${PDS_HOSTNAME:-localhost}
71 PDS_PORT: 3001 # Match external port for correct DID registration
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:3001/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:3001/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 # Health check disabled for dev - container has no HTTP clients installed
158 # Jetstream logs show it connects and runs successfully
159 healthcheck:
160 disable: true
161 profiles:
162 - jetstream
163
164 # PostgreSQL Database for PLC Directory (Port 5436)
165 # Separate database for local PLC directory to avoid conflicts
166 postgres-plc:
167 image: postgres:15
168 container_name: coves-dev-postgres-plc
169 ports:
170 - "5436:5432"
171 environment:
172 POSTGRES_DB: plc_dev
173 POSTGRES_USER: plc_user
174 POSTGRES_PASSWORD: plc_password
175 volumes:
176 - postgres-plc-data:/var/lib/postgresql/data
177 networks:
178 - coves-dev
179 healthcheck:
180 test: ["CMD-SHELL", "pg_isready -U plc_user -d plc_dev"]
181 interval: 5s
182 timeout: 5s
183 retries: 5
184 profiles:
185 - plc
186
187 # Local PLC Directory - For E2E testing without polluting production plc.directory
188 # This allows dev mode DID registration for testing community provisioning
189 #
190 # Usage:
191 # docker-compose --profile plc up postgres-plc plc-directory
192 # Or with all services: docker-compose --profile jetstream --profile plc up
193 #
194 # Configuration in your tests:
195 # PLC_DIRECTORY_URL=http://localhost:3002
196 # IS_DEV_ENV=false # Use production mode but point to local PLC
197 plc-directory:
198 image: node:18-alpine
199 container_name: coves-dev-plc
200 ports:
201 - "3002:3000" # PLC directory API
202 working_dir: /app
203 command: >
204 sh -c "
205 if [ ! -d '/app/.git' ]; then
206 echo 'First run: Installing PLC directory...' &&
207 apk add --no-cache git python3 make g++ yarn &&
208 git clone https://github.com/did-method-plc/did-method-plc.git . &&
209 yarn install --frozen-lockfile &&
210 yarn build &&
211 echo 'PLC directory installed successfully!'
212 fi &&
213 cd packages/server &&
214 yarn start
215 "
216 environment:
217 # Point to dedicated PLC PostgreSQL database
218 DATABASE_URL: postgresql://plc_user:plc_password@postgres-plc:5432/plc_dev?sslmode=disable
219
220 # Development settings
221 DEBUG_MODE: "1"
222 LOG_ENABLED: "true"
223 LOG_LEVEL: debug
224 LOG_DESTINATION: "1"
225 NODE_ENV: development
226
227 # API configuration
228 PORT: 3000
229 volumes:
230 # Persist the PLC repo so we don't rebuild every time
231 - plc-app-data:/app
232 networks:
233 - coves-dev
234 depends_on:
235 postgres-plc:
236 condition: service_healthy
237 healthcheck:
238 test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/"]
239 interval: 10s
240 timeout: 5s
241 retries: 10
242 start_period: 120s
243 profiles:
244 - plc
245
246 # Indigo Relay (BigSky) - OPTIONAL for local dev
247 # WARNING: BigSky is designed to crawl the entire atProto network!
248 # For local dev, consider using direct PDS firehose instead (see AppView config below)
249 #
250 # To use relay: docker-compose -f docker-compose.dev.yml up pds relay
251 # To skip relay: docker-compose -f docker-compose.dev.yml up pds
252 #
253 # If using relay, you MUST manually configure it to only watch local PDS:
254 # 1. Start relay
255 # 2. Use admin API to block all domains except localhost
256 # curl -X POST http://localhost:2471/admin/pds/requestCrawl \
257 # -H "Authorization: Bearer dev-admin-key" \
258 # -d '{"hostname": "localhost:3001"}'
259 relay:
260 image: ghcr.io/bluesky-social/indigo:bigsky-0a2d4173e6e89e49b448f6bb0a6e1ab58d12b385
261 container_name: coves-dev-relay
262 ports:
263 - "2471:2470" # Relay firehose WebSocket (avoiding conflicts)
264 environment:
265 # Relay Configuration
266 BGS_ADMIN_KEY: ${BGS_ADMIN_KEY:-dev-admin-key}
267 BGS_PORT: 2470
268
269 # IMPORTANT: Allow insecure WebSocket for local PDS (ws:// instead of wss://)
270 BGS_CRAWL_INSECURE_WS: "true"
271
272 # Database connection (uses PostgreSQL for relay state)
273 DATABASE_URL: postgresql://${POSTGRES_USER:-dev_user}:${POSTGRES_PASSWORD:-dev_password}@postgres:5432/${POSTGRES_DB:-coves_dev}?sslmode=disable
274
275 # Relay will discover PDSs automatically - use admin API to restrict!
276 # See comments above for how to configure allowlist
277
278 # Development settings
279 LOG_LEVEL: ${LOG_LEVEL:-debug}
280 networks:
281 - coves-dev
282 depends_on:
283 postgres:
284 condition: service_healthy
285 pds:
286 condition: service_healthy
287 healthcheck:
288 test: ["CMD", "wget", "--spider", "-q", "http://localhost:2470/xrpc/_health"]
289 interval: 10s
290 timeout: 5s
291 retries: 5
292 # Mark as optional - start with: docker-compose up pds relay
293 profiles:
294 - relay
295
296 # Coves AppView (Your Go Application)
297 # Subscribes to PDS firehose and indexes Coves-specific data
298 # Note: Uncomment when you have a Dockerfile for the AppView
299 # appview:
300 # build:
301 # context: .
302 # dockerfile: Dockerfile
303 # container_name: coves-dev-appview
304 # ports:
305 # - "8081:8080" # AppView API (avoiding conflicts)
306 # environment:
307 # # Database connection
308 # DATABASE_URL: postgresql://${POSTGRES_USER:-dev_user}:${POSTGRES_PASSWORD:-dev_password}@postgres:5432/${POSTGRES_DB:-coves_dev}?sslmode=disable
309 #
310 # # PDS Firehose subscription (direct, no relay)
311 # FIREHOSE_URL: ws://pds:3000/xrpc/com.atproto.sync.subscribeRepos
312 #
313 # # PDS connection (for XRPC calls)
314 # PDS_URL: http://pds:3000
315 #
316 # # Application settings
317 # PORT: 8080
318 # ENV: development
319 # LOG_LEVEL: ${LOG_LEVEL:-debug}
320 # networks:
321 # - coves-dev
322 # depends_on:
323 # postgres:
324 # condition: service_healthy
325 # pds:
326 # condition: service_healthy
327
328networks:
329 coves-dev:
330 driver: bridge
331 name: coves-dev-network
332
333volumes:
334 postgres-data:
335 name: coves-dev-postgres-data
336 postgres-test-data:
337 name: coves-test-postgres-data
338 postgres-plc-data:
339 name: coves-dev-postgres-plc-data
340 pds-data:
341 name: coves-dev-pds-data
342 jetstream-data:
343 name: coves-dev-jetstream-data
344 plc-app-data:
345 name: coves-dev-plc-app-data