name: personal-lifecycle-tracker
services:
db:
image: postgres:16-alpine
container_name: personal-lifecycle-tracker-db
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
POSTGRES_DB: ${POSTGRES_DB:-lifecycle}
ports:
- "${POSTGRES_PORT:-5434}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-lifecycle}"]
interval: 5s
timeout: 5s
retries: 5
start_period: 5s
backend:
build:
context: ./backend
dockerfile: Dockerfile
target: base
container_name: personal-lifecycle-tracker-backend
environment:
PORT: 8000
PYTHONUNBUFFERED: "1"
CORS_ORIGINS: "http://localhost:3000,http://localhost:3003,http://localhost:5173,http://127.0.0.1:3000,http://127.0.0.1:3003"
DATABASE_URL: "${DATABASE_URL:-postgresql://postgres:postgres@db:5432/lifecycle}"
APP_ENV: "${APP_ENV:-development}"
APP_VERSION: "${APP_VERSION:-dev-latest}"
OTEL_SERVICE_NAME: "api-backend"
OTEL_EXPORTER_OTLP_ENDPOINT: "${OTEL_EXPORTER_OTLP_ENDPOINT:-}"
OTEL_RESOURCE_ATTRIBUTES: "service.name=api-backend,deployment.environment=${APP_ENV:-development},service.version=${APP_VERSION:-dev-latest}"
ports:
- "${BACKEND_PORT:-8003}:8000"
volumes:
- ./backend:/app
networks:
- default
- observability-net
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:8000/health"]
interval: 5s
timeout: 10s
retries: 8
start_period: 10s
restart: unless-stopped
frontend:
image: personal-lifecycle-tracker-frontend:dev
build:
context: ./frontend
dockerfile: Dockerfile
target: dev
container_name: personal-lifecycle-tracker-frontend
environment:
PORT: 3000
VITE_API_URL: "${VITE_API_URL:-}"
VITE_BACKEND_URL: http://backend:8000
ports:
- "${FRONTEND_PORT:-3003}:3000"
volumes:
- ./frontend:/app
- /app/node_modules
depends_on:
backend:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
restart: unless-stopped
e2e:
build:
context: ./e2e
dockerfile: Dockerfile
container_name: personal-lifecycle-tracker-e2e
network_mode: host
environment:
BASE_URL: "${BASE_URL:-http://127.0.0.1:${FRONTEND_PORT:-3003}}"
BACKEND_URL: "${BACKEND_URL:-http://127.0.0.1:${BACKEND_PORT:-8003}}"
CI: "true"
volumes:
- ./e2e:/e2e
- /e2e/node_modules
depends_on:
frontend:
condition: service_healthy
backend:
condition: service_healthy
profiles: ["test", "e2e"]
volumes:
postgres_data:
networks:
default:
observability-net:
name: ${OBSERVABILITY_NET:-personal-lifecycle-observability-net}
external: true