5.9 KiB
Spiele-Redaktion
KI-Assistenz für Spielemagazin-Redaktionen — Multi-User-Webanwendung mit modularer Plugin-Architektur. Phase 1: lauffähiger Kern mit Plugin-System, Authentifizierung/Rollen, Migrationen und Plugin-Stubs.
Stack
- Backend: Python 3.11+, FastAPI, SQLAlchemy 2 (SQLite, Postgres-fähig)
- Frontend: HTMX + Jinja2 + Tailwind (CDN) + Alpine.js — kein Build-Step
- Auth: Session-Cookies (signiert), Passwort-Hashing mit Argon2id
- Plugins: Entry-Points (
importlib.metadata, Gruppespiele_redaktion.plugins) plus lokalesplugins/-Verzeichnis - Dependencies/Tests: uv + pytest
Setup
uv sync # venv + Dependencies
uv run uvicorn main:app --reload # Dev-Server auf http://127.0.0.1:8000
Beim ersten Start wird automatisch ein Admin-Konto angelegt:
| Benutzername | Passwort | Rolle |
|---|---|---|
admin |
admin |
admin |
⚠️ Für alles außer der lokalen Entwicklung vor dem Start
SPIELE_INITIAL_ADMIN_PASSWORDsetzen und das Passwort nach dem ersten Login ändern.
Umgebungsvariablen
| Variable | Default | Bedeutung |
|---|---|---|
SPIELE_DATABASE_URL |
sqlite:///./data/spiele-redaktion.db |
SQLAlchemy-URL (Postgres: z. B. postgresql+psycopg://…) |
SPIELE_SESSION_SECRET |
Dev-Wert | Secret für signierte Session-Cookies |
SPIELE_SESSION_DAUER |
43200 |
Session-Dauer in Sekunden (12 h) |
SPIELE_INITIAL_ADMIN_PASSWORD |
admin |
Passwort des initialen Admins |
SPIELE_PLUGINS_DIR |
<Projekt>/plugins |
Pfad zum lokalen Plugin-Verzeichnis |
Tests
uv run pytest
Abgedeckt: Plugin-Loader lädt alle Stubs (inkl. Lifecycle-Hooks und Entry-Point-Pfad), Migrations-Laufzeit inkl. Idempotenz, Login/Logout, Rollen-Zugriff (admin/redakteur vs. rezensent), Benutzerverwaltung.
Architektur
src/redaktionskern/ schlanker Kern — KEINE Fachlogik
├── app.py App-Fabrik: Discovery → Migrations → on_load → Routen
├── config.py Einstellungen (Umgebungsvariablen)
├── db.py Engine/Session (SQLite ↔ Postgres portabel)
├── migrationen.py Migrations-Laufzeit (Tabelle schema_migrations pro Plugin)
├── plugin_loader.py Entry-Points + plugins/-Verzeichnis, eindeutige Namen
├── contracts.py Plugin-Vertrag (BasePlugin, Migration, NavEntry, PluginContext)
└── auth/ Login/Logout, Rollen, Benutzerverwaltung
plugins/ ein Ordner pro Funktion (Phase-1: Stubs, ladbar)
├── neuheiten/ dedup/ planung/ archiv/
├── erinnerung/ benachrichtigung/ audit-log/ export/
└── … je __init__.py + templates/<name>/index.html
Der Plugin-Vertrag
Ein Plugin ist ein Paketordner unter plugins/ mit einem __init__.py, das
ein Modulattribut plugin (Instanz einer BasePlugin-Unterklasse) bereitstellt.
Alternativ: installiertes Paket mit Entry-Point in der Gruppe
spiele_redaktion.plugins.
from fastapi import Depends, Request
from redaktionskern.auth.deps import require_user
from redaktionskern.contracts import BasePlugin, Migration, NavEntry
class MeinPlugin(BasePlugin):
name = "meinplugin" # eindeutig, = Ordnername
title = "Mein Plugin" # deutscher Anzeigename
description = "Was es tut."
def migrations(self): # eigene Schema-Migrationen (optional)
return []
def navigation(self): # Einträge in der Hauptnavigation (optional)
return [NavEntry(label=self.title, url="/meinplugin")]
def on_load(self, context): # Lifecycle-Hook beim Start
super().on_load(context) # context.engine/.session_factory/.templates/.settings
def on_unload(self): # Lifecycle-Hook beim Herunterfahren
super().on_unload()
plugin = MeinPlugin()
Der Kern stellt jedem Plugin über context.templates eine gemeinsame Jinja-
Umgebung bereit (Plugin-Templates erben base.html), dazu Engine und
Session-Fabrik. Migrationen laufen transaktional und werden pro Plugin in
schema_migrations protokolliert; die up-Funktionen bekommen eine
SQLAlchemy-Connection und können bei Dialekt-Unterschieden verzweigen.
Deployment (später)
Docker/Podman Compose ist vorgesehen (Henry-Lab, danach Kundenhardware).
Für Postgres genügt SPIELE_DATABASE_URL; die Migrationen sind portabel
geschrieben.
Projekt-Fortschritt
Diese Tabelle ist der Live-Status. Sie wird bei jedem Push aktualisiert.
| # | Baustein | Status |
|---|---|---|
| 1 | Kern: FastAPI, Plugin-System, DB/Migrationen, Auth/Rollen, HTMX-Layout | ✅ fertig (28 Tests grün) |
| 2 | Plugin benachrichtigung (E-Mail/Telegram/In-App, User-Präferenzen) |
🔄 in Arbeit |
| 3 | Plugin audit-log (Wer/Was/Wann, Admin-Ansicht) |
🔄 in Arbeit |
| 4 | Plugin neuheiten (BGG-Sync, APScheduler, Filter) |
🔄 in Arbeit |
| 5 | Plugin dedup (Verlags-Konflikt, deutsche Version, Vorgänger-/Planungs-Check) |
⏳ offen |
| 6 | Plugin planung (Verschiebung, händischer Eintrag + Prüfungen + Benachrichtigung) |
⏳ offen |
| 7 | Plugin archiv (12-Monats-Autopilot) |
⏳ offen |
| 8 | Plugin erinnerung (Redaktionsschluss pro Ausgabe, 4-Wochen-Erinnerung) |
⏳ offen |
| 9 | Plugin export (CSV + PDF via WeasyPrint) |
⏳ offen |
| 10 | Integrationstests über alle Plugins | ⏳ offen |
| 11 | Deployment auf swen.henry.insight-it.de (Compose + Traefik, Live-Check) | ⏳ offen |
Legende: ✅ fertig · 🔄 in Arbeit · ⏳ offen · ⚠️ fertig mit offenen Punkten
Offene Punkte (nicht Teil von Phase 1)
- CSRF-Schutz für Formulare (aktuell SameSite=Lax-Cookie als Basisschutz)
- Hintergrund-Jobs (APScheduler) für BGG-Sync und Erinnerungen
- WeasyPrint für PDF-Export (Systemabhängigkeiten im Container)
- Tailwind via CDN nur für Dev; für Produktion lokal gehostete Assets