Phase 6: Verwendungs-Sicht pro Grundquelle

Backend
- /api/sources/global liefert pro Quelle articles_7d, articles_30d und
  tenant_excluded_count (eine aggregierte Query mit CTEs, kein N+1).
- Match-Logik fuer Articles: LOWER(articles.source) = LOWER(sources.name)
  - articles.source_url ist Artikel-URL, NICHT Feed-URL, daher matcht das
    nicht mit sources.url. source-Name-Match liefert sinnvolle Treffer.
- tenant_excluded_count zaehlt distinct organization_ids aus
  user_excluded_domains (per LOWER(domain)-Match).

Frontend
- dashboard.html: zwei neue sortierbare Spalten Aktivitaet (7d/30d) +
  Sperren in der Grundquellen-Tabelle.
- style.css: .activity-cell + .exclude-badge Styles (mit zero-Variante
  fuer ruhigen Look bei keiner Aktivitaet/Sperre).
- sources.js:
  - cols 9 -> 11
  - Render: 7d-Wert fett, 30d-Wert dezent, Tooltip 7 Tage / 30 Tage
  - Sort-Logik: NUMERIC_FIELDS um articles_7d/articles_30d/tenant_excluded_count
    erweitert (numerischer Compare statt localeCompare)
Dieser Commit ist enthalten in:
claude-dev
2026-05-09 03:23:42 +00:00
Ursprung 6b70a7195e
Commit e9ff2bac02
4 geänderte Dateien mit 77 neuen und 21 gelöschten Zeilen

Datei anzeigen

@@ -328,6 +328,8 @@
<th class="sortable" data-sort="domain" onclick="sortGlobalSources('domain')">Domain <span class="sort-icon"></span></th>
<th class="sortable" data-sort="source_type" onclick="sortGlobalSources('source_type')">Typ <span class="sort-icon"></span></th>
<th class="sortable" data-sort="article_count" onclick="sortGlobalSources('article_count')">Artikel <span class="sort-icon"></span></th>
<th class="sortable" data-sort="articles_30d" onclick="sortGlobalSources('articles_30d')">Aktivität <span class="sort-icon"></span></th>
<th class="sortable" data-sort="tenant_excluded_count" onclick="sortGlobalSources('tenant_excluded_count')">Sperren <span class="sort-icon"></span></th>
<th class="sortable" data-sort="last_seen_at" onclick="sortGlobalSources('last_seen_at')">Letzter Treffer <span class="sort-icon"></span></th>
<th class="sortable" data-sort="health_status" onclick="sortGlobalSources('health_status')">Health <span class="sort-icon"></span></th>
<th class="sortable" data-sort="status" onclick="sortGlobalSources('status')">Status <span class="sort-icon"></span></th>