115 lines
6.7 KiB
Markdown
115 lines
6.7 KiB
Markdown
# Architektur
|
|
|
|
## Systemgrenze
|
|
|
|
Sendewerk ist ein einzelner SvelteKit-Prozess. Browserseiten, serverseitige
|
|
Actions, spätere REST-Endpunkte und Hintergrundaufgaben verwenden dieselbe
|
|
Geschäftslogik. SQLite und ein lokales Upload-Verzeichnis sind die einzigen
|
|
persistenten Laufzeitabhängigkeiten. Externe Mail-, RSS- oder KI-Dienste sind
|
|
nicht Voraussetzung für Kernfunktionen.
|
|
|
|
```text
|
|
Browser -> SvelteKit-Routen -> Anwendungsdienste -> SQLite
|
|
| -> Upload-Verzeichnis
|
|
+-> später: Mail/RSS über Adapter
|
|
```
|
|
|
|
Servercode lebt unter `src/lib/server` und darf nicht in Browser-Bundles
|
|
gelangen. Routen liefern nur die für ihre Ansicht erlaubten Daten. Fachlogik
|
|
wird nicht an Svelte-Komponenten gebunden, damit Browseraktionen und die
|
|
spätere API dieselben Regeln verwenden.
|
|
|
|
## Laufzeit und Speicher
|
|
|
|
- Lokal: `.data/sendewerk.sqlite` und `.data/uploads`, jeweils konfigurierbar.
|
|
- Tests: pro Lauf ein temporäres Verzeichnis unter dem Betriebssystem-Tempdir.
|
|
- Cloudron: `/app/data/sendewerk.sqlite` und `/app/data/uploads`.
|
|
- Migrationen liegen nummeriert unter `migrations/`, laufen in Transaktionen
|
|
und werden in `schema_migrations` protokolliert.
|
|
- Der Seed nutzt stabile IDs und Transaktionen. Wiederholung liefert denselben
|
|
fachlichen Ausgangsbestand, ohne Migrationstabellen anzutasten.
|
|
- Zeitpunkte werden als ISO-8601-UTC-Text gespeichert. Dauern sind nichtnegative
|
|
ganze Sekunden. Zeitzonendarstellung ist `Europe/Berlin`.
|
|
|
|
## Geplantes Gesamtdatenmodell
|
|
|
|
Etappe 1 materialisiert nur den für echte Vorschau- und Seed-Daten benötigten
|
|
Kern. Folgende Grenzen sind für spätere Migrationen bereits festgelegt.
|
|
|
|
| Bereich | Geplante Entitäten und Beziehungen |
|
|
| ----------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
| Identität | `users`, Rollen, Sessions, Einladungen, Reset-Tokens und Sperren sind umgesetzt; technische Zugänge folgen später |
|
|
| Taxonomie | getrennte `section_categories`, `formats`, `topics`; Pieces und Vorschläge über Zuordnungstabellen mehrfach verknüpft |
|
|
| Inhalt | `pieces` mit Status und Dauer; Quellen, Medien, private Recherche, Moderation, Präsentation und Vorlagen als getrennte Daten |
|
|
| Sendungsbau | `shows`, geordnete `show_sections`, kopierte `piece_usages`, Reservebank und Sendungsvorlagen; Original-ID bleibt Referenz |
|
|
| Live | expliziter Live-Stand, aktuelles Element, Status je Verwendung, tatsächliche Zeiten und getrennte Präsentationsausgabe |
|
|
| Historie | unveränderliche Abschluss-Snapshots und Verwendungshistorie; Übersprungenes zählt nicht als gesendet |
|
|
| Freigaben | widerrufbare, gehashte Lesetokens mit Sendung, Umfang, Passwortoption und Ablaufzeit |
|
|
| RSS | Feedquellen, Abrufläufe und externe Einträge mit stabiler Herkunfts-ID sowie Status neu/übernommen/verworfen |
|
|
| API/Audit | technische Berechtigungen, Idempotenzschlüssel und Audit-Ereignisse mit Akteur, Aktion und Ziel |
|
|
| Betrieb | Anwendungseinstellungen und spätere Job-Zustände, keine Geheimnisse im Klartext ohne begründete Schutzstrategie |
|
|
|
|
### Historien- und Kopierregel
|
|
|
|
Beim Einplanen entsteht eine bearbeitbare `piece_usage`-Kopie der
|
|
sendungsrelevanten Texte und Dauer. Das Original bleibt verknüpft, wird aber
|
|
nicht live gespiegelt. Beim Abschluss wird der damalige Sendungsinhalt stabil
|
|
eingefroren. Eine historische Sendung wird dupliziert, nie weiterbearbeitet.
|
|
|
|
### Dauerregel
|
|
|
|
Eine Abschnittsdauer ist entweder die Summe ihrer eingeplanten Verwendungen
|
|
oder eine explizite Abschnittsdauer. Beides wird nie addiert. Reserveelemente
|
|
zählen erst nach dem Einplanen. Geplante und tatsächliche Dauer bleiben
|
|
getrennt.
|
|
|
|
## Anmeldung und Rechte
|
|
|
|
Etappe 2 ergänzt lokale Konten mit den festen Rollen `barkeeper` und
|
|
`thekencrew`. Passwörter werden mit Argon2id gespeichert. Sitzungs-, Einladungs-
|
|
und Reset-Tokens entstehen aus kryptografischem Zufall; in SQLite liegt jeweils
|
|
nur ihr SHA-256-Hash. Der Browser erhält ausschließlich das rohe Sitzungstoken
|
|
in einem `HttpOnly`-, `SameSite=Lax`-Cookie.
|
|
|
|
`hooks.server.ts` löst die Sitzung für jeden Request auf. Die Datenbankabfrage
|
|
verbindet die Session immer mit dem aktuellen Nutzerzustand, sodass Sperren und
|
|
Rollenwechsel ohne verzögerte Token-Erneuerung wirken. Geschützte Routen
|
|
erfordern eine Anmeldung; Verwaltungs-Loads und jede Verwaltungs-Action prüfen
|
|
zusätzlich die Barkeeper-Rolle. Sperrung und Passwortwechsel löschen bestehende
|
|
Sessions transaktional.
|
|
|
|
Der Erstadmin benötigt sowohl eine leere Nutzertabelle als auch ein extern
|
|
konfiguriertes Setup-Token. Einladungs- und Reset-Links sind 24 Stunden gültig,
|
|
werden erst beim bestätigenden POST verbraucht und sind genau einmal nutzbar.
|
|
Fehlgeschlagene Loginversuche werden pro E-Mail-Schlüssel und Clientadresse in
|
|
einem Zeitfenster begrenzt, ohne das Konto dauerhaft zu sperren.
|
|
|
|
Mail verwendet einen Adapter: `local` schreibt geschützte Dateien in den
|
|
konfigurierten Outbox-Pfad, `smtp` nutzt Nodemailer nur nach expliziter Auswahl.
|
|
Die feste Anwendungs-Origin erzeugt Links und bestimmt den `Secure`-Status der
|
|
Cookies; sie wird nicht aus ungeprüften Request-Headern übernommen.
|
|
|
|
## Oberflächenstruktur
|
|
|
|
Die Hauptnavigation umfasst Eingang, Fundus, Sendungen, Archiv und Verwaltung.
|
|
Auf dem Desktop bleibt eine feste Seitenleiste sichtbar; Verwaltung liegt an
|
|
ihrem unteren Ende. Bis einschließlich `52rem` ersetzen eine obere Leiste und
|
|
die untere Hauptnavigation die Seitenleiste vollständig. Auf breiten Ansichten
|
|
stehen Fundus und Ablauf nebeneinander. Bis einschließlich `72rem` werden sie
|
|
über eine gut erreichbare Umschaltung einzeln gezeigt, damit auch schmale
|
|
Desktopfenster ohne horizontalen Überlauf bedienbar bleiben.
|
|
Der Live-Modus ist eine eigene, fokussierte Ansicht; die spätere
|
|
Präsentationsausgabe erhält eine separate, strikt reduzierte Datenansicht.
|
|
|
|
Etappe 1 zeigt Fundus, Sendungsbau und Live-Modus als sichtbare
|
|
`Gestaltungsvorschau`. Die Daten kommen bereits aus SQLite, mutierende
|
|
Fachabläufe werden jedoch nicht vorgetäuscht.
|
|
|
|
## Sicherheitsgrenzen ab den Folgeetappen
|
|
|
|
Authentifizierung und Autorisierung werden seit Etappe 2 serverseitig an jeder
|
|
betroffenen Route und Action geprüft. Markdown und fremdes HTML werden vor Ausgabe bereinigt.
|
|
Uploadzugriff folgt denselben Rechten. Netzwerkabrufe erhalten Schutz gegen
|
|
interne Ziele, Größen-/Zeitlimits und kontrollierte Redirects. Diese Regeln
|
|
sind geplant, aber nicht Bestandteil der Etappe-1-Vorschauen.
|