`duxt.sources` ist eine Liste von Quelleneinträgen; `duxt.sourceOptions` sagt,
wie daraus URLs werden. Beide werden zur Build-Zeit gelesen. Was sie erzeugen
und warum, steht in [Quellen](/concepts/sources).

Refs erfordern ein explizites `repo`, auch für einen anderen Ref dieses
Repositorys. Ohne `repo` liest eine Quelle den aktuellen lokalen Checkout und
lehnt `refs` (einschließlich `latest`) sowie lokale `ref`-Overrides pro Sprache
ab. `origin.repo` und `origin.ref` liefern nur Herkunftslinks; sie wählen keine
Inhalte aus. Eine Sprache mit eigenem explizitem `repo` darf einen eigenen `ref`
wählen. Für lokale Versionen dienen `version` an Quellen mit getrennten Ordnern
oder dateibasierte `versions` eines generierten Abschnitts.

## Ein Quelleneintrag

| Feld      | Typ                      | Anmerkungen                                                        |
| :-------- | :----------------------- | :------------------------------------------------------------------ |
| `path`    | `string`                 | Ordner mit dem Markdown, relativ zur Repository-Wurzel               |
| `repo`    | `string`                 | `owner/name` oder eine git-URL. **Weggelassen heißt lokaler Checkout** |
| `refs`    | Ref-Liste                | Refs als Versionen; erfordern ein explizites `repo` |
| `releases` | `{ select, prereleases? }` | Release-Tags als Versionen entdecken — siehe unten |
| `tagComponent` | `string`            | Nur die `<name>@vX.Y.Z`-Tags eines Pakets veröffentlichen — siehe [Komponenten-Tags](#komponenten-tags) |
| `version` | `string`                 | Die Version, die diese Quelle selbst ist |
| `label`   | Text                     | Im Umschalter gezeigt und in der URL genutzt; standardmäßig der Ref  |
| `name`    | Text                     | Wie diese Quelle **heißt**, wo die Seite sie benennt. Nur Anzeige — siehe unten |
| `slug`    | `string`                 | Das URL-Segment dieser Quelle. **Wer eines nennt, beansprucht es** — siehe unten |
| `status`  | Status                   | Lebenszyklus jeder Version, die dieser Eintrag veröffentlicht        |
| `statusDefaults` | `{ latest?, branch?, tag? }` | Standard-Lebenszyklus je Ref-Art |
| `origin`  | `{ repo, ref?, path? }`  | Wo von der Platte gelesene Seiten liegen, für Links zurück           |
| `history` | `boolean`                | Die git-Historie dieser Quelle lesen                                 |
| `content` | `boolean`                | `false`, wenn die Quelle nur generierte Inhalte trägt |
| `exclude` | `{ drafts?, partials? }` | Quellenbezogene Globs für Entwürfe und Partials |
| `flavor`  | `'tfplugindocs'`         | Den Markdown-Baum als unterstützten Quellen-Dialekt lesen |
| `locales` | Locale-Liste             | Sprachen, in denen diese Quelle vorliegt — siehe unten               |
| `generated` | Sektionsliste           | Artefakte, die neben dem Markdown als Seiten veröffentlicht werden — siehe unten |

Zwei Felder sind leicht zu verwechseln und teuer, wenn man sie falsch setzt:

- **`repo` lädt herunter, `origin` verlinkt nur.** Das eigene Repository in
  `repo` zu nennen lässt den Build den Checkout klonen, in dem er bereits steht.
- **`origin.path` ist der Ordner auf der Forge.** Setze ihn, wo der Ordner auf
  der Platte eine Kopie ist – in einen Build-Kontext kopierte Inhalte oder ein
  über `../` gelesener Nachbar-Checkout –, damit „Edit this page“ `docs/…` statt
  des Kopie-Pfads öffnet. Sprachordner werden über den `path` der Quelle
  abgebildet und müssen deshalb darunter liegen.
- **`history` kostet einen vollständigen Clone.** Content klont ein entferntes
  Repository mit `--depth 1`, sein Checkout hält also einen Commit und jede
  Datei sieht aus, als hätte sie die Person geschrieben, die die Spitze gesetzt
  hat — falsche Daten, keine fehlenden. Das einzuschalten macht den Clone einmal
  vollständig. Eine von der Platte gelesene Quelle ist ohnehin ein vollständiger
  Checkout und wird unabhängig davon gelesen.

**`slug` beansprucht ein Segment.** Ein Segment bekommt eine Quelle sonst erst,
wenn die Liste mehr als ein Repository nennt — alles oder nichts, für die ganze
Seite. Eine Quelle, die einen eigenen `slug` schreibt, wird ohnehin darunter
ausgeliefert, und die Quellen ohne bleiben, wo sie sind. Genau das lässt eine
Sache unter `/demo` neben einer Dokumentation stehen, die die Wurzel behält.


**`name` ist ein Name, `label` und `slug` sind Adressen.** Der Suchdialog
beschriftet jedes Ergebnis mit der Quelle, aus der es stammt, und vor diesem
Schlüssel konnte er das nur aus der URL ablesen — eine an der Wurzel
ausgelieferte Dokumentation meldete sich also als `/`, und eine Quelle, deren
Segment eine Abkürzung ist, als `tf`. `name` dient nur der Anzeige: Er erreicht
keine Collection, kein Präfix, keine Version und kein Ranking — genau deshalb
darf er Prosa sein und darf übersetzt werden.

```ts
sources: [
  // Ein Locale-Record, weil der Name ein Substantiv ist, das sich übersetzt.
  {
    repo: 'acme/docs',
    path: 'docs',
    name: { 'en-GB': 'Handbook', de: 'Handbuch', fr: 'Manuel' }
  },
  // Ein einfaches Literal, weil ein Produktname überall dasselbe Wort ist.
  { repo: 'acme/terraform-provider-acme', path: 'docs', slug: 'tf', name: 'Terraform Provider' }
]
```

Ohne Angabe fällt der Name auf das eigene Segment der Quelle zurück (`demo` →
**Demo**) und dann auf `duxt.title`, das auf einer Seite ohne Titel selbst das
lokalisierte Label **Dokumentation** ist. Lohnt sich überall dort, wo das
Segment eine Abkürzung ist. Zwei verschiedene Quellen, die auf einem Namen
landen würden, werden automatisch über ihr Repository oder ihren Ordner
unterschieden.

### Content, Ausschlüsse und Quellen-Dialekte

`content: false` veröffentlicht keine gewöhnlichen Markdown-Seiten aus der
Quelle, lässt ihre `generated`-Deklarationen aber aktiv. `exclude.drafts` und
`exclude.partials` ersetzen die jeweiligen quellenbezogenen Globs, wenn ein
Repository andere Konventionen nutzt.

`flavor: 'tfplugindocs'` liest die Verzeichnis-, Überschriften- und
Kategorieform eines von tfplugindocs erzeugten Markdown-Baums. Die Seiten
bleiben gewöhnliche Content-Seiten für Suche, Versionen, Locales und
Machine-Reader. Siehe
[Terraform-Provider-Dokumentation veröffentlichen](/guides/publish-terraform-provider-docs).

## Refs

Eine bloße Zeichenkette ist ein **Branch**. Ein Tag muss das sagen: git hält
Branches und Tags in getrennten Namensräumen, und einen Tag unter `refs/heads`
zu verlangen lässt den Build mit `Could not find refs/heads/…` scheitern.

```ts
refs: [
  'main',                                     // ein Branch
  { branch: 'next', status: 'upcoming' },     // derselbe, mit einem Lebenszyklus
  { tag: 'v2.0.0', label: 'v2' },             // ein Tag
  'latest'                                    // der neueste Semver-Tag, im Build aufgelöst
]
```

`'latest'` ist reserviert. Ein Branch, der wirklich `latest` heißt, braucht die
Form `{ branch }`.

## Releases

`releases` entdeckt Tags, statt eine lange Historie in der Konfiguration zu
pflegen. Die Erkennung ist opt-in und nennt immer ihre Auswahl: Ein implizites
„alle Releases“ gibt es nicht, weil dauerhaft erreichbare URLs eine Entscheidung
der Site sind.

```ts
{
  repo: 'acme/sdk',
  path: 'docs',
  releases: { select: 'minor' }
}
```

| `select`  | Veröffentlicht                                      |
| :-------- | :-------------------------------------------------- |
| `'all'`   | jeden Release                                       |
| `'minor'` | den neuesten Release jeder Minor-Linie              |
| `'major'` | den neuesten Release jeder Major-Linie              |

Pre-Releases bleiben ausgeschlossen, bis `prereleases: true` sie bewusst
einschließt. Der neueste ausgewählte Release ist standardmäßig aktiv; ein Ref
mit `default: true` oder `sourceOptions.defaultRef` gewinnt weiterhin.

Lebenszyklen ändern sich nicht: Der Status der Quelle oder `statusDefaults.tag`
gilt für jeden entdeckten Tag. Aus dem Alter eines Releases wird nichts
abgeleitet.

`refs` bleibt neben `releases` verfügbar. Ein Eintrag für einen entdeckten Tag
überschreibt dessen Label, Status, Default und Locales; alles andere wird daneben
veröffentlicht.

```ts
{
  repo: 'acme/sdk',
  releases: { select: 'major' },
  refs: [
    { tag: 'v1.4.2', label: 'v1', status: 'deprecated' },
    { branch: 'main', status: 'upcoming' }
  ]
}
```

Eine Auswahl ohne passenden Tag stoppt den Build und nennt Quelle und Auswahl.
Ein nicht lesbares Repository wird getrennt als Git-Fehler gemeldet. Dieselbe
Unterscheidung gilt für `latest`.

### Komponenten-Tags

Ein Monorepo, das mehrere Pakete getrennt veröffentlicht, taggt jedes nach
seiner **Komponente** — release-please schreibt `duxt@v0.4.0` neben
`duxt-typesense@v0.1.0`. Beide Formen sind Versionen: `latest`, `releases` und
die Reihenfolge im Umschalter lesen `<name>@vX.Y.Z` genau wie `vX.Y.Z`, und
Label und URL-Segment zeigen nur die Version — `v0.4.0`, nie `duxt@v0.4.0`. Der
Ref behält den vollständigen Tag, denn unter diesem Namen kennt git ihn.

Taggt das Repository mehr als ein Paket, bedeutet „der neueste Tag“ nichts,
solange nicht gesagt ist, wessen. `tagComponent` nennt das Paket:

```ts
{
  repo: 'kirchDev/duxt',
  path: 'docs',
  tagComponent: 'duxt',
  refs: [{ tag: 'latest', default: true }]   // duxt@v…, nie duxt-typesense@v…
}
```

**Einfache `vX.Y.Z`-Tags zählen weiterhin**: Sie sind die Releases des Pakets
aus der Zeit vor den Komponenten-Tags, und sie wegzulassen würde jedes davon
depublizieren. Tags einer anderen Komponente zählen nie. Ohne `tagComponent` ist
jeder Tag, der sich als Version liest, ein Kandidat — mit oder ohne Präfix.

## Locales

Weggelassen hat die Quelle eine Sprache und eine Collection. Aufgelistet wird
jeder Eintrag zu einer eigenen Collection.

```ts
locales: [
  'en-GB',                                              // der Standard: docs/ selbst
  'de',                                                 // docs/de/
  { locale: 'fr', path: 'translations/fr' },            // woanders in diesem Repository
  { locale: 'es', repo: 'acme/docs-es', path: 'docs' }  // ein anderes Repository
]
```

Eine Zeichenkette ist ein Ordner innerhalb des `path` der Quelle. Die
Objektform überschreibt `path`, `repo` und `ref` allein für diese Sprache — und
genau das lässt eine Übersetzung in einem eigenen Repository leben, mit eigenen
Betreuern und eigenem Releaseplan.

**Die Standard-Locale ist der Baum in `path` selbst und nimmt keinen Ordner.**
Welche das ist, kommt aus `sourceOptions.defaultLocale`, und sie muss mit
`i18n.defaultLocale` übereinstimmen — der Build scheitert, wenn sie abweichen,
denn `content.config.ts` löst die Collections ohne Zugriff auf die
Nuxt-Konfiguration auf.

Ein Ref darf eigene `locales` tragen, die die der Quelle überschreiben, genau
wie `status`. Das ist die übliche Form: Die aktuelle Version ist übersetzt, die
dahinter nicht.

```ts
refs: [
  { tag: 'v2.0.0' },                     // erbt die Locales der Quelle
  { tag: 'v1.0.0', locales: ['en-GB'] }  // nur das Original
]
```

Benenne einen Ordner nach der **Sprache**, wo eine Region nichts hinzufügt:
`docs/pt/` bedient sowohl `pt-PT` als auch `pt-BR`, weil eine Seite über ihre
Basissprache zurückfällt. Dieselbe Regel, der die Locale-Dateien der Ebene
folgen.

## Status

`statusDefaults` setzt einen Lebenszyklus je Ref-Art, wenn der Ref selbst keinen
nennt: `latest` gilt für den durch den reservierten Eintrag gewählten Tag,
`branch` für Branches und `tag` für explizite oder entdeckte Tags. Ein expliziter
Ref-Status gewinnt; der Status der Quelle ist der gemeinsame Fallback.

```ts
statusDefaults: {
  latest: 'current',
  branch: 'upcoming',
  tag: 'deprecated'
}
```

| Wert         | Bedeutet                                            |
| :----------- | :-------------------------------------------------- |
| `upcoming`   | Noch nicht veröffentlicht — kann sich noch ändern    |
| `current`    | Die Dokumentation, die zu lesen ist                  |
| `maintained` | Älter, weiterhin unterstützt                         |
| `deprecated` | Älter, und der Leser sollte aktualisieren            |
| `eol`        | Tot — wird gewarnt, und aus der Sitemap heraus       |

Was jeder Wert eine Seite kostet, steht in
[URLs und Versionen](/concepts/urls-and-versions).

## Generierte Sektionen

`generated` listet Artefakte auf, die kein Markdown sind, und den Typ, der jedes
davon zu Seiten liest. Was der Mechanismus ist und welche zwei Richtlinien ein
Typ beantwortet, steht in
[Generierte Sektionen](/concepts/generated-sections); die Felder unten sind
dieselben, welcher Typ sie auch liest.

| Feld         | Typ                      | Anmerkungen                                                       |
| :----------- | :----------------------- | :----------------------------------------------------------------- |
| `type`       | `string`                 | Der Registry-Schlüssel des Typs — `changelog`, `openapi`, `bruno`, ein eigener |
| `path`       | `string`                 | Das Artefakt, relativ zur eigenen Wurzel der Quelle                 |
| `label`      | `string`                 | Der Navbar-Eintrag und — slugifiziert — das URL-Segment             |
| `slug`       | `string`                 | Überschreibt das Segment, das das Label ergeben würde               |
| `options`    | Objekt                   | Die Knöpfe dieses Typs; jeder Typ prüft seine eigenen               |
| `versions`   | Versionsliste            | Versionen dieses Artefakts — siehe unten                            |
| `locales`    | `Record<string, string>` | Ein Artefakt pro Locale, nur von einem `per-locale`-Typ gelesen     |
| `navigation` | Platzierung              | `'sections'` (Standard), `'navigation'` oder `false`                |
| `icon`       | `string`                 | Fällt auf das Icon des Typs zurück                                  |

**`path` ist ein Pfad und nie eine URL.** Bei einer Quelle, die Content klont,
ist er relativ zur Wurzel dieses Checkouts — das Artefakt reist also mit der
Version, zu der es gehört, eine Regel in beide Richtungen. Ein beliebiger Ort
würde erlauben, ein Artefakt von überall zu holen, und die Frage nach Netzwerk
zur Build-Zeit wieder öffnen, die `sources` bereits geschlossen hat.

**`label` ist eine einfache Zeichenkette und kein übersetzter Text**, aus
demselben Grund, aus dem das Label einer Version einer ist: Ein übersetzter Text
ist keine stabile URL.

### Eine Sektion mit eigenen Versionen

Eine Version ist normalerweise ein **Checkout**: `refs` an der Quelle
veröffentlicht jede ihrer Sektionen einmal pro Ref. Eine API liegt dagegen oft
als `openapi/v1.yaml` neben `openapi/v2.yaml` im selben Repository und ist nach
**Datei** versioniert. Ohne `versions` wären das zwei unabhängige Sektionen und
zwei Einträge in der Navigation.

```ts [app/app.config.ts]
generated: [
  {
    type: 'openapi',
    label: 'API',
    path: 'openapi/v2.yaml',
    versions: [
      { version: 'v2', path: 'openapi/v2.yaml' },
      { version: 'v1', path: 'openapi/v1.yaml', status: 'deprecated' }
    ]
  }
]
```

| Feld      | Anmerkungen                                                       |
| :-------- | :---------------------------------------------------------------- |
| `version` | Im Umschalter angezeigt und in der URL verwendet                  |
| `path`    | Das Artefakt dieser Version; fällt auf den Pfad der Deklaration zurück |
| `locales` | Artefakte je Locale für diese Version                              |
| `status`  | Lebenszyklus — `deprecated`, `eol`, `upcoming`                     |
| `default` | Ohne Versionssegment ausgeliefert; standardmäßig der erste Eintrag |

Der Standard liegt unter `/api`, jede andere Version unter ihrem Segment wie
`/v1/api`. Der Umschalter bietet sie wie die Refs einer Quelle an, einschließlich
Warnung, `noindex` und Canonical für eine nicht aktuelle Version.

Sie stehen absichtlich in **einer Deklaration statt in zwei Quellen**: Nur
Varianten aus derselben Deklaration werden als Versionen voneinander angeboten.
Eine eigene Quelle je API-Version würde außerdem den Dokumentationsbaum doppelt
veröffentlichen.

Verwende sie **nie neben `refs` derselben Quelle**. Beide beanspruchen dasselbe
URL-Segment und der Build lehnt die Kombination ab. Ein `global`-Typ lehnt sie
ebenfalls ab, weil er genau eine Historie unter einer versionsneutralen URL
veröffentlicht. Ein Changelog ist nicht global: Es wird je Version veröffentlicht
und kann wie eine API-Referenz `versions` tragen.

### Welche Version ist welche?

Drei Dinge heißen rund um eine Referenzseite Version, aber nur zwei gehören zu
duxt:

- **Die Version in URL und Umschalter** ist ein Ref oder ein oben deklarierter
  `version`-Wert. Das Badge zeigt, welche Variante gelesen wird.
- **`duxt.version`** ist die Zeichenkette der Site. Sie steht nur dann im Badge,
  wenn es nichts umzuschalten gibt.
- **`info.version` eines OpenAPI-Dokuments** ist die eigene Aussage des Dokuments
  über die beschriebene API. Sie erscheint als **API-Version** auf der
  Referenzseite, nie im Umschalter-Badge.

Die Zahlen sind oft ähnlich, bleiben aber verschiedene Fakten; duxt leitet keine
aus der anderen ab.

`options` ist für alles außer dem Typ, der sie liest, undurchsichtig — eine
Granularität bedeutet einem Changelog etwas und einer API-Referenz nichts. Ein
Schlüssel, den der Typ nicht kennt, lässt den Build scheitern, statt ignoriert zu
werden: Eine falsch geschriebene Option ist eine Site, die still nicht bekommt,
was sie konfiguriert hat.


## Quellenoptionen

| Feld            | Standard          | Was es tut                                                 |
| :-------------- | :---------------- | :--------------------------------------------------------- |
| `showRepo`      | aus               | Erzwingt ein Repository-Segment bei einem einzelnen Repository |
| `showVersion`   | aus               | Erzwingt ein Versionssegment bei einer einzelnen Version    |
| `defaultRef`    | der erste Ref     | Der Ref, der ohne Versionspräfix ausgeliefert wird          |
| `defaultLocale` | die erste Locale  | Die Locale, die aus `path` selbst ausgeliefert wird, ohne Ordner |

## Das aufgelöste Manifest

Der Build macht aus der Liste oben `duxt.resolvedSources`, und das ist es, was
das Theme liest. `useDuxtCollection()` legt es offen; jeder Eintrag trägt den
Collection-Namen, das URL-`prefix`, `repo`, `version`, `name`, `isDefault`,
`locale`,
`isDefaultLocale`, `status`, das Repository und den Ref, aus denen die Seiten
kamen, und ob seine `history` gelesen wurde.

Der Locale fehlt bewusst im `prefix`: i18n stellt ihn dem Pfad ohnehin voran,
jede Sprache einer Quelle teilt sich also ein Präfix und unterscheidet sich nur
durch die Collection.

## Dokumentationsmedien

Generierte Dokumentationsbilder gehören nach `docs/_assets/`. Referenzen sind relativ zur Markdown-Datei: `docs/1.guides/1.demo.md` verwendet `../_assets/demo.gif`. Ein führendes `/_assets/` bezeichnet die Dokumentationswurzel der Quelle. Dies gilt auch für das Bildattribut `dark`.

duxt veröffentlicht PNG-, JPEG-, GIF-, SVG-, WebP-, AVIF-, APNG- und ICO-Ausgaben automatisch, auch aus entfernten Quellen am ausgewählten Ref. Öffentliche URLs trennen Repository, Dokumentationswurzel und Ref; Seitenlinks und Bildanbieter bleiben erhalten. `_assets/` wird weder Abschnitt noch Seite. Tapes, Skripte, Dockerfiles und andere Aufnahmequellen werden nicht veröffentlicht.

Sprachneutrale Bilder bleiben im gemeinsamen `_assets/`-Verzeichnis. Eine Seite unter `docs/de/` kann `../_assets/demo.gif` verwenden; eine ausdrücklich erzeugte deutsche Variante unter `docs/de/_assets/` verwendet `_assets/demo.gif`. Bilder stammen aus dem Repository und Ref der Seite. Ein Sprach-Repository teilt Bilder innerhalb seines Checkouts, lädt jedoch keine Medien aus einem anderen Repository. Alt-Text und Bildunterschriften werden mit der Seite übersetzt.