compose.yml
Rama main · réplica de lectura del repositorio original.
name: eve-space
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-eve_space}
POSTGRES_USER: ${POSTGRES_USER:-eve_space}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in .env}
ports:
- '${POSTGRES_PORT:-5432}:5432'
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}']
interval: 10m
timeout: 3s
retries: 3
start_period: 30s
start_interval: 2s
queue-redis:
image: redis:7.4.7-alpine
command:
[
'redis-server',
'--appendonly',
'yes',
'--appendfsync',
'always',
'--maxmemory',
'${QUEUE_REDIS_MAXMEMORY:-512mb}',
'--maxmemory-policy',
'noeviction',
]
volumes:
- queue_redis_data:/data
ports:
- '${QUEUE_REDIS_PORT:-6379}:6379'
healthcheck:
test:
[
'CMD-SHELL',
'redis-cli ping | grep -qx PONG && redis-cli --raw config get maxmemory-policy | grep -qx noeviction && maxmemory=$$(redis-cli --raw config get maxmemory | grep -E ''^[0-9]+$$'') && used=$$(redis-cli --raw info memory | grep ''^used_memory:'' | cut -d: -f2) && test "$$maxmemory" -gt 0 && test "$$used" -lt "$$((maxmemory * 90 / 100))"',
]
interval: 10m
timeout: 3s
retries: 3
start_period: 30s
start_interval: 2s
cache-redis:
image: redis:7.4.7-alpine
command:
[
'redis-server',
'--appendonly',
'no',
'--save',
'',
'--maxmemory',
'${CACHE_REDIS_MAXMEMORY:-256mb}',
'--maxmemory-policy',
'allkeys-lfu',
]
ports:
- '${CACHE_REDIS_PORT:-6380}:6379'
healthcheck:
test:
[
'CMD-SHELL',
'redis-cli ping | grep -qx PONG && redis-cli --raw config get maxmemory-policy | grep -qx allkeys-lfu && maxmemory=$$(redis-cli --raw config get maxmemory | grep -E ''^[0-9]+$$'') && used=$$(redis-cli --raw info memory | grep ''^used_memory:'' | cut -d: -f2) && test "$$maxmemory" -gt 0 && test "$$used" -lt "$$((maxmemory * 90 / 100))"',
]
interval: 10m
timeout: 3s
retries: 3
start_period: 30s
start_interval: 2s
api:
build:
context: .
dockerfile: api/Dockerfile
stop_grace_period: 40s
# Pool, refresh, cache, and heartbeat tuning is documented in `.env.example` and read by
# `env.ts` in both processes. The explicit `environment` map below still wins, so topology
# stays container-relative.
env_file:
- path: .env
required: false
environment:
NODE_ENV: production
PORT: 8787
DATABASE_URL: postgres://${POSTGRES_USER:-eve_space}@postgres:5432/${POSTGRES_DB:-eve_space}
PGPASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in .env}
WEB_ORIGIN: ${WEB_ORIGIN:-http://localhost:3000}
EVE_CLIENT_ID: ${EVE_CLIENT_ID:-}
EVE_CLIENT_SECRET: ${EVE_CLIENT_SECRET:-}
EVE_CALLBACK_URL: ${EVE_CALLBACK_URL:-http://localhost:8788/auth/eve/callback}
EVE_SCOPES: ${EVE_SCOPES:-esi-assets.read_assets.v1 esi-wallet.read_character_wallet.v1 esi-markets.read_character_orders.v1 esi-markets.structure_markets.v1 esi-contracts.read_character_contracts.v1 esi-location.read_location.v1 esi-location.read_ship_type.v1 esi-skills.read_skills.v1 esi-skills.read_skillqueue.v1 esi-clones.read_clones.v1 esi-clones.read_implants.v1 esi-mail.read_mail.v1 esi-mail.organize_mail.v1 esi-mail.send_mail.v1 esi-search.search_structures.v1 esi-characters.read_contacts.v1 esi-characters.read_corporation_roles.v1 esi-corporations.read_corporation_membership.v1 esi-characters.read_freelance_jobs.v1 esi-corporations.read_freelance_jobs.v1 esi-corporations.read_projects.v1 esi.activity.char:read}
ESI_USER_AGENT: ${ESI_USER_AGENT:-EveSpace/0.1 (+https://github.com/mskry/eve-space) @evespace/esi-client/3.1.0}
TOKEN_ENCRYPTION_KEY: ${TOKEN_ENCRYPTION_KEY:-}
ADMIN_SETUP_SECRET: ${ADMIN_SETUP_SECRET:-}
QUEUE_REDIS_URL: redis://queue-redis:6379
CACHE_REDIS_URL: redis://cache-redis:6379
ports:
- '8788:8787'
depends_on:
postgres:
condition: service_healthy
queue-redis:
condition: service_healthy
cache-redis:
condition: service_started
healthcheck:
test:
[
'CMD',
'node',
'-e',
"fetch('http://localhost:8787/health').then(r => { if (!r.ok) process.exit(1) })",
]
interval: 10m
timeout: 3s
retries: 3
start_period: 30s
start_interval: 2s
worker:
build:
context: .
dockerfile: api/Dockerfile
init: true
entrypoint: ['node', 'dist/worker.js']
stop_grace_period: 40s
env_file:
- path: .env
required: false
environment:
NODE_ENV: production
DATABASE_URL: postgres://${POSTGRES_USER:-eve_space}@postgres:5432/${POSTGRES_DB:-eve_space}
PGPASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in .env}
QUEUE_REDIS_URL: redis://queue-redis:6379
CACHE_REDIS_URL: redis://cache-redis:6379
EVE_SCOPES: ${EVE_SCOPES:-esi-assets.read_assets.v1 esi-wallet.read_character_wallet.v1 esi-markets.read_character_orders.v1 esi-markets.structure_markets.v1 esi-contracts.read_character_contracts.v1 esi-location.read_location.v1 esi-location.read_ship_type.v1 esi-skills.read_skills.v1 esi-skills.read_skillqueue.v1 esi-clones.read_clones.v1 esi-clones.read_implants.v1 esi-mail.read_mail.v1 esi-mail.organize_mail.v1 esi-mail.send_mail.v1 esi-search.search_structures.v1 esi-characters.read_contacts.v1 esi-characters.read_corporation_roles.v1 esi-corporations.read_corporation_membership.v1 esi-characters.read_freelance_jobs.v1 esi-corporations.read_freelance_jobs.v1 esi-corporations.read_projects.v1 esi.activity.char:read}
QUEUE_PLANNER_SCHEDULE: ${QUEUE_PLANNER_SCHEDULE:-*/15 * * * *}
QUEUE_PLANNER_SCHEDULE_OFFSET_MS: ${QUEUE_PLANNER_SCHEDULE_OFFSET_MS:-}
QUEUE_PLANNER_INITIAL_DELAY_MAX_MS: ${QUEUE_PLANNER_INITIAL_DELAY_MAX_MS:-60000}
depends_on:
api:
condition: service_healthy
queue-redis:
condition: service_healthy
cache-redis:
condition: service_started
healthcheck:
test: ['CMD', 'node', 'dist/worker/health.js']
interval: 10m
timeout: 3s
retries: 3
start_period: 30s
start_interval: 2s
volumes:
postgres_data:
queue_redis_data: