126 lines
4.6 KiB
Markdown
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)
|