190 lines
4.1 KiB
Markdown
190 lines
4.1 KiB
Markdown
|
|
# Deployment Runbook — ERP Nutzfahrzeuge
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
1. **PostgreSQL** — running and accessible (managed or self-hosted)
|
||
|
|
2. **Redis** (optional) — if async features (OCR, retouch, mobile.de push) are needed
|
||
|
|
3. **Node.js** — for frontend build (if building at deploy time)
|
||
|
|
4. **Python 3.11+** — for backend runtime
|
||
|
|
5. **Coolify** (or Docker) — for containerized deployment
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Pre-Deployment Steps
|
||
|
|
|
||
|
|
### 1. Verify Environment Variables
|
||
|
|
|
||
|
|
Ensure all required variables are configured in Coolify or `.env`:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Required
|
||
|
|
DATABASE_URL=postgresql+asyncpg://<user>:<password>@<host>:5432/<dbname>
|
||
|
|
JWT_SECRET=<generate with: openssl rand -hex 32>
|
||
|
|
|
||
|
|
# Important
|
||
|
|
APP_ENV=production
|
||
|
|
CORS_ORIGINS=https://your-frontend-domain.com
|
||
|
|
UPLOAD_DIR=/app/uploads # persistent volume
|
||
|
|
|
||
|
|
# Optional (feature-dependent)
|
||
|
|
REDIS_URL=redis://<host>:6379/0
|
||
|
|
OPENROUTER_API_KEY=<key>
|
||
|
|
MOBILE_DE_API_KEY=<key>
|
||
|
|
MOBILE_DE_SELLER_ID=<id>
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Build Frontend
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd frontend
|
||
|
|
npm ci
|
||
|
|
npm run build
|
||
|
|
```
|
||
|
|
|
||
|
|
Build artifacts are output to `frontend/.next/`.
|
||
|
|
|
||
|
|
### 3. Verify Backend Dependencies
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd backend
|
||
|
|
/opt/venv/bin/pip install -r requirements.txt
|
||
|
|
/opt/venv/bin/python -c "from app.main import app; print('Import OK')"
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Database Migration (if applicable)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd backend
|
||
|
|
/opt/venv/bin/python -m alembic upgrade head # if Alembic is configured
|
||
|
|
# Or ensure tables are created via app startup
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Deployment Steps (Coolify)
|
||
|
|
|
||
|
|
### Step 1: Create Resource
|
||
|
|
|
||
|
|
1. In Coolify, create a new resource (Docker Compose or Dockerfile-based)
|
||
|
|
2. Configure the source repository
|
||
|
|
3. Set the build/pack type
|
||
|
|
|
||
|
|
### Step 2: Configure Environment
|
||
|
|
|
||
|
|
1. Navigate to resource → Environment Variables
|
||
|
|
2. Add all variables from `deploy/env.md`
|
||
|
|
3. Ensure `JWT_SECRET` is a secure random value
|
||
|
|
4. Set `APP_ENV=production`
|
||
|
|
|
||
|
|
### Step 3: Configure Health Check
|
||
|
|
|
||
|
|
1. Set health check path to `/api/v1/health`
|
||
|
|
2. Set port to `8000`
|
||
|
|
3. See `deploy/healthcheck.md` for full configuration
|
||
|
|
|
||
|
|
### Step 4: Configure Persistent Storage
|
||
|
|
|
||
|
|
1. Mount a persistent volume for `UPLOAD_DIR` (e.g., `/app/uploads`)
|
||
|
|
2. Ensure database volume is persistent
|
||
|
|
|
||
|
|
### Step 5: Deploy
|
||
|
|
|
||
|
|
1. Click **Deploy** in Coolify
|
||
|
|
2. Wait for build and startup to complete
|
||
|
|
3. Verify health check passes (green status)
|
||
|
|
4. Test endpoints:
|
||
|
|
- `GET /api/v1/health` → 200 `{"status":"ok"}`
|
||
|
|
- `GET /` → 200 app metadata
|
||
|
|
- `GET /openapi.json` → 200 OpenAPI schema
|
||
|
|
|
||
|
|
### Step 6: Post-Deployment Verification
|
||
|
|
|
||
|
|
1. Verify frontend is accessible at the configured domain
|
||
|
|
2. Test login flow: `POST /api/v1/auth/login` with valid credentials
|
||
|
|
3. Verify CORS headers are present for frontend origin
|
||
|
|
4. Check logs for any errors:
|
||
|
|
```bash
|
||
|
|
docker logs <container_name> --tail 50
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Deployment Steps (Docker Compose)
|
||
|
|
|
||
|
|
### docker-compose.yml (template)
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
version: '3.8'
|
||
|
|
|
||
|
|
services:
|
||
|
|
backend:
|
||
|
|
build: ./backend
|
||
|
|
ports:
|
||
|
|
- "8000:8000"
|
||
|
|
environment:
|
||
|
|
- DATABASE_URL=postgresql+asyncpg://user:pass@db:5432/erp
|
||
|
|
- JWT_SECRET=${JWT_SECRET}
|
||
|
|
- APP_ENV=production
|
||
|
|
- CORS_ORIGINS=https://your-domain.com
|
||
|
|
- UPLOAD_DIR=/app/uploads
|
||
|
|
- REDIS_URL=redis://redis:6379/0
|
||
|
|
volumes:
|
||
|
|
- uploads:/app/uploads
|
||
|
|
depends_on:
|
||
|
|
- db
|
||
|
|
- redis
|
||
|
|
healthcheck:
|
||
|
|
test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/health"]
|
||
|
|
interval: 30s
|
||
|
|
timeout: 5s
|
||
|
|
retries: 3
|
||
|
|
start_period: 10s
|
||
|
|
|
||
|
|
db:
|
||
|
|
image: postgres:16-alpine
|
||
|
|
environment:
|
||
|
|
- POSTGRES_USER=erp_user
|
||
|
|
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||
|
|
- POSTGRES_DB=erp
|
||
|
|
volumes:
|
||
|
|
- pgdata:/var/lib/postgresql/data
|
||
|
|
|
||
|
|
redis:
|
||
|
|
image: redis:7-alpine
|
||
|
|
volumes:
|
||
|
|
- redisdata:/data
|
||
|
|
|
||
|
|
frontend:
|
||
|
|
build: ./frontend
|
||
|
|
ports:
|
||
|
|
- "3000:3000"
|
||
|
|
depends_on:
|
||
|
|
- backend
|
||
|
|
|
||
|
|
volumes:
|
||
|
|
uploads:
|
||
|
|
pgdata:
|
||
|
|
redisdata:
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Start Command (standalone)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd backend && /opt/venv/bin/python -m uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||
|
|
```
|
||
|
|
|
||
|
|
For production with workers:
|
||
|
|
```bash
|
||
|
|
cd backend && /opt/venv/bin/python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Rollback
|
||
|
|
|
||
|
|
See `deploy/rollback.md` for rollback procedure.
|