Repository navigation
Expand file tree
/
Copy pathcompose.dev.yml
More file actions
219 lines (212 loc) · 10.7 KB
/
Copy pathcompose.dev.yml
File metadata and controls
219 lines (212 loc) · 10.7 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
---
# Local development stack for bunyip (PSA Systems): PostgreSQL + the actix-web
# backend (bunyip-api) + the Axum SSR frontend (bunyip-web). The whole backend
# is self-contained in this workspace, so the api service just mounts this repo
# at /app and cargo-watch hot-reloads.
#
# Run with: just dev (or: USER=$(whoami) docker compose -f compose.dev.yml up --build)
#
# The `dev-sso` overlay (compose.dev-sso.yml) layers Traefik routing on top for
# *.a8n.run SSO testing; `just dev-sso` is the supported entry point.
name: bunyip-${USER:?USER missing - run via just dev}
services:
# PostgreSQL database (used by the api). The api runs migrations against it on
# startup (sqlx::migrate!).
postgres:
# Postgres 18, matching compose.yml + the deployed template (BUNYIP-350).
image: postgres:18.2-alpine3.23
container_name: dev-bunyip-postgres-${USER}
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-bunyip}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-devpassword}
POSTGRES_DB: ${POSTGRES_DB:-bunyip}
expose:
- "5432"
volumes:
# Whole tree, not .../data: Postgres >= 18 defaults PGDATA to
# /var/lib/postgresql/<MAJOR>/docker (BUNYIP-350). On an existing PG16 dev
# volume, PG18 just initializes fresh under the new subpath (the old
# .../data tree is ignored, not migrated); run `just dev-clean` to drop the
# stale volume for a clean start. Dev data is disposable.
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready --username ${POSTGRES_USER:-bunyip} --dbname ${POSTGRES_DB:-bunyip}"]
interval: 5s
timeout: 5s
retries: 5
start_period: 5s
networks:
- private
# actix-web backend (bunyip-api). Source is bind-mounted; cargo-watch rebuilds.
# The dunite git dep is anonymously readable; DUNITE_GIT_TOKEN is optional.
api:
build:
context: .
dockerfile: bunyip-api/Dockerfile
args:
HOST_UID: ${HOST_UID:-1000}
HOST_GID: ${HOST_GID:-1000}
CARGO_BUILD_JOBS: ${CARGO_BUILD_JOBS:-default}
user: "${HOST_UID:-1000}:${HOST_GID:-1000}"
container_name: dev-bunyip-api-${USER}
working_dir: /app
restart: unless-stopped
environment:
# Resolve bunyip-oidc's compile-time query! macros offline.
SQLX_OFFLINE: "true"
DATABASE_URL: ${DATABASE_URL:-postgres://bunyip:${POSTGRES_PASSWORD:-devpassword}@postgres:5432/bunyip}
# BUNYIP-360: activate per-user RLS. The api provisions the unprivileged
# NOBYPASSRLS `bunyip_app` role at startup using BUNYIP_APP_PASSWORD (over
# the primary superuser pool above), then serves self-service reads on
# APP_DATABASE_URL as that role. Both default off POSTGRES_PASSWORD so a
# fresh `just dev` activates RLS with no extra config; they must agree.
BUNYIP_APP_PASSWORD: ${BUNYIP_APP_PASSWORD:-${POSTGRES_PASSWORD:-devpassword}}
APP_DATABASE_URL: ${APP_DATABASE_URL:-postgres://bunyip_app:${BUNYIP_APP_PASSWORD:-${POSTGRES_PASSWORD:-devpassword}}@postgres:5432/bunyip}
HOST_IP: 0.0.0.0
APP_PORT: "4401"
ENVIRONMENT: ${ENVIRONMENT:-development}
APP_NAME: ${APP_NAME:-PSA Systems}
CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:4400}
# BUNYIP-749: explicit rather than left to fall back to CORS_ORIGIN's
# first entry, matching compose.yml. Plain `just dev` serves bunyip-web
# at localhost:4400, the same default CORS_ORIGIN already uses.
APP_URL: ${APP_URL:-http://localhost:4400}
BUNYIP_WEB_ORIGIN: ${BUNYIP_WEB_ORIGIN:-http://localhost:4400}
COOKIE_DOMAIN: ${COOKIE_DOMAIN:-}
# BUNYIP-409: trust bunyip-web (and Traefik on dev-sso) on the internal
# Docker network so a forwarded X-Forwarded-For surfaces the end-user IP on
# the Active Sessions list instead of the internal Docker peer. RFC1918
# ranges; the API is only reachable over the Docker network + Traefik.
TRUSTED_PROXY_CIDR: ${TRUSTED_PROXY_CIDR:-172.16.0.0/12,10.0.0.0/8,192.168.0.0/16}
RUST_LOG: ${RUST_LOG:-info,bunyip_api=debug,bunyip_core=info}
# BUNYIP-542: the ONE store for the governed integration secrets (SMTP
# password, Stripe secret key, Stripe webhook secret). `database` is what
# dev has always used - they are entered on the admin pages - so `just
# dev` is unchanged.
SECRETS_STORAGE: ${SECRETS_STORAGE:-database}
JWT_SECRET: ${JWT_SECRET:-dev-only-jwt-secret-at-least-32-characters-long-000000}
# BUNYIP-483: the ONE at-rest AES-256-GCM key for the secrets stored in
# user_totp / stripe_config / email_config. NOT Stripe API configuration
# (BUNYIP-482). APP_ENCRYPTION_KEY_PREV is the comma-separated list of
# keys still needed to read rows written under an earlier key.
APP_ENCRYPTION_KEY: ${APP_ENCRYPTION_KEY:-}
APP_ENCRYPTION_KEY_PREV: ${APP_ENCRYPTION_KEY_PREV:-}
# BUNYIP-482: Stripe API keys and checkout URLs live ONLY in the
# stripe_config DB row; enter them on the admin Stripe page. The checkout
# URLs default to the first CORS_ORIGIN entry. See docs/stripe-test-mode.md.
SETUP_DEFAULT_ADMIN: ${SETUP_DEFAULT_ADMIN:-}
# BUNYIP-290: bootstrap the first admin from an email (no password in env).
# Promotes on sign-up / sign-in while zero admins exist; inert afterwards.
BOOTSTRAP_ADMIN_EMAIL: ${BOOTSTRAP_ADMIN_EMAIL:-}
EMAIL_ENABLED: ${EMAIL_ENABLED:-false}
# BUNYIP-603: verifies the mailer bounce/complaint feedback webhook's
# X-Webhook-Signature. Unlike compose.yml's _FILE indirection, this is
# the plain dev .env fallback .env.example documents (BUNYIP-777).
MAILER_WEBHOOK_SECRET: ${MAILER_WEBHOOK_SECRET:-}
# Bunyip IS the OIDC issuer; Ed25519 keys mounted from ./secrets/oidc (volumes).
OIDC_ISSUER: ${OIDC_ISSUER:-http://localhost:4401}
OIDC_JWT_PRIVATE_KEY_PATH: /run/secrets/oidc/dev-2026.pem
OIDC_JWT_ACTIVE_KID: ${OIDC_JWT_ACTIVE_KID:-dev-2026}
OIDC_JWT_PUBLIC_KEYS_DIR: /run/secrets/oidc
# Optional Forgejo token to fetch the dunite git dep on the first build.
DUNITE_GIT_TOKEN: ${DUNITE_GIT_TOKEN:-}
# ── Distribution proxy (downloads + OCI registry) ─────────────────────
# Both verticals stay disabled until FORGEJO_BASE_URL + FORGEJO_API_TOKEN
# are set in .env. Token scopes: see docs/oci-registry-verification.md.
FORGEJO_BASE_URL: ${FORGEJO_BASE_URL:-}
FORGEJO_API_TOKEN: ${FORGEJO_API_TOKEN:-}
DOWNLOAD_CACHE_DIR: /var/cache/bunyip-downloads
OCI_REGISTRY_ENABLED: ${OCI_REGISTRY_ENABLED:-false}
# Container-internal listener port (fixed). BUNYIP_OCI_PORT changes only
# the host side of the port mapping below.
OCI_REGISTRY_PORT: "18081"
# What docker on the HOST sees: the advertised service name and token
# realm track BUNYIP_OCI_PORT, so overriding the published port keeps
# docker login working with no extra configuration.
OCI_REGISTRY_SERVICE: ${OCI_REGISTRY_SERVICE:-localhost:${BUNYIP_OCI_PORT:-18081}}
OCI_REGISTRY_REALM: ${OCI_REGISTRY_REALM:-http://localhost:${BUNYIP_OCI_PORT:-18081}/auth/token}
OCI_BLOB_CACHE_DIR: /var/cache/bunyip-oci
# Distribution limits + cache TTLs (BUNYIP-42). Defaults mirror
# crates/bunyip-domain/src/config.rs so `docker compose config` shows the
# effective value; override any of them in .env to exercise enforcement.
DOWNLOAD_CONCURRENCY_PER_USER: ${DOWNLOAD_CONCURRENCY_PER_USER:-2}
DOWNLOAD_DAILY_LIMIT_PER_USER: ${DOWNLOAD_DAILY_LIMIT_PER_USER:-50}
FORGEJO_RELEASE_CACHE_TTL_SECS: ${FORGEJO_RELEASE_CACHE_TTL_SECS:-300}
OCI_CONCURRENT_MANIFESTS_PER_USER: ${OCI_CONCURRENT_MANIFESTS_PER_USER:-2}
OCI_PULLS_PER_USER_PER_DAY: ${OCI_PULLS_PER_USER_PER_DAY:-50}
OCI_MANIFEST_CACHE_TTL_SECS: ${OCI_MANIFEST_CACHE_TTL_SECS:-300}
OCI_TOKEN_TTL_SECS: ${OCI_TOKEN_TTL_SECS:-900}
volumes:
- .:/app
- cargo-target:/app/target
# OIDC signing keys live in their own subdir (matches compose.yml; keeps
# any production secret value files in ./secrets/ out of the container).
- ./secrets/oidc:/run/secrets/oidc:ro
- download-cache:/var/cache/bunyip-downloads
- oci-cache:/var/cache/bunyip-oci
ports:
- "${BUNYIP_API_PORT:-4401}:4401"
- "${BUNYIP_OCI_PORT:-18081}:18081"
depends_on:
postgres:
condition: service_healthy
networks:
- private
# Axum SSR frontend (bunyip-web), the browser-facing BFF. Talks to api over the
# internal network. Source bind-mounted; cargo-watch rebuilds, Tailwind watches.
web:
build:
context: .
dockerfile: bunyip-web/Dockerfile
args:
HOST_UID: ${HOST_UID:-1000}
HOST_GID: ${HOST_GID:-1000}
CARGO_BUILD_JOBS: ${CARGO_BUILD_JOBS:-default}
user: "${HOST_UID:-1000}:${HOST_GID:-1000}"
container_name: dev-bunyip-web-${USER}
working_dir: /app
restart: unless-stopped
environment:
BUNYIP_BIND_ADDR: 0.0.0.0:4400
BUNYIP_API_URL: ${BUNYIP_API_URL:-http://api:4401}
# BUNYIP-192 / BUNYIP-510: browser-facing origin of bunyip-api (SSE +
# the prefilled Stripe webhook URL). Loopback IS the public URL in dev.
BUNYIP_API_PUBLIC_ORIGIN: ${BUNYIP_API_PUBLIC_ORIGIN:-http://localhost:4401}
BUNYIP_APP_DOMAIN: ${BUNYIP_APP_DOMAIN:-localhost}
BUNYIP_COMMUNITY_URL: ${BUNYIP_COMMUNITY_URL:-}
# BUNYIP-409: trust the ingress (Traefik on dev-sso) so bunyip-web reads
# the end-user IP from X-Forwarded-For and forwards it to bunyip-api.
# RFC1918 ranges; no effect on plain localhost dev (the browser sends no
# XFF, so nothing is forwarded).
TRUSTED_PROXY_CIDR: ${WEB_TRUSTED_PROXY_CIDR:-172.16.0.0/12,10.0.0.0/8,192.168.0.0/16}
RUST_LOG: ${RUST_LOG:-info}
volumes:
- .:/app
- cargo-target:/app/target
- web-node-modules:/app/bunyip-web/node_modules
ports:
- "${BUNYIP_WEB_PORT:-4400}:4400"
depends_on:
- api
networks:
- private
volumes:
postgres-data:
name: dev-bunyip-postgres-${USER}
cargo-target:
name: dev-bunyip-cargo-target-${USER}
web-node-modules:
name: dev-bunyip-web-node-modules-${USER}
download-cache:
name: dev-bunyip-download-cache-${USER}
oci-cache:
name: dev-bunyip-oci-cache-${USER}
networks:
# Declared external so compose attaches to the per-developer network the
# `just dev*` recipes pre-create (docker network create) rather than trying to
# own it. Without this, compose expects its own `com.docker.compose.network`
# label on the pre-created network and aborts: "incorrect label ... set to ''".
private:
external: true
name: dev-bunyip-private-${USER}