Files
clicktrack/docker-compose.yml
AJ Avezzano 5b772655c6 feat: initial scaffold for ClickTrack monorepo
Full self-hosted click track generator for cover bands.

Core technical pieces implemented:
- CTP (Click Track Protocol) TypeScript schema, Zod validator, and WAV
  renderer (44.1 kHz, 16-bit PCM, accented downbeats, ramp sections)
- MusicBrainz API client with 1 req/s rate limiting
- PostgreSQL schema (songs, tempo_maps, registry_sync_log) with triggers
- Git registry sync logic (clone/pull → validate CTP → upsert DB)
- Next.js 14 App Router: search page, track page, API routes
  (/api/songs, /api/tracks, /api/generate)
- UI components: SearchBar, SongResult, TempoMapEditor, ClickTrackPlayer
  (Web Audio API in-browser playback + WAV download)
- Docker Compose stack: app + postgres + redis + nginx + registry-sync
- Multi-stage Dockerfile with standalone Next.js output
- .env.example documenting all configuration variables
- README with setup instructions, CTP format spec, and API reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 11:14:46 -04:00

122 lines
4.0 KiB
YAML

version: "3.9"
# ClickTrack — full self-hosted stack
# Usage: docker compose up -d
# First run: docker compose up -d --build
services:
# ── Next.js application ──────────────────────────────────────────────────────
app:
build:
context: .
dockerfile: docker/Dockerfile
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://clicktrack:${POSTGRES_PASSWORD:-clicktrack}@postgres:5432/clicktrack
REDIS_URL: redis://redis:6379
REGISTRY_REPO: ${REGISTRY_REPO:-}
REGISTRY_BRANCH: ${REGISTRY_BRANCH:-main}
NEXT_PUBLIC_APP_NAME: ${NEXT_PUBLIC_APP_NAME:-ClickTrack}
MUSICBRAINZ_USER_AGENT: ${MUSICBRAINZ_USER_AGENT:-ClickTrack/0.1 (self-hosted)}
NODE_ENV: production
expose:
- "3000"
networks:
- internal
# ── PostgreSQL 16 ─────────────────────────────────────────────────────────────
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: clicktrack
POSTGRES_USER: clicktrack
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-clicktrack}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./docker/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U clicktrack -d clicktrack"]
interval: 5s
timeout: 5s
retries: 10
networks:
- internal
# ── Redis 7 ───────────────────────────────────────────────────────────────────
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --save 60 1 --loglevel warning
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
networks:
- internal
# ── Nginx reverse proxy ───────────────────────────────────────────────────────
nginx:
image: nginx:1.27-alpine
restart: unless-stopped
depends_on:
- app
ports:
- "${HTTP_PORT:-80}:80"
- "${HTTPS_PORT:-443}:443"
volumes:
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro
# Mount TLS certificates here for HTTPS (optional):
# - /etc/letsencrypt:/etc/letsencrypt:ro
networks:
- internal
# ── Registry sync (optional cron container) ───────────────────────────────────
registry-sync:
build:
context: .
dockerfile: docker/Dockerfile
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgres://clicktrack:${POSTGRES_PASSWORD:-clicktrack}@postgres:5432/clicktrack
REDIS_URL: redis://redis:6379
REGISTRY_REPO: ${REGISTRY_REPO:-}
REGISTRY_BRANCH: ${REGISTRY_BRANCH:-main}
NODE_ENV: production
# Run the sync script on a cron schedule inside the container.
# Requires REGISTRY_REPO to be set; the container exits cleanly if not.
command: >
sh -c '
while true; do
node -e "
const { syncRegistry } = require(\"./lib/registry/sync\");
syncRegistry().then(r => console.log(\"Sync:\", JSON.stringify(r))).catch(console.error);
" || true;
sleep ${REGISTRY_SYNC_INTERVAL:-3600};
done
'
profiles:
- registry
networks:
- internal
volumes:
postgres_data:
redis_data:
networks:
internal:
driver: bridge