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

- 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:
apairon committed 2026-10-16 22:49:07 +00:00
1 parent acb1d32355
commit 1897bb50d9
101 files changed
+8980 -68

No files matched your search

@@ -0,0 +1,166 @@
---
title: 'Sammlungen anlegen'
description: 'Eigene Collection in api/collections definieren: Schema, Meta, Indizes, Suche.'
---
import { Aside, Steps, FileTree } from '@astrojs/starlight/components';
Eine **Sammlung** (Collection) ist eine Tabelle deines Projekts.
Du legst sie als YAML-Datei in `api/collections/` an.
Der Dateiname ist frei, entscheidend ist das Feld `name`.
Beispiel-Sammlungen zum Abschauen: `content`, `navigation`, `medialib`, `tag`, `comment`.
<FileTree>
- api/
- collections/
- content.yml
- navigation.yml
- medialib.yml
- tag.yml
- comment.yml
</FileTree>
## Minimal-Beispiel
Die kleinste Sammlung braucht `name` **und `permissions`** (beides Pflicht laut Schema) — `fields` ist dagegen optional.
Abgeschaut von `tag.yml` (vereinfacht):
```yaml title="api/collections/notiz.yml — Minimal-Beispiel (vereinfacht aus tag.yml)"
# api/collections/notiz.yml
# yaml-language-server: $schema=../../tibi-types/schemas/config/collection.schema.json
name: notiz
uploadPath: ../media/notiz
audit:
enabled: true
permissions:
public:
methods:
get: true
user:
methods:
get: true
post: true
put: true
delete: true
indexes:
- name: name_unique
key:
- name
unique: true
background: true
search:
- name: default
mode: regex
fields: [name, text]
fields:
- name: name
type: string
meta:
label: { de: "Name", en: "Name" }
- name: text
type: string
meta:
label: { de: "Text", en: "Text" }
```
<Steps>
1. Datei `api/collections/<name>.yml` anlegen, Schema-Zeile aus dem Beispiel kopieren.
2. `name` kleinschreiben, keine Umlaute und keine Leerzeichen (`content`, `tag`, `comment` als Vorbild).
3. `permissions` setzen — sonst liest niemand die Daten (Details: [Rechte und Tokens](/projekt/rechte-tokens/)).
4. `uploadPath` setzen, auch wenn die Sammlung keine Dateien enthält (`../media/<name>` wie in allen Starter-Sammlungen).
5. Projekt neu laden, damit der tibi-server die Datei einliest.
6. Testen: `POST` anlegen, doppelten Wert schicken → `409` bei Unique-Index.
</Steps>
## Meta: Label, Gruppe, Icon, Vorschau
`meta` steuert, wie tibi-admin die Sammlung anzeigt.
Pflicht ist nichts davon — aber ohne `label` rätst du im Admin.
| Schlüssel | Wirkung | Beispiel aus dem Starter |
|---|---|---|
| `label` | Anzeigename (`de`/`en`) | `tag.yml`: `{ de: "Schlagwörter", en: "Tags" }` |
| `group` | Gruppierung in der Navigation | `content`, `content`, `community` (`comment.yml`) |
| `muiIcon` | Icon im Admin | `label`, `menu`, `chat`, `folder-multiple-image` |
| `imageUrl` | Vorschaubild für Karten | Unsplash-URL in `content.yml` |
| `preview` | Listenvorschau: `label`, `secondary`, `tertiary`, `image` | `content.yml`: `label: name`, `secondary: path`, `tertiary: lang` |
| `viewHint` | Darstellungsart im Admin | siehe unten |
| `sidebar` | Eigene Seitenleiste mit Gruppen | `content.yml`: `publishing`, `seo` |
| `i18n.entry` | Übersetzungs-Kopplung | `content.yml`: `languageField: lang`, `groupField: translationKey` |
Felder positionierst du mit `meta.position`: `main`, `sidebar:<gruppe>` oder `sidebar:settings`.
Beispiel: `lang` liegt in `content.yml` auf `sidebar:settings`, `active` auf `sidebar:publishing`.
`viewHint` aus dem Starter (geprüft, alle drei Varianten):
- `viewHint: cards` — Kartenansicht (`content.yml`).
- `viewHint.media` — Medienansicht mit Upload und KI-Alt-Text (`medialib.yml`).
- `viewHint.navigation` — Baumansicht mit `nodesField` und `declaredTrees` (`navigation.yml`, Bäume: Header/Footer je Sprache).
## Indizes und Suche
### Indizes
Jeder Eintrag in `indexes` braucht nur `key` (`name` ist freiwillig).
`key` ist eine Liste von Feldnamen, Text-Index mit `"$text:$**"`.
```yaml title="content.yml — Text-Index plus zwei Unique-Indizes"
# aus content.yml — Text-Index plus zwei Unique-Indizes
indexes:
- name: content_text
key:
- "$text:$**"
defaultLanguage: none
background: true
- name: path_lang
key:
- path
- lang
unique: true
background: true
- name: translation
key:
- translationKey
- lang
unique: true
background: true
```
`unique: true` schützt vor Doppelten: der zweite `POST` mit gleichem `path` + `lang` scheitert — modern mit `409`, im Legacy-Default (Standard) mit `500` (siehe [Fehlerbilder](/reference/fehlercodes/)).
So erzwingt der Starter auch einzelne Navigationsbäume (`type_language` in `navigation.yml`) und einzelne Tag-Namen (`name_unique` in `tag.yml`).
### Suche
Jeder Eintrag in `search` braucht nur `name` und `mode` (`fields` ist freiwillig).
Vier Modi kommen im Starter vor:
| Modus | Wofür | Beispiel |
|---|---|---|
| `regex` | Einfache Teilstringsuche | `tag.yml`, `navigation.yml`, `comment.yml`: `default` |
| `ngram` | Fehlertolerante Fuzzy-Suche | `content.yml`: `fuzzy` mit `autoRegenerate: true` |
| `vector` | Semantische Vektorsuche | `content.yml`: `semantic` mit `vector: { provider: bge_m3 }` |
| `combined` | Hybrid aus semantisch + fuzzy (RRF) | `content.yml`: `combined` mit `rrf: { k: 60, topK: 100 }` |
Abfrage dazu: `GET …/content?q=…&qName=combined`.
Details stehen unter [Lesen und suchen](/projekt/abfragen-lesen/).
## Häufige Fehler
| Fehlerbild | Ursache | Lösung |
|---|---|---|
| `409` beim Anlegen | `unique`-Index verletzt (`path`+`lang`, `translationKey`+`lang`, Tag-`name`) | Vor `POST` per `filter` prüfen, ob der Datensatz schon existiert |
| `project not found` | Projekt nicht registriert oder Namespace falsch | Siehe [Neues Projekt](/einstieg/neues-projekt/) Schritt 5 |
| Validierung schlägt fehl | Pflichtfeld fehlt oder `pattern` verletzt (z. B. `path` ohne führenden `/`) | Feldregeln stehen unter [Felder und Widgets](/projekt/felder-widgets/) |
| Öffentlich leere Liste, mit Token voll | `active:true` fehlt — der `filter_public`-Hook filtert alles weg | Siehe [Rechte und Tokens](/projekt/rechte-tokens/) |
| Datei-Upload landet falsch | `uploadPath` fehlt oder zeigt ins falsche Verzeichnis | `../media/<name>` wie in allen Starter-Sammlungen setzen |
<Aside type="tip">
Lege neue Felder zuerst in einer Test-Sammlung an, nicht in `content`.
`content` hat Pagebuilder-Blöcke und drei Such-Indizes — Fehler dort tun mehr weh.
</Aside>
Verifiziert am e3f92eb 2026-10-14 (tibi-svelte-starter), am 4c55f82 2026-10-12 (tibi-types).