README.md95 lines · main
1# `infra/datapane/`
2
3briven per-project Postgres backend stack — Phase 6 of `BACKEND_FORK_BRIEF.md`.
4
5This is the **data plane**: the Postgres + REST + Auth + Realtime + meta services that the Studio (`apps/studio`) and end-user projects talk to. It is **separate** from the **control plane** at `infra/dokploy/` (the briven.tech dashboard, billing, projects table).
6
7## Services
8
9| service | image | exposed via | purpose |
10| ---------- | -------------------------------- | ----------- | ------------------------------------ |
11| `caddy` | `caddy:2.10-alpine` | 80 / 443 | reverse proxy; strips upstream headers |
12| `db` | `supabase/postgres:15.8.1.085` | 5432 | Postgres data plane |
13| `auth` | `supabase/gotrue:v2.186.0` | `/auth/v1` | JWT auth, sign-up/login |
14| `rest` | `postgrest/postgrest:v14.8` | `/rest/v1` | REST API auto-gen from schema |
15| `realtime` | `supabase/realtime:v2.76.5` | `/realtime` | WebSocket subscriptions |
16| `meta` | `supabase/postgres-meta:v0.96.3` | `/pg` | schema introspection (Studio dep) |
17
18## Services NOT in this stack (and why)
19
20| service | reason |
21| ---------- | ------------------------------------------------------------- |
22| `studio` | deployed separately as a Next.js app (`apps/studio`) |
23| `kong` | replaced with caddy — see `BACKEND_FORK_PLAN.md` §1 |
24| `storage` | deferred to Phase 9 per brief §5 |
25| `imgproxy` | couples to storage; deferred to Phase 9 |
26| `functions`| briven has separate Deno isolate plan; deferred |
27| `analytics`| Logflare not used; briven logs to Loki via filesystem tail |
28| `vector` | bind-mounts `/var/run/docker.sock` — hard violation of `docs/DOCKER.md` rule 6. Never re-add |
29| `supavisor`| connection pooler; deferred to Phase 9 (matters only at scale)|
30
31## Local run
32
33```bash
34cd infra/datapane
35cp .env.example .env
36# edit .env, fill in real secrets
37docker compose up -d
38docker compose ps
39```
40
41Health-check the stack:
42
43```bash
44# REST should respond with PostgREST's OpenAPI doc — but headers should NOT name PostgREST.
45curl -sI http://localhost:8000/rest/v1/
46# Expected:
47# Server: briven
48# (no X-Powered-By, no Server: postgrest/...)
49
50# Auth health endpoint.
51curl -sI http://localhost:8000/auth/v1/health
52
53# Meta schema introspection.
54curl -s http://localhost:8000/pg/version
55```
56
57## Demo (per brief §5 Phase 6)
58
59> `docker-compose up from infra/` brings up the full Briven backend stack. `curl` against any endpoint returns headers and error messages that contain zero references to Supabase, GoTrue, PostgREST by name, or any other underlying component identifier.
60
61After `docker compose up -d`:
62
63```bash
64# Pass: server header is "briven", upstream identifiers are stripped.
65curl -sI http://localhost:8000/rest/v1/ | grep -iE "server|powered|via"
66
67# Fail (sanity): would return non-empty if upstream headers leaked.
68curl -sI http://localhost:8000/rest/v1/ | grep -iE "postgrest|gotrue|supabase|kong|caddy"
69```
70
71## Companion files
72
73| file | purpose |
74| --------------------------------- | ------------------------------------------------ |
75| `compose.yml` | the live stack — what `docker compose up` runs |
76| `compose.upstream.yml` | preserved rebrand-swept upstream supabase compose, for comparison. NOT used at runtime. |
77| `compose.caddy.yml` | upstream's caddy variant — preserved for reference |
78| `.env.example` | env template |
79| `volumes/proxy/caddy/Caddyfile` | reverse-proxy config; strips identifying headers |
80| `volumes/db/*.sql` | init scripts (roles, jwt, realtime, webhooks) |
81| `CONFIG.upstream.md` | upstream supabase docs for reference |
82| `versions.upstream.md` | upstream image version pins for reference |
83
84## Hard rules (cross-ref `infra/CLAUDE.md`)
85
86Every service has `logging: *briven-logging` (10MB × 3 files). No service mounts `/var/run/docker.sock`. No service polls the Docker daemon. Re-run the log-cap audit when adding services:
87
88```bash
89python3 -c "
90import yaml
91with open('infra/datapane/compose.yml') as fh: d=yaml.safe_load(fh)
92missing=[s for s,c in d['services'].items() if c.get('restart')=='unless-stopped' and 'logging' not in c]
93print('missing log cap:', missing or 'none')
94"
95```
Preview

infra/datapane/

briven per-project Postgres backend stack — Phase 6 of BACKEND_FORK_BRIEF.md.

This is the data plane: the Postgres + REST + Auth + Realtime + meta services that the Studio (apps/studio) and end-user projects talk to. It is separate from the control plane at infra/dokploy/ (the briven.tech dashboard, billing, projects table).

Services

serviceimageexposed viapurpose
caddycaddy:2.10-alpine80 / 443reverse proxy; strips upstream headers
dbsupabase/postgres:15.8.1.0855432Postgres data plane
authsupabase/gotrue:v2.186.0/auth/v1JWT auth, sign-up/login
restpostgrest/postgrest:v14.8/rest/v1REST API auto-gen from schema
realtimesupabase/realtime:v2.76.5/realtimeWebSocket subscriptions
metasupabase/postgres-meta:v0.96.3/pgschema introspection (Studio dep)

Services NOT in this stack (and why)

servicereason
studiodeployed separately as a Next.js app (apps/studio)
kongreplaced with caddy — see BACKEND_FORK_PLAN.md §1
storagedeferred to Phase 9 per brief §5
imgproxycouples to storage; deferred to Phase 9
functionsbriven has separate Deno isolate plan; deferred
analyticsLogflare not used; briven logs to Loki via filesystem tail
vectorbind-mounts /var/run/docker.sock — hard violation of docs/DOCKER.md rule 6. Never re-add
supavisorconnection pooler; deferred to Phase 9 (matters only at scale)

Local run

cd infra/datapane
cp .env.example .env
# edit .env, fill in real secrets
docker compose up -d
docker compose ps

Health-check the stack:

# REST should respond with PostgREST's OpenAPI doc — but headers should NOT name PostgREST.
curl -sI http://localhost:8000/rest/v1/
# Expected:
#   Server: briven
#   (no X-Powered-By, no Server: postgrest/...)

# Auth health endpoint.
curl -sI http://localhost:8000/auth/v1/health

# Meta schema introspection.
curl -s http://localhost:8000/pg/version

Demo (per brief §5 Phase 6)

docker-compose up from infra/ brings up the full Briven backend stack. curl against any endpoint returns headers and error messages that contain zero references to Supabase, GoTrue, PostgREST by name, or any other underlying component identifier.

After docker compose up -d:

# Pass: server header is "briven", upstream identifiers are stripped.
curl -sI http://localhost:8000/rest/v1/ | grep -iE "server|powered|via"

# Fail (sanity): would return non-empty if upstream headers leaked.
curl -sI http://localhost:8000/rest/v1/ | grep -iE "postgrest|gotrue|supabase|kong|caddy"

Companion files

filepurpose
compose.ymlthe live stack — what docker compose up runs
compose.upstream.ymlpreserved rebrand-swept upstream supabase compose, for comparison. NOT used at runtime.
compose.caddy.ymlupstream's caddy variant — preserved for reference
.env.exampleenv template
volumes/proxy/caddy/Caddyfilereverse-proxy config; strips identifying headers
volumes/db/*.sqlinit scripts (roles, jwt, realtime, webhooks)
CONFIG.upstream.mdupstream supabase docs for reference
versions.upstream.mdupstream image version pins for reference

Hard rules (cross-ref infra/CLAUDE.md)

Every service has logging: *briven-logging (10MB × 3 files). No service mounts /var/run/docker.sock. No service polls the Docker daemon. Re-run the log-cap audit when adding services:

python3 -c "
import yaml
with open('infra/datapane/compose.yml') as fh: d=yaml.safe_load(fh)
missing=[s for s,c in d['services'].items() if c.get('restart')=='unless-stopped' and 'logging' not in c]
print('missing log cap:', missing or 'none')
"