diff --git a/.gitignore b/.gitignore index 708dd82..11619ed 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ frontend/coverage/ # Docker Config Volume # =================== config/ +config-dev/ # =================== # Environment & Secrets diff --git a/README.md b/README.md index 22b0bd9..0fa62b1 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,22 @@ set `PUID`/`PGID` (see the commented lines in `docker-compose.yml`) to run the backend as that uid/gid — `/config` is chown'd accordingly on startup so the database and logs end up owned by your host user instead of root. +### Development with Docker + +`docker-compose.dev.yml` runs both halves from source with auto-reload +(uvicorn `--reload`, Vite HMR) — the production `docker-compose.yml` is +untouched: + +```bash +docker compose -f docker-compose.dev.yml up + +# Frontend (proxies /api and /ws): http://localhost:5173 +# Backend API directly: http://localhost:8000 +``` + +Dev data lives in `./config-dev` (separate from the production `./config`); +dependencies are cached in named volumes, so only the first start installs. + ### Manual Installation #### Backend diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..f49ff43 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,48 @@ +# Development compose: source is bind-mounted and both services reload on +# change (uvicorn --reload / vite HMR). Production stays docker-compose.yml. +# +# docker compose -f docker-compose.dev.yml up +# +# Frontend: http://localhost:5173 (proxies /api and /ws to the backend). +# Backend API directly: http://localhost:8000. +# Data/logs live in ./config-dev so dev never touches the production ./config. +# Dependencies are cached in named volumes; the first start installs them. + +services: + backend: + image: python:3.14-slim + container_name: steamselfgifter-dev-backend + working_dir: /app + command: > + bash -c "python -m venv /opt/venv && + /opt/venv/bin/pip install --quiet -e '.[dev]' && + cd src && + /opt/venv/bin/uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload" + volumes: + - ./backend:/app:z + - ./config-dev:/config:z + - backend-venv:/opt/venv + environment: + - ENVIRONMENT=development + - DEBUG=true + ports: + - "8000:8000" + + frontend: + image: node:24-alpine + container_name: steamselfgifter-dev-frontend + working_dir: /app + command: sh -c "npm install --no-audit --no-fund && npm run dev -- --host 0.0.0.0" + volumes: + - ./frontend:/app:z + - frontend-node-modules:/app/node_modules + environment: + - VITE_PROXY_TARGET=http://backend:8000 + ports: + - "5173:5173" + depends_on: + - backend + +volumes: + backend-venv: + frontend-node-modules: diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 252b469..b30e88a 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -2,6 +2,10 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import path from 'path' +// Backend the dev server proxies to; docker-compose.dev.yml points this at +// the backend container, plain local dev keeps the localhost default. +const proxyTarget = process.env.VITE_PROXY_TARGET || 'http://localhost:8000' + // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], @@ -15,11 +19,11 @@ export default defineConfig({ proxy: { // Proxy API requests to backend '/api': { - target: 'http://localhost:8000', + target: proxyTarget, changeOrigin: true, }, '/ws': { - target: 'ws://localhost:8000', + target: proxyTarget.replace(/^http/, 'ws'), ws: true, }, },