mindnet/docs/03_Technical_References/03_tech_frontend.md
2025-12-16 18:46:11 +01:00

172 lines
7.1 KiB
Markdown

---
doc_type: technical_reference
audience: developer, frontend_architect
scope: architecture, graph_viz, state_management
status: active
version: 2.7.0
context: "Technische Dokumentation des modularen Streamlit-Frontends, der Graph-Engines und des Editors."
---
# Technical Reference: Frontend & Visualization
**Kontext:** Mindnet nutzt Streamlit nicht nur als einfaches UI, sondern als komplexe Applikation mit eigenem State-Management, Routing und Persistenz.
---
## 1. Architektur & Modularisierung (WP19)
Seit Version 2.6 ist das Frontend (`app/frontend/`) kein Monolith mehr, sondern in funktionale Module unterteilt.
### 1.1 Dateistruktur & Aufgaben
| Modul | Funktion |
| :--- | :--- |
| `ui.py` | **Router.** Der Entrypoint. Initialisiert Session-State und entscheidet anhand der Sidebar-Auswahl, welche View gerendert wird. |
| `ui_config.py` | **Konstanten.** Zentraler Ort für Farben (`GRAPH_COLORS`), API-Endpunkte und Timeouts. |
| `ui_api.py` | **Backend-Bridge.** Kapselt alle `requests`-Aufrufe an die FastAPI. |
| `ui_callbacks.py` | **State Transitions.** Logik für View-Wechsel (z.B. Sprung vom Graph in den Editor). |
| `ui_utils.py` | **Helper.** Markdown-Parsing (`parse_markdown_draft`) und String-Normalisierung. |
| `ui_graph_service.py`| **Data Logic.** Holt Daten aus Qdrant und bereitet Nodes/Edges auf (unabhängig von der Vis-Library). |
| `ui_graph_cytoscape.py`| **View: Graph.** Implementierung mit `st-cytoscape` (COSE Layout). |
| `ui_editor.py` | **View: Editor.** Logik für Drafts, manuelles Editieren und **Async Feedback**. |
### 1.2 Konfiguration (`ui_config.py`)
Zentrale Steuerung der visuellen Semantik.
# Mapping von Node-Typen zu Farben (Hex)
GRAPH_COLORS = {
"project": "#ff9f43", # Orange
"decision": "#5f27cd", # Lila
"experience": "#feca57", # Gelb (Empathie)
"concept": "#54a0ff", # Blau
"risk": "#ff6b6b" # Rot
}
---
## 2. Graph Visualisierung
Mindnet nutzt primär **Cytoscape** für Stabilität bei großen Graphen.
### 2.1 Engine: Cytoscape (`st-cytoscape`)
* **Algorithmus:** `COSE` (Compound Spring Embedder).
* **Vorteil:** Verhindert Überlappungen aktiv (`nodeRepulsion`).
### 2.2 Architektur-Pattern: "Active Inspector, Passive Graph"
Ein häufiges Problem bei Streamlit-Graphen ist das "Flackern" (Re-Render) bei Klicks. Wir lösen das durch Entkopplung:
1. **Stable Key:** Der React-Key der Komponente hängt *nicht* von der Selektion ab, sondern nur vom Zentrum (`center_id`) und Layout-Settings.
2. **CSS-Selektion:** Wir nutzen **nicht** den nativen `:selected` State (buggy bei Single-Select), sondern injizieren eine CSS-Klasse `.inspected`.
**Stylesheet Implementierung (`ui_graph_cytoscape.py`):**
stylesheet = [
{
"selector": "node",
"style": { "background-color": "data(bg_color)" }
},
# Wir steuern das Highlight manuell über eine Klasse
{
"selector": ".inspected",
"style": {
"border-width": 6,
"border-color": "#FFC300", # Gelb/Gold
"z-index": 999
}
},
# Native Selektion wird unterdrückt/unsichtbar gemacht
{
"selector": "node:selected",
"style": { "overlay-opacity": 0, "border-width": 0 }
}
]
---
## 3. Editor & Single Source of Truth
Ein kritisches Design-Pattern ist der Umgang mit Datenkonsistenz beim Editieren ("File System First").
### 3.1 Das Problem
Qdrant speichert Metadaten und Chunks, aber das Feld `fulltext` im Payload kann veraltet sein oder Formatierungen verlieren.
### 3.2 Die Lösung (Logic Flow)
Der `switch_to_editor_callback` in `ui_callbacks.py` implementiert folgende Kaskade:
def switch_to_editor_callback(note_payload):
# 1. Pfad aus Qdrant Payload lesen
origin_fname = note_payload.get('path')
content = ""
# 2. Versuch: Hard Read von der Festplatte (Source of Truth)
if origin_fname and os.path.exists(origin_fname):
with open(origin_fname, "r", encoding="utf-8") as f:
content = f.read()
else:
# 3. Fallback: Rekonstruktion aus der DB ("Stitching")
# Nur Notfall, falls Docker-Volume fehlt
content = note_payload.get('fulltext', '')
# State setzen (Transport via Message-Bus)
st.session_state.messages.append({
"role": "assistant",
"intent": "INTERVIEW",
"content": content,
"origin_filename": origin_fname
})
st.session_state["sidebar_mode_selection"] = "📝 Manueller Editor"
### 3.3 Async Save Pattern (Neu in v2.7 / WP-14)
Um Timeouts bei der Smart-Edge-Berechnung zu vermeiden, nutzt der Editor ein **"Fire & Forget"** Muster.
1. **Request:** UI sendet Markdown an `/ingest/save`.
2. **Backend:**
* Validiert Request.
* Speichert Datei auf Disk (Persistenz garantiert).
* Startet `BackgroundTasks` für LLM-Analyse und Embedding.
* Returniert sofort `status: queued`.
3. **UI Feedback:**
* Editor zeigt "Erfolgreich eingereiht".
* User muss nicht warten.
* (ToDo: WebSocket Notification bei Abschluss).
---
## 4. State Management Patterns
### 4.1 URL Persistenz (Deep Linking)
Layout-Einstellungen werden in der URL gespeichert, damit sie einen Page-Refresh (F5) überleben.
# ui_graph_cytoscape.py
def update_url_params():
st.query_params["depth"] = st.session_state.cy_depth
st.query_params["rep"] = st.session_state.cy_node_repulsion
# Init
if "cy_depth" not in st.session_state:
st.session_state.cy_depth = int(st.query_params.get("depth", 2))
### 4.2 Resurrection Pattern
Verhindert Datenverlust, wenn der Nutzer während des Tippens den Tab wechselt. Der Editor-Inhalt wird bei jedem Keystroke (`on_change`) in `st.session_state` gespiegelt und beim Neuladen der Komponente von dort wiederhergestellt.
### 4.3 Healing Parser (`ui_utils.py`)
Das LLM liefert oft invalides YAML oder Markdown. Der Parser (`parse_markdown_draft`):
* Repariert fehlende Frontmatter-Trenner (`---`).
* Extrahiert JSON/YAML aus Code-Blöcken.
* Normalisiert Tags (entfernt `#`).
---
## 5. Constraints & Security (Known Limitations)
### 5.1 File System Security
Der Editor ("File System First") vertraut dem Pfad im Qdrant-Feld `path`.
* **Risiko:** Path Traversal (z.B. `../../etc/passwd`).
* **Mitigation:** Aktuell findet keine strikte Prüfung statt, ob der Pfad innerhalb des `./vault` Ordners liegt. Das System setzt voraus, dass die Vektor-Datenbank eine **Trusted Source** ist und nur vom internen Importer befüllt wird.
* **ToDo:** Bei Öffnung der API für Dritte muss hier eine `Path.resolve().is_relative_to(VAULT_ROOT)` Prüfung implementiert werden.
### 5.2 Browser Performance
Die Graph-Visualisierung (`st-cytoscape`) rendert Client-seitig im Browser.
* **Limit:** Ab ca. **500 Knoten/Kanten** kann das Rendering träge werden.
* **Design-Entscheidung:** Das UI ist auf **Ego-Graphen** (Nachbarn eines Knotens) und gefilterte Ansichten ausgelegt, nicht auf die Darstellung des gesamten Knowledge-Graphs ("Whole Brain Visualization").