Files
dashboard-cpsp-executive/DOCKER.md
T
2026-09-11 14:48:18 +07:00

211 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Docker Deployment Guide
Deploy **dashboard-cpsp-executive** (HQ) with Docker Compose. Same layout as site `dashboard-cpsp` (Postgres + API + Nginx frontend + cron), with HQ ports and city-edge syncs **off** by default.
## Architecture
```
┌──────────────────────────────────────────────────────────────┐
│ HQ Host Server │
│ │
│ ┌─────────────┐ /api/* ┌──────────────┐ │
│ │ frontend │────────────►│ api │ │
│ │ (Nginx) │ │ (Django) │ │
│ │ port 80 │ │ port 8000 │ │
│ └─────────────┘ └──────┬───────┘ │
│ │ │
│ ┌─────────────┐ ▼ │
│ │ cron │────────────► ┌──────────────┐ │
│ │ (same image)│ │ database │ │
│ └─────────────┘ │ (PostgreSQL) │ │
│ │ port 15433* │ │
│ └──────────────┘ │
└──────────────────────────────────────────────────────────────┘
* 15433 on host → 5432 in container (SSH tunnel / DBeaver)
Host API debug port: 18001 → 8000 (site app uses 18000 / 15432)
```
| Container | Image / build | Host port | Role |
| ---------- | ------------------ | ---------------- | ----------------------------- |
| frontend | `docker/Dockerfile.web` | 80 → 80 | React SPA + Nginx API proxy |
| api | `docker/Dockerfile.api` | 18001 → 8000 | Gunicorn, migrations, static |
| cron | same as api | — | KPI rollups (+ optional edge syncs) |
| database | postgres:16-alpine | 15433 → 5432 | PostgreSQL |
## Prerequisites
- Docker 20.10+
- Docker Compose v2+
- Ports available: **80** (UI; set `FRONTEND_PORT=8080` in `.env` if busy), **18001** (direct API), **15433** (Postgres on localhost)
```bash
docker --version
docker compose version
```
## Quick start
```bash
cd dashboard-cpsp-executive
cp docker/.env.example .env
# Edit .env — set SECRET_KEY and DB_PASSWORD
docker compose up -d --build
```
API entrypoint runs `migrate` + `bootstrap_admin` on every start (needs `BOOTSTRAP_ADMIN_PASSWORD` in `.env`).
**Production** (empty database, no demo data): log in with the bootstrap admin, then create users/sites via the UI. Do **not** run `seed_demo` on production.
**Dev / demo** (sample data):
```bash
docker compose exec api python manage.py seed_demo
```
### Verify
```bash
docker compose ps
docker compose logs -f
curl http://localhost/health
curl http://localhost/api/v1/health/
```
Open **http://localhost** in a browser.
## Configuration files (`docker/`)
| File | Purpose |
| ---- | ------- |
| `Dockerfile.web` | Frontend image (Vite + Nginx) |
| `Dockerfile.api` | Backend image (Django + Gunicorn) |
| `nginx.conf` | Nginx proxy config for frontend |
| `entrypoint-api.sh` | API container startup |
| `entrypoint-cron.sh` | Cron container startup |
| `crontab` | Fallback schedule; runtime regenerated from `DASHBOARD_PUBLISH_*` |
| `.env.example` | Compose env template → copy to project root `.env` |
| `compose.override.local.example` | Optional local Postgres port override |
## Configuration
Compose reads variables from a root `.env` file. Template: `docker/.env.example`.
Important production values:
| Variable | Purpose |
| -------- | ------- |
| `SECRET_KEY` | Django secret — use a long random string |
| `DB_PASSWORD` | PostgreSQL password |
| `CSRF_TRUSTED_ORIGINS` | Must include your public UI origin (e.g. `https://executive.example.com`) |
| `CORS_ALLOWED_ORIGINS` | Same as above if the SPA is on a different origin |
| `BOOTSTRAP_ADMIN_USER` | Superuser username for `bootstrap_admin` (default `admin`) |
| `BOOTSTRAP_ADMIN_PASSWORD` | Superuser password (required) |
| `BOOTSTRAP_STAFF_USER` | Optional GM username; leave empty to skip |
| `BOOTSTRAP_STAFF_PASSWORD` | GM password (required when `BOOTSTRAP_STAFF_USER` is set) |
| `BOOTSTRAP_API_KEY` | Optional fixed API key for city inbound / scripts (hashed at rest) |
City-edge sync flags default to **false** at HQ. Enable only if this host also pulls directly from IoT / karung / chicken-counting edge APIs.
## Management
```bash
# Start / stop
docker compose start
docker compose stop
docker compose restart
# Logs
docker compose logs -f api
docker compose logs -f frontend
docker compose logs -f cron
# Django shell
docker compose exec api python manage.py shell
# Database (psql)
docker compose exec database psql -U executive -d executive
# From host (port 15433)
psql -h localhost -p 15433 -U executive -d executive
```
### Update after code changes
```bash
git pull
docker compose down
docker compose up -d --build
```
Rolling update (less downtime):
```bash
docker compose build
docker compose up -d --no-deps --build api
docker compose up -d --no-deps --build cron
docker compose up -d --no-deps --build frontend
```
### Local DBeaver on Mac
```bash
cp docker/compose.override.local.example docker-compose.override.yml
```
Adds `127.0.0.1:5432:5432` while keeping the server’s `15433` mapping.
## Cron jobs
The `cron` service runs:
- **Every 10 min** — `sync_iot_from_api` / `sync_chicken_counting_from_edge` (no-op while sync flags are false)
- **At `DASHBOARD_PUBLISH_HOUR`:`DASHBOARD_PUBLISH_MINUTE` daily** — optional karung sync then `recompute_kpi_rollups`
Karung 30s loop starts only when `KARUNG_WEB_ADMIN_SYNC_ENABLED=true`.
Logs: `docker compose exec cron tail -f /var/log/cron.log`
## Troubleshooting
**API unhealthy**
```bash
docker compose logs api
docker compose exec api python manage.py migrate --plan
```
**Frontend 502 on /api**
```bash
docker compose ps
curl http://127.0.0.1:18001/api/v1/health/
```
**Database connection errors**
Check Postgres is healthy and credentials in `.env` match `docker-compose.yml` defaults.
**Port conflicts**
Change mappings in `docker-compose.yml`, e.g. `"8080:80"` for frontend. Site app already uses 80 / 18000 / 15432 on city hosts.
**Reset database** (destructive)
```bash
docker compose down -v
docker compose up -d --build
```
## Security notes
- Do not commit `.env` with real secrets.
- Use strong `SECRET_KEY` and `DB_PASSWORD` in production.
- Restrict database port `15433` to localhost (already bound to `127.0.0.1`).
- Put HTTPS in front of port 80 (reverse proxy + Let's Encrypt) for public deployment.
---
Docker deployment guide — dashboard-cpsp-executive