- AGENTS.md: neue Pflichtregel 'Ton in Fehlerabschnitten' (Tabelle Meldung|Bedeutung|Vorgehen; verbotene Muster + Ersatzformen) - anwender/*: 12 Seiten umgeschrieben - 'Wenn etwas schiefgeht'/'Wenn nicht alles klappt' -> 'Fehler'-Tabellen; 'bitte deine Betreuung/Teamleitung' -> konkrete Instanz mit Link; 'Zeichen fuer Zeichen', 'hoechstens drei Versuche', 'statt weiter zu raten' entfernt - hilfe.md komplett neu: Fehleruebersicht + Zustaendigkeiten als Tabellen (Titel 'Hilfe bei Stoerungen') - admin/ki-funktionen: Produkt-Zitat als solches belassen; projekt/audit-backup, sammlungen-anlegen, llm-nutzen entbelehrt - Belege nachgezogen: upload.maxBodySize/allowedMimeTypes, Konflikt = Unique-Index (409/500), Passwort-Reset in der Benutzerverwaltung - Build 71 Seiten gruen, 0 tote Links/Tabellen
13 KiB
title, description
| title | description |
|---|---|
| Änderungen und Sicherung | Audit-Log lesen, Snapshots nutzen, Backup und Restore ausführen. |
import { Aside, Steps, Card, CardGrid } from '@astrojs/starlight/components';
Wer hat was geändert — und wie kommst du zurück? Drei Ebenen: Das Audit-Log protokolliert Änderungen, Snapshots frieren Datenstände ein, Backups sichern alles für den Ernstfall. Suchbegriffe: Änderungshistorie, Verlauf, Wiederherstellen, Snapshot, Datensicherung.
Protokolliert Änderungen — wer, wann, vorher/nachher. Frieren Datenstände im Ordner `snapshotPath` ein. Voll-Export als ZIP für Umzug und Ernstfall.Audit einschalten und lesen
Audit ist zweistufig: Es läuft nur, wenn Server und Projekt es erlauben.
audit:
enabled: true
| Ebene | Schalter | Standard |
|---|---|---|
| Server | audit.enabled, TTL audit.defaultTTL: 720h (30 Tage, "0" = ewig) |
Betreiber-Sache |
| Projekt | audit.enabled: true |
Starter: an |
| Sammlung | audit: { enabled, actions: [create, update, delete] } |
Standard-Aktionen: anlegen, ändern, löschen |
| Action | audit: { enabled, actions: [get, post] } |
Nur was du einschaltest |
- Etwas ändern (z. B. Seitentitel per
PUT). - Im tibi-admin die Änderungshistorie des Eintrags öffnen — wer, wann, vorher/nachher.
- Alte Fassung per Wiederherstellen zurückschreiben (erst an Testdaten üben).
- Per API lesen geht mit
GET /api/v1/audit(Rechtaudit.readnötig).
Verlauf im Admin
Du musst nicht per API lesen: Der Admin zeigt den Verlauf pro Eintrag (letzte 50 Änderungen mit Vorher/Nachher-Vergleich und Wiederherstellen einzelner Felder) sowie global als Audit-Log. Details zur Bedienung — Verlaufspanel, Diff-Ansicht, Wiederherstellen-Dialog, Seitenleiste — stehen unter Eintrags-Editor.
Snapshots
Snapshots sind eingefrorene Datenstände im Ordner snapshotPath (../snapshots im Starter):
snapshotPath: ../snapshots
snapshots:
- name: daily # 12:00 Uhr, redaktionelle Daten + Medien, 14 Stück
schedule: "0 12 * * *"
collections: [content, navigation, tags, medialib, ssr]
includeMedia: true
retention: { maxCount: 14 }
- name: full-daily
schedule: "0 3 * * *" # 03:00 Uhr, alles + Medien, 14 Stück
includeMedia: true
retention: { maxCount: 14 }
- name: full-weekly # sonntags 05:00 Uhr, 12 Stück
schedule: "0 5 * * 0"
collections: [] # leer = alle Sammlungen
includeMedia: true
retention: { maxCount: 12 }
- name: full-monthly # monatlich, Langzeitarchiv, 12 Stück
schedule: "0 6 1 * *"
collections: []
includeMedia: true
retention: { maxCount: 12 }
| Regel | Bedeutung |
|---|---|
collections: [] (leer) |
Alle Sammlungen sichern |
| Liste mit Namen | Nur diese sichern (Medien nur mit includeMedia: true, per Hardlink) |
retention.maxCount |
Älteste fliegen automatisch raus |
| Speicherung | json (BSON-Extended-JSON auf Platte, Standard); db/both sind Zukunft |
Snapshot-Config-Felder
Alle Felder aus snapshot_config.go:11-58 — nur diese Namen verwenden:
| Feld | YAML-Name | Bedeutung |
|---|---|---|
| Name | name |
Eindeutige Profil-Kennung (Pflicht, sonst snapshot config: name is required) |
| Beschreibung | description |
Freitext, optional |
| Sammlungen | collections |
[] = alle; String-Kurzform "content" = include; Objektform {name, mode} (include oder exclude) — gemischt include + exclude ist ein Validierungsfehler |
| Medien | includeMedia |
Datei-Felder per Hardlink sichern (Standard: true) |
| Deduplizierung | collectionDedup |
SHA256-Dedup identischer Collection-Exporte über .store/collections/ per Hardlink — nur für große, selten geänderte Sammlungen |
| Modus | mode |
""/json = Platte (Standard, implementiert); db/both = MongoDB-$out-Kopie (Zukunft) — Medien immer Hardlink, egal welcher Modus |
| Aufbewahrung | retention: { maxCount, maxAge, maxSizeBytes } |
Auto-Prune-Regeln, alle optional |
| Zeitplan | schedule |
Cron-Ausdruck; leer = nur manuell per Trigger-API |
| Team-Rechte | permissions |
Liste reiner Berechtigungsnamen — Phase 2, aktuell gilt AllowSnapshots |
| An/Aus | enabled |
false = Scheduler überspringt das Profil; manueller Trigger geht trotzdem |
snapshots:
- name: redaktionell
description: "Täglich, ohne Systemdaten"
collections:
- content # Kurzform = include
- name: ssr # Objektform
mode: exclude
includeMedia: true
collectionDedup: false
mode: json
retention: { maxCount: 14, maxAge: "336h", maxSizeBytes: 10737418240 }
schedule: "0 12 * * *"
permissions: []
enabled: true
Snapshot-Routen
Alle Routen aus setup.go:436-495 (GET liest, POST löst aus, DELETE löscht):
| Methode | Pfad (hinter /api/v1/_/:project/_/admin) |
Zweck |
|---|---|---|
GET |
/snapshots/configs |
Alle Profile aus der Projekt-YAML lesen (AdminSnapshotConfigs) |
POST |
/snapshots/configs/:name/trigger |
Profil manuell auslösen — geht auch bei enabled: false |
GET |
/snapshots |
Alle Einträge auflisten (Scannt das entries-Verzeichnis) |
GET |
/snapshots/download/:file |
Datei-Download (vor :id registriert, damit download kein :id matcht) |
GET |
/snapshots/:id |
Einzelnen Eintrag ansehen |
DELETE |
/snapshots/:id |
Eintrag löschen |
POST |
/snapshots/:id/restore?merge=1&collections=a,b |
Zurückspielen (merge=1 = zusammenführen; collections = Auswahl) |
GET |
/snapshots/:id/download |
Eintrag als ZIP laden |
GET |
/snapshots/stats |
Belegung prüfen |
POST |
/snapshots/prune |
Retention-Aufräumen manuell anstoßen |
Im tibi-admin (/projects/:id/snapshots, drei Tabs):
| Tab | Was du tust |
|---|---|
| Configs | Profile ansehen |
| Entries | Auslösen (mit Fortschritt), herunterladen (ZIP), zurückspielen, löschen, aufräumen |
| Stats | Belegung prüfen |
Zum Zurückspielen braucht dein Token allowSnapshots: true.
Übe das Zurückspielen nur mit Testdaten — es überschreibt den Live-Stand.
Backup-Routen
Alle Routen aus setup.go:398-432:
| Methode | Pfad (hinter /api/v1/_/:project/_/admin) |
Zweck |
|---|---|---|
GET |
/backup/analyze-download?collections=a,b |
Schätzung (Dokument-/Medien-Zahlen) ohne Voll-Export — vor dem Download prüfen |
GET |
/backup |
Voll-ZIP erzeugen und laden (?collections= schränkt ein, ?sse=1 streamt) |
GET |
/backup/download/:file |
Fertiges Temp-ZIP aus dem SSE-Modus laden (One-Time-Use: zweiter Request = 404) |
POST |
/backup?sse=1 |
ZIP hochladen und analysieren → antwortet mit restoreToken |
POST |
/backup/:restoreToken?collections=…&merge=true&sse=1 |
Restore aus dem analysierten Temp-Verzeichnis ausführen |
DELETE |
/backup/:restoreToken |
Temp-Daten zum Token manuell aufräumen |
Restore-Token-Lebenszyklus
POST /backup erzeugt Token plus Temp-Verzeichnis (admin_backup.go:204-234), POST /backup/:restoreToken verbraucht es, DELETE räumt auf.
- Analyse: ZIP per
POST /backuphochladen — Antwort enthältrestoreToken,sourceNamespace,createdAt,expiresAt(admin_backup.go:378-384). Mit?sse=1kommt der Fortschritt als Stream (init→done, jeweils mitrestoreToken). - Prüfen:
collections-Analyse in der Antwort lesen (Quelle gegen Ziel abgleichen, ggf.?collections=für Teil-Restore vormerken). - Restore:
POST /backup/:restoreTokenausführen — bei Erfolg landetrestoredCollections/totalDocuments/mediaFilesin der Antwort, alles wird als Audit-Actionbackup/restoreprotokolliert. Danach ist das Token verbraucht (Eintrag wird vor dem Restore aus dem Store entfernt). - Cleanup: Läuft der Restore ohne
sse, löscht der Server das Temp-Verzeichnis selbst (os.RemoveAll). Bei Abbruch oder abgelaufenem Token perDELETE /backup/:restoreTokenaufräumen — Antwort404 restore token not found or already cleaned upheißt: schon weg. Abgelaufene Tokens räumt zusätzlich ein Hintergrund-Job weg.
Rechte und Auth-Reihenfolge
| Ebene | Schalter | Beleg |
|---|---|---|
| Server-Token | Scope project.backup / project.snapshot (scope.go:53-55) |
X-Admin-Token oder Authorization: Bearer |
| Projekt-Token | allowBackup / allowSnapshots in der Projekt-Config (project.go:118-120) |
Nur mit passendem Flag |
| JWT-Login | Rolle AdminRole plus Scope-Check (EnforceScope) |
Persönliche Tokens bleiben durch ihre Scopes begrenzt |
Der Check läuft in admin_auth.go:20-74 immer in dieser Reihenfolge:
- Server-Token mit passendem Scope (
config.GetAdminTokenInfo). - Projekt-Token mit passendem Flag (
AllowBackup/AllowSnapshotsperConstantTimeCompare). - JWT-Login mit Admin-Rolle plus Scope-Prüfung — sonst
403 permission denied.
Backup und Restore
Backups sind der Voll-Export für Umzug und Desaster-Fall — im Admin unter /projects/:id/backup:
- Export-Tab: Sammlungen wählen (Kopf-Kästchen = alle), „Start backup“ klicken, Fortschritt abwarten, Datei mit Größenangabe laden.
- Bricht der Download ab: erst Analyse (
backup/analyze-download), dann neu laden. - Import-Tab: ZIP in die Zone ziehen, Analyse lesen, Restore bestätigen.
- Danach: Reload und SSR-Cache prüfen, Seite anonym aufrufen.
| Unterschied | Snapshot | Backup |
|---|---|---|
| Wofür | Schneller Rücksprung im Alltag | Umzug, Desaster, Weitergabe |
| Wo | snapshotPath auf dem Server |
ZIP-Datei bei dir |
| Recht | allowSnapshots |
Projekt-Admin plus AllowBackup |
| Fortschritt | Ja (Stream) | Ja (SSE-Stream) |
Fehler
| Fehlerbild | Ursache | Lösung |
|---|---|---|
| Audit bleibt leer | audit.enabled im Projekt fehlt oder Server-Flag aus |
Beide Schalter prüfen, Änderung erneut auslösen |
| Alte Einträge verschwinden | TTL (720h) abgelaufen |
Wichtige Stände als Snapshot sichern, TTL ggf. auf "0" |
| Snapshot-Button fehlt | Token ohne allowSnapshots |
Flag allowSnapshots am Projekt-Token setzen (siehe Rechte und Auth-Reihenfolge) |
| Backup-Button fehlt | Kein Projekt-Admin oder AllowBackup fehlt |
Projekt-Admin-Rolle bzw. Flag AllowBackup am Projekt-Token prüfen (siehe Rechte und Auth-Reihenfolge) |
400 missing restoreToken |
Restore ohne Token aufgerufen | Erst POST /backup (Analyse), Token aus der Antwort nehmen |
404 restore token not found or expired |
Token verbraucht, aufgeräumt oder TTL abgelaufen | Analyse erneut hochladen, neues Token holen |
403 invalid entry id / 404 snapshot not found |
Snapshot-Restore mit falscher/gelöschter ID | ID aus GET /snapshots neu lesen |
snapshot config: name is required |
Profil ohne name |
name in der YAML ergänzen |
| Restore zeigt keine Wirkung | Cache alt | Reload plus ?clear=1 (siehe Veröffentlichen) |
Wie ein Redakteur eine Sicherung einspielt: Backup einspielen.
Verifiziert am e3f92eb 2026-10-17 (tibi-svelte-starter, config.yml audit- und snapshots-Blöcke), am 68b4278 2026-10-17 (tibi-server, audit-, backup- und snapshot-docs), am 2b091d8 2026-10-17 (tibi-admin-nova, test-pläne 43 und 44, AuditView, AuditHistoryPanel, AuditDiff, AuditRestoreDialog, AuditSidebarHistory)