siftlode/docker-compose.localdev.yml

92 lines
3.3 KiB
YAML
Raw Normal View History

# Self-contained local development stack — Postgres + API + scheduler, all on this machine.
#
# Fully decoupled: its own local database (a Docker volume) and its own scheduler, so there
# is no shared DB and no migration coupling with any other instance. Edit code, rebuild, and
# everything (including the background sync) runs right here.
#
# docker compose -f docker-compose.localdev.yml up -d --build
#
# Browse at http://localhost:8080 — Google login works because the OAuth redirect is
# http://localhost:8080/auth/callback. The API runs `alembic upgrade head` on startup, so it
# applies local migrations to THIS local DB only. Seed the catalog once with a pg_dump from
# another instance if you want real data (see RUNBOOK).
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: ${POSTGRES_USER:-siftlode}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-siftlode}
POSTGRES_DB: ${POSTGRES_DB:-siftlode}
volumes:
- pgdata:/var/lib/postgresql/data
security_opt:
- apparmor:unconfined
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-siftlode} -d ${POSTGRES_DB:-siftlode}"]
interval: 5s
timeout: 5s
retries: 12
restart: unless-stopped
api:
build:
context: .
dockerfile: Dockerfile
args:
APP_VERSION: ${APP_VERSION:-dev}
GIT_SHA: ${GIT_SHA:-unknown}
BUILD_DATE: ${BUILD_DATE:-}
env_file: .env
environment:
# Own local database (overrides whatever DATABASE_URL is in .env).
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-siftlode}:${POSTGRES_PASSWORD:-siftlode}@db:5432/${POSTGRES_DB:-siftlode}
# This instance owns its scheduler now (its own DB, so no double-write concern).
SCHEDULER_ENABLED: "true"
# Download center: the API serves finished files (it does NOT run the worker loop).
DOWNLOAD_ROOT: /downloads
WORKER_ENABLED: "false"
depends_on:
db:
condition: service_healthy
# Harmless on Docker Desktop; needed on some nested/hardened Docker hosts.
security_opt:
- apparmor:unconfined
ports:
- "${APP_PORT:-8080}:8000"
volumes:
# Downloaded media lives on the host so you can inspect the generated Plex tree.
# Gitignored. The worker writes here; the API reads it to serve local downloads.
- ./downloads:/downloads
restart: unless-stopped
# Dedicated download worker: same image, runs the yt-dlp job loop instead of the API.
# It shares the DB (job queue) and the downloads mount with the API.
worker:
build:
context: .
dockerfile: Dockerfile
args:
APP_VERSION: ${APP_VERSION:-dev}
GIT_SHA: ${GIT_SHA:-unknown}
BUILD_DATE: ${BUILD_DATE:-}
command: ["python", "-m", "app.worker"]
env_file: .env
environment:
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-siftlode}:${POSTGRES_PASSWORD:-siftlode}@db:5432/${POSTGRES_DB:-siftlode}
# The worker must not also run the scheduler; the API owns that.
SCHEDULER_ENABLED: "false"
DOWNLOAD_ROOT: /downloads
WORKER_ENABLED: "true"
depends_on:
db:
condition: service_healthy
security_opt:
- apparmor:unconfined
volumes:
- ./downloads:/downloads
restart: unless-stopped
volumes:
pgdata: