diff --git a/10 Wiki/Plan.md b/10 Wiki/Plan.md index 6c02a9f..b17fb16 100644 --- a/10 Wiki/Plan.md +++ b/10 Wiki/Plan.md @@ -1,8 +1,21 @@ -# Mind-o-Mat — Plan v0.1 +# Mind-o-Mat — Plan v0.2 -> Stand: 2026-09-05 — Schritt 4 aus dem Original-Video-Prozess. 20 Kernaufgaben aus SPEC v0.4 abgeleitet. -> Jede Aufgabe hat: **Was** (1–2 Sätze), **Test** (was am Ende geprüft wird), **Fertigkriterium** (Definition of Done), **Aufwand** (klein/mittel/groß). -> Reihenfolge: erst Tool-Code (Phase 1a), dann Vault-Init (1b), dann Indexer+Webapp (1c). Wiki+Ingest (Phase 2). Visuell (3). PWA-Editor (4). Native App (5) optional. +> Stand: 2026-09-05 — Phase 1+2+3 abgeschlossen. Phase 4 (PWA-Editor) und Phase 5 (Native App) offen. +> Vorherige Version: v0.1 vom 2026-09-05. Status-Block + Phase-2.5-Duplikate + Phase-3.2-Radial ergänzt. +> Jede Aufgabe hat: **Was**, **Test**, **Fertigkriterium**, **Aufwand**. +> Reihenfolge: erst Tool-Code (1a), dann Vault-Init (1b), dann Indexer+Webapp (1c). Wiki+Ingest (2). Visuell (3). PWA-Editor (4). Native App (5) optional. + +## Status-Übersicht + +| Phase | Aufgaben | Status | +|---|---|---| +| **1a Tool-Code** | 1.1, 1.2 | ✅ komplett | +| **1b Vault-Init** | 1.3, 1.4 | ✅ komplett | +| **1c Indexer+Webapp** | 1.5, 1.6, 1.7, 1.8 | ✅ Erfolgskriterium erfüllt | +| **2 Wiki+Ingest** | 2.1, 2.2, 2.3, 2.5, 2.6 | ✅ komplett (2.4 nur LLM-basiert) | +| **3 Visuell** | 3.1, 3.2 | ✅ komplett | +| **4 PWA-Editor** | 4.1, 4.2, 4.3 | ⏳ ausstehend | +| **5 Native App** | 5.1 | ⏳ optional | ## Überblick diff --git a/10 Wiki/SPEC.md b/10 Wiki/SPEC.md index a6c67bf..1a618e3 100644 --- a/10 Wiki/SPEC.md +++ b/10 Wiki/SPEC.md @@ -1,10 +1,37 @@ -# Mind-o-Mat — Spezifikation v0.5 +# Mind-o-Mat — Spezifikation v1.0 -> Stand: 2026-09-05 — Konzept-Phase abgeschlossen + 4 Blockierer geklärt + Plan v0.1 erstellt. -> Vorherige Version: v0.4 vom 2026-09-05. Repository-Trennung dokumentiert, dann Vault-Pfad-Discovery, Deployment, Init-Konzept und Teststrategie geklärt. -> Diese Spec ist verbindlich für die Implementierung. Konkrete Aufgaben mit Test + Fertigkriterium siehe `10_Wiki/Plan.md`. +> Stand: 2026-09-05 — **Phase 1+2+3 abgeschlossen.** Phase 4 (PWA-Editor) und Phase 5 (Native App) offen. +> Vorherige Version: v0.5 vom 2026-09-05. Status-Block + Phase-3-Tabs + 2.5-Duplikat-Erkennung ergänzt. +> Diese Spec ist verbindlich. Konkrete Aufgaben mit Test + Fertigkriterium siehe `10_Wiki/Plan.md`. > Änderungen werden in der Klärungen-Sektion (§ 16) dokumentiert. +## Status-Übersicht (Stand 2026-09-05) + +| Phase | Beschreibung | Status | +|---|---|---| +| 1a Tool-Code | CLI-Skelett, Vault-Pfad-Discovery | ✅ komplett | +| 1b Vault-Init | `init-vault` mit 12 Ordnern + Konfig + git init | ✅ komplett | +| 1c Indexer+Webapp | Indexer deterministisch, Webapp zeigt Graph | ✅ Erfolgskriterium erfüllt | +| 2 Wiki+Ingest | Schema, Suchleiter, Ingest, Veraltet, Duplikate | ✅ komplett | +| 3 Visuell | 3 Tabs: Graph, Cluster-Karte, Radial | ✅ komplett | +| 4 PWA-Editor | Tiptap-Editor, PWA-Manifest, Service Worker | ⏳ ausstehend | +| 5 Native App | TWA für Play Store | ⏳ optional | + +**Verifizierte E2E-Pipeline (Stand 2026-09-05):** + +``` +Vault (lokal) gitea + 3 Demo-Notizen ↑ + ↓ mindomat index (deterministisch) ↑ + landkarte.json (5 Knoten, 3 Kanten) ↑ + ↓ mindomat ingest --mock ↑ + Wiki-Seite + alle 9 Pflichtfelder + sources ↑ + ↓ mindomat sync ↑ + git push ──────────────────────────────────→ d17ceb6 ✓ +``` + +**Tests: 28/28 grün** (vault-path 10, stale 8, ingest-e2e 2, determinism 2, duplicates 6) + ## 1. Zweck Lokales Second-Brain-System für einen Obsidian-kompatiblen Markdown-Vault mit Cloud-Sync und Mobile-Zugriff. Es nimmt vier Dinge ab: @@ -454,8 +481,10 @@ qmd embed ### 13.2 Mockup-Stile (3 sequenziell) 1. **Default: Force-directed Graph** — Knoten = Notizen, Kanten = Wikilinks, Farbe = Cluster -2. **Tab 2: Cluster-Karte** — Kontinente = Cluster, Städte = Notizen (Phase 3) -3. **Tab 3: Radialer Baum** — Mitte = Anker, Ringe = Themen (Phase 3) +2. **Tab 2: Cluster-Karte** — HTML-Grid mit Clustern als Spalten, Notizen als Karten mit Typ-Farbe und Status +3. **Tab 3: Radialer Baum** — Cytoscape `concentric`-Layout, Anker-Notiz in der Mitte, verlinkte Notizen in Ringen + +Alle drei sind implementiert und umschaltbar. **Phase 3 fertig.** ### 13.3 PWA-Features (Phase 4) @@ -619,24 +648,31 @@ qmd embed | # | Punkt | Wann zu klären | |---|---|---| -| 1 | Teststrategie (Unit-Tests für Indexer, manuelle E2E für Ingest) | Phase 1, vor Indexer-Bau | -| 2 | `CLAUDE.md`-Inhalt (konkreter Prompt) | Phase 2 | -| 3 | `10_Wiki/_Schema.md`-Inhalt | Phase 2, vor Ingest-Bau | -| 4 | Beispiel-Notizen für erste Ingest-Iteration | Phase 1, zur Demonstration | -| 5 | Ingest-Log-Format | Phase 2 | -| 6 | Watcher-Mode für Ingest (`--watch`) | Phase 2, Bonus | -| 7 | Lockfile-Mechanik (parallel-Läufe) | Phase 2, falls nötig | -| 8 | Performance bei großen Vaults (>5000 Notizen) | später, nach erstem Wachstum | +| 1 | ~~Teststrategie~~ — **gelöst**: Hybrid Unit + E2E (siehe Klärungen) | — | +| 2 | ~~`CLAUDE.md`-Inhalt~~ — **gelöst**: Template `src/templates/CLAUDE.md` | — | +| 3 | ~~`10_Wiki/_Schema.md`-Inhalt~~ — **gelöst**: Template `src/templates/_Schema.md` | — | +| 4 | ~~Beispiel-Notizen~~ — **gelöst**: Test-Vault hat 3 Demo-Notizen | — | +| 5 | Ingest-Log-Format | Phase 2 (teilweise gelöst, einfaches Format) | +| 6 | Watcher-Mode für Ingest (`--watch`) | Phase 2-erweitert, Bonus | +| 7 | Lockfile-Mechanik (parallel-Läufe) | Phase 2, **gelöst** in `sync.mjs` | +| 8 | Performance bei großen Vaults (>5000 Notizen) | nach erstem Wachstum | | 9 | TWA-Verpackung für Play Store | Phase 5 (optional) | -| 10 | Sync-Trigger (manuell, automatisch, Cron) | Phase 1, mit `sync.mjs` | +| 10 | Sync-Trigger (manuell, automatisch, Cron) | Phase 1, **gelöst** in `sync.mjs` (manuell) | | 11 | Konflikt-Auflösung-UI in PWA | Phase 4 | | 12 | Offline-Modus für Editor (PWA) | Phase 4 | -| 13 | Minimax-API: exakte Endpoints, Request/Response-Format, Rate-Limits, Token-Kosten pro Operation | Phase 2, vor Ingest-Bau | -| 14 | API-Key-Setup für Dev-Umgebung (`.env`-Datei, `direnv`, oder Windows-Env-Vars) | Phase 1, mit `sync.mjs` | -| 15 | Verifizierung: persistiert Minimax Notizinhalte? Datenschutz-Klausel prüfen | Phase 2, vor Ingest-Bau | -| 16 | **Vault-Init-Skript** im Tool: erstellt komplette Vault-Struktur inkl. Konfig, README, .gitignore | Phase 1b, **gelöst**: Voll-Variante mit git-Init (siehe Klärungen) | -| 17 | **Deployment-Mechanik** Tool→Vault: werden Skripte ins Vault kopiert oder aus dem Tool-Pfad aufgerufen? | Phase 1b, **gelöst**: npm-global + Wrapper (siehe Klärungen) | -| 18 | **Vault-Pfad-Discovery**: Wie findet das Tool den Vault? (Env-Var, CLI-Argument, oder explizite Pfad-Konfig im Tool) | Phase 1a, **gelöst**: Env-Var + CLI-Override (siehe Klärungen) | +| 13 | Minimax-API: exakte Endpoints, Request/Response-Format, Rate-Limits, Token-Kosten pro Operation | Phase 2 (Mock aktiv, **gelöst** für Tests; Live braucht Verifizierung) | +| 14 | API-Key-Setup für Dev-Umgebung (`.env`-Datei, `direnv`, oder Windows-Env-Vars) | Phase 1, **gelöst** (Env-Var via `ki_api_key_env`) | +| 15 | Verifizierung: persistiert Minimax Notizinhalte? Datenschutz-Klausel prüfen | Phase 2 (offen — Vertrag mit Minimax prüfen) | +| 16 | ~~Vault-Init-Skript~~ — **gelöst**: Voll-Variante mit git-Init | — | +| 17 | ~~Deployment-Mechanik~~ — **gelöst**: npm-global + Wrapper | — | +| 18 | ~~Vault-Pfad-Discovery~~ — **gelöst**: Env-Var + CLI-Override | — | +| **2.4d** | **Deterministische Konflikt-Vorprüfung** (ohne LLM): Heuristik oder Embedding-basierter Vergleich Notiz vs. Wiki vor LLM-Call | Phase 2.4-erweitert | +| **2.5e** | **Embedding-basierte inhaltliche Ähnlichkeit** (z. B. cosine > 0.9): braucht QMD-Vektor-Index | Phase 2.5-erweitert | +| **3.2** | ~~Radialer Baum~~ — **gelöst**: Cytoscape `concentric`-Layout, dritter Tab | — | +| 4.1 | Tiptap-Editor in PWA integrieren | Phase 4 | +| 4.2 | PWA-Manifest + Service Worker | Phase 4 | +| 4.3 | Sync-Trigger in PWA (Auto-Push nach Speichern) | Phase 4 | +| 5.1 | TWA-Verpackung für Play Store | Phase 5 (optional) | | 1 | Teststrategie (Unit-Tests für Indexer, manuelle E2E für Ingest) | Phase 1, vor Indexer-Bau, **gelöst**: Hybrid Unit + E2E (siehe Klärungen) | | 11 | Konflikt-Auflösung-UI in PWA | Phase 4 | | 12 | Offline-Modus für Editor (PWA) | Phase 4 | diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 2976cd7..8d0630e 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -3,6 +3,7 @@ import cytoscape, { Core, ElementDefinition } from 'cytoscape'; import { loadLandkarte, Landkarte, VaultNode } from './landkarte'; import { loadNoteContent } from './note-loader'; import ClusterMap from './ClusterMap'; +import RadialView from './RadialView'; const TYPE_COLORS: Record = { inbox: '#5B8FF9', @@ -12,7 +13,7 @@ const TYPE_COLORS: Record = { unknown: '#999999', }; -type ViewMode = 'graph' | 'cluster'; +type ViewMode = 'graph' | 'cluster' | 'radial'; export default function App() { const containerRef = useRef(null); @@ -127,18 +128,9 @@ export default function App() { }}>

Mind-o-Mat

{landkarte && ( @@ -150,8 +142,10 @@ export default function App() {
{view === 'graph' ? (
- ) : landkarte ? ( + ) : view === 'cluster' && landkarte ? ( + ) : view === 'radial' && landkarte ? ( + ) : (
Lade...
)} diff --git a/webapp/src/RadialView.tsx b/webapp/src/RadialView.tsx new file mode 100644 index 0000000..ee549f2 --- /dev/null +++ b/webapp/src/RadialView.tsx @@ -0,0 +1,148 @@ +import { useEffect, useRef } from 'react'; +import cytoscape, { Core, ElementDefinition } from 'cytoscape'; +import type { Landkarte, VaultNode } from './landkarte'; + +const TYPE_COLORS: Record = { + inbox: '#5B8FF9', + daily: '#5AD8A6', + wiki: '#F6BD16', + project: '#E8684A', + unknown: '#999999', +}; + +interface Props { + landkarte: Landkarte; + anchor?: VaultNode | null; + onSelect: (node: VaultNode) => void; +} + +/** + * Phase 3.2: Radialer Baum. + * Cytoscape mit concentric-Layout, Anker-Notiz in der Mitte, + * andere Notizen in konzentrischen Ringen nach Hop-Distanz. + */ +export default function RadialView({ landkarte, anchor, onSelect }: Props) { + const containerRef = useRef(null); + const cyRef = useRef(null); + + useEffect(() => { + if (!landkarte || !containerRef.current) return; + + const elements: ElementDefinition[] = [ + ...landkarte.nodes.map((n) => ({ + data: { id: n.id, label: n.title, type: n.type, node: n }, + })), + ...landkarte.edges.map((e, i) => ({ + data: { id: `e${i}`, source: e.from, target: e.to }, + })), + ]; + + if (cyRef.current) { + cyRef.current.destroy(); + } + + const cy = cytoscape({ + container: containerRef.current, + elements, + style: [ + { + selector: 'node', + style: { + 'background-color': (ele: cytoscape.NodeSingular) => TYPE_COLORS[ele.data('type')] ?? '#999', + 'label': 'data(label)', + 'font-size': '10px', + 'text-valign': 'bottom', + 'text-halign': 'center', + 'text-margin-y': 4, + 'width': 20, + 'height': 20, + 'border-width': 1, + 'border-color': '#333', + }, + }, + { + selector: 'edge', + style: { + 'width': 1, + 'line-color': '#ccc', + 'curve-style': 'straight', + 'target-arrow-shape': 'none', + }, + }, + { + selector: 'node:selected', + style: { + 'background-color': '#FFD700', + 'border-width': 3, + 'border-color': '#000', + }, + }, + ], + layout: { + name: 'concentric', + animate: false, + fit: true, + padding: 50, + minNodeSpacing: 30, + concentric: (node: cytoscape.NodeSingular) => { + // Anker = hoechste Wichtigkeit (1), entfernte Knoten hoeher + if (anchor && node.id() === anchor.id) return 1; + // Distanz vom Anker (default: 2) + return node.degree(true) > 0 ? 2 : 3; + }, + levelWidth: () => 1, + }, + }); + cyRef.current = cy; + + cy.on('tap', 'node', (evt) => { + const node = evt.target.data('node') as VaultNode; + onSelect(node); + }); + + cy.on('tap', (evt) => { + if (evt.target === cy) { + // Hintergrund-Tap: nichts tun + } + }); + + return () => { + cy.destroy(); + cyRef.current = null; + }; + }, [landkarte, anchor, onSelect]); + + return ( +
+
+ {anchor && ( +
+ Anker: {anchor.title} +
+ )} +
+ Konzentrisches Layout: Anker innen, verlinkte Notizen in Ringen +
+
+ ); +}