deploy + ops
Tier topology
| tier | web URL | CF Pages project | Fly Hocuspocus app | Neon branch | beta gate |
|---|---|---|---|---|---|
| prod | patchtogether.live | patchtogether-live | patchtogether-server | production | off |
| autotest | autotest.patchtogether.live | patchtogether-live-autotest | patchtogether-server-autotest | autotest | beta:robotsonly |
| dev | dev.patchtogether.live | patchtogether-live-dev | patchtogether-server-dev | dev | beta:2600hz |
What deploys when
- PR open / push → preview at
pr-N.patchtogether-live-autotest.pages.dev. Inherits the autotest Clerk env so auth round-trips work. - merge to main → autotest + dev fan-out, in parallel. Both stay in sync.
- version bump on main → prod deploy. Detected by diffing
package.json:.versionagainstHEAD~1. - workflow_dispatch → manual override. Requires the latest CI run on the chosen branch to be green.
Why Cloudflare Pages can't drive Postgres directly
Three Postgres drivers were tried in sequence; only one works from Workers:
pg.Clientover TCP — fails. Workers'node:netshim returns "proxy request failed";pg's socket layer doesn't speakcloudflare:sockets.@neondatabase/serverlessWebSocketPool— fails. CF's egress proxy 403s the outbound WebSocket handshake.@neondatabase/serverlessHTTPneontemplate tag — works.fetch()under the hood.
Consequence: anything in packages/web/src/lib/server/ that needs atomicity has to
be a single SQL statement, typically a CTE. See rackspaces.ts for the pattern. The
Hocuspocus server on Fly is regular Node — it uses pg.Pool over TCP without
trouble.
Beta gate
Basic-auth wrapper enforced in hooks.server.ts. Off in prod, on in autotest + dev. /api/health bypasses the gate (live-smoke + uptime probes), and so does the /docs/* tree (so the in-app docs read the same pre- and post-launch).
Browser auth + session flows still work behind it because Playwright passes credentials via use.httpCredentials.
Hocuspocus on Fly
Three Fly apps, one per tier. Each app runs the @patchtogether.live/server Node bundle — Hocuspocus + Clerk JWT verification +
capacity enforcement (4 connections per doc). Yjs snapshots flush to the matching
Neon branch. WebSocket URL is baked into the web bundle at build time via VITE_SERVER_WS_URL.
Local dev shortcut
flox activate -- task setup # install + Playwright Chromium
flox activate -- task dev # SvelteKit + DSP one-shot build
flox activate -- task server:dev # Hocuspocus on ws://localhost:1235 Hocuspocus binds 1235, not 1234 — BitwigStudio reserves 1234 for OSC on this machine. Postgres
for local dev: see db/README.md.