Files
serienbrief_django/serienbrief/README.md
T
2026-05-21 10:36:16 +02:00

126 lines
4.6 KiB
Markdown

# Serienbrief
Django-Webanwendung zur Erzeugung von Serienbriefen aus DOCX-Vorlagen und CSV-Empfängerlisten.
Läuft als Compose-Stack, HTTP-only — TLS terminiert ein **vorgelagerter Nginx-Reverse-Proxy** außerhalb dieses Stacks.
## Architektur
```
LAN-Client ──HTTPS──▶ Externer Nginx-Proxy ──HTTP──▶ App-Stack (dieses Repo)
(TLS-Terminierung) │
├─ nginx (intern, :8080)
├─ web (Gunicorn / Django)
├─ worker (Celery)
├─ beat (Celery Scheduler)
├─ db (PostgreSQL 16)
├─ redis (Celery Broker)
└─ backup (nightly pg_dump)
```
Der externe Proxy muss diese Header setzen:
- `X-Forwarded-Proto: https`
- `X-Forwarded-For: <client>`
- `Host: <serienbrief.lan>`
## Verzeichnisstruktur
```
serienbrief/
├── docker-compose.yml # Prod-Stack
├── docker-compose.override.yml # Dev-Overrides (Auto-Merge)
├── .env.example # Konfig-Template
├── .devcontainer/ # VS Code Dev-Container
├── .vscode/ # Launch, Tasks, Settings
├── nginx/ # App-interner Nginx (HTTP)
├── app/ # Django-Projekt
│ ├── Dockerfile # Multi-Stage: builder/dev/runtime
│ ├── requirements.txt
│ ├── requirements-dev.txt
│ ├── pyproject.toml # Ruff & Pytest
│ ├── manage.py
│ ├── config/ # Settings, URLs, WSGI
│ └── mailmerge/ # Django-App: Models, Views, Tasks
├── postgres/init/ # SQL-Init-Scripts (optional)
├── secrets/ # Passwort-Files (chmod 600)
└── backups/ # DB- & Media-Dumps
```
## Erstinbetriebnahme (Prod)
```bash
cp .env.example .env
nano .env # Werte setzen
mkdir -p secrets
openssl rand -base64 32 > secrets/postgres_password.txt
chmod 600 secrets/postgres_password.txt
docker compose -f docker-compose.yml build
docker compose -f docker-compose.yml up -d
docker compose exec web python manage.py createsuperuser
```
Der externe Proxy zeigt dann z.B. so auf den Stack:
```nginx
location / {
proxy_pass http://app-host:8080;
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 https;
}
```
## Entwicklung in VS Code
### Variante A — Dev-Container (empfohlen)
1. VS Code öffnet das Projekt
2. Extension **Dev Containers** installiert
3. Command Palette → `Dev Containers: Reopen in Container`
4. VS Code startet Compose mit Override (Build-Target `dev`, Code-Mount, Hot-Reload)
5. Terminal im Container: `python manage.py migrate`
6. Browser: `http://localhost:8000`
### Variante B — Lokal mit Compose im Hintergrund
```bash
docker compose up -d # Override wird automatisch geladen
docker compose logs -f web
```
Code-Änderungen sind sofort wirksam (Bind-Mount + `runserver` mit Auto-Reload).
### Debugging
Im Container läuft `debugpy` auf Port **5678**. In VS Code:
- Run & Debug → **Django: attach (debugpy in Container)**
- Breakpoints überall im Code setzen
Alternativ Task **django: start debugpy** ausführen und attachen.
### Häufige VS-Code-Tasks
`Strg+Shift+P``Tasks: Run Task`:
| Task | Wirkung |
|---|---|
| compose: up | Stack starten |
| compose: logs web | Live-Logs |
| django: makemigrations | Migrations erzeugen |
| django: migrate | Migrations anwenden |
| django: shell | Django-Shell |
| django: createsuperuser | Admin-User anlegen |
| tests: pytest | Tests laufen lassen |
| lint: ruff | Linting |
## Härtungs-Hinweise
- Externe Proxy-Konfiguration (TLS, HSTS, CSP, Rate-Limit) **muss** vorhanden sein
- `APP_BIND_IP=127.0.0.1` in `.env` außer der externe Proxy läuft auf anderem Host
- `DJANGO_ALLOWED_HOSTS` und `CSRF_TRUSTED_ORIGINS` strikt setzen
- `SECURE_PROXY_SSL_HEADER` ist gesetzt — damit erkennt Django korrekt, dass der Client über HTTPS kam
- Postgres und Redis sind **nicht** nach außen exponiert (nur im backend-Netz)
- Container laufen non-root, `read_only`, mit `no-new-privileges`
- Backups regelmäßig auf zweites System spiegeln (Borg/Restic)