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

7.1 KiB

doc_type audience scope status version context
technical_reference developer, frontend_architect architecture, graph_viz, state_management active 2.7.0 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").