-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
240 lines (233 loc) · 10.1 KB
/
Copy pathdocker-compose.yml
File metadata and controls
240 lines (233 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# ---------------------------------------------------------------------------
# WARNING: the default credentials in this file are for local development
# only. The ONLY secret operators set directly is POSTGRES_PASSWORD. All
# cryptographic keys are generated by the trex-init service on first boot
# and written to ./secrets/{root.env,derived.env}. Mount that directory as
# a secret-grade volume in production and back it up — losing root.env
# invalidates every encrypted secret in trex.{secret,database_credential}
# and every issued JWT.
# ---------------------------------------------------------------------------
# Two-node cluster: trex-data (data node, holds the pool + Flight) + trex-server
# (non-data node, serves the UI/API and opens remote sessions to trex-data).
# Gossip seeds are auto-derived from the `nodes` map below, so the two converge
# automatically. Flight binds 0.0.0.0 but the db extension advertises it to
# gossip under each node's gossip host (trex-data / trex-server) so peers get a
# routable endpoint — advertising 0.0.0.0 made the server dial itself, so every
# data-backed resolver failed with "create_session failed" and the UI hung.
x-swarm-config: &swarm-config
SWARM_CONFIG: >-
{"cluster_id":"local","nodes":{
"data":{
"gossip_addr":"trex-data:4200","data_node":true,
"extensions":[
{"name":"flight","config":{"host":"0.0.0.0","port":50051}}
]},
"server":{
"gossip_addr":"trex-server:4200","data_node":false,
"extensions":[
{"name":"trexas","config":{"host":"0.0.0.0","port":8001,"main_service_path":"/usr/src/core/server/index.eszip","event_worker_path":"/usr/src/core/event/index.eszip","tls_port":8000,"tls_cert_path":"/usr/src/server.crt","tls_key_path":"/usr/src/server.key"}},
{"name":"pgwire","config":{"host":"0.0.0.0","port":5432}}
]}
}}
volumes:
core-pgdata:
claude-config:
gh-config:
studio-snippets:
studio-edge-functions:
services:
trex-init:
image: ghcr.io/ohdsi/trexsql:latest
entrypoint: /usr/local/bin/trex-init
environment:
TREX_SECRETS_DIR: /shared
# Prometheus (FHIR analytics UI) ships in the image under plugins-dev;
# this registers it in the web shell's top nav (parity with the dx compose).
TREX_WEB_NAV_EXTRA: '[{"path":"/prometheus","label":"Prometheus","plugin":"prometheus"}]'
volumes:
- ./secrets:/shared
restart: "no"
postgres:
image: postgres:16
container_name: trexsql-postgres
ports:
- 65433:5432
command:
- postgres
- -c
- wal_level=logical
- -c
- max_replication_slots=10
- -c
- max_wal_senders=10
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mypass}
POSTGRES_DB: testdb
volumes:
- core-pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 10
trex-data:
image: ghcr.io/ohdsi/trexsql:latest
volumes:
- claude-config:/home/node/.claude
- gh-config:/home/node/.config/gh
# core/server, core/schema and the plugins (web, studio, storage, pg-meta)
# are built into the image (see the builder stages in the Dockerfile), so
# we do NOT bind-mount host source over them here — doing so shadowed the
# built artifacts (e.g. web/dist) and broke the UIs. For live development
# against host source, use docker-compose.dev.yml, which mounts only the
# built outputs (e.g. ./plugins/web/dist).
# Shared with the studio sidecar: Studio's deploy writes here, trex reads.
- studio-edge-functions:/app/edge-functions
depends_on:
trex-init:
condition: service_completed_successfully
postgres:
condition: service_healthy
env_file:
- path: ./secrets/root.env
required: false
- path: ./secrets/derived.env
required: false
environment:
<<: *swarm-config
SWARM_NODE: data
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-mypass}@postgres:5432/testdb
SCHEMA_DIR: /usr/src/core/schema
PLUGINS_PATH: /usr/src/plugins
PLUGINS_DEV_PATH: /usr/src/plugins-dev
healthcheck:
# Probe the flight gRPC port with node (the image ships node, not nc).
test:
- CMD-SHELL
- "node -e \"require('net').connect(50051,'127.0.0.1').on('connect',()=>process.exit(0)).on('error',()=>process.exit(1))\""
interval: 5s
timeout: 3s
retries: 30
start_period: 30s
trex-server:
image: ghcr.io/ohdsi/trexsql:latest
ports:
- 8000:8000
- 8001:8001
- 5433:5432
volumes:
- claude-config:/home/node/.claude
- gh-config:/home/node/.config/gh
# Plugins (web, studio, storage, pg-meta) and core/server are built into
# the image; not bind-mounting host source over them (that shadowed the
# built artifacts and broke the UIs). Use docker-compose.dev.yml for
# live development against host source.
# Shared with the studio sidecar: Studio's deploy writes here, trex reads.
- studio-edge-functions:/app/edge-functions
depends_on:
trex-init:
condition: service_completed_successfully
trex-data:
condition: service_healthy
env_file:
- path: ./secrets/root.env
required: false
- path: ./secrets/derived.env
required: false
environment:
<<: *swarm-config
SWARM_NODE: server
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-mypass}@postgres:5432/testdb
BASE_PATH: /trex
# Native email/password IDP (auth-router). Off by default in the
# engine; standalone/dev trex opts in so admin@trex.local can log in.
TREX_IDP_ENABLED: "true"
BETTER_AUTH_URL: http://localhost:8001/trex
PLUGINS_INFORMATION_URL: "https://feeds.dev.azure.com/data2evidence/d2e/_apis/packaging/Feeds/d2e/packages?api-version=7.1&includeDescription=true"
TPM_REGISTRY_URL: "https://pkgs.dev.azure.com/data2evidence/d2e/_packaging/d2e/npm/registry"
PLUGINS_PATH: /usr/src/plugins
PLUGINS_DEV_PATH: /usr/src/plugins-dev
# REST is served in-process by the @trex/postgrest plugin, which
# consumes these PGRST_* values; PGRST_JWT_SECRET comes from
# ./secrets/derived.env (see env_file above).
PGRST_DB_URI: postgres://authenticator:authenticator_pass@postgres:5432/testdb
PGRST_DB_SCHEMAS: public
PGRST_DB_ANON_ROLE: anon
PGRST_DB_PRE_REQUEST: public.postgrest_pre_request
PGRST_OPENAPI_SERVER_PROXY_URI: http://localhost:8001/trex/rest/v1
STUDIO_INTERNAL_URL: http://studio:3000
EDGE_FUNCTIONS_MANAGEMENT_FOLDER: /app/edge-functions
# Pythia: the agent worker proxies to the pythia plugin on the internal
# port (33001), and agents without an explicit model need this fallback.
BAO_AGENT_UPSTREAM_BASE: ${BAO_AGENT_UPSTREAM_BASE:-http://localhost:33001/plugins/ohdsi/pythia}
TREX_AGENTS_DEFAULT_MODEL: ${TREX_AGENTS_DEFAULT_MODEL:-bedrock/${BAO_AGENT_MODEL:-us.anthropic.claude-sonnet-4-6}}
healthcheck:
# /trex/api/ready returns 503 until supabaseEnvVars is populated, which is
# set immediately after ensureAuthKeys() writes anon/service keys to
# trex.setting. The auth/v1/health probe wasn't enough — it answered 200
# as soon as the HTTP server listened, which could be a few ms before the
# keys hit the DB. studio's depends_on then raced and read empty keys.
test:
- CMD-SHELL
- 'node -e "fetch(''http://localhost:8001/trex/api/ready'').then(r => { if (r.status !== 200) throw new Error(r.status) })"'
interval: 10s
timeout: 5s
retries: 30
start_period: 60s
# Studio sidecar — internal-only; trex proxies /plugins/trex/studio/** to it.
# Runs from the published image (the trex-specific entrypoint + key-fetch
# helper are baked in). To build/refresh it locally for testing:
# docker build plugins/studio/supabase-studio \
# -f plugins/studio/supabase-studio/apps/studio/Dockerfile \
# --target production \
# --build-arg NEXT_PUBLIC_BASE_PATH=/plugins/trex/studio \
# -t ghcr.io/ohdsi/trex-studio:latest
studio:
image: ghcr.io/ohdsi/trex-studio:latest
container_name: trex-studio
restart: unless-stopped
# NOT exposing a host port: direct access would bypass trex's admin-only gate.
depends_on:
trex-init:
condition: service_completed_successfully
trex-server:
condition: service_healthy
volumes:
# The wrapper entrypoint + fetch-trex-keys.cjs (which read
# SUPABASE_ANON_KEY / SUPABASE_SERVICE_KEY from trex.setting at boot) are
# baked into the image, so no host bind mounts are needed here.
- studio-snippets:/app/snippets
- studio-edge-functions:/app/edge-functions
healthcheck:
test:
- CMD-SHELL
- 'node -e "fetch(''http://localhost:3000/plugins/trex/studio/api/platform/profile'').then(r => { if (r.status !== 200) throw new Error(r.status) })"'
interval: 10s
timeout: 5s
retries: 5
env_file:
- path: ./secrets/derived.env
required: false
environment:
HOSTNAME: "0.0.0.0"
STUDIO_PG_META_URL: http://trex-server:8001/trex/pg/v1
POSTGRES_HOST: postgres
POSTGRES_PORT: "5432"
POSTGRES_DB: testdb
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mypass}
# Override Studio's self-hosted defaults — trex's postgres has no supabase_admin user.
POSTGRES_USER_READ_WRITE: postgres
POSTGRES_USER_READ_ONLY: postgres
# PG_META_CRYPTO_KEY and AUTH_JWT_SECRET come from ./secrets/derived.env.
PGRST_DB_SCHEMAS: public,storage
DEFAULT_ORGANIZATION_NAME: trex
DEFAULT_PROJECT_NAME: default
SUPABASE_URL: http://trex-server:8001/trex
SUPABASE_PUBLIC_URL: http://localhost:8001/trex
SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY:-}
SUPABASE_SERVICE_KEY: ${SUPABASE_SERVICE_KEY:-}
NEXT_ANALYTICS_BACKEND_PROVIDER: postgres
NEXT_PUBLIC_ENABLE_LOGS: "false"
SNIPPETS_MANAGEMENT_FOLDER: /app/snippets
EDGE_FUNCTIONS_MANAGEMENT_FOLDER: /app/edge-functions