Doku-Vollausbau: 62 Seiten (Projekt/Admin/Anwender/Referenz), Hook-Referenz mit Signaturen, Corporate-Screenshots, Coverage-Inventar
Deploy tibi-docs / build-and-deploy (push) Failing after 38s
Deploy tibi-docs / build-and-deploy (push) Failing after 38s
- Einstieg: Schnellstart + Neues Projekt aus Starter-Skill, Was-ist-Tibi mit Backend/Website-Trennung - Projekt: Sammlungen, Felder, Abfragen, Rechte, Hooks, Dateien, i18n, Suche, SSR, Pagebuilder, Jobs, Audit, Deploy, LLM, MCP - Hook-Referenz: 66 Symbole mit Signatur + Beispiel + Fehlerfall (5 Kapitel) - Admin: Ansichten, Editor, Medien, Exporte, Aktionen, Rechte, KI, Setup, Customizing - Anwender: 11 Anleitungen im professionellen Du-Ton, 30 Corporate-Screenshots - Referenz: Schemas, Token-Köpfe, Fehlerbilder, Shortcuts, OpenAPI-Platzhalter - ADR-0001 bis 0003, Coverage-Skript (282 Items) + Map, Plan-Dateien
This commit is contained in:
1 parent
acb1d32355
commit
1897bb50d9
101 files changed
+8980
-68
No files matched your search
@@ -0,0 +1,91 @@
|
||||
---
|
||||
title: 'Aktionen'
|
||||
description: 'Actions im Admin starten: Parameter ausfüllen, ausführen, Ausgabe und Fortschritt lesen.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge, FileTree } from '@astrojs/starlight/components';
|
||||
|
||||
Du stößt im **tibi-admin** (Verwaltungs-Backend, Release Nova) eine **Action** an — z. B. Versand, Import oder Aufräum-Job. Du füllst Parameter aus, klickst Ausführen und liest das Ergebnis. Diese Seite beschreibt die Bedienung — das Schreiben von Actions steht unter [Jobs und Actions](/projekt/jobs-actions/).
|
||||
|
||||
## Starten
|
||||
|
||||
<Steps>
|
||||
|
||||
1. Projekt öffnen, Sammlung **Actions** (Seitenleiste) wählen.
|
||||
2. Action anklicken — Route `/projects/:projekt/actions/:name`.
|
||||
3. Methode per Reiter wählen (`GET` oder `POST`; die Wahl steht auch als `?method=` in der URL).
|
||||
4. Formular ausfüllen, **Ausführen** klicken.
|
||||
5. Ergebnis unterhalb lesen (Karte „Letztes Ergebnis“).
|
||||
|
||||
</Steps>
|
||||
|
||||
| Element | Verhalten |
|
||||
|---|---|
|
||||
| Methoden-Reiter | Nur `GET`/`POST` sind ausführbar (`runnableMethods` in `ActionView.svelte`); `PUT`/`DELETE` erscheinen höchstens als Ansicht, nicht als Startknopf |
|
||||
| Ausführen-Knopf | Aktiv nur bei Startrecht **und** gültigem Formular; während der Ausführung dreht sich das Icon und der Knopf ist gesperrt |
|
||||
| Upload-Toast | Enthält die Eingabe Datei-Bytes, zeigt der Admin einen Byte-Fortschritt (`upload-progress`) |
|
||||
| Verlauf | Werkzeug-Menü (Schild-Icon) → Audit mit Filter `collection=_actions/<name>` |
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): Action-Ansicht mit Methoden-Reitern, Eingabeformular und Ausführen-Knopf. -->
|
||||
|
||||
## Parameter
|
||||
|
||||
Das Formular (`ActionMethodScaffold.svelte`) trennt zwei Blöcke:
|
||||
|
||||
<Badge text="query" variant="note" /> <Badge text="data" variant="tip" />
|
||||
|
||||
| Block | Wohin gesendet |
|
||||
|---|---|
|
||||
| Abfrage-Felder (`query`) | Query-String der Action-URL (`?feld=wert`; Arrays wiederholt) |
|
||||
| Daten-Felder (`data`) | JSON-Body (`POST`/`PUT`); bei `GET` kein Body |
|
||||
|
||||
- Felder kommen aus `action.meta.methods.<methode>.query.fields` bzw. `data.fields` und nutzen dieselben [Widgets](/admin/eintrags-editor/) wie der Editor (inklusive `dependsOn`-Sichtbarkeit).
|
||||
- Validierung läuft live: Fehler erscheinen nach Verlassen des Felds (`blur`), der Knopf bleibt bis zur Korrektur gesperrt und nennt die Fehlerzahl.
|
||||
- **Technische Vorschau** (aufklappbar unter dem Formular) zeigt das exakte Payload-JSON `{ query, data }`.
|
||||
- Server-Aufruf: `POST /api/v1/<namespace>/_actions/<name>?…` mit Sitzungs-Kopf `X-Auth-Token` (siehe [Token-Köpfe](/reference/token-koepfe/)).
|
||||
|
||||
## Ausgabe und Fortschritt
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Kurfassung und Details">
|
||||
|
||||
`ActionOutputMapping.svelte` zeigt gemappte Felder statt Roh-JSON:
|
||||
|
||||
- **Kurzfassung** (`output.mapping.summary.fields`) — immer sichtbar, Werte per `source`-Pfad aus dem Ergebnis gelesen (`deepGet`, z. B. `totals.grandTotal`).
|
||||
- **Details** (`output.mapping.details.fields`) — aufklappbar, als Widgets gerendert.
|
||||
- Ohne Mapping zeigt der Admin das Ergebnis als formatiertes JSON; kennt die Methode nur einen Titel ohne Felder, steht dort „keine Ausgabefelder“.
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Fortschritt (SSE)">
|
||||
|
||||
Liefert die Action Live-Events (`Content-Type: text/event-stream`), zeigt `ActionProgressMapping.svelte`:
|
||||
|
||||
- Balken aus `index` / `count` (`index/count × 100`, sonst Prozent oder Zählertext).
|
||||
- Status- und Meldungstext aus `progress.statusField` / `progress.messageField`.
|
||||
- Optionale Zusatzfelder (`progress.fields`) aus jedem Event.
|
||||
|
||||
<Aside type="note">Ohne `output.mapping.progress` in der Action-Meta gibt es bewusst **keinen** Balken — ein 0-%-Balken bei jeder alten Action wäre irreführend. Dann bleibt JSON das Ergebnis.</Aside>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
```text title="Action-Ablauf im Überblick"
|
||||
Formular (query + data) → Ausführen → [SSE-Events → Balken] → Ergebnis (Mapping oder JSON)
|
||||
└─ Verlauf: Audit mit _actions/<name>
|
||||
```
|
||||
|
||||
## Rechte und Fehler
|
||||
|
||||
| Fehlerbild | Ursache | Lösung |
|
||||
|---|---|---|
|
||||
| Kein Startknopf / „gesperrt“ | Methode nicht in deinen Rechten (`project.yourPermissions._actions.<name>`: `get`/`post`-Flag fehlt) | Rechte unter [Rechte und Tokens](/projekt/rechte-tokens/) klären |
|
||||
| Formularfehler genannt | Pflicht-/Formatfehler im Eingabeblock | Felder korrigieren — die Vorschau zeigt, was gesendet würde |
|
||||
| Servertext im roten Kasten | Hook oder Server meldet fachlichen Fehler | Meldung wörtlich nehmen (der Admin reicht sie durch) |
|
||||
| `permission` / `not found` | Falscher Kopf oder Action gelöscht | [Token-Köpfe](/reference/token-koepfe/) und Action-Namen prüfen |
|
||||
| Netzwerkfehler | Server nicht erreichbar | [Admin einrichten](/admin/setup/) prüfen, erneut versuchen |
|
||||
|
||||
<Aside type="caution">Actions können Daten ändern. Starte eine unbekannte Action erst in einer Testumgebung — der Verlauf (`_actions/<name>` im Audit) zeigt nur, was bereits lief.</Aside>
|
||||
|
||||
Klick-Abläufe dazu stehen im Test-Plan `docs/test-plans/40-actions.md` (Methoden-Tabs, ausführbar vs. gesperrt, Ergebnis und Fortschritt).
|
||||
|
||||
Verifiziert am 2b091d899590b392491c59a54f50de43f1057280 2026-10-16 (tibi-admin-nova)
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: 'Ansichten und Listen'
|
||||
description: 'Tabellen-, Karten-, Medien- und Navigations-Ansichten, Suche, Sortierung, Filter, Blättern.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge } from '@astrojs/starlight/components';
|
||||
|
||||
Du öffnest eine Sammlung im **tibi-admin** (Verwaltungs-Backend, Release Nova) und siehst eine Liste aller Einträge. Suche, Sortierung, Filter und Blättern funktionieren in allen Ansichten gleich. Diese Seite beschreibt die Bedienung aus Redakteurs- und Projekt-Sicht — Konzept und Einordnung stehen unter [Admin-Konzept](/admin/konzept/).
|
||||
|
||||
## Ansichtsarten
|
||||
|
||||
Die Sammlung schlägt ihre Startansicht über `meta.viewHint` vor (Details: [Sammlungen anlegen](/projekt/sammlungen-anlegen/)). Du wechselst die Ansicht jederzeit per Ansichtswähler — deine Wahl landet im URL-Parameter `view`.
|
||||
|
||||
<Badge text="table" variant="note" /> <Badge text="cards" variant="tip" /> <Badge text="media" variant="note" /> <Badge text="navigation" variant="note" />
|
||||
|
||||
| Ansicht | `viewHint` | Wofür |
|
||||
|---|---|---|
|
||||
| Tabelle | — (Standard) | Viele Einträge vergleichen, Spalten sortieren, Mehrfachauswahl |
|
||||
| Karten | `cards` | Vorschau mit Bild, Titel und Zusatzzeilen (`meta.preview`: `label`, `secondary`, `tertiary`, `image`) |
|
||||
| Medien | `viewHint.media` | Raster mit Drag-and-drop-Upload direkt über dem Raster (siehe [Medien](/admin/medien/)) |
|
||||
| Navigation | `viewHint.navigation` | Baumvorschau je Navigationsbaum (`nodesField`, `declaredTrees`) |
|
||||
|
||||
<Aside type="note">
|
||||
`viewHint` ist nur der Startwert. Sobald `view=…` in der URL steht, gilt deine Wahl — auch nach Neuladen.
|
||||
</Aside>
|
||||
|
||||
Die Tabelle zeigt die Spalten aus `preview.table` oder erkennt sie automatisch aus den Feldern. Ein Klick auf einen Spaltenkopf sortiert auf- oder absteigend. Systemfelder der Eintrags-Übersetzung (`translationKey`, `lang`) blendet die Tabelle in der Kopfzeile aus — sie bleiben über die [Übersetzungsleiste](/admin/eintrags-editor/) erreichbar.
|
||||
|
||||
### Unter-Navigation
|
||||
|
||||
Manche Sammlungen haben Reiter über der Liste (`meta.subNavigation`, z. B. `?sub=published`). Jeder Reiter hat eigenen Filter, eigene Standardsortierung und eigene Trefferzahl (parallele `/_count`-Aufrufe). Die aktive Auswahl steht im URL-Parameter `sub`.
|
||||
|
||||
## Suchen, Sortieren, Filtern
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Suche">
|
||||
|
||||
- Suchfeld oben über der Liste, entprellt während der Eingabe.
|
||||
- Bei laufender Suche gilt **Relevanz-Sortierung**: eine manuell gewählte Sortierung wird verworfen, der Server rankt nach Trefferqualität. Du kannst danach erneut sortieren.
|
||||
- Hat die Sammlung mehrere Suchmodi (`collection.search[].meta`), wählst du den Modus am Suchfeld. Wechsel-Tastenkürzel: `Strg + Umschalt + F`.
|
||||
- Die Trefferzahl für Filter-Warnungen (z. B. vor [Exporten](/admin/exporte/)) kommt aus der `/_count`-Route, nicht aus der geladenen Seite.
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Sortierung">
|
||||
|
||||
- Spaltenkopf anklicken oder Sortier-Popover öffnen (`o`-Taste).
|
||||
- Standard ohne Auswahl: Feld `updateTime`, absteigend — oder `meta.defaultSort` der Sammlung bzw. des aktiven Reiters.
|
||||
- Bei Suche ohne manuelle Sortierung entfällt `sort` in Anfrage und URL (Relevanz).
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Filter">
|
||||
|
||||
- Filter-Popover öffnen (`f`-Taste). Zurücksetzen: `x`-Taste.
|
||||
- Filterbare Felder meldet das Schema per `meta.filter` an — inklusive Unterfelder von Objekten, die sich per `meta.filter` anmelden.
|
||||
- Ausgeschlossen sind standardmäßig: Fremd-Medien-Widgets (`foreignMedia`, `foreignFile` u. ä.), native Datei-Felder und reine Objekt-Kästen ohne angemeldete Unterfelder.
|
||||
- Fremdschlüssel-Felder bieten eine Auswahl mit Suche statt Freitext.
|
||||
- Die Vorschläge für Auswahlwerte (`_facet`-Route) liefern je Wert die Trefferzahl mit.
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Blättern">
|
||||
|
||||
- Fußzeile mit Seitenzahlen, Ellipsen bei vielen Seiten und Anzeige „Eintrag X–Y von Z“.
|
||||
- Seitengröße umschaltbar (Standard 25). Tastatur: `[` / `]` für vor/zurück, `p` + Ziffer für direkte Seite, `p` + `0` wechselt die Seitengröße.
|
||||
- Die Gesamtzahl lädt der Admin über `GET …/<sammlung>/_count` — Details zu den Routen stehen unter [Lesen und suchen](/projekt/abfragen-lesen/).
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Mehrfachauswahl und Tastatur
|
||||
|
||||
- Auswahl per Checkbox, `Leertaste` oder `a` (alle umschalten). Pfeiltasten bewegen den Fokus, `Enter` öffnet den Eintrag.
|
||||
- Mit Auswahl öffnest du die Massenbearbeitung (`e`-Taste: Werte setzen, Bedingungen prüfen, Vorschau) oder das Löschen mit Referenzen-Prüfung.
|
||||
- Neue Einträge: `n`-Taste. Befehlspalette und Feldsuche im Editor stehen unter [Eintrags-Editor](/admin/eintrags-editor/).
|
||||
|
||||
```text title="URL-State einer Liste"
|
||||
# URL-State einer Liste — kopierbar und teilbar
|
||||
/content?view=cards&q=hero&qm=combined&sort=name&order=asc&page=2&size=25&sub=published&f_lang=de
|
||||
```
|
||||
|
||||
| Parameter | Bedeutung | Standard |
|
||||
|---|---|---|
|
||||
| `q` | Suchtext | leer (keine Suche) |
|
||||
| `qm` | Suchmodus (`qName` aus dem `search`-Block der Sammlung) | Standard-Modus |
|
||||
| `sort` / `order` | Sortierfeld und -richtung | `updateTime` / `desc` (oder `meta.defaultSort`) |
|
||||
| `page` / `size` | Seite und Seitengröße | `1` / `25` |
|
||||
| `view` | `table`, `cards`, `media`, `navigation` | `table` |
|
||||
| `sub` | Aktiver Unter-Reiter | keiner |
|
||||
| `f_*` | Feld-Filter, z. B. `f_lang=de` (Objekte als JSON) | keine |
|
||||
|
||||
<Aside type="tip">
|
||||
Teile eine gefilterte Liste per URL — Empfänger sehen exakt dieselbe Auswahl, weil der Zustand vollständig in der Adresse steht.
|
||||
</Aside>
|
||||
|
||||
## Häufige Fehler
|
||||
|
||||
| Fehlerbild | Ursache | Lösung |
|
||||
|---|---|---|
|
||||
| Liste leer trotz Einträgen | Reiter-Filter (`sub`) oder Feld-Filter aktiv | `x` drücken oder Filter-Popover leeren |
|
||||
| Sortierung „springt zurück“ | Suche aktiv → Relevanz schlägt manuelle Sortierung | Suchtext leeren oder Sortierung nach der Suche erneut wählen |
|
||||
| Gesamtzahl fehlt oder lädt lange | `/_count` auf altem Server nicht verfügbar | Direkt laden lassen (Fallback) oder Server aktualisieren |
|
||||
| Ansicht startet „falsch“ | `viewHint` der Sammlung schlägt die Startansicht vor | Ansicht einmal wechseln — `view=…` in der URL gewinnt |
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): Listenansicht mit Suchfeld, Filter-Popover und Paginierung, Alt-Text deutsch, max. 200 KB unter src/assets/. -->
|
||||
|
||||
Verifiziert am 2b091d89 2026-10-13 (tibi-admin-nova)
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: 'Benutzer, Teams, Tokens'
|
||||
description: 'Anmelden, Personen, Teams und Orgs verwalten, Rollen und Berechtigungen, PATs, Stellvertretung.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge, FileTree } from '@astrojs/starlight/components';
|
||||
|
||||
Du verwaltest im **tibi-admin** (Verwaltungs-Backend, Release Nova), wer sich anmelden und was jede Person darf: Benutzerkonten, Teams, Organisationen, Rollen, persönliche Token (PATs) und die Stellvertretung. Server-Regeln dazu stehen unter [Rechte und Tokens](/projekt/rechte-tokens/), die vier HTTP-Köpfe unter [Token-Köpfe](/reference/token-koepfe/).
|
||||
|
||||
## Anmelden und Sitzung
|
||||
|
||||
<Steps>
|
||||
|
||||
1. Login-Seite öffnen (`LoginPage.svelte`): Benutzername und Passwort eingeben.
|
||||
2. Bei Erfolg legt der Admin ein JWT in den Store und plant die Auffrischung (`scheduleTokenRefresh`); danach landet du auf `/projects`.
|
||||
3. Bei Sitzungsende warnt `SessionTimeoutWarning.svelte`: **60-Sekunden-Countdown** mit Verlängern- oder Abmelden-Knopf — ohne Reaktion folgt die Abmeldung.
|
||||
4. Sprache (DE/EN) und Theme stellst du auf der Login-Karte um.
|
||||
|
||||
</Steps>
|
||||
|
||||
| Verhalten | Quelle |
|
||||
|---|---|
|
||||
| Fehlgeschlagener Login | Rote Fehlerbox, keine Weiterleitung |
|
||||
| Inaktivitäts-Timer | `utils/inactivityTracker` + Countdown-Dialog (`resetInactivityTimer`) |
|
||||
| Eigene Daten ändern | Profilseite („Mein Profil"): Name, E-Mail, Firma, Abteilung, Avatar, Passwort (min. 6 Zeichen, doppelt bestätigt) |
|
||||
|
||||
## Personen, Teams, Orgs
|
||||
|
||||
Die Kette lautet **Org → Team → Benutzer → Projekt**. Du pflegst sie im Admin-Hub (`components/admin/`):
|
||||
|
||||
| Ebene | Komponenten | Inhalt |
|
||||
|---|---|---|
|
||||
| Benutzer | `UserTab` (Liste mit Suche, Filter, Sortierung, Paginierung), `UserCreateDrawer`, `UserDetailDrawer` | Name, Login, Rolle, Org-/Team-Mitgliedschaften |
|
||||
| Teams | `TeamTab`, `TeamCreateDrawer`, `TeamDetailDrawer` | Name, Farbe, Org-Zugehörigkeit, Mitglieder, Berechtigungen |
|
||||
| Orgs | `OrgTab`, `OrgCreateDrawer`, `OrgDetailDrawer` | Name, Mitglieder (`OrgAssignmentSection`), Projekte |
|
||||
| Projekte | `ProjectAdminView`, `ProjectDetailDrawer`, `ProjectCreateDrawer` | Name, Status (online/offline), Org-Zuordnung, Rechte-Matrix |
|
||||
|
||||
<Steps>
|
||||
|
||||
1. Org anlegen (`OrgCreateDrawer`).
|
||||
2. Team in dieser Org anlegen (`TeamCreateDrawer`).
|
||||
3. Benutzer anlegen und Team zuordnen (`UserCreateDrawer`, Reiter Mitgliedschaften).
|
||||
4. Projekt der Org zuordnen und Team-Rechte setzen (`ProjectDetailDrawer`).
|
||||
|
||||
</Steps>
|
||||
|
||||
## Rollen und Chips
|
||||
|
||||
<Badge text="role: 0" variant="tip" /> <Badge text="role: 1" variant="note" />
|
||||
|
||||
| Rolle | Wert | Bedeutung |
|
||||
|---|---|---|
|
||||
| Admin | `role: 0` | Vollzugriff, violettes Badge (`RoleSection.svelte`) |
|
||||
| Benutzer | `role: 1` | Zugriff nur über Org-/Team-Mitgliedschaft, neutrales Badge |
|
||||
|
||||
- Die Rolle stellst du per Auswahl um (mit Admin-Warnung); im Nur-Lesen-Modus zeigt der Admin nur das Badge.
|
||||
- Feinrechte vergibst du als **Chips** (`PermissionChipsInput.svelte`): Eintippen, Vorschlag anklicken oder Entfernen per ×. Vorschläge kommen aus der Projekt-Meta (`project-meta`) oder als Team-Rückfall (`team-fallback`); Platzhalter-Beispiel: `pages, media`.
|
||||
|
||||
## Tokens
|
||||
|
||||
Persönliche Token (PATs) pflegst du auf zwei Wegen: im eigenen **Profil** (`TokenSettings.svelte`) oder als Admin im **Token-Reiter** (`TokenAdminTab.svelte`).
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Erstellen">
|
||||
|
||||
1. **Neu** klicken → `TokenFormDrawer`: Name plus Scopes per `TokenScopePicker` wählen.
|
||||
2. Speichern → `TokenCreatedDialog` zeigt den Wert **genau einmal** — kopiere ihn sofort, danach ist er weg.
|
||||
3. Bearbeiten ändert nur wirklich geänderte Felder (Name/Scopes als Patch).
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Verwerfen und Grenzen">
|
||||
|
||||
- Widerrufen per Löschen (`deleteToken` → Liste neu laden).
|
||||
- Antwortet der Server mit `404` auf die Token-Liste, blendet der Admin den Bereich still aus (Feature-Erkennung `isTokenFeatureDisabled`).
|
||||
- Aufrufe laufen mit deiner Login-Sitzung (`X-Auth-Token`-JWT via `fetchWithAuth`); Token-Verwaltung selbst braucht kein separates PAT.
|
||||
- **Während einer Stellvertretung ist die Token-Verwaltung gesperrt** (`disabled`, solange `impersonatedBy` gesetzt ist).
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Stellvertretung (Impersonation)
|
||||
|
||||
Admins können sich als ein Benutzerkonto anmelden, um dessen Sicht zu prüfen:
|
||||
|
||||
| Schritt | Technik (`api/auth.ts`) |
|
||||
|---|---|
|
||||
| Starten | `POST /login/impersonate { userId }` → neues Token + `impersonatedBy`-Vermerk |
|
||||
| Erkennen | Banner/Status zeigt die Stellvertretung (`AdminLayout`, `AdminHub`, `UserDetailDrawer`) |
|
||||
| Beenden | `POST /login/impersonate?logout=1` → Server löscht den Stellvertretungs-Cookie und stellt die Admin-Sitzung wieder her |
|
||||
|
||||
<Aside type="caution">Stellvertretung nur mit Freigabe nutzen — du handelst mit den Rechten der vertretenen Person, und der Vorgang wird protokolliert (Audit). Währenddessen keine Token erstellen.</Aside>
|
||||
|
||||
## Fehler
|
||||
|
||||
| Fehlerbild | Ursache | Lösung |
|
||||
|---|---|---|
|
||||
| Login schlägt fehl | Falsche Zugangsdaten | Eingaben prüfen; Konto beim Admin erfragen |
|
||||
| Countdown erscheint | Inaktivität | Sitzung verlängern oder neu anmelden |
|
||||
| Benutzer/Team/Org fehlt | Keine Leserechte auf diese Ebene | Admin um Freigabe bitten |
|
||||
| Token-Bereich leer | Server ohne Token-Feature (`404`) | Normal — kein Fehler, Bereich bleibt verborgen |
|
||||
| `permission denied` | Kopf oder Recht falsch | [Token-Köpfe](/reference/token-koepfe/) und Chips prüfen |
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): Hub mit Benutzerliste und Detail-Drawer inkl. Rollen-Badge und Chips. -->
|
||||
|
||||
Klick-Abläufe zur Stellvertretung stehen im Test-Plan `docs/test-plans/42-impersonation.md` (Auslöser, Bestätigungsdialog, Banner, Rückkehr zur Admin-Sitzung — nur im Mock-Modus testen).
|
||||
|
||||
Verifiziert am 2b091d899590b392491c59a54f50de43f1057280 2026-10-16 (tibi-admin-nova)
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
title: 'Admin anpassen'
|
||||
description: 'Sammlungen, Ansichten, Widgets, Fremdschlüssel, Vorschau, Aktionen, Suche und eigene Exporte im Admin.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge, FileTree } from '@astrojs/starlight/components';
|
||||
|
||||
Du passt das **tibi-admin** (Verwaltungs-Backend, Release Nova) an dein Projekt an: Was Listen zeigen, welche Eingabeelemente Formulare nutzen, wie Datensätze verknüpft und gesucht werden. Das meiste steuerst du über die Sammlungs-Config — Schema-Details stehen unter [Sammlungen anlegen](/projekt/sammlungen-anlegen/) und [Felder und Widgets](/projekt/felder-widgets/).
|
||||
|
||||
## Ansichten und Spalten
|
||||
|
||||
| Mittel | Wirkung |
|
||||
|---|---|
|
||||
| `meta.views` (Tabelle, Karten, Kalender …) | Welche [Ansichten](/admin/ansichten-listen/) die Sammlung anbietet |
|
||||
| Sichtbare Spalten | Per Checkbox im Listen-Kopf; [Exporte](/admin/exporte/) übernehmen sie als Vorauswahl |
|
||||
| URL-Parameter | Ansicht ist teilbar: `?view=cards&q=hero&qm=combined&sort=name&order=asc&page=2&size=25` — `qm` ist der Suchmodus aus dem `search`-Block |
|
||||
| Sortierung | Klick auf Spaltenkopf; manuelle Reihenfolge per Drag, wo freigegeben |
|
||||
|
||||
## Widgets und Felder
|
||||
|
||||
Der `WidgetDispatcher` wählt das Eingabeelement: zuerst `meta.widget`, sonst der Feldtyp. Alle **25 Schema-Enum-Werte** kommen vor (`pagebuilder` und `pageBuilder` meinen dasselbe):
|
||||
|
||||
| Gruppe | Widgets |
|
||||
|---|---|
|
||||
| Text | `text`, `textarea`, `richtext`, `html`, `json` |
|
||||
| Zahl/Auswahl | `number`, `checkbox`, `switch`, `select`, `selectArray`, `chipArray`, `color` |
|
||||
| Datum | `date`, `datetime` |
|
||||
| Dateien | `file`, `image`, `foreignFile`, `foreignMedia` |
|
||||
| Verknüpfung | `foreignKey`, `foreignKeyChipArray` |
|
||||
| Struktur | `pagebuilder`/`pageBuilder`, `templateProps`, `containerLessObject`, `containerLessObjectArray` |
|
||||
|
||||
- Pflicht, Formate und `dependsOn`-Sichtbarkeit kommen aus dem Feld-Schema — Bedienung siehe [Eintrags-Editor](/admin/eintrags-editor/).
|
||||
- Mehrsprachige Felder bekommen automatisch Sprachtabs (`I18nLanguageTabs`).
|
||||
|
||||
## Fremdschlüssel und Vorschau
|
||||
|
||||
| Baustein | Datei | Nutzen |
|
||||
|---|---|---|
|
||||
| Auswahl-Dialog | `entry/ForeignKeyDrawer.svelte` | Einträge anderer Sammlung suchen und verknüpfen |
|
||||
| Inline anlegen | `entry/InlineEntryForm.svelte` | Verknüpften Eintrag erzeugen, ohne die Ansicht zu verlassen |
|
||||
| Rückverweise | `entry/ReferencedBy.svelte` | Zeigt, wo der Eintrag verwendet wird |
|
||||
| Feldsuche | `entry/FieldSearch.svelte` | Springt zu Feldern in langen Formularen |
|
||||
| Vorschau | `entry/PreviewElement.svelte` + `preview-resolver` | Löst Pfade (`deepGet`, `_lookup`) für [Medien](/admin/medien/) und gemappte [Actions](/admin/aktionen/) auf |
|
||||
|
||||
## Aktionen und Suche
|
||||
|
||||
- **Actions** pro Sammlung/projektweit hängst du als Methoden-Meta an (`query`-/`data`-Felder, Ausgabe-Mapping, Fortschritt) — ausführen wie unter [Aktionen](/admin/aktionen/) beschrieben.
|
||||
- **Suche:** `search`-Block der Sammlung definiert Modi (`qm`-Parameter in der URL, z. B. `qm=combined`); Feld-Filter, Reiter-Filter (`sub`) und Freitext kombinieren sich — [Exporte](/admin/exporte/) übernehmen den Filter eins zu eins.
|
||||
- **Stapel:** `BulkEditPanel` für Mehrfach-Änderungen direkt aus der Liste.
|
||||
|
||||
## Eigene Bausteine und Exporte
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Custom-Export-Skript">
|
||||
|
||||
Projekt-Entwickler hinterlegen Berichte in `collection.meta.exports` (`name` + `file` Pflicht, z. B. `_/assets/exports/reports.mjs`). Das Modul exportiert **eine** Standard-Funktion:
|
||||
|
||||
```js title="Custom-Export-Skript (Beispiel)"
|
||||
export default async function (ctx) {
|
||||
const rows = await ctx.db.loadAll("orders", { select: ["orderNo"] });
|
||||
const wb = ctx.xlsx.utils.aoa_to_sheet([["Order"], ...rows.map((r) => [r.orderNo])]);
|
||||
return { workbook: { SheetNames: ["R"], Sheets: { R: wb } }, filename: "report-{date}.xlsx", contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" };
|
||||
}
|
||||
```
|
||||
|
||||
| Pflicht | Details |
|
||||
|---|---|
|
||||
| `ctx.db.loadAll` | Lädt in 500er-Paketen mit Fortschritt (`ctx.progress`) und Abbruch (`ctx.signal`) |
|
||||
| `ctx.xlsx` | Gebündelte `xlsx-js-style`-Lib — kein Eigen-Import nötig |
|
||||
| `filename` + `contentType` | Pflicht — ohne `contentType` wirft der Admin einen Fehler |
|
||||
| Genau ein Payload | `workbook`, `blob`, `text` **oder** `bytes` |
|
||||
|
||||
Volle Kontext-Tabelle in der Repo-Doku `custom-export-script.md`; Bedienung unter [Exporte](/admin/exporte/).
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Eigene Widgets/Seiten">
|
||||
|
||||
- Eigene Eingabeelemente registrierst du am `WidgetDispatcher` (Feldtyp + `meta.widget`-Name) — erst Schema in [Felder und Widgets](/projekt/felder-widgets/) prüfen.
|
||||
- Neue Admin-Bereiche folgen dem Muster `components/admin/*Tab + *CreateDrawer + *DetailDrawer` mit Suche, Filter, Sortierung und Paginierung.
|
||||
- KI-Kontext (`aiController`) bleibt automatisch konsistent, solange du `data-ai-id`-Attribute setzt.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<Aside type="caution">Anpassungen an Sammlungs-Config und Skripten erst im lokalen Stack ([einrichten](/admin/setup/)) testen — falsche `meta`-Einträge blenden Ansichten oder Export-Reiter ersatzlos aus.</Aside>
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): angepasste Listenansicht mit Spaltenwahl und eigenem Export-Reiter. -->
|
||||
|
||||
Verifiziert am 2b091d899590b392491c59a54f50de43f1057280 2026-10-16 (tibi-admin-nova)
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: 'Eintrags-Editor'
|
||||
description: 'Felder ausfüllen, Widgets, Fremdschlüssel, i18n-Tabs, Verlauf, Tastaturkürzel.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge } from '@astrojs/starlight/components';
|
||||
|
||||
Du öffnest einen Eintrag aus einer [Liste](/admin/ansichten-listen/) und bearbeitest seine Felder im Editor des **tibi-admin** (Verwaltungs-Backend, Release Nova). Links liegt das Formular, rechts die Seitenleiste mit Aktionen und Gruppen (`meta.position`: `main`, `sidebar:<gruppe>`, `sidebar:settings`). Diese Seite beschreibt die Bedienung — Feldtypen und Schema-Details stehen unter [Felder und Widgets](/projekt/felder-widgets/).
|
||||
|
||||
## Aufbau
|
||||
|
||||
<Steps>
|
||||
|
||||
1. Eintrag in der Liste anklicken oder mit `n` neu anlegen.
|
||||
2. Felder im Hauptbereich ausfüllen, Gruppen in der Seitenleiste prüfen.
|
||||
3. Pflichtfehler beheben — der Speichern-Knopf zeigt die ersten Fehler als Tooltip.
|
||||
4. Speichern mit `Strg + S` oder Knopf. Bei Erfolg toastet der Admin die Meldung.
|
||||
|
||||
</Steps>
|
||||
|
||||
- **Ungespeicherte Änderungen:** Der Editor erkennt Abweichungen zum geladenen Stand (Sortierung der Schlüssel ignoriert er) und warnt dich.
|
||||
- **Rückgängig/Wiederholen:** `Strg + Z` und `Strg + Umschalt + Z` (oder `Strg + Y`) wirken auf Feldänderungen, inklusive Array-Operationen.
|
||||
- **Validierung:** Beim Verlassen eines Felds sofort, vor dem Speichern für alle sichtbaren Felder. Server-Fehler landen zusätzlich im Formular; der erste Fehler wird angescrollt.
|
||||
- **Verlauf:** Über das Verlaufs-Symbol öffnest du die Audit-Historie des Eintrags und stellst eine ältere Version per Diff-Auswahl wieder her.
|
||||
- **JSON-Overlay:** Für Technikfälle bearbeitest du den Roh-Datensatz direkt (Systemfelder-Einfügung inklusive).
|
||||
|
||||
## Widgets
|
||||
|
||||
Der `WidgetDispatcher` wählt das Eingabeelement aus `meta.widget` — sonst aus dem Feldtyp. Alle 25 Schema-Widgets aus [Felder und Widgets](/projekt/felder-widgets/) werden unterstützt (`text`, `textarea`, `number`, `checkbox`, `switch`, `select`, `selectArray`, `chipArray`, `date`, `datetime`, `file`, `image`, `json`, `richtext`, `html`, `foreignKey`, `foreignKeyChipArray`, `foreignFile`, `foreignMedia`, `pagebuilder`/`pageBuilder`, `templateProps`, `containerLessObject`, `containerLessObjectArray`, `color`).
|
||||
|
||||
| Eingabe | Widgets | Hinweis |
|
||||
|---|---|---|
|
||||
| Kurztext | `text` | Eine Zeile, Standard für `string` |
|
||||
| Langtext | `textarea`, `richtext`, `html` | Editor mit Werkzeugleiste bei `richtext` |
|
||||
| Zahl | `number` | Auch für `number[]` |
|
||||
| Ja/Nein | `checkbox`, `switch` | Reine Flags brauchen kein Widget |
|
||||
| Auswahl | `select`, `selectArray`, `chipArray` | Optionen aus `meta.choices` |
|
||||
| Datum | `date`, `datetime` | Zeitanteil nur bei `datetime` |
|
||||
| Datei/Bild | `file`, `image` | Vorschau plus [Bildeditor](/admin/medien/) |
|
||||
| Struktur | `json`, `templateProps`, `containerLessObject(-Array)` | Freies JSON ohne `subFields` |
|
||||
| Seite | `pagebuilder` | Blöcke mit Typ-Umschalter und `dependsOn`-Feldern |
|
||||
| Farbe | `color` | Farbwähler |
|
||||
| Verweis | `foreignKey`, `foreignKeyChipArray`, `foreignFile`, `foreignMedia` | Siehe unten |
|
||||
|
||||
<Aside type="note">
|
||||
Felder mit `meta.dependsOn.eval` blendet der Editor per JavaScript ein oder aus (z. B. Block-Optionen nur beim passenden Blocktyp). `meta.hide: true` versteckt Technikfelder dauerhaft.
|
||||
</Aside>
|
||||
|
||||
## Fremdschlüssel und Drill-Down
|
||||
|
||||
Verweisfelder (`foreignKey` und Verwandte) öffnen einen **Auswahl-Dialog**: Suche, Sortierung und Blättern wie in der [Liste](/admin/ansichten-listen/), aber gegen die Zielsammlung. Du übernimmst einen Eintrag oder legst ihn inline neu an — Vorbelegung aus dem Filter inklusive.
|
||||
|
||||
- **Mehrfach-Verweise** (`foreignKeyChipArray`) sammeln mehrere Ziele als Chips.
|
||||
- **Datei-Verweise** (`foreignFile`, `foreignMedia`) zeigen auf die [Mediathek](/admin/medien/); die Auflösung beim Lesen per `lookup` steht unter [Lesen und suchen](/projekt/abfragen-lesen/).
|
||||
- **Verlinkter Editor:** Aus dem Dialog öffnest du den Zieleintrag in einem gestapelten Drawer und bearbeitest ihn, ohne deinen Eintrag zu verlassen.
|
||||
- **Drill-Down:** Tiefe Objekt-Arrays öffnet der Editor als Ebene mit **Brotkrumen-Navigation** — ein Klick auf eine Ebene springt zurück, `Esc` geht eine Stufe hoch.
|
||||
|
||||
## Mehrsprachigkeit
|
||||
|
||||
Zwei Muster — beide aus Projekt-Sicht konfiguriert ([Felder und Widgets](/projekt/felder-widgets/), [Navigation und Sprachen](/projekt/navigation-i18n/)):
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Sprach-Objekt">
|
||||
|
||||
Felder wie `alt.de` / `alt.en` liegen als Unterfelder nebeneinander. Der Editor gruppiert sie mit Sprach-Reitern (`I18nFieldWrapper`, `I18nLanguageTabs`) — du wechselst die Sprache pro Feldgruppe.
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Einträge koppeln">
|
||||
|
||||
Jede Sprache ist ein eigener Eintrag mit gleichem Gruppenschlüssel (`meta.i18n.entry`: `languageField`, `groupField`). Die **Übersetzungsleiste** über dem Formular zeigt Geschwister (anklickbar), fehlende Sprachen (per `+` anlegbar, optional mit KI-Übersetzung) und das Entkoppeln aus der Gruppe.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Sprachwechsel-Tastenkürzel: `Strg + L` (zyklisch durch die Inhaltssprachen).
|
||||
|
||||
## Tastatur
|
||||
|
||||
| Kürzel | Wirkung |
|
||||
|---|---|
|
||||
| `Strg + S` | Speichern |
|
||||
| `Strg + Z` / `Strg + Umschalt + Z` | Rückgängig / Wiederholen |
|
||||
| `Strg + F` | Feldsuche im Formular |
|
||||
| `Strg + L` | Inhaltssprache wechseln |
|
||||
| `Strg + Umschalt + F` | Suchmodus der Verweis-Dialoge wechseln |
|
||||
| `Umschalt + N` | Eintrag duplizieren |
|
||||
| `Esc` | Drill-Down-Ebene zurück / Dialog schließen |
|
||||
| `?` | Tastaturhilfe öffnen |
|
||||
|
||||
<Aside type="tip">
|
||||
Drücke `?` im Editor — die Hilfe listet alle Kürzel inklusive Listen-Kürzel (`s`, `f`, `x`, `o`, `v`, `p` + Ziffer).
|
||||
</Aside>
|
||||
|
||||
## Häufige Fehler
|
||||
|
||||
| Fehlerbild | Ursache | Lösung |
|
||||
|---|---|---|
|
||||
| Speichern blockiert, rote Felder | Pflichtfeld leer oder `pattern`/`in`-Regel verletzt | Tooltip am Speichern-Knopf lesen, erstes rot markiertes Feld füllen |
|
||||
| Verweis lässt sich nicht wählen | Zieleintrag ohne Leserecht oder Filter zu eng | Filter im Dialog leeren, Rechte unter [Rechte und Tokens](/projekt/rechte-tokens/) prüfen |
|
||||
| Übersetzung fehlt in der Leiste | Kein Gruppenschlüssel oder Sprache nicht konfiguriert | `translationKey`/`lang` prüfen, fehlende Sprache per `+` anlegen |
|
||||
| Änderung „verschwunden“ | Drawer geschlossen ohne Speichern | Auf Änderungs-Warnung achten, erst Drawer-, dann Haupt-Speichern |
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): Editor mit Formular, Seitenleiste und Übersetzungsleiste, Alt-Text deutsch, max. 200 KB unter src/assets/. -->
|
||||
|
||||
Verifiziert am 2b091d89 2026-10-13 (tibi-admin-nova)
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
title: 'Exporte'
|
||||
description: 'CSV, XLSX, JSON aus Listen, vordefinierte und eigene Skript-Exporte.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge } from '@astrojs/starlight/components';
|
||||
|
||||
Du exportierst Einträge einer Sammlung im **tibi-admin** (Verwaltungs-Backend, Release Nova) direkt aus der [Liste](/admin/ansichten-listen/): als Datei für Tabellenkalkulation, Datenaustausch oder eigene Berichte. Exportiert wird, was du siehst — Filter und Suche der Liste gelten auch für den Export.
|
||||
|
||||
## Listen-Export
|
||||
|
||||
<Steps>
|
||||
|
||||
1. Liste filtern und sortieren, bis sie zeigt, was du brauchst.
|
||||
2. Export-Knopf über der Liste klicken.
|
||||
3. Format wählen: `JSON`, `CSV` oder `XLSX`.
|
||||
4. Spalten per Checkbox anhaken (Vorauswahl: sichtbare Tabellenspalten; `object[]`-Felder erscheinen einmal und werden beim Schreiben aufgefächert).
|
||||
5. Herunterladen — der Dateiname enthält Sammlung und Datum.
|
||||
|
||||
</Steps>
|
||||
|
||||
| Format | Technik | Wofür |
|
||||
|---|---|---|
|
||||
| `JSON` | Rohdatensätze als Datei | Weiterverarbeitung, Sicherung, Import anderswo |
|
||||
| `CSV` | Tabellenzeilen aus der `xlsx-js-style`-Bibliothek | Excel-, Numbers- oder Skript-Import |
|
||||
| `XLSX` | Arbeitsmappe aus derselben Bibliothek (Zell-Stile möglich) | Formatierte Weitergabe an Menschen |
|
||||
|
||||
<Aside type="note">
|
||||
`xlsx-js-style` (SheetJS-Fork mit Zell-Stilen) ist die einzige Tabellen-Bibliothek im Admin — beide Tabellenformate kommen aus ihr (`json_to_sheet` für XLSX, `sheet_to_csv` für CSV).
|
||||
</Aside>
|
||||
|
||||
- **Große Mengen:** Vor dem Laden schätzt der Admin die Trefferzahl über `GET …/<sammlung>/_count` (gleicher Filter wie die Liste, Suche als Obergrenze) und warnt dich vor sehr großen Exporten.
|
||||
- **Dynamische Spalten:** Wachsen Arrays unterschiedlich lang, fragt der Dialog nach, ob er die Spalten auffächern soll — brichst du ab, bleibt der Dialog offen.
|
||||
|
||||
## Vordefinierte Skript-Exporte
|
||||
|
||||
Stehen im Export-Dialog eigene Reiter **vor** dem Standard-Tab, hat das Projekt fertige Berichte in `collection.meta.exports` hinterlegt (Name, Datei, optional Dateiname mit `{date}`-Platzhalter). Ein Klick führt das Skript mit dem aktuellen Listenfilter aus — inklusive Fortschrittsbalken.
|
||||
|
||||
```yaml title="Export-Definition in der Sammlungs-Config"
|
||||
# Beispiel-Eintrag in der Sammlungs-Config
|
||||
exports:
|
||||
- name: bestellreport
|
||||
label: { de: "Bestellreport", en: "Order report" }
|
||||
file: "_/assets/exports/reports.mjs"
|
||||
filename: "bestellreport-{date}.xlsx"
|
||||
```
|
||||
|
||||
## Eigenes Skript
|
||||
|
||||
Projekt-Entwickler legen eigene Exporte als ES-Modul unter `meta.exports[].file` ab (Pfad mit `_/`-Präfix = projekt-relativ, empfohlen). Das Modul exportiert **eine Standard-Funktion**, die Kontext (Filter, Auswahl, Fortschritt) bekommt und genau ein Ergebnis zurückgibt:
|
||||
|
||||
| Rückgabe | Inhalt |
|
||||
|---|---|
|
||||
| `workbook` | XLSX-Arbeitsmappe (wird als `.xlsx` gespeichert) |
|
||||
| `blob` | Fertiger `Blob` (z. B. aus Fremd-Lib) |
|
||||
| `text` | Text wie CSV oder HTML |
|
||||
| `bytes` | Binärdaten wie PDF (`Uint8Array`/`ArrayBuffer`) |
|
||||
|
||||
Dazu Pflicht: `filename` und `contentType` (z. B. `text/csv`, `application/pdf`) — ohne `contentType` wirft der Admin einen Fehler. Genau ein Payload pro Ergebnis.
|
||||
|
||||
```js title="reports.mjs (vereinfacht)"
|
||||
// reports.mjs — stark vereinfacht
|
||||
export default async function (ctx) {
|
||||
const rows = await ctx.db.loadAll({ filter: ctx.filter });
|
||||
ctx.progress(1, 1, "Fertig");
|
||||
const wb = ctx.xlsx.utils.json_to_sheet(rows);
|
||||
return { workbook: { SheetNames: ["Report"], Sheets: { Report: wb } }, filename: "bestellreport-{date}.xlsx", contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" };
|
||||
}
|
||||
```
|
||||
|
||||
Details für Entwickler (Kontext-Felder, Dateinamen-Platzhalter, Sanitizing) stehen in der Admin-Repo-Doku `custom-export-script.md` — im Zweifel gilt der Code (`utils/load-custom-export.ts`, `utils/custom-export-context.ts`, `utils/export.ts`).
|
||||
|
||||
## Häufige Fehler
|
||||
|
||||
| Fehlerbild | Ursache | Lösung |
|
||||
|---|---|---|
|
||||
| Export enthält „falsche“ Einträge | Listenfilter (Reiter, Feld-Filter, Suche) enger als gedacht | Filter in der Liste prüfen — der Export übernimmt sie eins zu eins |
|
||||
| Spalten-Warnung erscheint | Arrays ungleicher Länge brauchen aufgefächerte Spalten | Auffächern bestätigen oder Spaltenauswahl verkleinern |
|
||||
| Eigener Reiter fehlt | `meta.exports`-Eintrag ohne `name` oder `file` | Projekt-Config ergänzen (beide Pflicht), Admin neu laden |
|
||||
| Skript-Fehler im Dialog | Modul ohne Standard-Export oder Laufzeitfehler | Browser-Konsole lesen, Modul-Export und Rückgabeformat prüfen |
|
||||
| Leere Datei trotz Treffern | Leserecht auf Zielfelder fehlt | Rechte unter [Rechte und Tokens](/projekt/rechte-tokens/) klären |
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): Export-Dialog mit Formatwahl und Spaltenliste, Alt-Text deutsch, max. 200 KB unter src/assets/. -->
|
||||
|
||||
Verifiziert am 2b091d89 2026-10-13 (tibi-admin-nova)
|
||||
@@ -0,0 +1,134 @@
|
||||
---
|
||||
title: 'KI-Funktionen'
|
||||
description: 'Chat, Zusammenfassen, Stimme und Werkzeuge im Admin: was die KI kann und wo ihre Grenzen liegen.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge, FileTree } from '@astrojs/starlight/components';
|
||||
|
||||
Die KI im **tibi-admin** (Verwaltungs-Backend, Release Nova) hilft dir beim Redigieren: Sie chattet im Kontext der aktuellen Ansicht, fasst lange Verläufe zusammen, hört zu (STT) und liest vor (TTS). **Wichtig vorab: Im Frontend wählst du kein Modell** — alle Modellentscheidungen trifft der Proxy (`config/ai-proxy.config.json`); das Frontend ruft nur Endpunkte aus `frontend/assets/system.config.json` auf.
|
||||
|
||||
## Chat
|
||||
|
||||
<Steps>
|
||||
|
||||
1. **„Nova öffnen“** klicken (`AiButton.svelte`) — der Chat (`AiChat.svelte`) öffnet sich mit Verlauf (`AiConversationList.svelte`). Begrüßung: „Hallo! Ich bin Nova. Wie kann ich dir helfen?“
|
||||
2. Frage in **„Nachricht eingeben…“** stellen und **„Senden“** drücken — die KI sieht den aktuellen UI-Kontext (kompaktes JSON-Snapshot, < 500 Token).
|
||||
3. Antwort prüfen: Werkzeug-Schritte zeigt `AiToolStatus.svelte`, Details der Aufrufe `AiToolInspector.svelte`.
|
||||
4. Weiterfragen oder über **„Neuer Chat“** von vorn beginnen (`start_new_chat`-Werkzeug).
|
||||
|
||||
</Steps>
|
||||
|
||||
Was die KI dabei sieht (`aiController.ts`, `AiChat.svelte`): Neben dem UI-Snapshot hängt der Chat deine Aktionen außerhalb des Chats an die nächste Nachricht an (`[User actions performed outside of chat] … [User message] …`) und markiert die erste Nachricht mit `[lang=de]` (bzw. deiner Sprache). Manche Provider verlangen die Systemnachricht genau einmal vorn — deshalb wandern Aktionen in die Benutzer-Nachricht, nicht in eine zweite Systemnachricht.
|
||||
|
||||
| Baustein | Datei | Aufgabe |
|
||||
|---|---|---|
|
||||
| Verlauf | `lib/aiChatHistory.ts` | Gespräche in `localStorage` (`tibi-ai-conversations`, weiches Limit ~4 MB, älteste zuerst raus) |
|
||||
| Steuerung | `lib/aiController.ts` | Kontext lesen, Aktionen ausführen (nicht destruktiv; Heikles nur mit deiner Bestätigung), Cursor-Animation mit Tempo 0–3 |
|
||||
| Werkzeug-Definitionen | `lib/aiTools.ts` | Funktionsaufrufe für den Chat (nächster Abschnitt) |
|
||||
| Schätzung | `lib/aiTokenEstimator.ts` | Heuristik ~4 Zeichen ≈ 1 Token, nur für Vorab-Entscheidungen |
|
||||
|
||||
**„Token-Status“** (Knopf im Chat, `showTokenStatus`): Das Popover zeigt **„Kontext-Auslastung“** (Prozent mit Farbstufe: grün < 40 %, gelb < 70 %, orange < 85 %, rot darüber — `getContextStatus`), **„Letzter Turn“** (**„Prompt-Tokens“**, **„Completion-Tokens“**, **„Gesamt-Tokens“**, **„Geschätzte Kosten“**), **„Konversation gesamt“** (inkl. Zusammenfassungs-, Spracheingabe- und Sprachausgabe-Kosten) sowie **„Modell“** und **„Kontextfenster“**. Gezählt wird zweigleisig: Die Schätzung (`estimateTokens`, `estimateSystemOverhead`) steuert Vorab-Entscheidungen, die echten Zähler kommen aus der Stream-Antwort (`stream_options`) und landen in **„Geschätzte Kosten“** über die Anzeigetabelle `TEXT_TOKEN_PRICING` — reine Anzeige, keine Abrechnung.
|
||||
|
||||
Das **„Kontextfenster“** liest der Chat aus dem Modellkatalog (Endpunkt `/api/ai/models`, `configured.chat.contextWindow`); antwortet der Katalog nicht, gelten 96 000 Token (`MODEL_CONTEXT_WINDOW`). Aktuell meldet der Proxy 262 144 (siehe `config/ai-proxy.config.json`, `chat.contextWindow`).
|
||||
|
||||
Tempo der Cursor-Animation: **„Nova-Speed“** mit **„Hyperspeed“** (0, alles sofort), **„Schnell“** (1, Standard), **„Mittel“** (2), **„Langsam“** (3) — als Befehle (**„Nova-Speed: …“**) und Kennung `ai-animation-speed` in `localStorage`. Bei zu vielen Schritten stoppt Nova von selbst: „Automatisch gestoppt – zu viele aufeinanderfolgende Aktionen. Nova wurde nach {count} Schritten angehalten …“ — dann Anfrage neu formulieren oder Felder manuell prüfen.
|
||||
|
||||
## Zusammenfassen
|
||||
|
||||
Wächst ein Gespräch Richtung Kontextgrenze, komprimiert `lib/aiSummarizer.ts` in zwei Stufen:
|
||||
|
||||
| Stufe | Schwelle | Verhalten |
|
||||
|---|---|---|
|
||||
| Verdichten (kostenlos, synchron) | Mehr als 12 Werkzeug-Aktivitäten | `condenseHistoricalToolMessages`: abgeschlossene alte Werkzeug-Gruppen werden zu je einer Historie-Notiz (`[HISTORY-CONDENSED: …]`, Rolle `user`), die neuesten 12 Aktivitäten bleiben roh |
|
||||
| Zusammenfassen per LLM | 60 % des Fensters (`SUMMARIZE_THRESHOLD`) | Ältere Nachrichten per LLM zusammenfassen, neueste ~6 Nachrichten (max. ~8 000 Token) roh behalten |
|
||||
| 85 % (`HARD_TRUNCATE_THRESHOLD`) | Hart kürzen: älteste Nachrichten verwerfen |
|
||||
|
||||
- Reserviert sind 10 000 Token für System-Prompt, Werkzeug-Definitionen und Antwort (`RESERVED_TOKENS`).
|
||||
- Zusammenfassungs-Modell: `proxy-managed` — auch hier entscheidet der Proxy, nicht das Frontend. Der Aufruf geht an den Zusammenfassungs-Endpunkt mit Profil `summarizer` und liest einen SSE-Strom (inkl. Zähler); Antwort leer oder Netzfehler → Rückfall auf hartes Kürzen.
|
||||
- Hartes Kürzen hält Werkzeug-Paare zusammen: Verwaiste `tool`-Antworten und `assistant`-Nachrichten ohne vollständige Ergebnisse fliegen raus (`hardTruncate`, `sanitizeWireMessages`) — sonst würde die API den Turn ablehnen.
|
||||
- UI: Währenddessen steht **„Kontext wird zusammengefasst…“**, danach **„Kontext zusammengefasst“** bzw. **„Zusammenfassung aktiv“** mit **„{count} Nachrichten komprimiert · ~{tokens} Tokens gespart“**.
|
||||
- Themenwechsel: Schlägt Nova einen neuen Chat vor (**„Neuen Chat starten?“** — **„Neuen Chat starten“** oder **„Nein, weiter“**), fasst `summarizeForTransfer` den ganzen Verlauf zusammen und stellt deine letzte Nachricht wörtlich unter „LATEST REQUEST“. Im neuen Chat erscheint das als **„Kontext aus vorherigem Chat“** (**„{count} Nachrichten aus vorherigem Chat · ~{tokens} Tokens übertragen“**).
|
||||
|
||||
## Stimme
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Diktieren (STT)">
|
||||
|
||||
**„Spracheingabe“** (`lib/aiVoiceInput.ts`, `VoiceRecorder`): Sprich deinen Prompt statt ihn zu tippen.
|
||||
|
||||
1. Mikro-Knopf drücken — zuerst versucht der Browser **native Spracherkennung** (Status **„Hört auf diesem Gerät“**, Sprache aus `<html lang>`, Standard `de-DE`).
|
||||
2. Klappt das nicht, zeichnet der Admin Audio auf (**„Nimmt für KI-Transkription auf“**) und schickt es an `/api/ai/transcribe` (Proxy-Modell `large-v3-turbo`, Antwort als Text — Status **„Transkribiert mit KI“** bzw. **„Erkennt auf diesem Gerät“**).
|
||||
3. Das Transkript landet im Chat-Eingabefeld (**„Wird transkribiert…“** währenddessen); Dauer und Quelle (`browser`/`api`) stehen dabei. **„Aufnahme stoppen“** beendet manuell, **„Abbrechen“** verwirft.
|
||||
|
||||
Grenzen: Stille beendet automatisch nach 3 s (mobil 3,5 s, frühestens nach 600 ms Aufnahme); Schnipsel unter ~1 000 Byte werden ohne Transkription verworfen. Kostenkopf der Antwort (`X-AI-Cost-Usd`, `X-AI-Model`) zählt in **„Konversation gesamt“** unter **„Spracheingabe“**.
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Vorlesen (TTS)">
|
||||
|
||||
Antworten anhören statt lesen (`lib/aiTTS.ts`, Endpunkt `/api/ai/tts`) — Knopf **„Vorlesen“**, Stopp über **„Wiedergabe stoppen“** (**„Audio wird geladen…“** während des Ladens):
|
||||
|
||||
| Einstellung | Wert (`system.config.json`) |
|
||||
|---|---|
|
||||
| Stimmen | `eva-de` (Standard), `kerstin-de`, `ramona-de` |
|
||||
| Tempo | **„Geschwindigkeit“** 0,5–2,0, Schritt 0,1, Standard **1,3** (**„Zurücksetzen“** stellt den Standard wieder her) |
|
||||
| Format | MP3 (`responseFormat: mp3`) — Opus im WebM, wenn dein Browser es kann (`preferredTTSFormat`) |
|
||||
|
||||
Verhalten: Quelle zuerst Browser-**„Systemstimme auf diesem Gerät“** (passend zu deiner Dokumentsprache, Standard `de-DE`), sonst **„KI-Stimme“** (Proxy-Modell `qwen3-tts-0.6b-base`) — Anzeige **„Stimme: {voice}“**. Beim Streamen spricht Nova satzweise mit: erster Block ab ~60 Zeichen, danach ~120-Zeichen-Bündel, bis zu 2 parallele Anfragen, lückenlos aneinandergereiht. Schalter **„Sprachausgabe“** / **„Sprachausgabe aus“**; Zeichen und Kosten meldet der Server per Kopf (`X-AI-Characters`, `X-AI-Cost-Usd`) und landen unter **„Sprachausgabe“** in **„Konversation gesamt“**.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Zusatz: **Vision** (`/api/ai/vision`) beschreibt Bilder für CMS-Felder („erfinde keine nicht sichtbaren Fakten“); **Übersetzung** (`/api/ai/chat` mit System-Prompt) hält das angeforderte Ausgabeformat exakt ein.
|
||||
|
||||
## Werkzeuge
|
||||
|
||||
Die KI ruft UI-Werkzeuge statt zu raten (`aiTools.ts` → `aiController.ts`). Labels wörtlich aus `de.json` (`admin.ai.tools.*`); Status dazu: **„Arbeitet…“** währenddessen, danach **„1 Aktion ausgeführt“** bzw. **„{count} Aktionen ausgeführt“**, **„Details“** öffnet den **„Tool-Inspector“** (**„Tool-Aufruf“** / **„Tool-Rückgabe“**, **„Formatiert“** / **„Roh“**, **„Alle Schritte kopieren“**):
|
||||
|
||||
| Gruppe | Werkzeuge (UI-Name) |
|
||||
|---|---|
|
||||
| Navigation | `navigate` (**„Navigieren“**), `guide_to` (**„Geführte Tour“**), `list_projects` (**„Projekte auflisten“**), `select_project` (**„Projekt öffnen“**), `select_collection` (**„Collection öffnen“**) |
|
||||
| Liste | `search` (**„Suchen“**), `set_search_mode` (**„Suchmodus wechseln“**), `set_filter` (**„Filter setzen“**), `clear_filters` (**„Filter löschen“**), `sort_by` (**„Sortieren“**), `set_page` (**„Seite wechseln“**), `set_page_size` (**„Seitengröße ändern“**) |
|
||||
| Auswahl | `select_records` (**„Datensätze auswählen“**), `select_all` (**„Alle auswählen“**), `deselect_all` (**„Auswahl aufheben“**), `open_collection_record` (Datensatz öffnen), `set_view_mode` (**„Ansicht wechseln“**) |
|
||||
| Stapel | `open_bulk_edit` (**„Massenbearbeitung“**), `prepare_bulk_delete` (**„Löschung vorbereiten“**) |
|
||||
| Eintrag & Formular | `get_entry_context` (**„Eintrag-Kontext abrufen“**), `fill_field` (**„Feld ausfüllen“**), `fill_form` (**„Formular ausfüllen“**), `focus_field` (**„Feld fokussieren“**), `save_entry` (**„Eintrag speichern“**), `cancel_entry` (**„Bearbeitung abbrechen“**), `create_entry` (**„Neuen Eintrag anlegen“**), `duplicate_entry` (**„Eintrag duplizieren“**) |
|
||||
| Array-Felder | `add_array_item` (**„Array-Element hinzufügen“**), `remove_array_item` (**„Array-Element entfernen“**), `duplicate_array_item` (**„Array-Element duplizieren“**), `reorder_array_items` (**„Array-Elemente sortieren“**), `clear_array` (**„Array leeren“**) |
|
||||
| Verknüpfungen | `search_foreign_options` (**„Verknüpfte Einträge durchsuchen“**), `create_foreign_entry` (**„Verknüpften Eintrag erstellen“**) |
|
||||
| Navigation (Inhalt) | `open_navigation_node` (**„Navigationsknoten öffnen“**), `add_navigation_node` (**„Navigationsknoten hinzufügen“**), `move_navigation_node` (**„Navigationsknoten verschieben“**), `delete_navigation_node` (**„Navigationsknoten löschen“**) |
|
||||
| Medien | `upload_media` (**„Medien hochladen“**), `quick_upload_all` (**„Alle schnell hochladen“**), `edit_image` (**„Bild bearbeiten“**), `inline_edit_title` (**„Medieneintrag öffnen“**), Warteschlange: `list_queue_items` (**„Warteschlange anzeigen“**), `edit_queue_item` (**„Element bearbeiten“**) |
|
||||
| Verlauf | `get_audit_history` (**„Verlauf abrufen“**), `list_audit_log` (**„Audit-Log anzeigen“**), `restore_from_audit` (**„Aus Audit übernehmen“**) |
|
||||
| Oberfläche | `toggle_sidebar` (Seitenleiste, Tool-Name als Anzeige), `open_field_search` (Feldsuche, Tool-Name als Anzeige), `set_theme` (**„Theme wechseln"**), `switch_language` (**„Sprache wechseln"**), `highlight_element` (**„Element hervorheben"**), `explain_ui` (**„UI erklären"**), `list_ui_elements` (**„UI-Elemente auflisten"**), `click_element` (**„Element klicken"**), `drill_navigate` (Ansicht lesen, Tool-Name als Anzeige) |
|
||||
| Daten lesen | `get_collection_records` (Datensätze lesen, Tool-Name als Anzeige), `get_collection_schema` (Schema lesen, Tool-Name als Anzeige), `list_users` (**„Benutzer auflisten"**) |
|
||||
| Chat | `start_new_chat` (**„Neuer Chat“**), `run_tool_batch` (**„Batch ausführen“**) |
|
||||
|
||||
Stapel-Limits (`aiTools.ts`): `run_tool_batch` fasst bis zu 40 ändernde Schritte (100 bei rein lesenden wie **„Kontext abrufen“**, **„Projekte auflisten“**, **„Benutzer auflisten“**) — darüber verweigert der Batch. `get_context` (**„Kontext abrufen“**) und `get_entry_context` lesen gezielt nach: Standardablauf ist erst Eintrag öffnen, dann `get_entry_context`, dann die Feld-Updates möglichst als ein Batch.
|
||||
|
||||
<Aside type="note">Alle Aktionen sind nicht destruktiv angelegt; `prepare_bulk_delete` bereitet nur vor und `restore_from_audit` (**„Aus Audit übernehmen"**) fragt vorher bei dir nach. Zwei Debug-Ansichten: `AiDebugContext.svelte` (Befehlspalette: **„Debug: KI-Kontext anzeigen"**) zeigt, welchen Kontext die KI gerade sieht; `AiVisionOverlay.svelte` (Befehlspalette: **„Debug: KI-Vision"**, Schalter **„Debug: KI-Vision (steuerbare Elemente anzeigen)"**) legt ein Röntgen-Overlay über alle steuerbaren Elemente mit ihren Kennungen.</Aside>
|
||||
|
||||
## Grenzen und Kosten
|
||||
|
||||
Wichtig zur Einordnung: Der Admin-Chat läuft über den Proxy (`/api/ai/chat`, `/api/ai/vision`, `/api/ai/transcribe`, `/api/ai/tts`) — **nicht** über `POST /api/v1/llm/chat` am tibi-server. Die Benutzer-/Org-Budgets mit `429` aus [LLM nutzen](/projekt/llm-nutzen/) greifen daher hier nicht; was hier begrenzt, steht in `config/ai-proxy.config.json` und `frontend/assets/system.config.json`:
|
||||
|
||||
| Punkt | Stand |
|
||||
|---|---|
|
||||
| Modellwahl | Gibt es im Frontend nicht — Proxy-Config entscheidet (Chat, Zusammenfassen, Übersetzung, Vision je eigenes Modell/Fenster) |
|
||||
| Preise im Proxy | Aktuell `0` (interne Test-Modelle: alle `pricing`-Felder `0`); die Schätztabelle im Frontend (`TEXT_TOKEN_PRICING`) dient nur der Anzeige im **„Token-Status“** |
|
||||
| Fenster & Antwortlänge | Chat 262 144 / max. 12 000 Token, Zusammenfassen und Übersetzung je 262 144 / 6 000, Vision 32 768 / 6 000 |
|
||||
| Verlauf | Nur lokal im Browser (`localStorage`: `tibi-ai-conversations`, weich ~4 MB — älteste zuerst raus; Single-Chat-Notbremse: nur letzte 4 Wire-Nachrichten bleiben) |
|
||||
| Stapel | `run_tool_batch`: max. 40 ändernde bzw. 100 rein lesende Schritte |
|
||||
| Sprache | 3 s Stille beendet (mobil 3,5 s), Schnipsel < ~1 KB verfallen; TTS-Bündel ab ~60/120 Zeichen |
|
||||
| Offline | Ohne Server keine KI — Chat, STT, TTS brauchen ihre Endpunkte |
|
||||
|
||||
| Fehlerbild | Ursache | Lösung |
|
||||
|---|---|---|
|
||||
| Chat antwortet nicht | Endpunkt `/api/ai/chat` unerreichbar oder Proxy down | [Admin einrichten](/admin/setup/) prüfen, später erneut versuchen |
|
||||
| **„KI-Dienst ist nicht erreichbar. Bitte versuche es später erneut.“** | Endpunkt fehlt (404) oder Proxy liefert JSON statt Nutzdaten | [Admin einrichten](/admin/setup/) prüfen |
|
||||
| **„KI-Dienst nicht konfiguriert. Bitte kontaktiere den Administrator.“** | 401/403 am Proxy (Schlüssel/Config) | Administrator ansprechen |
|
||||
| **„Rate-Limit erreicht. Bitte warte einen Moment und versuche es erneut.“** | 429 am Proxy | Kurz warten, erneut versuchen |
|
||||
| **„Der KI-Dienst ist vorübergehend nicht erreichbar. Bitte versuche es später erneut.“** | 5xx am Proxy | Später erneut versuchen |
|
||||
| **„Mikrofon-Zugriff verweigert. …“** | Browser-Recht fehlt | Mikrofon in den Browser-Einstellungen freigeben |
|
||||
| **„Transkription fehlgeschlagen: {error}“** | Rate-Limit, Netz oder Proxy-Fehler | Kürzeren Abschnitt sprechen, erneut versuchen |
|
||||
| Stimme klingt falsch | Andere Stimme aktiv | Stimme in den KI-Einstellungen zurück auf `eva-de` setzen |
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): geöffneter KI-Chat mit Werkzeugstatus und Mikro-Knopf. -->
|
||||
|
||||
Verifiziert am 2b091d89 2026-10-16 (tibi-admin-nova: AiChat/AiButton/AiConversationList/AiToolStatus/AiToolInspector/AiDebugContext, aiChatHistory/aiController/aiTools/aiTokenEstimator/aiVoiceInput/aiSummarizer/aiTTS/aiModelCatalog, config/ai-proxy.config.json, frontend/assets/system.config.json, de.json admin.ai + Befehle)
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: Admin-Konzept
|
||||
description: Was tibi-admin ist, wie es läuft und wie es zum Server passt.
|
||||
---
|
||||
|
||||
import { Card, CardGrid } from '@astrojs/starlight/components';
|
||||
|
||||
> **Handseite.** Wird vom Sync nie überschrieben (`keep`).
|
||||
|
||||
**tibi-admin** ist das Verwaltungs-Backend — die Bedienoberfläche zum Tibi-Server (aktuelles Release **Nova**). Code-Repo: `tibi-admin-nova` — das ist das einzig gültige Repo, alte `tibi-admin`-Repos werden ignoriert. Projekt-Websites (kleine Websites, Shops, Intranet-Anwendungen aus `tibi-svelte-starter`) sind eigenständig und laufen getrennt davon.
|
||||
|
||||
- Svelte-SPA als statisches Bundle, läuft lokal im Mock-Modus (Projekt `t1`) und in Staging/Live hinter Reverse Proxy gegen den echten tibi-server.
|
||||
- Laufzeitwerte in `frontend/assets/system.config.json`, Proxy-Ziele/Modelle in `config/ai-proxy.config.json`.
|
||||
- Screens: `frontend/src/lib/components/admin/` (Hub, Orgs, Teams, User, Projekte) und `components/entry/` (Editor, Widgets, Drawers, Preview).
|
||||
|
||||
## Wo finde ich was?
|
||||
|
||||
<CardGrid stagger>
|
||||
<Card title="Einrichten">
|
||||
Docker-Stack, Mock-Modus, URLs. [Lesen](/admin/setup/).
|
||||
</Card>
|
||||
<Card title="Anpassen">
|
||||
Ansichten, Widgets, Fremdschlüssel, Exporte, Skripte. [Lesen](/admin/customizing/).
|
||||
</Card>
|
||||
<Card title="Arbeiten mit Inhalten">
|
||||
[Ansichten und Listen](/admin/ansichten-listen/), [Eintrags-Editor](/admin/eintrags-editor/), [Medien](/admin/medien/), [Exporte](/admin/exporte/).
|
||||
</Card>
|
||||
<Card title="Steuern und Rechte">
|
||||
[Aktionen](/admin/aktionen/), [Benutzer und Rechte](/admin/benutzer-rechte/), [KI-Funktionen](/admin/ki-funktionen/).
|
||||
</Card>
|
||||
<Card title="Anwender-Anleitung">
|
||||
Bereich [Anwender](/anwender/anmelden/): Bedienung des Verwaltungs-Backends für Redakteure und Betreiber — nicht Anleitung für Besucher der Projekt-Websites.
|
||||
</Card>
|
||||
</CardGrid>
|
||||
|
||||
Verifiziert am 2b091d89 2026-10-13 (tibi-admin-nova).
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
title: 'Medien im Admin'
|
||||
description: 'Raster, Upload-Warteschlange, Bildeditor, Vorschau aus Admin-Sicht.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge } from '@astrojs/starlight/components';
|
||||
|
||||
Bilder, PDFs und andere Dateien verwaltest du im **tibi-admin** (Verwaltungs-Backend, Release Nova) in einer Medien-Sammlung — meist `medialib` mit `viewHint.media`. Dieselben Werkzeuge stecken auch in Datei-Feldern des [Eintrags-Editors](/admin/eintrags-editor/). Projekt-Grundlagen (Pfade, Größen, Formate) stehen unter [Dateien und Bilder](/projekt/dateien-bilder/).
|
||||
|
||||
## Raster
|
||||
|
||||
Die Medienansicht zeigt Kacheln mit Vorschaubild, Titel und Auswahl-Status. Darüber liegen Suche, Sortierung, Filter und Blättern wie in jeder [Liste](/admin/ansichten-listen/).
|
||||
|
||||
- **Klick** öffnet die Vollbild-**Vorschau** (Lightbox): Blättern per Pfeiltasten und Knöpfe, Download-Knopf, PDF-Vorschau per eingebettetem Rahmen.
|
||||
- **Mehrfachauswahl** per Checkbox oder `Leertaste` — danach Massenbearbeitung oder Löschen wie in der Tabellenansicht.
|
||||
- **Titel-Erkennung:** Fehlt eine explizite `autoFill`-Konfiguration, rät der Admin das Titelfeld aus üblichen Namen (`title`, `name`, `titel`, `label`, `bezeichnung`).
|
||||
- **Hervorhebung:** Suchtreffer markiert das Raster im passenden Feld.
|
||||
|
||||
## Upload
|
||||
|
||||
<Steps>
|
||||
|
||||
1. Dateien auf das Raster ziehen oder den Upload-Knopf klicken (Mehrfachauswahl möglich).
|
||||
2. Pro Datei füllt der Admin Titel und Alternativtext aus dem Dateinamen vor (`autoFill`-Konfiguration der Sammlung).
|
||||
3. Die **Warteschlange** lädt mit Fortschrittsbalken — einzeln sofort oder alle als Stapel.
|
||||
4. Nach dem Hochladen lädt das Raster neu; die neuen Einträge sind direkt verlinkbar.
|
||||
|
||||
</Steps>
|
||||
|
||||
- **Dateinamen-Import:** Die Warteschlange erkennt Titel aus Dateinamen und schlägt Alternativtexte vor.
|
||||
- **KI-Alt-Text:** Ist er für die Sammlung konfiguriert, läuft die Generierung pro Warteschlangen-Eintrag mit Statusanzeige (wartend, laufend, abbrechbar).
|
||||
- **Inline-Anlage:** Aus Datei-Feldern heraus legst du Medien-Datensätze im Drawer an, ohne den Editor zu verlassen.
|
||||
- **Grenzen:** Erlaubte Typen und maximale Größe kommen aus dem Feld-Validator (`accept`, `maxFileSize`, z. B. `"50MB"` in `medialib.yml`) — Schema-Details unter [Felder und Widgets](/projekt/felder-widgets/).
|
||||
|
||||
## Bildeditor
|
||||
|
||||
Den Editor öffnest du aus der Kachel oder aus Datei-Feldern (`Bild bearbeiten`). Er arbeitet rein im Browser (Canvas/CSS, keine Zusatzbibliothek) und schreibt das Ergebnis ins Dateifeld zurück.
|
||||
|
||||
| Werkzeug | Was du einstellst |
|
||||
|---|---|
|
||||
| Zuschnitt | Freies oder festes Seitenverhältnis, pixelgenau |
|
||||
| Drehen/Spiegeln | 90°-Schritte, horizontal/vertikal (Zuschnitt wird dabei zurückgesetzt) |
|
||||
| Anpassen | Helligkeit, Kontrast, Sättigung mit Live-Vorschau |
|
||||
| Fokuspunkt | Klickpunkt für Ausschnitt-Steuerung in der Projekt-Website |
|
||||
| Skalieren | Zielgröße in Pixeln |
|
||||
| Palette | Dominante Farben prüfen und pflegen |
|
||||
|
||||
Welche Werkzeuge verfügbar sind, steuert die Projekt-Konfiguration (`crop`, `rotate`, `flip`, `scale`, `focalPoint`, `adjust`, `palette`).
|
||||
|
||||
## Einbetten
|
||||
|
||||
Aus Redakteurs-Sicht gibt es drei Wege, eine Datei in Inhalte zu bringen:
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Bild-Feld">
|
||||
|
||||
`foreignMedia`-Felder (z. B. `blocks.heroImage.image`) verweisen auf die Mediathek. Wähle den Eintrag im Verweis-Dialog — die Projekt-Website löst ihn per `lookup` auf ([Lesen und suchen](/projekt/abfragen-lesen/)).
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Datei-Feld">
|
||||
|
||||
`file`- und `image`-Felder halten den Upload direkt am Eintrag (Klick oder Drag-and-drop, Vorschau, Bildeditor). Erlaubte Typen liest der Admin aus `validator.accept`.
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Richtext">
|
||||
|
||||
Bilder im Fließtext verwaltet das `richtext`-Widget des Editors (siehe [Eintrags-Editor](/admin/eintrags-editor/)).
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Häufige Fehler
|
||||
|
||||
| Fehlerbild | Ursache | Lösung |
|
||||
|---|---|---|
|
||||
| Upload abgelehnt | Typ nicht in `accept` oder Datei über `maxFileSize` | Kleinere oder passende Datei wählen, ggf. Projekt-Konfiguration anpassen |
|
||||
| Vorschaubild fehlt | Kein Bildfeld erkannt oder Datei kein Bild | Titel- und Dateifeld der Sammlung prüfen, PDF öffnet sich in der Vorschau statt als Bild |
|
||||
| Bild-Einbettung bleibt leer | Verweis ohne `lookup` gelesen oder Eintrag nicht öffentlich | `lookup` auf `medialib` prüfen, `active`-Status und Rechte unter [Rechte und Tokens](/projekt/rechte-tokens/) klären |
|
||||
| Editor-Änderung weg | Dialog ohne Übernehmen geschlossen | Erst im Bildeditor übernehmen, dann den Eintrag speichern |
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): Medienraster mit Warteschlange und Bildeditor-Dialog, Alt-Text deutsch, max. 200 KB unter src/assets/. -->
|
||||
|
||||
Verifiziert am 2b091d89 2026-10-13 (tibi-admin-nova)
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
title: 'Admin einrichten'
|
||||
description: 'tibi-admin lokal starten und mit dem Server verbinden: Installieren, Docker-Stack, URLs, Mock-Modus.'
|
||||
---
|
||||
|
||||
import { Aside, Tabs, TabItem, Steps, Card, CardGrid, Badge, FileTree } from '@astrojs/starlight/components';
|
||||
|
||||
Du richtest das **tibi-admin** (Verwaltungs-Backend, Release Nova) lokal ein und verbindest es mit dem Tibi-Server. Code-Repo ist ausschließlich `tibi-admin-nova` — alte `tibi-admin`-Repos ignorieren. Stack: **Svelte 5**, **esbuild**-Build, **Tailwind 4**, **Playwright**-Tests (siehe `package.json`).
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
| Braucht | Wofür |
|
||||
|---|---|
|
||||
| Node 20 + `yarn` | `yarn install`, esbuild-Build (`scripts/esbuild-wrapper.js`) |
|
||||
| Docker + Compose | Lokaler Stack (`docker-compose-local.yml`, Profile `tibi` / `tibi-dev`) |
|
||||
| Datei `.env` | Projekt-Name, URLs, Ports (Beispielwerte unten) |
|
||||
|
||||
```sh title="Versionen prüfen"
|
||||
node --version # 20.x
|
||||
yarn --version
|
||||
docker compose version
|
||||
```
|
||||
|
||||
## Starten
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Docker-Stack (empfohlen)">
|
||||
|
||||
<Steps>
|
||||
|
||||
1. `cp .env.example .env` (falls vorhanden) und `PROJECT_NAME` setzen.
|
||||
2. `make init` — legt `tmp/`-Verzeichnisse an.
|
||||
3. `make docker-up` — startet Frontend-Build, `tibiserver`, Mongo, Maildev (`--profile tibi`).
|
||||
4. Admin-URL aus `.env` öffnen (z. B. `https://<projekt>.code.testversion.online` bzw. lokal Port **3000**).
|
||||
5. Auf der [Login-Seite](/admin/benutzer-rechte/) anmelden.
|
||||
|
||||
</Steps>
|
||||
|
||||
| Dienst | Port/Exposed | Hinweis |
|
||||
|---|---|---|
|
||||
| `yarnstart` (Admin-Frontend) | **3000** | Baut per `yarn install && yarn start…` mit `API_BASE` aus `.env` |
|
||||
| `tibiserver` | **8080** | API unter `/api`, Admin ruft `/api/v1` |
|
||||
| Mongo / Maildev | intern | Über Compose-Namen verdrahtet |
|
||||
|
||||
Nützliche Ziele: `make docker-ps`, `make docker-logs`, `make docker-down`, `make docker-restart-frontend`.
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Nur Frontend (ohne Docker)">
|
||||
|
||||
<Steps>
|
||||
|
||||
1. `yarn install`
|
||||
2. `API_BASE=https://<server>/api/v1 yarn start` (Dev) bzw. `yarn build` (statisches Bundle).
|
||||
3. Browser auf die ausgegebene lokale URL zeigen.
|
||||
|
||||
</Steps>
|
||||
|
||||
`API_BASE` entscheidet, gegen welchen Server du arbeitest — Staging-URL steht in `.env` als `STAGING_TIBI_API_URL` (z. B. `https://dev-tibi-server.staging.testversion.online/api/v1`).
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Verbinden und Mock-Modus
|
||||
|
||||
| Modus | Erkennen | Verhalten |
|
||||
|---|---|---|
|
||||
| Echter Server | `API_BASE` zeigt auf laufenden tibi-server | Alle Daten live; Login per Benutzername/Passwort |
|
||||
| Mock-Modus | Kein Server erreichbar / Mock-Flag (`isMockMode()`) | Lokale Demo-Daten, Demo-Projekt `t1`; Actions simulieren Fortschritt (`simulateMockProgress`) |
|
||||
|
||||
- Laufzeitwerte liegen in `frontend/assets/system.config.json` (KI-Endpunkte, TTS-Stimmen); Proxy-Ziele und Modelle in `config/ai-proxy.config.json` — siehe [KI-Funktionen](/admin/ki-funktionen/).
|
||||
- Fehlerbilder bei falscher Verbindung: Login-Fehlerbox, Netzwerkfehler bei Listen/Actions — dann `API_BASE`, Server-Container (`make docker-ps`) und [Token-Köpfe](/reference/token-koepfe/) prüfen.
|
||||
|
||||
## Prüfen
|
||||
|
||||
```sh title="Build und Tests"
|
||||
yarn validate # svelte-check + tsc
|
||||
yarn build # esbuild-Bundle, muss fehlerfrei durchlaufen
|
||||
yarn test:e2e # Playwright E2E
|
||||
```
|
||||
|
||||
<Aside type="tip">Läuft `yarn build` grün und zeigt der Admin nach Login die Projektliste, ist das Setup fertig. Weiter geht es mit [Admin anpassen](/admin/customizing/).</Aside>
|
||||
|
||||
<!-- Screenshot-Platzhalter (T-SHOTS): frisch gestarteter Admin mit Projektliste nach Login. -->
|
||||
|
||||
Verifiziert am 2b091d899590b392491c59a54f50de43f1057280 2026-10-16 (tibi-admin-nova)
|
||||
Reference in new issue
Block a user