Read-only PRD for a coding agent
Das bestehende Tagging-System erkennt Tags generisch und unterscheidet nicht zwischen…
1. Problem, goal & success metric
- Problem: Das bestehende Tagging-System erkennt Tags generisch und unterscheidet nicht zwischen biologischen und formalen Kategorien. Verwandte Begriffe liegen verstreut in der Mindmap, die Map ist schwer erkundbar.
- Goal: Das Tagging-System soll automatisch biologische Kategorien (Organ, Gewebe, Zelltyp, Krankheit, Funktion) und formale Kategorien (Methode, Ergebnis, Definition, Beispiel, Literatur) erkennen. Knoten derselben Kategorie clusterieren in der Map; biologische Kategorien liegen außen, formale Kategorien innen.
- Success metric: Bei 10 Testdokumenten werden mindestens 80 % der Tags der richtigen Kategorie zugeordnet. Die Mindmap startet unter 2 Sekunden bei 121 Tags.
2. Users & roles
- Studierende: laden Vorlesungsmaterialien (PDF/TXT/DOCX) hoch, erkunden Dokumente als interaktive Mindmap, bearbeiten und mergen Tags.
- Keine weiteren Rollen; es gibt kein Auth-/Nutzerkonzept.
Default: Keine weiteren Rollen, kein Auth.
3. Core workflows
- Studierende laden eine Datei (PDF/TXT/DOCX) hoch über den Upload-Dialog.
- Das Backend extrahiert Text, segmentiert Sätze, extrahiert Keywords (c-TF-IDF), clustert Tags bottom-up (L1–L5) und erzeugt eine Zusammenfassung.
- Die neue Kategorisierungs-Erkennung ordnet jedem Tag eine Kategorie (biologisch/formal + Unterkategorie) zu.
- Die Mindmap rendert Tags als Dots; Knoten derselben Kategorie clusterieren, biologische außen, formale innen.
- Studierende filtern nach Ebenen/Tags, bearbeiten Tags inline, mergen/löschen globale Tags und öffnen Dokumenten-Vorschau mit Summary.
4. Features & requirements
Upload ohne Größenbegrenzung
- Es gibt keine feste maximale Dateigröße.
- Ab 20 MB erscheint im Upload-Status der Hinweis „Große Datei – die Analyse kann länger dauern“.
- Der Hinweis blockiert den Upload nicht; die Mindmap-Startzeit (unter 2 s bei 121 Tags) bleibt davon unberührt.
5. Scope: must / later / never
Must
- Biologisch/formal-Kategorisierung jedes Tags (biologisch = Organ, Gewebe, Zelltyp, Krankheit, Funktion; formal = Methode, Ergebnis, Definition, Beispiel, Literatur). Prüfung: A9.
- Kategorienbasierte Positionierung in der Mindmap: Knoten derselben Kategorie clustern; biologische Cluster außen, formale innen. Prüfung: A10.
- Einmalige automatische Hintergrund-Neuanalyse bestehender Dokumente beim ersten Start nach dem Umbau; die Mindmap startet sofort und wird nie blockiert. Prüfung: A9, A10.
- Automatische Neuanalyse eines Dokuments nur bei Upload oder bei Änderung der Analyseversion. Prüfung: A9.
- Upload ohne feste Größenbegrenzung mit Hinweis „Große Datei – die Analyse kann länger dauern“ ab 20 MB, nur im Upload-Status, solange die Analyse läuft. Prüfung: A9.
- Retry fehlgeschlagener Analysen beim nächsten Start (max. 3 Versuche, Zähler dauerhaft gespeichert, Reset bei erneutem Upload). Prüfung: A9, A9b, A9c.
- Messbare Akzeptanz: 80 % korrekte Kategorisierung bei 10 Testdokumenten; Mindmap startet unter 2 s bei 121 Tags. Prüfung: A10, A10b.
Later
Leer. Erweiterungen werden bei Bedarf neu bewertet.
Never
- Benutzerkonten, Login, Berechtigungen, Microservices, Queues, Kubernetes.
- Manueller Button „Neu kategorisieren“ oder Retry-Button; die automatische Logik übernimmt beides.
- Blockierender Start: die Mindmap wartet nie auf die Hintergrund-Neuanalyse.
- Feste Größenbegrenzung beim Upload.
- Playwright-Test als Build-Gate: ein Fehlschlag erzeugt nur eine Terminal-Warnung.
6. Screens & UI
Upload-Status
- Ab 20 MB Dateigröße erscheint im Upload-Status der Hinweis „Große Datei – die Analyse kann länger dauern“, solange die Analyse läuft.
- Der Hinweis verschwindet automatisch, sobald die Analyse abgeschlossen ist.
- Schlägt die Analyse fehl, verschwindet der Hinweis; an seiner Stelle erscheint der Status „Analyse fehlgeschlagen“.
- Der Hinweis blockiert den Upload nicht; die Mindmap startet unverändert.
- In der Dokument-Vorschau erscheint kein zusätzlicher Hinweis; dort gilt nur der normale Analysestatus.
7. Design system & visual style
- 15490 characters is too long for small coding models: cut it under 2500, in short bullets without repeats
Dateien:
src/index.css: Design-Tokens, Wasserfarben-Textur, Art-Déco-Rahmen,
Eck-Ornamente, Layer-/Übergangsregeln.src/components/Dashboard.tsx: Haupt-Panels im Deco-Look, Suchleiste,
Tag-Fenster, Status-/Level-Panels.src/components/MindmapView.tsx: Label-Platzierung, Kollisionsauflösung,
Legenden-Plakette, LOD-Übergänge.src/components/WeightedEdge.tsx: gewichtete Kanten (aus Schritt 5).src/components/TagEditor.tsx,MindmapFilterMenu.tsx,TagManager.tsx,DocumentViewerModal.tsx: einheitliche Deco-Rahmen und Hintergründe.
Design-Tokens & Palette
- Primär-Grün
#1F331A(rgb 31, 51, 26) für aktive Elemente, Header,
Buttons, Fokuszustände und primäre Akzente. - Sand-Beige
#DDDDC7(rgb 221, 218, 199) als Sekundär- und Rahmenton,
Papierton#FAF8F5für Kartenflächen. - Die Variablen liegen in
@layer utilities(:root):--deco-green,--deco-beige. - Utility-Klassen:
.bg-watercolor-soft,.art-deco-border,.art-deco-card. - Wasserfarben-Textur:
body(fixierter Doppel-Verlauf) sowie Hauptcontainer
und Canvas über.bg-watercolor-soft; Panels erhalten zusätzlich einen
dezenten Radialverlauf.
Art-Déco-Rahmen & Verzierung
- Alle Haupt-Panels (Status, Abstraktionslevel, Gewählter Knoten,
Dokument-Vorschau, Tag-Fenster, Zusammenfassung, Mindmap, Footer-Suche)
nutzen.art-deco-card .art-deco-border: 2-px-Rahmen plus inset-Doppelring
(#DDDDC7/#1F331A). .art-deco-card .art-deco-borderergänzt vier kleine Rauten in den Ecken
(SVG-Data-URI imbackground-image) – rein dekorativ, ohne Layout-Einfluss..deco-headingzieht eine klassische Trennlinie mit verdickten Enden unter
Panel-Titeln; Rauten-Marker dienen als Titel-Akzente.- Modale nutzen
.deco-scrim(gedecktes Grün statt kühlem Stein) und
denselben Doppelrahmen. - Typografie unverändert nach Vorgabe: Cinzel (Versalien, weites Tracking)
für Überschriften, Labels und Buttons; Times New Roman für Fließtext,
Zähler, Titel, Badges und das Suchfeld.
Label-Platzierung (Stand: feste Verankerung, Schritt 10)
- Die Labels werden direkt in den Node-Komponenten gerendert
(GalaxyNode,DocumentNode,GroupNode), als Kind desInvZoomLayer
im DOM des Punkts. Dadurch laufen sie bei Drag, Zoom und Layoutwechsel
immer exakt mit ihrem Punkt mit – ein Abkoppeln ist baulich unmöglich. - Feste Anker statt freier Verschiebung: Standard ist zentriert direkt
unter dem Punkt (Abstand = Punktradius +LABEL_GAP= 6 px). Ist dieser
Platz durch einen fremden Punkt belegt, sitzt das Label direkt darüber,
sonst direkt links bzw. rechts daneben (Text zeigt zum Punkt hin).labelAnchorStyle()liefert dafür nurleft/top/transform
relativ zum Punkt. Es gibt keine Zeilen, keine X-Versätze und keine
Platzierung quer über die Karte mehr. - `placeLabels()` prüft nur noch die Sichtbarkeit: Es berechnet die
Screen-Rechtecke dieser festen Anker, vergleicht sie mit bereits
vergebenen Labels und allen sichtbaren Punkten und markiert Kollisionen
alshidden(Hover blendet sie ein). Kein Label wird verschoben. - Echter Viewport statt Canvas-Mitte: Die Screen-Position eines Punkts
istview.x + x · zoombzw.view.y + y · zoom. Der Viewport wird beim
Berechnen direkt übergetViewport()gelesen;labelZoombleibt nur der
entprellte Trigger, damit während einer Geste nicht jedes Frame neu
platziert wird. - Beim ersten Render existiert noch kein zentrierter Viewport;
onInit
stößt nachsetCentereinmalig eine Neuberechnung an (viewVersion). - Punkte sind Hindernisse: Neben bereits platzierten Labels zählen alle
sichtbaren Punkte als Hindernis – auch die Punkte feiner Tags, die auf der
aktuellen Stufe kein eigenes Label bekommen. Geprüft wird der Abstand zur
Kreisfläche (Radius + 4 px), nicht die Bounding-Box: Ein Label, das
nur die Ecke des Punkt-Quadrats berührt, verschwindet dadurch nicht. - Kollisionsbox ≈ sichtbare Schriftfläche: Breite aus der Zeichenzahl
(Cinzel-Versalien inkl.letterSpacingbreiter als Times), lange Namen
brechen auf zwei Zeilen um (max. 132 px); die Schätzung ist bewusst
konservativ (Zuschlag 14 px), damit die gemessene Schriftfläche nie
größer ist als die Box. - Priorisierung: Makro-Labels zuerst, danach der fokussierte Rang, zuletzt
der Rest. So bleiben die Hauptbegriffe am längsten lesbar. - Strikte Auflösung: Findet ein Label an keinem der vier Anker einen
kollisionsfreien Platz, wird es ausgeblendet und beim Hover wieder
eingeblendet (.mm-label-hidden). Labels werden nie übereinander gelegt.
Die Anzahl ausgeblendeter Labels hängt von der Canvas-Größe ab (bei
1600×1000: L3 19/22, L4 94/104 sichtbar; bei 1280×800: L3 9/22, L4 77/104). - Die Kraftsimulation nutzt einen labelbreitenabhängigen Kollisionsradius
(tagCollisionRadius,d3.forceCollide), damit die Knoten bereits im
Layout Abstand halten.
Radikaler Art-Déco-Reset (Logik-Erhalt)
Das komplette UI wurde ohne Änderung an Datenfluss, Hooks, Props oder
Handlern neu gestaltet. Angepasst wurden ausschließlich Klassen, Inline-Styles
und dekorative Elemente.
Neue Design-Elemente in `src/index.css`:
| Klasse | Wirkung |
|---|---|
.deco-surface-dark | Tiefgrüne Fläche mit Gold-Verlauf (Header, Toolbar, Auswahlkarte) |
.deco-rule-gold | Goldene Haarlinie mit Rauten-Akzente |
.deco-ornament-fan | Bogen- und Fächerlinien (Referenz „Musterplakat") |
.deco-ornament-corner | Feiner Eckwinkel für Karten |
.deco-ornament-star | Kleiner Rautenstern als Akzent |
.deco-arch | Bogenförmige Kachel (Dateisymbole) |
.art-deco-border-gold | Doppelrahmen mit zusätzlicher Gold-Haarlinie |
.deco-heading-gold | Gold-Trennlinie unter Panel-Titeln |
.deco-btn / .deco-btn-invert / .deco-btn-active | Bedienelemente (hell/dunkel/aktiv) |
Farbwelt: Primär #1F331A, Sand #DDDDC7, Papier #FAF8F5,
Gold #B08D57 / #D8C08C (neu in @theme als --color-gold).
Alle neutralen Tailwind-Töne (bg-gray-*, border-gray-*, bg-white,border-black/*, shadow-sm) wurden entfernt – im Quellcode kommt kein
Grauton mehr vor.
Datei für Datei umgesetzt:
Dashboard.tsx– Kopfzeile als tiefgrüne Deco-Bande mit Fächerornament,
Goldlinie und invertierten Buttons; Status-Panel mit Eckwinkel und Stern;
Abstraktionslevel mit Gold-Akzentkante; „Gewählter Knoten" als
dunkle Goldkarte; Suchleiste mit Gold-Haarlinie; Dokumentkarten mit
Bogen-Kachel.MindmapView.tsx– Toolbar als tiefgrüne Bande mit Gold-Aktionen,
Legende inline in der Toolbar (kein Overlay mehr auf der Karte),
Hover-Card mit Gold-Doppelrahmen, Eckwinkel und Stern.WeightedEdge.tsx– Kantenfarben der neuen Palette (Grün, Salbei, Gold).mindmapLevels.ts– Punktskala: Makro#1F331A→ Fein#DDDDC7,
Punktgrößen 14/13/12/11 px.DocumentPreview.tsx,DocPlaceholder.tsx,TagEditor.tsx,TagManager.tsx,DocumentViewerModal.tsx,MindmapFilterMenu.tsx,MarkdownText.tsx,NewTabLink.tsx– einheitliche Rahmen, Goldakzente,
Bogen-Kacheln, Fächerornamente, Cinzel-Überschriften.
Punkte & Edges in React Flow: Der fokussierte Rang (Stufe 1/2) und die
Makro-Knoten tragen einen goldenen Ring; Edges nutzen die Palette der neuen
Tokens. Die D3-Kollision (d3.forceCollide, labelbreitenabhängiger Radius)
bleibt unverändert, die Label-Platzierung zusätzlich um einen 2-px-Sicherheits-
abstand zwischen den Textflächen erweitert.
Gemini-Analyse (Schritt 8)
Dateien
src/services/geminiService.ts– Client, Prompt, robustes JSON-Parsing.src/api.ts–updateDocumentSummary().src/components/DocumentPreview.tsx– „Gemini"-Aktion + Statusleiste.src/components/Dashboard.tsx– Ablauf, Tag-/Level-Anzeige.backend/app/{models,store,main}.py–PATCH /api/documents/{id}/summary.
Konfiguration (.env, Vorlage in .env.example):
VITE_GEMINI_API_KEY=<Key aus https://aistudio.google.com/app/apikey>
VITE_GEMINI_MODEL=gemini-3.5-flash # Modellkette, kommagetrennt
VITE_GEMINI_BASE_URL= # optional, z. B. eigener ProxyDer Key ist in .env eingetragen (Datei ist in .gitignore).gemini-2.5-flash ist für neue AI-Studio-Keys gesperrt (404 „no longer
available to new users“) und neuere Modelle zeitweise überlastet (503 „high
demand"). Der Dienst probiert deshalb eine Modell-Kette durch
(gemini-3.5-flash → 3.6 → 3.7 → 3.8 → gemini-flash-latest) und
nutzt das erste erreichbare Modell. Das genutzte Modell wird in der
Statusleiste angezeigt.
> Sicherheit: VITE_*-Variablen landen im JS-Bundle und sind im Browser
> sichtbar. Der Key ist damit nur für Entwicklung/Demonstration geeignet.
> Produktiv den Key serverseitig halten und die Anfrage über das Backend
> proxyen. .env ist in .gitignore ausgenommen.
Ablauf
- Die Analyse startet automatisch nach dem Upload (siehe Schritt 11):
Das Backend analysiert die Datei beim Hochladen lokal (das erzeugt die
Tag-Hierarchie), direkt danach läuft – sofern ein Key hinterlegt ist –
die Gemini-Verfeinerung von Zusammenfassung und Tags im Hintergrund.
Einen „Analysieren"-Button gibt es nicht mehr. analyzeDocumentWithGemini()schickt max. 15 000 Zeichen an das erste
erreichbare Modell der Kette und erwartet{summary, tags[], abstractionLevel}.- Der Parser entfernt Markdown-Fences, extrahiert das erste JSON-Objekt
auch aus Fließtext und validiert die Felder (Abstraktionslevel L1–L4). - Die Zusammenfassung wird per
PATCH /api/documents/{id}/summary
dauerhaft gespeichert (analysisProvider: "gemini"), die Keywords
ersetzen die bisherigen. - Jeder Tag wird über die bestehende Tag-API angelegt und verknüpft – er
erscheint damit sofort als interaktiver Chip im Tag-Fenster, in der
Mindmap und in den Level-Zählern. - Die Statusleiste zeigt „Gemini-Analyse", das Abstraktionslevel und die
extrahierten Tags (ohne technische Modell-Bezeichnung); während des Laufs
steht dort „✨ Analysiere Dokument …". Das Abstraktionslevel-Panel weist
das Gemini-Abstraktionslevel aus; das Zusammenfassungs-Panel trägt ein
„Gemini"-Siegel.
Kopfzeile der Dokument-Vorschau (Standort ist nur 588 px breit):
Zeile 1 zeigt Icon, Dateiname und Metadaten, Zeile 2 die geschlossene
Aktionsgruppe „In neuem Tab öffnen · Dokument öffnen".
Fehlerverhalten: Ohne Key, ohne Text oder bei API-Fehlern bleibt die App
voll funktionsfähig – die lokale Backend-Analyse beim Upload läuft
unverändert weiter, der Status springt auf „Fehler".
Automatische Analyse nach dem Upload (Schritt 11)
Die Gemini-Verfeinerung ist an den Upload gekoppelt; ein manueller Klick ist
nicht mehr nötig. Der Upload-Dialog blockiert dabei nicht.
Ablauf in `Dashboard.tsx`
addFiles()lädt jede Datei überapi.uploadDocument()hoch. Die
Antwort enthält den neuen Gesamtzustand (inkl.text,summaryund der
lokal erzeugten Tags). Neue Dokumente werden per ID-Vergleich gegen den
vorherigen Stand gesammelt (uploaded).- Nach dem letzten Upload werden Zustand und Auswahl aktualisiert
(setState,setSelectedId(uploaded[0].id)) undbusyfällt auffalse– die Oberfläche ist sofort wieder bedienbar. - Die Notice meldet „… hochgeladen – die KI-Analyse läuft im Hintergrund.“
enqueueGeminiAnalysis(uploaded)setzt für jedes neue Dokument den
Statusrunningund hängt die Arbeit an eine Promise-Warteschlange
(geminiQueue,useRef). Mehrere Uploads bzw. schnelle Folge-Uploads
werden sequenziell abgearbeitet, damit sich die Zustandsantworten
des Backends (updateDocumentSummary, Tag-API) nicht überholen.- Pro Dokument läuft
applyGemini(): Text an Gemini, speichern der
Zusammenfassung/Keywords (analysisProvider: "gemini"), Anlegen und
Verknüpfen der Tags,setState()mit dem Serverzustand. Vorschau,
Tag-Chips, Level-Zähler und Mindmap aktualisieren sich dadurch ohne
weiteren Klick. - Fehler (kein Key, leerer Text, API-/Netzwerkfehler) setzen den
Dokumentstatus auferror; die lokal erzeugte Analyse bleibt erhalten.
UI-Indikatoren während des Laufs
- Dokument-Vorschau (Dashboard): Statusleiste „✨ Analysiere Dokument …“.
- Status-Panel links: zusätzliche Zeile „✨ KI-Analyse · läuft · n“, solange
mindestens eine Analyse aktiv ist (runningAnalysesausgeminiStatus).
Diese Zeile ist auch in der Mindmap-Ansicht sichtbar, wo die Vorschau-
Karte fehlt. - Notice-Toast direkt nach dem Upload (4 s).
Entfernt
- „Analysieren"-Button in
DocumentPreview.tsxsamtonAnalyze-Prop undRefreshCw-Import;analyzeDoc()inDashboard.tsx. - Leerer-Zusammenfassung-Hinweis verweist nicht mehr auf den Button
(„Noch keine Zusammenfassung vorhanden.“). api.analyzeDocument()bleibt als Mapping auf den bestehenden EndpointPOST /api/documents/{id}/analyzeerhalten (derzeit ohne UI-Aufrufer).
Politur: Zierelemente, Abstände, Kontrast
Nach dem Design-Reset wurden die verbliebenen Artefakte bereinigt:
- Grüne Flächen ohne Textur:
.deco-surface-darkist flaches#1F331A
ohne Gold-Verlauf. Die Fächer-Overlays (deco-ornament-fan) wurden aus
Header, Mindmap-Toolbar und „Gewählter Knoten" entfernt – auf dunklem
Grund wirkten sie wie ein kopiertes Muster. Gold bleibt den echten
Akzenten vorbehalten (Rauten, Linien, aktive Buttons). - Eck-Rauten auf dem Rahmen: Die vier Rauten der
.art-deco-card.art-deco-bordersind jetzt 8 px groß und überbackground-origin: border-boxauf dem Rahmen platziert. Sie dringen
dadurch höchstens ~4 px in den Innenbereich ein; mitp-4bleiben
Text und Icons ≥ 12 px entfernt (gemessen: 25 px für alle
Panel-Überschriften, 29–30 px für Toolbar und Suchfeld). - Kein Stern, keine gestapelten Rauten: Der Stern im Status-Panel und
die Rauten-Marker neben den Panel-Überschriften wurden entfernt.
Übrig bleibt je Panel eine einzige saubere Gold-Trennlinie. - Titel-Raute: Der Kopfzeilen-Diamant
◇sitzt jetzt mitpl-8undleft-1vollständig sichtbar. - Suchleiste: Innenabstand
px-6 py-3, Lupe und Platzhalter durchgap-3getrennt, Goldlinie aufinset-x-6eingerückt. - Innenabstände: Hover-Card
p-4, Filtermenüpx-4 py-3, Vorschau-
Sektionenp-4, Tag-Editor/Tag-Verwaltung/Viewerpx-5 py-4. - Kontrast: Beschriftungen im Status-Panel (
DOKUMENTE,AUSSTEHEND,TAGS) stehen jetzt in vollem#1F331A; der Erklärungstext unten links
in#1F331A(Versalien) bzw.#3E4136(Serif). Die Level-Badges beziehen
Farbe und Textfarbe aus der Rang-Palette statt aus einem zufälligen
Backend-Tag – dadurch bleibt das Badge unabhängig von den Daten lesbar.
Übergänge
- Knoten-Ein-/Ausblenden: 380 ms, Label-Opacity 300 ms.
- Labels: nur Opacity (300 ms) – die Position ist fest am Punkt verankert
und wird nicht mehr animiert. Beim Wechsel des Ankers springt das Label
bewusst direkt (kein Wandern über die Karte). - Punkt-Hover/Selektion: 160 ms (Ring, Kontur).
- Kanten: 220 ms für
stroke-widthundopacity. prefers-reduced-motion: reduceschaltet alle Übergänge ab.
Layout-Stabilität
- Das 12-Spalten-Grid (
grid-cols-12 gap-4) bleibt unverändert; alle
Panels sind fest, interne Scroll-Container scrollen nur intern. - Verifiziert: Grid, Footer und Suchfeld bleiben pixelgleich beim Wechsel
von Ebene, Modus, Auswahl und Hover; kein globales Scrollen.
---
8. Data model
| Entität | Feld | Typ | Pflicht | |
|---|---|---|---|---|
| Doc | id | string | ja | |
| Doc | name | string | ja | |
| Doc | type | string | ja | |
| Doc | size | number | ja | |
| Doc | status | string | ja | |
| Doc | summary | string | nein | |
| Doc | keywords | string[] | nein | |
| Doc | tagIds | string[] | nein | |
| Doc | text | string | nein | |
| Doc | fileUrl | string | nein | |
| Doc | uploadedAt | datetime | ja | |
| Doc | analyzedAt | datetime | nein | |
| Doc | analysisProvider | string | nein | |
| Doc | failedAttempts | number (≥0, Startwert 0, Reset auf 0 bei erneutem Upload) | ja | |
| Tag | id | string | ja | |
| Tag | name | string | ja | |
| Tag | level | number (1–5) | ja | |
| Tag | parentId | string | nein | |
| Tag | childCount | number | ja | |
| Tag | color | string | ja | |
| Tag | textColor | string | ja | |
| Tag | documentIds | string[] | ja | |
| Tag | category | enum (biologisch \ | formal) | ja |
| Tag | subcategory | enum (organ, gewebe, zelltyp, krankheit, funktion, methode, ergebnis, definition, beispiel, literatur) | ja |
Verbindlich: failedAttempts wird im Datenspeicher persistent abgelegt und übersteht Neustarts. Ein erneuter Upload setzt den Wert auf 0 zurück.
9. APIs & integrations
Backend-Routen (FastAPI, Port 8000)
- GET /api/state · POST /api/documents · GET /api/documents/{id}/file · POST /api/documents/{id}/analyze · GET /api/documents/{id}/prompt · DELETE /api/documents/{id}
- POST /api/documents/{id}/tags · DELETE /api/documents/{id}/tags/{tagId}
- GET /api/tags · PATCH /api/tags/{id} · DELETE /api/tags/{id} · POST /api/tags/merge · GET /api/health
Optional extern
- Gemini API über
VITE_GEMINI_API_KEY(in Entwicklung clientseitig; für Produktion serverseitig proxyen). - OpenAI-kompatibler LLM-Client über
LLM_API_KEY,LLM_BASE_URL,LLM_MODEL,LLM_TIMEOUT; ohne Schlüssel rein lokal.
Default: CORS nur für http://localhost:5173; alle Routen wie in der bestehenden Datei.
10. Auth, permissions & security
- Nicht nötig: Keine Benutzerkonten, kein Login, keine Berechtigungen. Alle Nutzer sehen denselben Zustand.
- Default: Kein Auth-Konzept, wie in Ihrer Datei beschrieben.
11. Performance, privacy & accessibility
Build-Verhalten
npm run buildbricht bei TypeScript- oder Build-Fehlern weiterhin ab.- Der Playwright-Hilfslauf in Slice 4 erzeugt bei Abweichungen nur eine Warnung im Terminal; der Build läuft trotzdem durch.
Performance
- Messbedingung: typischer Laptop mit 4 bis 8 GB RAM, Browser mit weiteren geöffneten Tabs.
- Messpunkt: vom ersten Render bis alle 121 Knoten sichtbar; Schwelle 2 Sekunden.
- Die Messung erfolgt manuell vor der Abgabe; der Playwright-Lauf dient nur als Hilfe.
- Die Startzeit gilt auch während die Hintergrund-Neuanalyse läuft; die Mindmap wartet nie darauf.
- Zoom/Pan ohne sichtbares Flackern; Label-Kollisionen 0 bei 1280×800 bis 1920×1080.
- Positionsanpassung nach Kategorie-Update: sanfte Animation ca. 300 ms, ohne Sprünge und ohne Neuaufbau des Layouts.
Privacy
- Keine Benutzerdaten, keine Auth; Dokumente bleiben lokal auf dem Rechner.
Accessibility
prefers-reduced-motion: reduceschaltet alle Übergänge ab, auch die 300-ms-Positionsanpassung.- Kontrast der Level-Badges unabhängig von der Backend-Tagfarbe.
12. Edge cases & errors
Wiederholungen bei fehlgeschlagener Analyse
- Jedes Dokument speichert die Anzahl fehlgeschlagener Analyseversuche (
failedAttempts, Startwert 0) dauerhaft im Datenspeicher; der Wert bleibt nach einem Neustart erhalten. - Beim nächsten Start werden Dokumente mit Status „Analyse fehlgeschlagen“ automatisch erneut analysiert, solange
failedAttemptskleiner als 3 ist; kein Button. - Nach dem dritten fehlgeschlagenen Versuch wird nicht mehr automatisch wiederholt; der Status „Analyse fehlgeschlagen“ bleibt sichtbar, bis das Dokument erneut hochgeladen wird.
- Ein erneuter Upload setzt
failedAttemptsauf 0 zurück.
13. Stack & constraints
- Frontend: React 19, Vite, TypeScript, Tailwind, @xyflow/react, d3-force, @google/genai (optional). Backend: FastAPI, Python 3.9.6, uvicorn, In-Memory-Store, pdf.js/react-pdf für PDF-Extraktion.
- Default: Stack aus Ihrer Datei übernommen.
14. Existing code & do-not-change
- Backend: backend/app/{main.py, store.py, analysis.py, pipeline.py, prompts.py, llm.py, hierarchy.py, models.py}. Frontend: src/components/{Dashboard.tsx, MindmapView.tsx, TagEditor.tsx, TagManager.tsx, MindmapFilterMenu.tsx, DocumentPreview.tsx, DocumentViewerModal.tsx, WeightedEdge.tsx, MarkdownText.tsx}, src/api.ts, src/mindmapLevels.ts, src/mindmapFilters.ts, src/mindmapDocuments.ts, src/mindmapOverlap.ts, src/index.css.
- Default: Alle bestehenden Dateien aus Ihrer Datei übernommen, dürfen nicht ohne Not geändert werden.
15. Build order
- Slice 1 – Kategorisierung im Backend:
category+subcategoryin Pipeline und Modelle; Analyseversion je Dokument speichern; Test mit 10 Dokumenten gegen Referenzkategorien. - Slice 2 – Hintergrund-Neuanalyse: Beim ersten Start nach dem Umbau Dokumente ohne aktuelle Analyseversion sequenziell im Hintergrund neu analysieren; Mindmap startet sofort mit bestehenden Daten und aktualisiert Kategorien und Positionierung je fertigem Dokument; danach nur bei Upload oder Versionswechsel.
- Slice 3 – Positionierung: Cluster-Kräfte in
mindmapOverlap.ts/mindmapDocuments.ts; biologisch außen, formal innen; Anzeige inMindmapView.tsx. - Slice 4 – Performance & End-to-End-Prüfung: React-Memo, d3-force-Ticks begrenzen; Playwright-Lauf für Upload, Hintergrund-Neuanalyse, Kategorien, Filter, Startzeit, keine Konsolenfehler.
16. Acceptance criteria & tests
| # | Check | Erwartetes Ergebnis |
|---|---|---|
| A9 | Fehler bei Neuanalyse | Fehlgeschlagenes Dokument bleibt sichtbar mit bisherigen Kategorien und Status „Analyse fehlgeschlagen“; beim nächsten Start wird automatisch erneut analysiert, ohne Button |
| A9b | Retry-Grenze | Nach drei fehlgeschlagenen Versuchen (über Neustarts hinweg gezählt) wird nicht mehr automatisch wiederholt; der Status bleibt bis zum erneuten Upload sichtbar |
| A9c | Zähler-Reset | Erneuter Upload eines fehlgeschlagenen Dokuments setzt failedAttempts auf 0 und startet die Analyse neu |
| A10 | Startzeit | Manuelle Messung vor der Abgabe auf typischem Laptop (4–8 GB RAM, Browser mit weiteren Tabs): alle 121 Knoten sichtbar in unter 2 s ab erstem Render |
| A10b | Playwright-Hilfslauf | Playwright-Lauf in Slice 4 meldet Abweichungen nur als Warnung; der Build bricht nicht ab |
17. Deployment, environments & secrets
Umgebung: lokal-first. Backend uvicorn app.main:app --port 8000, Frontend npm run dev auf Port 5173.
Hosting: kein externes Hosting; alles läuft auf dem Rechner der Studierenden.
Secrets: VITE_GEMINI_API_KEY und LLM_API_KEY nur in .env bzw. Umgebungsvariablen; .env bleibt in .gitignore.
Build: npm run build muss fehlerfrei durchlaufen.
18. Open questions & assumptions
Default: Bestehende Dokumente werden per Button neu kategorisiert, nicht automatisch.