Audit + Umbau: Faktenfehler behoben, Server-/Admin-Lücken geschlossen, 49 Screenshots, Schema-Matrix generiert
- Audit: plans/doku-audit.md (Befunde, Phasen P1-P9, Ausführungsprotokoll) + plans/audit/ (8 Detailreports) + plans/offene-issues.md - Werkzeuge: scripts/audit-docs.mjs (Links/Anker/Bilder/Tabellen), scripts/gen-schema-matrix.mjs (npm run gen:schemas) - Neue Seiten: projekt/feld-rechte, reference/rest-system, reference/schema-properties, projekt/tests, 5 Anwender-Seiten - Fehler behoben: EMBEDDING_BGE_M3_*-Env, allowSnapshots, MCP-Scopes (.read/.create/.update), meta.views, loadAll-Signatur, OpenAPI-Endpunkt, MongoDB 8, Befehlspalette - Screenshots: 9 Admin + 10 Anwender aus Mock-Projekt corporate (t1 entfernt), 49 Bilder gesamt - AGENTS.md: Sync-Behauptung richtiggestellt, Belegpflicht/UI-Namen/Screenshot-Regeln, Werkzeug-Abschnitt - Build: 71 Seiten grün, 0 tote Links, 0 kaputte Tabellen
This commit is contained in:
1 parent
1897bb50d9
commit
1928922e07
104 files changed
+4756
-1044
No files matched your search
@@ -47,15 +47,7 @@ Die Sammlung `ssr` (Cache) ist bewusst ausgenommen (`enabled: false`).
|
||||
|
||||
## Verlauf im Admin
|
||||
|
||||
Du musst nicht per API lesen: Der Admin zeigt den Verlauf an zwei Stellen — pro Eintrag im Editor und global als „Audit-Log“ (`/admin/audit` bzw. `/projects/:id/audit`, mit Filtern für Projekt, Collection, Aktion und Benutzer, 25 Zeilen pro Seite).
|
||||
|
||||
**Verlaufspanel pro Eintrag.** Im Editor lädt das Panel die letzten 50 Änderungen dieses Datensatzes, neueste zuerst. Jede Zeile zeigt Zeit, Aktion („erstellt“, „geändert“, „gelöscht“), Person und Quelle; bei „geändert“ steht zusätzlich, welche Felder betroffen sind. Ein Pfeil klappt die Zeile auf und zeigt den Vorher/Nachher-Vergleich. Bei „geändert“ und „gelöscht“ erscheint — nur mit Schreibrecht — der Schalter „Wiederherstellen“, der den alten Stand ins Formular übernimmt (danach noch speichern).
|
||||
|
||||
**Diff-Ansicht.** Jeder Vergleich zeigt pro Feld eine Karte mit Status-Badge: „hinzugefügt“, „entfernt“ oder „geändert“. Geänderte Texte stehen als „Vorher“ und „Nachher“ nebeneinander, bei kurzen Texten sind einzelne Wörter markiert. Lange Werte sind eingeklappt und lassen sich per Pfeil ganz aufklappen; jeder Wert hat einen Kopieren-Schalter. Feldnamen kommen aus der Sammlungs-Definition, der technische Pfad steht daneben. Gibt es nichts zu zeigen, meldet die Ansicht „Keine Änderungen“.
|
||||
|
||||
**Wiederherstellen-Dialog.** Der Dialog öffnet sich als seitliches Panel („Wiederherstellen“) und stellt „Aktuell“ (aus dem geöffneten Formular) und „Danach“ (aus dem Verlauf) gegenüber. Per Haken wählst du einzelne Felder aus — „Alle auswählen“ und „Keine“ helfen, der Zähler (z. B. 3 / 5) zeigt den Stand. Beachte den Hinweis „Media-Dateien werden nicht wiederhergestellt“. Bestätigen übernimmt die gewählten Felder ins Formular („Felder übernommen — bitte speichern“).
|
||||
|
||||
**Seitenleisten-Verlauf.** Unter dem Editor zeigt eine kompakte Liste die letzten 10 Änderungen mit Zeit, Aktion und Person. Sie blendet sich bei leerem Verlauf komplett aus — kein Titel, kein Hinweistext. Ein Klick auf eine Zeile öffnet den vollen Vergleich, bei mehr als 10 Einträgen führt „Ältere Einträge“ zur Gesamtansicht. Nach dem Speichern lädt die Liste automatisch neu.
|
||||
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](/admin/eintrags-editor/).
|
||||
|
||||
## Snapshots
|
||||
|
||||
@@ -92,8 +84,59 @@ snapshots:
|
||||
| `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 |
|
||||
|
||||
```yaml title="Snapshot-Profil — alle Felder (Beispiel)"
|
||||
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 |
|
||||
|
||||
<Aside type="caution" title="Typo im Starter: tags statt tag">
|
||||
Das `daily`-Profil oben ist vereinfacht aus der Starter-`config.yml` abgeschrieben (`description`/`enabled` weggelassen) — aber der Name `tags` darin steht wirklich so im Starter, obwohl die Sammlung `tag` heißt (siehe `api/collections/tag.yml`, `name: tag`). Übernimm die Liste nicht blind: prüfe jeden Namen gegen deine `api/collections/*.yml`, sonst sichert das Profil eine Sammlung, die es nicht gibt.
|
||||
Das `daily`-Profil oben ist vereinfacht aus der Starter-`config.yml` abgeschrieben (`description`/`enabled` weggelassen) — aber der Name `tags` darin steht wirklich so im Starter, obwohl die Sammlung `tag` heißt (siehe `api/collections/tag.yml`, `name: tag`). Prüfe jeden Namen gegen deine `api/collections/*.yml`, bevor du das Profil übernimmst — sonst sichert das Profil eine Sammlung, die es nicht gibt.
|
||||
</Aside>
|
||||
|
||||
Im **tibi-admin** (`/projects/:id/snapshots`, drei Tabs):
|
||||
@@ -104,9 +147,57 @@ Im **tibi-admin** (`/projects/:id/snapshots`, drei Tabs):
|
||||
| Entries | Auslösen (mit Fortschritt), herunterladen (ZIP), zurückspielen, löschen, aufräumen |
|
||||
| Stats | Belegung prüfen |
|
||||
|
||||
Zum Zurückspielen braucht dein Token `AllowSnapshot: true`.
|
||||
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.
|
||||
|
||||
<Steps>
|
||||
|
||||
1. **Analyse:** ZIP per `POST /backup` hochladen — Antwort enthält `restoreToken`, `sourceNamespace`, `createdAt`, `expiresAt` (`admin_backup.go:378-384`). Mit `?sse=1` kommt der Fortschritt als Stream (`init` → `done`, jeweils mit `restoreToken`).
|
||||
2. **Prüfen:** `collections`-Analyse in der Antwort lesen (Quelle gegen Ziel abgleichen, ggf. `?collections=` für Teil-Restore vormerken).
|
||||
3. **Restore:** `POST /backup/:restoreToken` ausführen — bei Erfolg landet `restoredCollections`/`totalDocuments`/`mediaFiles` in der Antwort, alles wird als Audit-Action `backup/restore` protokolliert. Danach ist das Token **verbraucht** (Eintrag wird vor dem Restore aus dem Store entfernt).
|
||||
4. **Cleanup:** Läuft der Restore ohne `sse`, löscht der Server das Temp-Verzeichnis selbst (`os.RemoveAll`). Bei Abbruch oder abgelaufenem Token per `DELETE /backup/:restoreToken` aufräumen — Antwort `404 restore token not found or already cleaned up` heißt: schon weg. Abgelaufene Tokens räumt zusätzlich ein Hintergrund-Job weg.
|
||||
|
||||
</Steps>
|
||||
|
||||
### 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**:
|
||||
|
||||
<Steps>
|
||||
|
||||
1. Server-Token mit passendem Scope (`config.GetAdminTokenInfo`).
|
||||
2. Projekt-Token mit passendem Flag (`AllowBackup` / `AllowSnapshots` per `ConstantTimeCompare`).
|
||||
3. JWT-Login mit Admin-Rolle plus Scope-Prüfung — sonst `403 permission denied`.
|
||||
|
||||
</Steps>
|
||||
|
||||
<Aside type="caution">
|
||||
Fehlt am Token das richtige Flag, antwortet der Endpunkt mit `403` — auch wenn du Projekt-Admin bist. `permissions: []` im Snapshot-Profil hilft dir heute nicht weiter (Phase 2); maßgeblich ist `allowSnapshots` am Token.
|
||||
</Aside>
|
||||
|
||||
## Backup und Restore (mit Betreiber)
|
||||
|
||||
Backups sind der Voll-Export für Umzug und Desaster-Fall — im Admin unter `/projects/:id/backup`:
|
||||
@@ -124,7 +215,7 @@ Backups sind der Voll-Export für Umzug und Desaster-Fall — im Admin unter `/p
|
||||
|---|---|---|
|
||||
| Wofür | Schneller Rücksprung im Alltag | Umzug, Desaster, Weitergabe |
|
||||
| Wo | `snapshotPath` auf dem Server | ZIP-Datei bei dir |
|
||||
| Recht | `AllowSnapshot` | Projekt-Admin plus `AllowBackup` |
|
||||
| Recht | `allowSnapshots` | Projekt-Admin plus `AllowBackup` |
|
||||
| Fortschritt | Ja (Stream) | Ja (SSE-Stream) |
|
||||
|
||||
<Aside type="caution">
|
||||
@@ -138,8 +229,14 @@ Fortschritt läuft als Stream (`text/event-stream`) — bei Abbrüchen nichts do
|
||||
|---|---|---|
|
||||
| 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 `AllowSnapshot` | Betreiber um Recht bitten |
|
||||
| Snapshot-Button fehlt | Token ohne `allowSnapshots` | Betreiber um Recht bitten |
|
||||
| Backup-Button fehlt | Kein Projekt-Admin oder `AllowBackup` fehlt | Betreiber um Recht bitten |
|
||||
| `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](/projekt/deploy/)) |
|
||||
|
||||
Verifiziert am e3f92eb 2026-10-14 (tibi-svelte-starter, config.yml audit- und snapshots-Blöcke), am 68b42785 2026-10-15 (tibi-server, audit-, backup- und snapshot-docs), am 2b091d89 2026-10-13 (tibi-admin-nova, test-pläne 43 und 44), am 2b091d89 2026-10-13 (tibi-admin-nova, AuditView, AuditHistoryPanel, AuditDiff, AuditRestoreDialog, AuditSidebarHistory).
|
||||
Wie ein Redakteur eine Sicherung einspielt: [Backup einspielen](/anwender/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)
|
||||
Reference in new issue
Block a user