22#
33# Coolify receives the opted-in PR head through its signed manual webhook and re-reads this file from
44# that commit, so a pull request's own copy defines its stack. The controller refuses to deploy a pull
5- # request that edits this file , and scripts/check-preview-stack.ts asserts the sandbox properties
6- # below on every pull request.
5+ # request that changes anything under docker/preview/ , and scripts/check-preview-stack.ts asserts the
6+ # sandbox properties below on every pull request.
77#
88# Every service runs the image CI published for this exact commit — the same artifacts staging and
99# production run, buildpack-built application server included. Nothing is built here, so a preview
1010# exercises the shipped runtime rather than a second recipe that could pass where the real one fails.
1111#
12- # This restates the reference stack rather than including it. Compose merges per key, so inheriting
12+ # This restates the reference stack rather than including it: Compose merges per key, so inheriting
1313# would arrive with sync, notifications and the agent digest requirement switched on, and with the
14- # Docker socket mounted — ADR 0035 option 6 has the rendered evidence. scripts/check-preview-stack.ts
15- # fails when the reference gains a variable this file neither sets nor records as omitted.
16- #
17- # This file declares no networks. Coolify runs every preview of this application under one Compose
18- # project — the project name is the application UUID, with no pull request in it — so a network named
19- # here would be `<uuid>_backend`, shared by every preview at once. Coolify instead gives each preview
20- # its own network and attaches its proxy to that, which is what keeps the stacks apart.
14+ # Docker socket mounted. ADR 0035 option 6 has the rendered evidence.
2115
2216services :
2317 postgres :
@@ -34,7 +28,7 @@ services:
3428 cap_drop :
3529 - ALL
3630 # The entrypoint chowns its data directory and drops to the postgres user; without these it exits
37- # with "failed switching to 'postgres'". Verified by running the stack, not inferred.
31+ # with "failed switching to 'postgres'".
3832 cap_add :
3933 - CHOWN
4034 - DAC_OVERRIDE
@@ -58,20 +52,15 @@ services:
5852 memory : 512M
5953 pids : 256
6054
61- # Clones the running staging database into this preview so it starts with real data. Reads over
62- # the network with a role that can only read: staging's data volume is never mounted, and no
63- # container here holds the Docker daemon. Every review entry point is paused, and the instance
64- # identity dropped, before the application server is allowed to boot. Runs once — a redeploy finds
65- # the marker table and exits.
66- #
67- # This is the image staging itself runs, so pg_dump always matches the server it reads.
55+ # Clones staging into this preview over the network with a role that can only read; staging's data
56+ # volume is never mounted. This is the image staging itself runs, so pg_dump always matches the
57+ # server it reads.
6858 seed-loader :
6959 image : ghcr.io/ls1intum/hephaestus/postgres:${SOURCE_COMMIT:?Coolify supplies the deployed commit}
7060 restart : " no"
7161 depends_on :
7262 postgres :
7363 condition : service_healthy
74- # Reaches staging's Postgres by name; its own database it reaches on Coolify's preview network.
7564 networks :
7665 - staging-shared
7766 environment :
@@ -188,8 +177,8 @@ services:
188177 DELETE FROM login_provider;
189178 SQL
190179
191- # The marker promises the policy is in force , so verify it against the database rather than
192- # trusting psql's exit status.
180+ # Every statement above succeeds when it matches nothing , so the marker is earned by
181+ # counting rather than by psql's exit status.
193182 echo "Verifying the preview policy took effect"
194183 LIVE=$$(psql -h "$$TARGET" -U hephaestus -d hephaestus -tAX -v ON_ERROR_STOP=1 -c "
195184 SELECT (SELECT count(*) FROM workspace
@@ -260,17 +249,15 @@ services:
260249 DATABASE_USERNAME : hephaestus
261250 DATABASE_PASSWORD : ${POSTGRES_PASSWORD}
262251 # The integration consumer reads staging's JetStream, so a preview sees the events a shared
263- # GitHub App delivers there rather than an empty broker. The agent job queue runs on
264- # PostgreSQL, not NATS, and stays local to this stack's own database.
252+ # GitHub App delivers there rather than an empty broker.
265253 NATS_SERVER : ${NATS_SERVER:-nats://nats-server:4222}
266254 NATS_ENABLED : " true"
267255 # Per-deploy durable name, so previews get their own JetStream consumers instead of competing
268256 # for one and stealing each other's messages.
269257 NATS_DURABLE_CONSUMER_NAME : ${SERVICE_NAME_APPSERVER:-appserver}-consumer
270- # A preview is deleted, not shut down, so it never removes the durables it created on the
271- # shared stream. Far shorter than the 30d a long-lived deployment uses, because a preview is
272- # abandoned the day its pull request merges. Still long enough that a redeploy, or a testing
273- # session paused overnight, resumes on its own cursor instead of skipping to the head.
258+ # A preview is deleted, not shut down, so it never removes its durables from the shared
259+ # stream. Shorter than the shipped 30d because a preview is abandoned at merge, and long
260+ # enough that a redeploy resumes on its own cursor.
274261 HEPHAESTUS_INTEGRATION_CONSUMER_INACTIVE_THRESHOLD : 72h
275262 HEPHAESTUS_AUTH_ISSUER : https://${SERVICE_FQDN_WEBAPP}
276263 HEPHAESTUS_AUTH_STATE_COOKIE_KEY : ${HEPHAESTUS_AUTH_STATE_COOKIE_KEY}
@@ -294,8 +281,8 @@ services:
294281 SENTRY_DSN : " "
295282 WEBHOOK_SECRET : ${WEBHOOK_SECRET}
296283 WEBHOOK_EXTERNAL_URL : " "
297- # Only the application server joins staging's network, and only to reach its broker. The
298- # database and the SPA stay on Coolify's per-preview network.
284+ # Joined to reach staging's broker; this stack's own database and SPA stay on Coolify's
285+ # per-preview network.
299286 networks :
300287 - staging-shared
301288 depends_on :
@@ -312,8 +299,8 @@ services:
312299 test : ["CMD", "/workspace/health-check"]
313300 interval : 15s
314301 timeout : 5s
315- # A first boot runs Liquibase against an empty database on a shared host, and the webapp waits
316- # on this. Nothing here benefits from failing fast, and failing fast fails the whole deploy .
302+ # First boot runs Liquibase over a freshly restored staging dump, on a host shared with
303+ # staging .
317304 retries : 10
318305 start_period : 300s
319306 logging :
0 commit comments