feat: Netzwerkanalyse-Feature (Wissensgraph)

Neues Feature zur Visualisierung von Entitäten und Beziehungen
aus ausgewählten Lagen als interaktiver d3.js-Netzwerkgraph.

- Haiku extrahiert Entitäten (Person, Organisation, Ort, Ereignis, Militär)
- Opus analysiert Beziehungen und korrigiert Haiku-Fehler
- 6 neue DB-Tabellen (network_analyses, _entities, _relations, etc.)
- REST-API: CRUD + Generierung + Export (JSON/CSV)
- d3.js Force-Directed Graph mit Zoom, Filter, Suche, Export
- WebSocket-Events für Live-Progress während Generierung
- Sidebar-Integration mit Netzwerkanalysen-Sektion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
Claude Dev
2026-03-16 00:34:26 +01:00
Ursprung d86dae1e86
Commit 9a35973d00
11 geänderte Dateien mit 4047 neuen und 603 gelöschten Zeilen

Datei anzeigen

@@ -518,10 +518,15 @@ const App = {
// Sidebar-Chevrons initial auf offen setzen (Archiv geschlossen)
document.querySelectorAll('.sidebar-chevron').forEach(c => c.classList.add('open'));
document.getElementById('chevron-archived-incidents').classList.remove('open');
var chevronNetwork = document.getElementById('chevron-network-analyses-list');
if (chevronNetwork) chevronNetwork.classList.add('open');
// Lagen laden (frueh, damit Sidebar sofort sichtbar)
await this.loadIncidents();
// Netzwerkanalysen laden
await this.loadNetworkAnalyses();
// Notification-Center initialisieren
try { await NotificationCenter.init(); } catch (e) { console.warn('NotificationCenter:', e); }
@@ -532,6 +537,9 @@ const App = {
WS.on('refresh_summary', (msg) => this.handleRefreshSummary(msg));
WS.on('refresh_error', (msg) => this.handleRefreshError(msg));
WS.on('refresh_cancelled', (msg) => this.handleRefreshCancelled(msg));
WS.on('network_status', (msg) => this._handleNetworkStatus(msg));
WS.on('network_complete', (msg) => this._handleNetworkComplete(msg));
WS.on('network_error', (msg) => this._handleNetworkError(msg));
// Laufende Refreshes wiederherstellen
try {
@@ -552,6 +560,17 @@ const App = {
}
}
// Zuletzt ausgewählte Netzwerkanalyse wiederherstellen
if (!savedId || !this.incidents.some(inc => inc.id === parseInt(savedId, 10))) {
const savedNetworkId = localStorage.getItem('selectedNetworkId');
if (savedNetworkId) {
const nid = parseInt(savedNetworkId, 10);
if (this.networkAnalyses.some(na => na.id === nid)) {
await this.selectNetworkAnalysis(nid);
}
}
}
// Leaflet-Karte nachladen falls CDN langsam war
setTimeout(() => UI.retryPendingMap(), 2000);
},
@@ -647,6 +666,10 @@ const App = {
document.getElementById('empty-state').style.display = 'none';
document.getElementById('incident-view').style.display = 'flex';
document.getElementById('network-view').style.display = 'none';
this.currentNetworkId = null;
localStorage.removeItem('selectedNetworkId');
this.renderNetworkSidebar();
// GridStack-Animation deaktivieren und Scroll komplett sperren
// bis alle Tile-Resize-Operationen (doppeltes rAF) abgeschlossen sind