perf(sources): Quellen-Health Pagination (default 100, plus mehr/alle laden)

Echter Bottleneck war der DOM-Render von 519 Tabellen-Zeilen, nicht
das Backend (45ms). Backend-Slim und Cache aus dem letzten Commit
haben Bandbreite und wiederholte Klicks beschleunigt, aber der erste
Klick blieb langsam, weil weiterhin alle 519 Items in einem
innerHTML-Schub gerendert wurden.

Lösung: Server-Side-Pagination.

Backend (/api/sources/health):
- Neue Query-Param: limit (default 100, max 5000), offset (default 0)
- Counters errors/warnings/ok/total_checks aus separater GROUP-BY-
  Aggregat-Query über den GESAMTEN Bestand, nicht über die Page.
- Neues Feld all_orgs in der Antwort: alle Tenants mit Health-Checks,
  damit das Filter-Dropdown auch im Pagination-Modus die volle
  Org-Liste hat.
- Neue Felder limit, offset, has_more.

Frontend (source-health.js):
- healthLoadLimit (default 100), wird durch loadMoreHealth() um 200
  hochgesetzt oder durch loadAllHealth() auf alles gesetzt.
- Cache-Key beinhaltet jetzt auch das aktuelle Limit, damit beim
  Mehr-laden nicht aus altem Cache bedient wird.
- Org-Liste kommt aus healthData.all_orgs statt aus den geladenen
  Page-Items, sonst wäre sie nach Pagination unvollständig.
- Footer mit zwei Buttons ("+200 laden", "Alle N weiteren laden")
  unter der Tabelle, nur sichtbar bei has_more=true.
- Counter-Anzeige: "X / Y angezeigt (von Z insgesamt)".

Cache-Buster für source-health.js auf 20260509f gebumpt.
Dieser Commit ist enthalten in:
claude-dev
2026-05-09 12:54:35 +00:00
Ursprung f6af21e6cb
Commit 657683d491
3 geänderte Dateien mit 93 neuen und 20 gelöschten Zeilen

Datei anzeigen

@@ -708,7 +708,7 @@
<script src="/static/js/app.js?v=20260509d"></script>
<script src="/static/js/sources.js?v=20260509d"></script>
<script src="/static/js/source-health.js?v=20260509e"></script>
<script src="/static/js/source-health.js?v=20260509f"></script>
<script src="/static/js/audit.js?v=20260509d"></script>
<div id="toastContainer" class="toast-container" aria-live="polite" aria-atomic="true"></div>
</body>