In Dokploy, services with a domain join the shared dokploy-network, where another project also has an `api`. nginx proxied /api to `api:3000`, so Docker DNS returned both containers and half of the requests went to the other app: 404 "Cannot POST /api/auth/token" on sign-in and "sign-in not configured" when /api/auth/config was answered by it. Services now get task-stream-* aliases on the project network and nginx and the API use them (task-stream-api, -postgres, -mongo, -redis). The API's OPENAPI_FILE is empty in the container; docs 07 explain the aliases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
3.4 KiB
YAML
107 lines
3.4 KiB
YAML
# TaskStream: web + API + infrastructure — production definition (Dokploy deploys this file).
|
|
# No ports are published here: services only talk over the compose network, and the web is
|
|
# exposed through the platform's proxy (Dokploy domain → service `web`, port 80).
|
|
#
|
|
# Services talk to each other by unique aliases (task-stream-*), never by the bare service
|
|
# name: on a shared network (Dokploy's dokploy-network) other projects also have an `api`,
|
|
# `postgres` or `redis`, and Docker DNS would hand out theirs too.
|
|
#
|
|
# Locally, `docker compose` also loads docker-compose.override.yml, which publishes the ports:
|
|
# docker compose up -d --build → everything: web on http://localhost:8080
|
|
# docker compose up -d postgres mongo redis → only infrastructure (then `npx nx serve api` / `npx nx serve web`)
|
|
#
|
|
# Building needs access to Pireon's Nexus (@pi/ui): set NEXUS_TOKEN in the environment or in .env
|
|
# (Dokploy: Environment tab). It reaches the build as a secret and never lands in an image layer.
|
|
services:
|
|
web:
|
|
build:
|
|
context: .
|
|
target: web
|
|
secrets: [nexus_token]
|
|
image: task-stream-web
|
|
expose: ['80']
|
|
networks: [default]
|
|
depends_on:
|
|
api: { condition: service_healthy }
|
|
restart: unless-stopped
|
|
|
|
api:
|
|
build:
|
|
context: .
|
|
target: api
|
|
secrets: [nexus_token]
|
|
image: task-stream-api
|
|
expose: ['3000']
|
|
networks:
|
|
default:
|
|
aliases: [task-stream-api]
|
|
environment:
|
|
POSTGRES_URL: postgres://taskstream:taskstream@task-stream-postgres:5432/taskstream
|
|
# No migrations yet: TypeORM creates the event store and lookup tables.
|
|
POSTGRES_SYNCHRONIZE: 'true'
|
|
MONGO_URL: mongodb://task-stream-mongo:27017/taskstream_read
|
|
REDIS_URL: redis://task-stream-redis:6379
|
|
EVENT_STREAM_KEY: task-stream:events
|
|
EVENTS_BRIDGE_ENABLED: 'true'
|
|
PIREON_BASE_URL: https://oauth.pireon.dev
|
|
PIREON_WEBHOOK_SECRET: ${PIREON_WEBHOOK_SECRET:-}
|
|
PIREON_CLIENT_ID: ${PIREON_CLIENT_ID:-}
|
|
PIREON_CLIENT_SECRET: ${PIREON_CLIENT_SECRET:-}
|
|
GRAPHQL_PLAYGROUND: 'true'
|
|
# The SDL / OpenAPI files are only useful in development (codegen); the
|
|
# document is still served at /api/docs-json.
|
|
GRAPHQL_SCHEMA_FILE: ''
|
|
OPENAPI_FILE: ''
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
mongo: { condition: service_healthy }
|
|
redis: { condition: service_healthy }
|
|
restart: unless-stopped
|
|
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
networks:
|
|
default:
|
|
aliases: [task-stream-postgres]
|
|
environment:
|
|
POSTGRES_USER: taskstream
|
|
POSTGRES_PASSWORD: taskstream
|
|
POSTGRES_DB: taskstream
|
|
volumes: [postgres-data:/var/lib/postgresql/data]
|
|
healthcheck:
|
|
test: ['CMD-SHELL', 'pg_isready -U taskstream']
|
|
interval: 5s
|
|
retries: 10
|
|
|
|
mongo:
|
|
image: mongo:8
|
|
networks:
|
|
default:
|
|
aliases: [task-stream-mongo]
|
|
volumes: [mongo-data:/data/db]
|
|
healthcheck:
|
|
test: ['CMD', 'mongosh', '--quiet', '--eval', 'db.adminCommand("ping")']
|
|
interval: 5s
|
|
retries: 10
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
networks:
|
|
default:
|
|
aliases: [task-stream-redis]
|
|
command: ['redis-server', '--appendonly', 'yes']
|
|
volumes: [redis-data:/data]
|
|
healthcheck:
|
|
test: ['CMD', 'redis-cli', 'ping']
|
|
interval: 5s
|
|
retries: 10
|
|
|
|
volumes:
|
|
postgres-data:
|
|
mongo-data:
|
|
redis-data:
|
|
|
|
secrets:
|
|
nexus_token:
|
|
environment: NEXUS_TOKEN
|