initial
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# ======================================================================
|
||||
# mycoolmusicapp — combined env for docker compose (dev).
|
||||
# Copy to .env: cp .env.example .env (or: make env)
|
||||
# Compose injects this into api, worker and webui. Never commit real .env.
|
||||
# Per-repo .env.example files still exist for running a service standalone.
|
||||
# ======================================================================
|
||||
|
||||
# ---- Postgres (db service) -------------------------------------------
|
||||
POSTGRES_USER=mcma
|
||||
POSTGRES_PASSWORD=mcma
|
||||
POSTGRES_DB=mcma
|
||||
POSTGRES_PORT=5432
|
||||
REDIS_PORT=6379
|
||||
|
||||
# ---- Backend (api + worker) ------------------------------------------
|
||||
ENVIRONMENT=dev # dev | test | prod
|
||||
LOG_LEVEL=INFO
|
||||
LOG_JSON=false # true in prod
|
||||
|
||||
# DATABASE_URL / REDIS_URL are overridden in compose to point at the db/redis
|
||||
# services. These localhost values are the fallback for host-run processes.
|
||||
DATABASE_URL=postgresql+asyncpg://mcma:mcma@localhost:5432/mcma
|
||||
DB_ECHO=false
|
||||
REDIS_URL=redis://localhost:6379/0
|
||||
|
||||
# auth — GENERATE a strong secret for prod: `openssl rand -hex 32`
|
||||
JWT_SECRET=change-me-in-prod
|
||||
ACCESS_TOKEN_TTL_SECONDS=900
|
||||
REFRESH_TOKEN_TTL_SECONDS=2592000
|
||||
|
||||
# media / storage (paths inside the container)
|
||||
MEDIA_PATH=/data/media
|
||||
TRANSCODE_CACHE_PATH=/data/transcode-cache
|
||||
MAX_PARALLEL_DOWNLOADS=2
|
||||
|
||||
# external services (all optional — backend degrades gracefully if unset)
|
||||
# ML_SERVICE_URL=http://ml:9000
|
||||
# ACOUSTID_API_KEY=
|
||||
MUSICBRAINZ_USER_AGENT=mcma-backend/0.1.0 ( https://github.com/your/repo )
|
||||
# YOUTUBE_COOKIES_PATH=/data/cookies.txt
|
||||
|
||||
# ---- Frontend (webui) ------------------------------------------------
|
||||
# Served same-origin behind nginx, so the default '/api/v1' just works.
|
||||
PUBLIC_API_BASE_URL=/api/v1
|
||||
@@ -0,0 +1,4 @@
|
||||
.env
|
||||
*.zip
|
||||
plans/
|
||||
modern-sk/
|
||||
@@ -0,0 +1,6 @@
|
||||
[submodule "mcma-backend"]
|
||||
path = mcma-backend
|
||||
url = ssh://git@git.ollyhearn.ru:49239/olly/mcma-backend.git
|
||||
[submodule "mcma-webui"]
|
||||
path = mcma-webui
|
||||
url = ssh://git@git.ollyhearn.ru:49239/olly/mcma-webui.git
|
||||
@@ -0,0 +1,105 @@
|
||||
# mycoolmusicapp — dev workflow shortcuts.
|
||||
# `make` or `make help` lists targets.
|
||||
|
||||
COMPOSE := docker compose
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
.PHONY: help env up build rebuild down stop restart ps logs logs-api logs-webui \
|
||||
sh-api sh-webui db-shell redis-cli migrate makemigration downgrade \
|
||||
test test-api test-webui lint fmt clean prune \
|
||||
prod-build prod-build-api prod-build-webui
|
||||
|
||||
help: ## Show this help
|
||||
@grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
|
||||
| awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
env: ## Create .env from .env.example (no overwrite)
|
||||
@test -f .env || cp .env.example .env && echo ".env ready"
|
||||
|
||||
## ---- lifecycle -------------------------------------------------------
|
||||
up: env ## Build (if needed) + start the full dev stack
|
||||
$(COMPOSE) up --build
|
||||
|
||||
build: ## Build all images
|
||||
$(COMPOSE) build
|
||||
|
||||
rebuild: ## Rebuild images with no cache
|
||||
$(COMPOSE) build --no-cache
|
||||
|
||||
down: ## Stop and remove containers
|
||||
$(COMPOSE) down
|
||||
|
||||
stop: ## Stop containers (keep them)
|
||||
$(COMPOSE) stop
|
||||
|
||||
restart: ## Restart all services
|
||||
$(COMPOSE) restart
|
||||
|
||||
ps: ## Show container status
|
||||
$(COMPOSE) ps
|
||||
|
||||
## ---- logs ------------------------------------------------------------
|
||||
logs: ## Tail logs (all services)
|
||||
$(COMPOSE) logs -f --tail=100
|
||||
|
||||
logs-api: ## Tail api logs
|
||||
$(COMPOSE) logs -f --tail=100 api
|
||||
|
||||
logs-webui: ## Tail webui logs
|
||||
$(COMPOSE) logs -f --tail=100 webui
|
||||
|
||||
## ---- shells ----------------------------------------------------------
|
||||
sh-api: ## Shell into the api container
|
||||
$(COMPOSE) exec api bash
|
||||
|
||||
sh-webui: ## Shell into the webui container
|
||||
$(COMPOSE) exec webui sh
|
||||
|
||||
db-shell: ## psql into the database
|
||||
$(COMPOSE) exec db psql -U $${POSTGRES_USER:-mcma} -d $${POSTGRES_DB:-mcma}
|
||||
|
||||
redis-cli: ## redis-cli into redis
|
||||
$(COMPOSE) exec redis redis-cli
|
||||
|
||||
## ---- database migrations (alembic) -----------------------------------
|
||||
migrate: ## Apply latest migrations
|
||||
$(COMPOSE) exec api alembic upgrade head
|
||||
|
||||
makemigration: ## Autogenerate a migration: make makemigration m="msg"
|
||||
$(COMPOSE) exec api alembic revision --autogenerate -m "$(m)"
|
||||
|
||||
downgrade: ## Roll back one migration
|
||||
$(COMPOSE) exec api alembic downgrade -1
|
||||
|
||||
## ---- quality ---------------------------------------------------------
|
||||
test: test-api test-webui ## Run all tests
|
||||
|
||||
test-api: ## Run backend tests
|
||||
$(COMPOSE) exec api pytest
|
||||
|
||||
test-webui: ## Run frontend tests
|
||||
$(COMPOSE) exec webui npm test
|
||||
|
||||
lint: ## Lint backend + frontend
|
||||
$(COMPOSE) exec api ruff check .
|
||||
$(COMPOSE) exec webui npm run lint
|
||||
|
||||
fmt: ## Format backend + frontend
|
||||
$(COMPOSE) exec api ruff format .
|
||||
$(COMPOSE) exec webui npm run format
|
||||
|
||||
## ---- cleanup ---------------------------------------------------------
|
||||
clean: ## Stop + remove containers AND volumes (DESTROYS db data)
|
||||
$(COMPOSE) down -v
|
||||
|
||||
prune: ## Docker system prune (dangling images/build cache)
|
||||
docker system prune -f
|
||||
|
||||
## ---- production image builds (no compose yet) ------------------------
|
||||
prod-build: prod-build-api prod-build-webui ## Build both prod images
|
||||
|
||||
prod-build-api: ## Build the backend prod image
|
||||
docker build -f mcma-backend/dockerfiles/Dockerfile.prod -t mcma-backend:prod ./mcma-backend
|
||||
|
||||
prod-build-webui: ## Build the webui prod image
|
||||
docker build -f mcma-webui/dockerfiles/Dockerfile.prod -t mcma-webui:prod ./mcma-webui
|
||||
@@ -0,0 +1,120 @@
|
||||
# DEV stack for mycoolmusicapp — one entrypoint at http://localhost:80.
|
||||
#
|
||||
# make up # build + start everything (db, redis, api, worker, webui, nginx)
|
||||
# make logs # tail logs
|
||||
# make down # stop
|
||||
#
|
||||
# Source is bind-mounted into api/worker/webui, so edits hot-reload without a
|
||||
# rebuild. PROD has NO compose yet — services there are built straight from
|
||||
# their dockerfiles/Dockerfile.prod (a separate prod compose lands later).
|
||||
#
|
||||
# Env: copy .env.example -> .env at the repo root (single combined file).
|
||||
|
||||
services:
|
||||
# -- backing services -----------------------------------------------------
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-mcma}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mcma}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-mcma}
|
||||
ports:
|
||||
- "${POSTGRES_PORT:-5432}:5432" # exposed so host-run tests can reach it
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-mcma}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
command: redis-server --save 60 1 --loglevel warning
|
||||
ports:
|
||||
- "${REDIS_PORT:-6379}:6379"
|
||||
volumes:
|
||||
- redisdata:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
|
||||
# -- application services -------------------------------------------------
|
||||
api:
|
||||
build:
|
||||
context: ./mcma-backend
|
||||
dockerfile: dockerfiles/Dockerfile.dev
|
||||
env_file: .env
|
||||
environment:
|
||||
# Service-name URLs override the localhost values from .env.
|
||||
DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-mcma}:${POSTGRES_PASSWORD:-mcma}@db:5432/${POSTGRES_DB:-mcma}
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
volumes:
|
||||
- ./mcma-backend:/app # live source (hot reload)
|
||||
- /app/.venv # keep the image's venv, don't shadow it
|
||||
- media:/data/media
|
||||
- transcode_cache:/data/transcode-cache
|
||||
ports:
|
||||
- "8000:8000" # direct access for debugging / docs
|
||||
depends_on:
|
||||
db: { condition: service_healthy }
|
||||
redis: { condition: service_healthy }
|
||||
restart: unless-stopped
|
||||
|
||||
worker:
|
||||
build:
|
||||
context: ./mcma-backend
|
||||
dockerfile: dockerfiles/Dockerfile.dev
|
||||
command: arq app.workers.arq_worker.WorkerSettings
|
||||
env_file: .env
|
||||
environment:
|
||||
DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-mcma}:${POSTGRES_PASSWORD:-mcma}@db:5432/${POSTGRES_DB:-mcma}
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
volumes:
|
||||
- ./mcma-backend:/app
|
||||
- /app/.venv
|
||||
- media:/data/media
|
||||
- transcode_cache:/data/transcode-cache
|
||||
depends_on:
|
||||
db: { condition: service_healthy }
|
||||
redis: { condition: service_healthy }
|
||||
restart: unless-stopped
|
||||
|
||||
webui:
|
||||
build:
|
||||
context: ./mcma-webui
|
||||
dockerfile: dockerfiles/Dockerfile.dev
|
||||
env_file: .env
|
||||
environment:
|
||||
RSBUILD_HOST: 0.0.0.0
|
||||
RSBUILD_PORT: "3000"
|
||||
# Browser reaches HMR through nginx on :80, not the container's :3000.
|
||||
RSBUILD_HMR_CLIENT_PORT: "80"
|
||||
volumes:
|
||||
- ./mcma-webui:/app
|
||||
- /app/node_modules # keep the image's install, don't shadow it
|
||||
expose:
|
||||
- "3000"
|
||||
restart: unless-stopped
|
||||
|
||||
# -- reverse proxy: single entrypoint at localhost:80 ---------------------
|
||||
nginx:
|
||||
image: nginx:1.27-alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
depends_on:
|
||||
- api
|
||||
- webui
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
redisdata:
|
||||
media:
|
||||
transcode_cache:
|
||||
Submodule
+1
Submodule mcma-backend added at 87b48e941e
Submodule
+1
Submodule mcma-webui added at 37c1a5944a
+60
@@ -0,0 +1,60 @@
|
||||
# DEV reverse proxy — single entrypoint at http://localhost:80.
|
||||
# / -> webui rsbuild dev server (with HMR websocket)
|
||||
# /rsbuild-hmr -> webui HMR websocket channel
|
||||
# /api/... -> backend API
|
||||
# /health... -> backend health/readiness probes
|
||||
#
|
||||
# This is the DEV topology only. Production gets its own proxy in the future
|
||||
# prod compose (the webui PROD image already self-serves static assets).
|
||||
|
||||
# WebSocket upgrade plumbing.
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
upstream webui_dev { server webui:3000; }
|
||||
upstream api_dev { server api:8000; }
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# Large media uploads — don't choke on big files.
|
||||
client_max_body_size 0;
|
||||
|
||||
# ---- backend -------------------------------------------------------
|
||||
location /api/ {
|
||||
proxy_pass http://api_dev;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_http_version 1.1;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location /health {
|
||||
proxy_pass http://api_dev;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
# ---- rsbuild HMR websocket ----------------------------------------
|
||||
location /rsbuild-hmr {
|
||||
proxy_pass http://webui_dev;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
# ---- webui dev server (catch-all) ---------------------------------
|
||||
location / {
|
||||
proxy_pass http://webui_dev;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user