# Querverweis-Übersicht

> Querverweis-Übersicht mit Link-Index für große Bäume

---

Es gibt drei Arten von Übersichten:

1. Übersicht über alle Daten für den Admin (**Admin-Übersicht**),
2. auf einen Stammbaum begrenzte Übersicht (**Benutzer-Übersicht**) und
3. auf einen Datensatz bezogene Übersicht in der Detailansicht (**Datensatz-Übersicht**, als Tab oder Modal).

Die **Admin-Übersicht** (Verwaltung → LinkEnhancer → Querverweis-Übersicht) ist eine serverseitig paginierte DataTable. Sie listet alle Datensätze auf, die klassische `@XREF@`-Querverweise oder LinkEnhancer-Links enthalten, mit einer Link-Auflistung pro-Datensatz.

Optionale Filter:
- referenzierte XREF (nur verfügbar, während ein frischer Link-Index aktiv ist — im Live-Scan-Modus ist das Feld ausgeblendet, da es dort nur ein grober Vorfilter wäre — keine klassischen Referenzen würden gefunden),
- Datensatz-Typ,
- Stammbaum und
- die Anzahl der pro Link-Klasse angezeigten Token (alle / 5 / 10 / 20, Default 5).

Die XREF-Zelle zeigt den Stammbaumnamen als zweite Zeile in dezenter Schrift. Der Datensatz-Typ ist eine eigene sortierbare Spalte. Jedes Inventar-Token wird als kurzer Anzeigekontext (Snippet) mit dem Link-Token selbst in Fett angezeigt.

![Admin overview](img/le/xref-overview-admin_de.png)

Optional kann man eine **Benutzer-Übersicht** pro Baum und eine **Datensatz-Übersicht** über die ein- und ausgehenden Referenzen pro GEDCOM-Datensatz aktivieren. Die Datensatz-Übersicht zeigt zudem die XREF und ggf. UIDs des Datensatzes an, damit diese Referenzen leichter in Notzen übernommen werden können.

![Record overview](img/le/xref-overview-record_de.png)

### Unterstützte Engines

| | Live-Übersicht | Link-Index (CLI) |
| --- | --- | --- |
| MariaDB / MySQL | ja (REGEXP-Gate) | ja |
| PostgreSQL | ja (REGEXP-Gate) | ja |
| SQLite / SQL Server | **Eingeschränkter Modus** — automatischer Fallback auf ein grobes `LIKE`-Gate + Volltabellen-Scan pro Anfrage (Banner auf der Seite); die exakte Klassifizierung erfolgt weiterhin in PHP | **nicht verfügbar** (braucht REGEXP + `MD5`) — die CLI beendet sich mit einem Fehler |

### Funktionsweise

Bei großen Bäumen kann der Live-Regex-Scan über die GEDCOM-Tabellen langsam sein, daher kann die Seite stattdessen einen **Link-Index** aus drei Modultabellen lesen (der Abschnitt [Entwicklung / Projekt-Struktur](../../dev/project-structure) enthält mehr Details zum Datenbank-Schema):

- `le_record_scan` — eine Zeile pro gescanntem Datensatz mit einem MD5-Fingerprint des Datensatztextes
- `le_link_index` — eine Zeile pro (Link, Ziel), das im Datensatz gefunden wurde (der zum Build-Zeitpunkt erfasste Anzeigekontext) — das Fundament für Anzeige der eingehenden Querverweise in der Datensatz-Übersicht
- `le_index_meta` — einzelne Zeile — der Zustand des letzten **vollständigen** Index-Laufs




<pre class="mermaid">flowchart TD
    CLI[&#34;🛠 cli/build-link-index.php&lt;br/&gt;Cron: */30 * * * *&#34;]

    subgraph Scan[&#34;🔍 Inkrementeller Scan&#34;]
        FP[&#34;MD5-Fingerabdruck&lt;br/&gt;pro Record&#34;]
        DIFF{&#34;🔀 Geändert?&lt;br/&gt;(neu / entfernt)&#34;}
    end

    subgraph Tables[&#34;💾 Tabellen&#34;]
        RS[(&#34;le_record_scan&lt;br/&gt;file, xref, hash&#34;)]
        LI[(&#34;le_link_index&lt;br/&gt;token, target, snippet&#34;)]
        META[(&#34;le_index_meta&lt;br/&gt;last_run, rows&#34;)]
    end

    PAGE[&#34;📄 XREF-Übersichtsseite&#34;]

    CLI --&gt; Scan
    FP --&gt; DIFF
    DIFF --&gt;|✅ ja| SCAN[&#34;PHP-Scan&lt;br/&gt;(XrefsService)&#34;]
    DIFF --&gt;|⏭ nein| SKIP[&#34;überspringen&#34;]
    SCAN --&gt; RS
    SCAN --&gt; LI
    CLI --&gt; META

    META --&gt;|&#34;🟢 fresh (&lt; 2 h)&#34;| PAGE
    META --&gt;|&#34;🟠 stale&#34;| LIVE[&#34;Live-Regex-Scan&#34;]
    LIVE --&gt; PAGE

    classDef scanStyle fill:#e3f2fd,stroke:#1565C0,stroke-width:2px
    classDef tablesStyle fill:#e8f5e9,stroke:#2E7D32,stroke-width:2px
    classDef decideStyle fill:#fff3e0,stroke:#E65100,stroke-width:2px
    classDef pageStyle fill:#fce4ec,stroke:#C2185B,stroke-width:2px

    class FP scanStyle
    class RS,LI,META tablesStyle
    class DIFF decideStyle
    class PAGE pageStyle
</pre>

Der Index wird durch <a href="https://codeberg.org/bschwede/linkenhancer/src/branch/main/cli/build-link-index.php" target="_blank" rel="noopener"><code>build-link-index.php</code></a>
 gepflegt:

- **Initialer Build** (erster Lauf oder `--rebuild`): Beide Indextabellen werden zurückgesetzt, alle Scan-Zeilen werden serverseitig in einer Bulk-Statement pro GEDCOM-Tabelle erstellt (schnell, null Zeilentransfer), und nur die Datensätze, die den Link-Vorfilter passieren, werden in PHP gescannt. Der initiale Build ist eine Einmal-Kosten — verwenden Sie einen höheren `--limit` dafür. Wenn er durch `--limit` unterbrochen wird, konvergiert der nächste Lauf (der Build ist idempotent).
- **Inkrementelle Läufe** (der normale Cron-Fall): Nur Datensätze, deren MD5-Fingerprint sich geändert hat — oder die hinzugefügt/entfernt wurden — werden neu gescannt (cursor chunked), sodass der Job auch auf großen Sites günstig bleibt.

Cron-Beispiel (alle 30 Minuten, max. 2000 Datensätze pro Lauf):

```
*/30 * * * * cd /path/to/webtrees && php modules_v4/linkenhancer/cli/build-link-index.php --limit=2000 >> /var/log/linkenhancer-index.log 2>&1
```

Nur ein **vollständiger Lauf** (ohne `--tree`), der **nicht durch `--limit` gekürzt** wird, markiert den Index als frisch (`le_index_meta.last_run`). Ein durch `--limit` gekürzter Lauf setzt dort fort, wo er aufgehört hat; ein `--tree`-Lauf aktualisiert nur diesen Baum.

### Index leeren (Flush)

`--flush` leert die Indextabellen und beendet sich (kein Rebuild) — für Tests (die Seite auf Live-Scan zwingen) und Wartung (sauberer Neustart bei kaputtem Index):

```
php modules_v4/linkenhancer/cli/build-link-index.php --flush            # alle Bäume
php modules_v4/linkenhancer/cli/build-link-index.php --flush --tree=5   # nur Baum 5
```

Das Frische-Flag wird immer zurückgesetzt, sodass die Seite zuverlässig auf den Live-Scan zurückfällt. Der nächste vollständige Lauf ist wieder ein **initialer Build** (Voll-Scan-Kosten). `--flush` kombiniert mit `--rebuild` ist redundant — `--rebuild` setzt bereits zurück und baut neu.

### Was zählt als Link

Die Übersicht und der Index verwenden einen gemeinsamen Vorfilter (einzelne Quelle: `XrefsService::linkPrefilterPatterns()`):

- `NOTE` (Level >= 1) mit `@XREF@` **oder** `](#@`-Link, mit Inhalt auf derselben Zeile. Ein NOTE-Wert, der *exactly eine Referenz* ist (`1 NOTE @N5@`), ist ein GEDCOM-**gemeinsamer Notiz-Pointer** — eine strukturelle Referenz, kein Text-Link, und wird nicht aufgelistet.
- `CONC`/`CONT`/`TEXT`/`_TODO` mit `@XREF@` (nackt ist ein Link) oder `](#@`-Link
- ein LE-Link kann einen optionalen `id=@XREF@`-Parameter tragen (maximal einer, die Position unter den Parametern ist egal) — wie die `wt=`-Parameter wird er als Link-Ziel indexiert
- der eigene Level-0-Text einer gemeinsamen Notiz (`0 @N1@ NOTE …`)
- die Übereinstimmung ist zeilenbasiert (keine Cross-Line-Matches), auf denselben Zeilen, die der Collector liest

Die Seite zeigt an, welche Quelle sie verwendet:

- **Index aktiv** (grüne Notiz): ein vollständiger, kompletter Index-Lauf ist vor weniger als 2 Stunden beendet (Default; `XrefsService::INDEX_FRESH_SECONDS`)
- **Live-Scan** (blaue Notiz): kein frischer Index — die Seite fällt auf den Live-Scan zurück
- **Eingeschränkter Modus** (gelbe Notiz, SQLite/SQL Server): siehe Enginetabelle oben

Verwenden Sie <a href="https://codeberg.org/bschwede/linkenhancer/src/branch/main/tests/p1-measure.php" target="_blank" rel="noopener"><code>p1-measure.php</code></a>
 (read-only) auf Ihrer Instanz, um zu prüfen, wie kostspielig der Live-Scan für Ihre Daten ist und den Cron-Zeitplan zu kalibrieren.
