- SCHEMA.md: users-Tabelle korrigiert, sessions-Tabelle ergänzt - API-ENDPOINTS.md: Auth-Routen + Tenant-Dashboard-Routen ergänzt - SERVER-KONZEPT.md: Abschnitte Authentifizierung, Middleware-Kette, Tenant-Dashboard neu - backend/README.md: komplett neu auf Basis aktueller Implementierung - DEVELOPMENT.md: veraltete "nicht vorhanden"-Punkte bereinigt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
381 lines
9.1 KiB
Markdown
381 lines
9.1 KiB
Markdown
# Info-Board Neu - Server-Konzept
|
||
|
||
## Ziel
|
||
|
||
Der Server ist die zentrale Steuer- und Verwaltungsinstanz der Plattform.
|
||
|
||
Er soll:
|
||
|
||
- Benutzer, Firmen und Screens verwalten
|
||
- Medien und Playlists bereitstellen
|
||
- globale Templates und Kampagnen steuern
|
||
- Provisionierung neuer Screens ausloesen
|
||
- Status, Screenshots und Heartbeats sammeln
|
||
- MQTT und HTTPS sauber trennen
|
||
|
||
## Grundprinzip
|
||
|
||
Der Server ist die Quelle der fachlichen Wahrheit.
|
||
|
||
Der Player bleibt trotzdem lauffaehig, wenn der Server temporaer nicht erreichbar ist.
|
||
|
||
Das bedeutet:
|
||
|
||
- Server verwaltet Konfiguration und Inhalte zentral
|
||
- Player fuehrt lokal und robust aus
|
||
- Server sendet Steuerimpulse, Player synchronisiert aktiv nach
|
||
|
||
## Hauptkomponenten
|
||
|
||
### Reverse Proxy
|
||
|
||
Aufgaben:
|
||
|
||
- TLS-Terminierung
|
||
- Routing fuer API und Web-UIs
|
||
- optionale Auth-/Header-Regeln
|
||
|
||
### Backend-API
|
||
|
||
Bevorzugte Sprache:
|
||
|
||
- `Go`
|
||
|
||
Aufgaben:
|
||
|
||
- Authentifizierung und Autorisierung
|
||
- CRUD fuer Tenants, Users, Screens, Medien, Playlists
|
||
- Verwaltung globaler Templates und Kampagnen
|
||
- Player-Sync-Endpunkte
|
||
- Speicherung von Status und Screenshots
|
||
- Start von Provisionierungsjobs
|
||
|
||
### Admin-UI
|
||
|
||
Aufgaben:
|
||
|
||
- Gesamtübersicht aller Screens
|
||
- Vorschau und Status
|
||
- Template-/Kampagnenverwaltung
|
||
- Kommandos und Provisionierung
|
||
|
||
### Tenant-UI
|
||
|
||
Aufgaben:
|
||
|
||
- Uploads und Medienverwaltung pro Firma
|
||
- Pflege der monitorbezogenen Playlist
|
||
- Vorschau des eigenen Screens
|
||
|
||
### Datenbank
|
||
|
||
Empfehlung:
|
||
|
||
- PostgreSQL
|
||
|
||
Aufgaben:
|
||
|
||
- Speicherung fachlicher Daten
|
||
- Status, Jobs, Revisionen, Zuordnungen
|
||
|
||
### MQTT-Broker
|
||
|
||
Empfehlung:
|
||
|
||
- Mosquitto
|
||
|
||
Aufgaben:
|
||
|
||
- Heartbeats
|
||
- Statusmeldungen
|
||
- Events
|
||
- Kommandos und ACKs
|
||
|
||
### Dateispeicher
|
||
|
||
Aufgaben:
|
||
|
||
- Uploads
|
||
- Screenshots
|
||
- ggf. serverseitig vorbereitete Medien
|
||
|
||
V1:
|
||
|
||
- Dateisystem ausreichend
|
||
|
||
## Fachliche Bereiche
|
||
|
||
## 1. Mandanten und Benutzer
|
||
|
||
Der Server trennt:
|
||
|
||
- globale Admins
|
||
- tenantgebundene Nutzer
|
||
|
||
Regel:
|
||
|
||
- Firmen sehen nur ihren Bereich
|
||
- Admins sehen alles
|
||
|
||
## 2. Screen-Verwaltung
|
||
|
||
Der Server kennt jeden Screen mit:
|
||
|
||
- ID
|
||
- Name
|
||
- Klasse
|
||
- Orientierung
|
||
- Rotation
|
||
- Tenant-Zuordnung
|
||
- technischem Registrierungsstatus
|
||
|
||
## 3. Medienverwaltung
|
||
|
||
Der Server verwaltet:
|
||
|
||
- Uploads
|
||
- externe Medienreferenzen
|
||
- Metadaten
|
||
- tenant- oder screenspezifische Zuordnung
|
||
|
||
## 4. Playlist-Verwaltung
|
||
|
||
Der Server verwaltet tenantbezogene Inhalte pro Screen.
|
||
|
||
Wichtige Felder:
|
||
|
||
- Reihenfolge
|
||
- Dauer
|
||
- `valid_from`
|
||
- `valid_until`
|
||
- Fehlerstrategie
|
||
- Cache-Politik
|
||
|
||
## 5. Template- und Kampagnenverwaltung
|
||
|
||
Der Server stellt den globalen Orchestrierungsbereich bereit.
|
||
|
||
Funktionen:
|
||
|
||
- Templates erstellen
|
||
- Szenen pflegen
|
||
- Zielgruppen waehlen
|
||
- Kampagnen aktivieren/deaktivieren
|
||
- Zeitfenster setzen
|
||
- Uebersteuerung sichtbar machen
|
||
|
||
## 6. Provisionierung
|
||
|
||
Der Server startet Provisionierungsjobs fuer neue Screens.
|
||
|
||
Aufgaben:
|
||
|
||
- Eingaben aus Admin-UI entgegennehmen
|
||
- Job anlegen
|
||
- Secret-Handling absichern
|
||
- Worker oder Jobrunner starten
|
||
- Fortschritt speichern
|
||
- Fehler sauber rueckmelden
|
||
|
||
## API-Bereiche
|
||
|
||
Die API soll mindestens diese Domänen haben:
|
||
|
||
- `auth`
|
||
- `tenants`
|
||
- `users`
|
||
- `screens`
|
||
- `media`
|
||
- `playlists`
|
||
- `templates`
|
||
- `campaigns`
|
||
- `player`
|
||
- `commands`
|
||
- `provisioning`
|
||
|
||
## Revisionsmodell
|
||
|
||
Der Server arbeitet mit Revisionen, damit Player effizient synchronisieren koennen.
|
||
|
||
Mindestens:
|
||
|
||
- `config_revision`
|
||
- `playlist_revision`
|
||
- `media_revision`
|
||
- `campaign_revision`
|
||
|
||
## Status- und Vorschaukonzept
|
||
|
||
Der Server speichert:
|
||
|
||
- letzten bekannten Heartbeat
|
||
- letzten Status
|
||
- letzten Screenshot
|
||
- aktuelle Inhaltsquelle pro Screen
|
||
|
||
Die Admin-UI soll damit erkennen:
|
||
|
||
- online/offline
|
||
- normaler tenantbezogener Betrieb
|
||
- globale Kampagnen-Uebersteuerung
|
||
- Fallback-Betrieb
|
||
- Fehlerzustand
|
||
|
||
## Provisionierungsjobrunner
|
||
|
||
Die Provisionierung soll nicht direkt in Web-Requests laufen.
|
||
|
||
Stattdessen:
|
||
|
||
- API legt Job an
|
||
- dedizierter Worker/Jobrunnner arbeitet ihn ab
|
||
- Fortschritt wird in DB gespeichert
|
||
|
||
Zusaetzlich fuer v1 festzulegen:
|
||
|
||
- ACK-Timeout-Handling fuer `device_commands` ueber Worker
|
||
- Secret-Handling fuer Provisionierungs-Bootstrap ueber kurzlebige Secret-Referenzen
|
||
- physische Netzposition des Workers fuer SSH-Erreichbarkeit als Betriebsparameter
|
||
|
||
## Docker-Compose-Zielbild
|
||
|
||
Sinnvolle Komponenten in `compose/`:
|
||
|
||
- `reverse-proxy`
|
||
- `backend`
|
||
- `postgres`
|
||
- `mosquitto`
|
||
- optional `worker`
|
||
|
||
## Authentifizierung
|
||
|
||
Der Server verwendet einen Session-basierten Login-Flow mit `bcrypt`-Passwort-Hashing.
|
||
|
||
### Login-Flow
|
||
|
||
1. `GET /login` rendert das Login-Formular (Bulma-Card zentriert).
|
||
2. `POST /login` prueft Username und Passwort:
|
||
- `AuthStore.GetUserByUsername` laedt den User inkl. Tenant-Slug.
|
||
- `bcrypt.CompareHashAndPassword` prueft das Passwort (Cost-Faktor 12).
|
||
- Bei Erfolg legt `AuthStore.CreateSession` eine Session an (TTL 24 Stunden).
|
||
- Das Session-Token wird als `morz_session`-Cookie gesetzt (`HttpOnly=true`, `Secure=true`).
|
||
- Im `DevMode` (`MORZ_INFOBOARD_DEV_MODE=true`) wird `Secure=false` gesetzt fuer lokalen HTTP-Betrieb.
|
||
- Weiterleitung je nach Rolle: `admin` → `/admin`, `tenant` → `/tenant/{slug}/dashboard`.
|
||
3. `POST /logout` loescht die Session in der DB und entfernt den Cookie.
|
||
|
||
### Cookie-Lebensdauer
|
||
|
||
- Standard-TTL: 24 Stunden
|
||
- Der Cookie verfaellt automatisch; die DB wird stuendlich durch `CleanExpiredSessions` bereinigt.
|
||
|
||
### Admin-User-Bootstrap
|
||
|
||
Beim Server-Start wird `EnsureAdminUser` aufgerufen, wenn `MORZ_INFOBOARD_ADMIN_PASSWORD` gesetzt ist.
|
||
Der Admin-User wird dem Tenant mit Slug `MORZ_INFOBOARD_DEFAULT_TENANT` (Standard: `morz`) zugeordnet.
|
||
Ist der User bereits vorhanden, passiert nichts. Fehler sind nicht fatal — der Server startet trotzdem.
|
||
|
||
---
|
||
|
||
## Middleware-Kette
|
||
|
||
Alle geschuetzten Routen werden durch Middleware-Funktionen in `internal/httpapi/middleware.go` abgesichert.
|
||
|
||
```
|
||
Eingehende Anfrage
|
||
│
|
||
▼
|
||
RequireAuth Liest morz_session-Cookie, prueft Session via DB,
|
||
speichert *store.User im Request-Context.
|
||
→ Fehler: Redirect zu /login?next=<Pfad>
|
||
│
|
||
├─► RequireAdmin Prueft user.Role == "admin"
|
||
│ → Fehler: 403 Forbidden
|
||
│
|
||
└─► RequireTenant Prueft user.TenantSlug == {tenantSlug} aus dem URL-Pfad.
|
||
Access Admins duerfen immer durch.
|
||
→ Fehler: 403 Forbidden
|
||
```
|
||
|
||
### Route-Gruppen im Router
|
||
|
||
| Gruppe | Middleware | Beispielrouten |
|
||
|----------------|------------------------------------|---------------------------------------------|
|
||
| Oeffentlich | keine | `/healthz`, `/login`, `/api/v1/screens/register` |
|
||
| Auth-only | RequireAuth | `/manage/{screenSlug}/...` |
|
||
| Admin-only | RequireAuth + RequireAdmin | `/admin`, `/admin/screens/...` |
|
||
| Tenant-scoped | RequireAuth + RequireTenantAccess | `/tenant/{tenantSlug}/...`, `/api/v1/tenants/{tenantSlug}/...` |
|
||
|
||
Der Hilfsfunktion `chain(middlewares...)` in `router.go` wrappet Handler von aussen nach innen.
|
||
|
||
---
|
||
|
||
## Tenant-Dashboard
|
||
|
||
Das Tenant-Self-Service-Dashboard ist unter `/tenant/{tenantSlug}/dashboard` erreichbar.
|
||
|
||
### URL-Schema
|
||
|
||
| Methode | Pfad | Beschreibung |
|
||
|---------|---------------------------------------------|---------------------------|
|
||
| GET | `/tenant/{tenantSlug}/dashboard` | Dashboard rendern |
|
||
| POST | `/tenant/{tenantSlug}/upload` | Medium hochladen |
|
||
| POST | `/tenant/{tenantSlug}/media/{mediaId}/delete` | Medium loeschen |
|
||
|
||
### Tabs
|
||
|
||
- **Tab A – Meine Monitore:** Zeigt Screen-Karten mit Live-Status. Der Status wird per JavaScript
|
||
aus `GET /api/v1/screens/status` geladen und alle 30 Sekunden aktualisiert.
|
||
Status-Badge: `is-success` (online), `is-danger` (offline), `is-warning` (unbekannt).
|
||
- **Tab B – Mediathek:** Upload-Formular (Bild, Video, PDF oder Web-URL) und Dateiliste
|
||
mit Loeschen-Button. Nach Upload oder Loeschen Redirect mit `?tab=media&flash=uploaded/deleted`.
|
||
|
||
### Eigentuemer-Pruefung beim Loeschen
|
||
|
||
`HandleTenantDeleteMedia` prueft, dass `asset.TenantID == tenant.ID`, bevor es loescht.
|
||
Damit ist sichergestellt, dass ein Tenant keine Assets anderer Tenants loeschen kann,
|
||
selbst wenn er die `mediaId` erraten wuerde.
|
||
|
||
---
|
||
|
||
## Sicherheitsgrundsaetze
|
||
|
||
- Root-Bootstrap-Geheimnisse nur kurzlebig oder referenziert speichern
|
||
- API- und MQTT-Zugaenge getrennt behandeln
|
||
- alle Admin-Kommandos auditieren
|
||
- Tenant-Trennung strikt serverseitig erzwingen
|
||
|
||
## API-Fehlermodell
|
||
|
||
Vor Implementierungsbeginn gilt ein einheitlicher Fehlerumschlag.
|
||
|
||
Empfehlung:
|
||
|
||
```json
|
||
{
|
||
"error": {
|
||
"code": "screen_not_found",
|
||
"message": "Screen existiert nicht",
|
||
"details": null
|
||
}
|
||
}
|
||
```
|
||
|
||
## Zielstruktur im Repo
|
||
|
||
Empfohlene Unterstruktur fuer den Server:
|
||
|
||
- `server/backend/`
|
||
- `server/admin-ui/`
|
||
- `server/tenant-ui/`
|
||
- `server/worker/`
|
||
- `compose/`
|
||
|
||
## Testfaelle fuer den Server
|
||
|
||
- Tenant sieht nur eigene Daten
|
||
- Admin sieht alle Daten
|
||
- Kampagne ueberschreibt tenantbezogenen Content korrekt
|
||
- Screen-Provisionierung legt Job sauber an
|
||
- Player-Sync ueber Revisionen funktioniert
|
||
- MQTT-Kommandos werden protokolliert
|
||
- Screenshot-Upload erscheint im Admin-Dashboard
|