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