INBOX/checkpoint-deployment.md
2026-08-07 16:01:24 +02:00

163 lines
3.6 KiB
Markdown

# CheckPoint Ehrenamt — Deployment & Betrieb
> Flask/Gunicorn · Docker · cpe.bujour.info · Stand: Juni 2026
---
## Überblick
CheckPoint Ehrenamt läuft als Docker-Container auf dem EU-VPS hinter Caddy.
Das Image wird direkt auf dem VPS aus dem geklonten Forgejo-Repo gebaut —
kein Container-Registry, kein CI/CD.
**URL:** https://cpe.bujour.info
**Repo:** https://git.bujour.de/patsy/CP_EHRENAMT
**Code auf VPS:** `~/apps/checkpoint/`
**Stack:** `~/stacks/checkpoint/`
---
## Stack-Struktur
```
~/stacks/checkpoint/
├── compose.yaml
└── .env ← SECRET_KEY (nicht im Git)
~/apps/checkpoint/
├── Dockerfile
├── wsgi.py
├── gunicorn.conf.py
├── seed.py
├── requirements.txt
├── app/
└── instance/ ← DB + Uploads (Docker Volume)
```
---
## compose.yaml
```yaml
services:
checkpoint:
build: /home/patsy/apps/checkpoint
container_name: checkpoint
restart: unless-stopped
environment:
- CP_ENV=production
- SECRET_KEY=${SECRET_KEY}
volumes:
- checkpoint_data:/app/instance
networks:
- proxy
expose:
- "8000"
volumes:
checkpoint_data:
networks:
proxy:
external: true
```
---
## Erstes Deployment (Einmalig)
```bash
# 1. Repo klonen
git clone ssh://git@git.bujour.de:2222/patsy/CP_EHRENAMT.git ~/apps/checkpoint
# 2. Secret generieren
python3 -c "import secrets; print('SECRET_KEY=' + secrets.token_urlsafe(48))" \
> ~/stacks/checkpoint/.env
# 3. Image bauen und Container starten
cd ~/stacks/checkpoint
docker compose build
docker compose up -d
# 4. Datenbank seeden (einmalig)
docker exec checkpoint python seed.py
# 5. Ersten Admin anlegen (einmalig)
docker exec -e SECRET_KEY=$(grep SECRET_KEY ~/stacks/checkpoint/.env | cut -d= -f2) \
checkpoint flask --app wsgi create-admin <nutzername> "<anzeigename>" "<passwort>"
```
---
## Update einspielen
```bash
cd ~/apps/checkpoint
git pull
cd ~/stacks/checkpoint
docker compose build
docker compose up -d
```
Neue Tabellen werden beim Start automatisch via `db.create_all()` angelegt.
**Achtung:** Bestehende Tabellen werden nicht migriert — bei Schema-Änderungen
vorher Backup ziehen und ggf. manuell migrieren.
---
## Weitere Admins anlegen
```bash
docker exec -e SECRET_KEY=$(grep SECRET_KEY ~/stacks/checkpoint/.env | cut -d= -f2) \
checkpoint flask --app wsgi create-admin <nutzername> "<anzeigename>" "<passwort>"
```
---
## Datenbank-Backup (manuell)
```bash
docker exec checkpoint sqlite3 /app/instance/checkpoint.sqlite \
".backup '/app/instance/checkpoint-backup-$(date +%Y%m%d).sqlite'"
```
Das Backup liegt im Volume unter `/app/instance/` und kann von dort kopiert werden.
---
## Logs
```bash
# Live-Logs
docker logs checkpoint -f
# Letzte 100 Zeilen
docker logs checkpoint --tail 100
```
---
## Fehlersuche
| Problem | Ursache | Lösung |
|---|---|---|
| 500 nach Deploy | Fehlendes `SECRET_KEY` | `.env` prüfen, Container neu starten |
| Login funktioniert nicht | `CP_ENV` nicht gesetzt | `docker exec checkpoint env \| grep CP_ENV` |
| App nicht erreichbar | Caddy oder Container down | `docker ps`, dann Caddy-Reload |
| „database is locked" | Zu viele Worker für SQLite | `workers` in `gunicorn.conf.py` auf 2 senken |
---
## Technischer Stack
| Komponente | Entscheidung |
|---|---|
| Backend | Python 3.13 + Flask |
| WSGI | gunicorn (3 Worker, gthread) |
| Datenbank | SQLite mit WAL-Modus |
| Templating | Jinja2, server-rendered |
| CSS | Selbst gebaut, kein Framework |
| JavaScript | Minimal, Vanilla (nur Chat-Polling + Sidebar) |
| CSRF | Selbst gebaut (Session-Token, kein Flask-WTF) |
| Hosting | IONOS EU-VPS, Docker, Caddy (TLS automatisch) |