Repository navigation
Expand file tree
/
Copy pathdocker-compose.dev.yml
More file actions
149 lines (143 loc) · 5.98 KB
/
Copy pathdocker-compose.dev.yml
File metadata and controls
149 lines (143 loc) · 5.98 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
# Full-stack local development stack (Savitura/Savitools#250).
#
# Two compose files exist, on purpose:
# docker-compose.yml -> infrastructure only (Postgres + Redis).
# This is what "Getting Started -> 3" in the README
# starts, for people running the apps with
# `npm run dev` on the host.
# docker-compose.dev.yml -> infrastructure AND the api + web containers, for
# people who want the whole stack in Docker
# (`make dev`).
#
# Both read the ROOT `.env` (Compose auto-loads it), created with
# `cp .env.example .env`. Per-app `.env` files are optional overrides only.
#
# Validate without starting anything:
# docker compose -f docker-compose.dev.yml config -q
name: savitools-dev
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
POSTGRES_DB: ${POSTGRES_DB:-savitools}
ports:
# Bound to loopback: the dev database should not be reachable from the
# rest of the network. Override POSTGRES_PORT when 5432 is taken.
- '127.0.0.1:${POSTGRES_PORT:-5432}:5432'
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-savitools}"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
restart: unless-stopped
ports:
# Loopback only - see the postgres note above.
- '127.0.0.1:${REDIS_PORT:-6379}:6379'
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
api:
image: node:20-alpine
working_dir: /app
volumes:
- ./:/app
# Cache dependencies in named volumes. The bind mount above would
# otherwise hide the host's node_modules, forcing a full re-install on
# every container start; with these the install is a no-op after the
# first run.
- node_modules:/app/node_modules
- api_node_modules:/app/apps/api/node_modules
- web_node_modules:/app/apps/web/node_modules
ports:
- '${API_PORT:-3001}:${API_PORT:-3001}'
environment:
NODE_ENV: development
# Inside the compose network the hosts are service names, not localhost,
# so these deliberately override whatever apps/api/.env says.
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-password}@postgres:5432/${POSTGRES_DB:-savitools}
REDIS_URL: redis://redis:6379
API_PORT: ${API_PORT:-3001}
API_PREFIX: ${API_PREFIX:-api}
WEB_ORIGIN: ${WEB_ORIGIN:-http://localhost:3000}
STELLAR_NETWORK: ${STELLAR_NETWORK:-testnet}
STELLAR_HORIZON_URL: ${STELLAR_HORIZON_URL:-https://horizon-testnet.stellar.org}
STELLAR_RPC_URL: ${STELLAR_RPC_URL:-https://soroban-rpc-testnet.stellar.org}
JWT_SECRET: ${JWT_SECRET:-dev-only-jwt-secret-do-not-use-in-production-0000}
ENCRYPTION_SECRET: ${ENCRYPTION_SECRET:-dev-only-encryption-secret-do-not-use-in-production}
# ContractsService calls getOrThrow + Keypair.fromSecret while the module
# is constructed, so the API cannot boot without a *syntactically valid*
# Stellar secret key. Generate a throwaway testnet keypair - see the
# "Contracts deployer key" variable in the README. Funding it is only
# needed to actually deploy a contract.
DEPLOYER_SECRET_KEY: ${DEPLOYER_SECRET_KEY:?set DEPLOYER_SECRET_KEY in .env - see README Contracts deployer key}
# Optional per-app overrides. Compose >= 2.24; absence of the file is not
# an error, so a fresh clone boots from the values above alone.
env_file:
- path: apps/api/.env
required: false
command: sh -c "npm install --no-audit --no-fund --prefer-offline && npm run dev -w @savitools/api"
# The API releases the monitor leader lease on SIGTERM (see
# enableGracefulShutdown in apps/api/src/main.ts). Docker's default 10 s
# grace period is shorter than MONITOR_LEADER_LEASE_MS (30 s by default), so
# a stop would SIGKILL the process mid-release and the next replica would
# wait out the full lease before taking over.
stop_grace_period: 45s
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "scripts/docker-healthcheck.mjs"]
interval: 5s
timeout: 5s
retries: 24
start_period: 90s
web:
image: node:20-alpine
working_dir: /app
volumes:
- ./:/app
- node_modules:/app/node_modules
- api_node_modules:/app/apps/api/node_modules
- web_node_modules:/app/apps/web/node_modules
ports:
- '${WEB_PORT:-3000}:${WEB_PORT:-3000}'
environment:
NODE_ENV: development
# Read by next dev; also the port published above.
PORT: ${WEB_PORT:-3000}
# The browser resolves this, not the container, so localhost is correct
# even though the API lives in a sibling container.
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001/api}
NEXT_PUBLIC_STELLAR_NETWORK: ${STELLAR_NETWORK:-testnet}
WEB_ORIGIN: ${WEB_ORIGIN:-http://localhost:3000}
env_file:
- path: apps/web/.env
required: false
command: sh -c "npm install --no-audit --no-fund --prefer-offline && npm run dev -w @savitools/web"
# Wait for the API to actually answer, not merely to have been created -
# otherwise the first requests race the API's boot.
depends_on:
api:
condition: service_healthy
volumes:
postgres_data:
redis_data:
node_modules:
api_node_modules:
web_node_modules:
# NOTE: if you change API_PORT/api prefix here, keep NEXT_PUBLIC_API_URL in
# step with it - the web app falls back to http://localhost:3001/api when the
# variable is unset (apps/web/src/lib/api.ts).