This makes it possible to exclude specific editors (e.g. Aranzinger) from edited-article results by default, including dashboard generation and scheduled SMTP runs. Co-authored-by: Cursor <cursoragent@cursor.com>
TK Wiki Newsletter Admin
Produktionsnahes internes Tool zur Erstellung von Thomas-Krenn.AG Newslettern auf Basis der letzten Wiki-Änderungen.
Funktionen
- Login und Benutzerverwaltung mit RBAC (
admin,editor,reader) - Verpflichtender CSRF-Schutz auf allen POST-Formularen
- Filter in der Web-UI:
- Zeitraum in Tagen oder „Letzter Monat“
- Artikel-Auswahl: alle, nur neue oder nur bearbeitete Artikel
- Kategorie
- Redaktioneller Feinschliff pro Ausgabe:
- Redaktionsnotiz – optionaler Hinweistext, der als eigene Box im Newsletter erscheint
- Top-Highlights – bis zu 3 Artikel per Titel hervorheben (erscheinen oben als Highlight-Box)
- Datenquelle: MediaWiki API (
recentchangesüberwikiDE/api.php) - E-Mail-Layout im Thomas-Krenn Corporate Design:
- Hero-Header mit Logo, Artikel-Karten mit „Zum Beitrag“-Button, Kontakt- und Adress-Footer
- Neu-/Bearbeitet-Trennung, Zusammenfassungs-Kacheln, Outlook-taugliche Kopiervorschau
- Export:
- Plain Text (für Outlook)
- Raw HTML
- Optionaler SMTP-Versand:
- UI-konfigurierbar (nur für Admins)
- Verteilerlisten mit E-Mail-Validierung
- Versand per BCC (Empfänger nicht im sichtbaren
To:-Header) - flexibler Zeitplan (täglich / wöchentlich / monatlich) über einen Hintergrund-Scheduler
- eigene Inhalts-Vorgaben für den geplanten Versand (Zeitraum, Artikel-Auswahl, Kategorie)
- „Generieren“ verschickt nie – manueller Versand nur per Button „Newsletter jetzt senden“
- automatischer Versand nur mit zwei aktiven Häkchen: Zeitplan + Bestätigung „ohne manuelle Freigabe“
- Versandprotokoll (nur für Editor/Admin sichtbar)
- Docker/Compose Betrieb mit Container-Hardening, inkl. automatischem Image-Build & Push in die Gitea Container Registry (per Versions-Tag)
Start mit Docker
-
Konfiguration anlegen:
cp .env.example .env -
Wichtige Werte in
.envsetzen (siehe auch Konfiguration):Variable Lokal (Entwicklung) Produktion ENVIRONMENTdevelopmentproductionHOST_PORTz. B. 8080nach Bedarf SECRET_KEYbeliebig lang mind. 32 zufällige Zeichen ALLOWED_HOSTSlocalhost,127.0.0.1konkreter Hostname COOKIE_SECUREfalsetrue(mit TLS)ADMIN_BOOTSTRAP_EMAILAdmin-E-Mail Admin-E-Mail ADMIN_BOOTSTRAP_PASSWORDBootstrap-Passwort starkes Passwort -
Start:
docker compose up --build -d -
Zugriff:
- http://localhost:8080/login (oder dein
HOST_PORT)
- http://localhost:8080/login (oder dein
Hinweis: Mit
ENVIRONMENT=productionprüft die App beim Start strikt die Konfiguration. Fehlen starke Secrets oder sind unsichere Defaults gesetzt, startet der Container nicht.
Konfiguration (.env)
Vollständige Vorlage: .env.example
| Variable | Beschreibung |
|---|---|
ENVIRONMENT |
development = lokale Entwicklung ohne harte Checks; production = erzwingt sichere Einstellungen |
SECRET_KEY |
JWT-Signierung und Verschlüsselung von SMTP-Passwörtern in der DB |
ALGORITHM |
JWT-Algorithmus (Standard: HS256) |
ACCESS_TOKEN_EXPIRE_MINUTES |
Gültigkeit der Login-Session in Minuten (Standard: 120) |
JWT_ISSUER / JWT_AUDIENCE |
JWT-Claims zur Token-Validierung |
HOST_PORT |
Host-Port für Docker Compose (nur Compose, nicht App-intern) |
DATABASE_URL |
SQLite (Standard) oder PostgreSQL |
WIKI_API_URL |
MediaWiki-API-Endpunkt |
ALLOWED_HOSTS |
Kommagetrennte erlaubte Host-Header |
COOKIE_SECURE |
Secure-Flag für Session- und CSRF-Cookies (Pflicht true in Produktion) |
HSTS_MAX_AGE |
HSTS-Header-Dauer in Sekunden (nur bei HTTPS) |
ADMIN_BOOTSTRAP_EMAIL / ADMIN_BOOTSTRAP_PASSWORD |
Erster Admin-Account beim Start |
ADMIN_BOOTSTRAP_RESET |
Admin auf .env-Werte zurücksetzen (nur Entwicklung/Notfall, in Produktion verboten) |
EDITOR_TIP_MAX_LENGTH |
Max. Zeichen für Redaktionsnotiz (Standard: 10000) |
HIGHLIGHTS_MAX_LENGTH |
Max. Zeichen für Top-Highlights (Standard: 5000) |
Container-Image (Gitea Packages)
Fertige Images werden automatisch in die Gitea Container Registry veröffentlicht:
git.hexahost.dev/smueller/tk-wiki-newsletter
Verfügbare Tags: latest, die Version (X.Y.Z, X.Y, X) sowie der kurze Commit-SHA.
Image ziehen und mit vorhandener .env starten:
docker login git.hexahost.dev
docker pull git.hexahost.dev/smueller/tk-wiki-newsletter:latest
docker run -d --name tk-newsletter-admin \
--env-file .env \
-p 8080:8000 \
-v newsletter_data:/app/data \
--read-only \
--tmpfs /tmp \
--security-opt no-new-privileges:true \
git.hexahost.dev/smueller/tk-wiki-newsletter:latest
Alternativ in docker-compose.yml statt build: . das Image referenzieren:
services:
newsletter-admin:
image: git.hexahost.dev/smueller/tk-wiki-newsletter:latest
# build: . # <- nicht mehr nötig, wenn das fertige Image genutzt wird
Die mitgelieferte docker-compose.yml setzt bereits read_only, no-new-privileges und ein tmpfs für /tmp. Persistente Daten liegen im Volume newsletter_data unter /app/data.
Automatischer Build (CI/CD)
Der Workflow .gitea/workflows/docker-build.yml baut und pusht das Image über Gitea Actions.
-
Auslöser: nur beim Setzen eines Versions-Tags
v*(kein Build bei normalen Pushes aufdev/main). -
Vor dem Build:
pip-auditprüft die Python-Abhängigkeiten ausrequirements.txt. -
Release-Ablauf (Build bei Merge
dev→mainmit Version):git checkout main git merge --no-ff dev git push origin main git tag v1.0.0 git push origin v1.0.0 # <- startet Build & Push -
Benötigte Repo-Secrets (Settings → Actions → Secrets):
REGISTRY_TOKEN: Gitea Access-Token mit Scope Package: Read and writeREGISTRY_USER(optional): Registry-Benutzername, falls abweichend vom Repo-Owner
-
Optionale Repo-Variable:
REGISTRY, um den Registry-Host zu überschreiben (Defaultgit.hexahost.dev).
Admin-Login & Passwort zurücksetzen
-
Das Login erfolgt über E-Mail + Passwort (kein separater Benutzername). Beim ersten Start wird der Admin aus
ADMIN_BOOTSTRAP_EMAIL/ADMIN_BOOTSTRAP_PASSWORDangelegt. -
Passwortpolitik: mindestens 10 Zeichen, mindestens ein Großbuchstabe, ein Kleinbuchstabe und eine Ziffer.
-
Rate-Limiting: nach 5 fehlgeschlagenen Anmeldeversuchen pro IP/E-Mail innerhalb von 5 Minuten wird der Login temporär blockiert.
-
Wichtig: Existiert der Admin bereits (persistente DB im Volume
newsletter_data), wird eine spätere Passwort-Änderung in der.envnormalerweise nicht übernommen. -
Um Passwort/Rolle/Status auf die
.env-Werte zurückzusetzen (nur Entwicklung):ADMIN_BOOTSTRAP_RESET=truesetzen und Container neu starten:docker compose up -d --force-recreateNach erfolgreichem Login
ADMIN_BOOTSTRAP_RESET=falsesetzen. InENVIRONMENT=productionistADMIN_BOOTSTRAP_RESET=truenicht erlaubt – die App startet dann nicht. -
Passwort ändern (Profil) oder Abmelden beendet alle aktiven Sessions des Benutzers.
Rollenmodell
| Rolle | Rechte |
|---|---|
reader |
Newsletter-Vorschau und Artikellisten ansehen |
editor |
Newsletter generieren, exportieren und manuell versenden; Versandprotokoll und Empfängerliste einsehen |
admin |
Zusätzlich Benutzerverwaltung (anlegen, Rolle ändern, aktivieren/deaktivieren) und SMTP-Konfiguration |
Admins können in der Benutzerverwaltung (/admin/users):
- neue Benutzer mit Rolle anlegen
- die Rolle bestehender Benutzer ändern (beendet deren Sessions)
- Benutzer aktivieren oder deaktivieren (beendet deren Sessions)
Das eigene Konto kann weder deaktiviert noch die eigene Rolle geändert werden.
Sicherheit
Eingebaute Schutzmaßnahmen
- bcrypt für Passwort-Hashes
- CSRF Double-Submit-Cookie auf allen POST-Formularen
- HttpOnly + SameSite=Strict Session-Cookies;
Securebei HTTPS (COOKIE_SECURE=true) - JWT mit
iss,aud, Ablaufzeit und Session-Version (session_version) - Session-Invalidierung bei Logout, Passwortwechsel, Rollen- oder Statusänderung
- SMTP-Passwort verschlüsselt in der Datenbank (Fernet), nicht im HTML-Formular
- Security-Header: CSP,
X-Frame-Options,X-Content-Type-Options,Referrer-Policy, HSTS (bei HTTPS),Cache-Control: no-storeauf geschützten Seiten - OpenAPI (
/docs,/redoc) in Produktion deaktiviert - Abhängigkeiten in
requirements.txtversioniert; CI führtpip-auditaus
Produktions-Checkliste
Bei ENVIRONMENT=production erzwingt die App beim Start:
SECRET_KEYmit mindestens 32 Zeichen (keine bekannten Defaults)- starkes
ADMIN_BOOTSTRAP_PASSWORD ADMIN_BOOTSTRAP_RESET=falseALLOWED_HOSTSmit konkreten Hostnamen (nicht*)COOKIE_SECURE=true
Zusätzlich empfohlen:
- Reverse Proxy (z. B. Nginx/Traefik) mit TLS vor den Container; Proxy muss
X-Forwarded-Proto: httpssetzen - Bootstrap-Admin-Passwort nach erstem Login im Profil ändern
- Netzwerkzugriff auf interne IPs/Netze beschränken
- Regelmäßige Backups des
newsletter_dataVolumes (SQLite-Datei unverschlüsselt)
Beispiel .env für Produktion
ENVIRONMENT=production
SECRET_KEY=<mind. 32 zufällige Zeichen>
ALLOWED_HOSTS=newsletter.intern.firma.de
COOKIE_SECURE=true
ADMIN_BOOTSTRAP_EMAIL=admin@firma.de
ADMIN_BOOTSTRAP_PASSWORD=<starkes Passwort>
ADMIN_BOOTSTRAP_RESET=false