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