services: db: image: postgres:18-alpine environment: POSTGRES_USER: bridzik POSTGRES_PASSWORD: bridzik POSTGRES_DB: bridzik ports: - "5432:5432" volumes: - pgdata:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U bridzik -d bridzik"] interval: 5s timeout: 5s retries: 5 backend: build: . environment: # Async SQLAlchemy URL -> the Postgres service above (asyncpg driver). DATABASE_URL: postgresql+asyncpg://bridzik:bridzik@db:5432/bridzik # Shared secret for the self-hosted /api/admin/* stats endpoints. ADMIN_TOKEN: tajneheslo # Optional: IP -> country for /api/track. Drop a .mmdb file (GeoLite2 or # a DB-IP/IP2Location Lite equivalent) at ./geoip/ -- it's already inside # the ./:/app bind mount below, no extra volume entry needed. Missing # file -> country is just recorded as "" (see api/stats.py:_country_for_ip). GEOIP_DB_PATH: /app/geoip/GeoLite2-Country.mmdb ports: - "5000:5000" volumes: - ./:/app depends_on: db: condition: service_healthy frontend: image: node:22-alpine working_dir: /app environment: # Inside the compose network the backend is reachable as `backend`. VITE_BACKEND_URL: http://backend:5000 volumes: - ./frontend:/app ports: - "5173:5173" command: sh -c "npm install && npm run dev -- --host" depends_on: - backend volumes: pgdata: