Files
MindSift/Doku/modules/workspace.md
T
sandrodachandClaude Opus 5.5 f82ab2fd32
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m25s
fix: mobile layout, task clicks, list tab corners, hashtags in URLs
Mobile
- Plus button in triage did nothing: the stored action returned the
  capture function instead of calling it
- Workspace: tabs share the full width; save status sits as an icon next
  to the note title instead of wrapping into its own row; "Neue Notiz" /
  "Neuer Ordner" only in the top menu (and +), not repeated in the list
- Outliner fields measured while hidden stayed one line high (cut-off
  callout); they are measured again when their width changes
- Task dialog: scrolls in a div instead of a fieldset, height in dvh,
  notes editor grows with its text, so long notes are fully reachable

Desktop
- Delete button of the selected task/shopping list sits inside the tab as
  its own rounded button (matches rounded themes like Soft)

Both
- Tasks sometimes did not open: every reload after an action replaced the
  list with a loading placeholder, swallowing clicks; reloads are now
  silent after the first load of a list, stale responses are dropped
- Hashtags need whitespace or "(" before "#", so URL anchors are no
  longer tags (server, browser); one-time cleanup of stored anchor tags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 16:50:51 +01:00

7.0 KiB
Raw Blame History

Modul: Workspace (Outliner-Notizen)

Code: WorkspaceView.tsx (Explorer, Tags, To-Do-Rollup), DocumentEditor.tsx, OutlinerTree.tsx, OutlinerBlock.tsx, CodeBlockItem.tsx, LinkModal.tsx; Backend: Dokument-, Ordner- und Tag-Handler, Sync-Handler in internal/api/docsync.go, internal/collab, internal/storage/docsync.go.

Datenhaltung

  • Eine Notiz ist ein Datensatz in documents plus ein Baum von Blöcken in blocks (parent_id, Sortierschlüssel order_key). Jede Änderung läuft über internal/collab und wird im Log doc_ops festgehalten. Ebene und Position für die Oberfläche berechnet der Server beim Lesen. Das Log und gelöschte Blöcke werden regelmäßig verdichtet (database.md). Alles liegt in SQLite; es gibt keine Dateien auf der Platte.
  • Bei jeder Änderung wird documents.markdown_cache neu erzeugt; block_tags wird aus #Hashtags der Blöcke neu aufgebaut.
  • Hashtag-Regel: #wort zählt nur am Textanfang oder nach Leerzeichen bzw. (. Anker in Links (example.com/blog#ueberschrift) und Wörter wie C# sind keine Tags. Gleiche Regel im Server (domain.ExtractTags) und im Browser (lib/hashtags.ts). Beim ersten Start nach der Umstellung entfernt migrateAnchorTags einmalig gespeicherte Tags, die nur aus Ankern stammten.
  • Der Export als .md erfolgt im Browser (Button im Editor, Blob-Download).
  • Blocktypen: Überschriften h1–h3, paragraph/text, bullet, todo, code, callout, divider, table, progress.

Editor

  • Outliner: Enter neuer Block, Tab/Shift+Tab ein-/ausrücken, Shift+Enter weicher Umbruch, Blöcke ein-/ausklappen.

  • Zoom (Hoisting): Klick auf den Bullet fokussiert den Ast; die Breadcrumb-Leiste führt zurück.

  • Drag & Drop verschiebt Blöcke samt Unterästen; auf einen anderen Block gezogen, wird der Block zum Unterpunkt.

  • Slash-Befehle: /todo, /link, /h1, /h2, /h3, /code, /callout, /divider (Liste in OutlinerBlock.tsx).

  • Links: [[Notiztitel]], Markdown-Links [Titel](url) und reine URLs werden als Token dargestellt; LinkModal hilft beim Verknüpfen von Notizen.

  • Einfügen: Mehrzeiliger Text wird anhand von Markdown-Präfixen und Einrückung in Blöcke zerlegt; Überschriften gruppieren darunterliegenden Text und Code.

  • Speichern: Jede Notiz hat im Browser eine DocSyncEngine (lib/docSync/). Der Editor meldet jede Änderung der Block-Liste; die Engine übersetzt sie in Operationen, speichert sie zuerst in IndexedDB und sendet sie dann gesammelt (300 ms) an POST /docs/{id}/sync. Beim Öffnen zeigt sie sofort den gespeicherten Stand, auch offline.

  • Abgleich bei geteilten oder mehrfach geöffneten Notizen, nach Verfügbarkeit:

    1. Push über WebSocket oder SSE: Der Server meldet DOC_SEQ, die Engine gleicht sofort ab (im Test 0,2–0,3 s).
    2. Long-Polling (/docs/{id}/changes), wenn ein Proxy WebSocket und SSE blockiert oder SSE puffert: ebenso schnell.
    3. Abfrage alle 3 s, wenn auch Long-Polling dreimal scheitert (bei online wird Long-Polling erneut versucht).

    Solange 1. oder 2. läuft, gleicht die Engine zusätzlich alle 7 s ab, wenn sie Sperren hält (Verlängerung), sonst alle 30 s zur Sicherheit. Ein Fokuswechsel meldet die Sperre sofort an. Der Editor zeigt den Weg an („Live“, „Live (Long-Polling)“, „Abgleich alle 3 s“).

  • Private Notizen, die nur einmal geöffnet sind, gleichen alle 30 s ab, außerdem sofort bei Rückkehr ins Netz oder in den Tab. Beim Verlassen sendet die Engine Ausstehendes mit keepalive und gibt ihre Sperren frei.

  • Textkonflikte: Jede Textänderung trägt die Version, die der Nutzer beim Tippen vor sich hatte. Hat jemand anderes den Bullet inzwischen geändert oder gesperrt, legt der Server eine Konfliktkopie an; es wird nie still überschrieben.

  • Sperren: Der Bullet mit dem Cursor, verlassene Bullets für 20 s und neu angelegte Bullets werden gehalten. Bullets, die jemand anderes hält, zeigen ein Schloss mit Namen und sind schreibgeschützt; Enter darin legt einen neuen Bullet darunter an. Löschen, Zusammenführen, Ein-/Ausrücken und Ziehen werden bei gesperrten Bullets nicht ausgeführt (Hinweis unten im Editor).

  • Präsenz: Im Kopf der Notiz steht, wer sie gerade sonst noch geöffnet hat.

  • Konfliktkopien sind farbig markiert („Konflikt – Version von …“) mit „Übernehmen“ (Text ersetzt den ursprünglichen Punkt bzw. den Titel, die Kopie verschwindet) und „Verwerfen“.

  • Rückgängig: Strg+Z/Cmd+Z nimmt die eigene letzte Änderung zurück, Strg+Umschalt+Z oder Strg+Y wiederholt (auch im Titel und über das Kontextmenü/mobile Tastaturen). Tippen im selben Punkt bis 1 s Pause ist ein Schritt; bis zu 200 Schritte je Tab. Hat jemand anderes den Punkt inzwischen geändert oder hält ihn gesperrt, wird der Schritt mit Hinweis übersprungen.

  • PUT /documents/{id} ändert nur noch Symbol, Anheften und Ordner (Titel wird ins Log übernommen); Inhalte laufen ausschließlich über die Engine. Das To-Do-Rollup hakt per einzelner Operation über denselben Sync-Endpunkt ab.

Explorer, Tags, To-Dos

  • Ordnerbaum mit Favoriten (doc_pins), Verschieben per Drag & Drop (/documents/{id}/move, /folders/move).
  • Tags: Alle #Hashtags werden aggregiert (/workspace/tags). Eine Tag-Seite zeigt alle Fundstellen gruppiert nach Notiz und kann eine eigene Freitext-Notiz tragen (tag_pages).
  • To-Do-Rollup: Die Ansicht „To-Dos“ sammelt alle todo-Blöcke aller Notizen, filterbar nach Ordner. Abhaken im Rollup ändert den Block in der Notiz.
  • Enhanced Tasks: Ein todo-Block lässt sich als verknüpfte Aufgabe führen (/documents/{id}/blocks/{blockId}/enhanced-task); Erledigt-Status bleibt zwischen Notiz und Aufgabenansicht synchron.

Freigabe

  • Einzelne Notizen und ganze geteilte Ordner lassen sich an Benutzer oder Gruppen geben. Empfänger haben nur Leserechte; nur der Eigentümer schreibt (sharing-and-permissions.md, FLAW-17).
  • Empfänger ordnen geteilte Notizen und Ordner in ihrem eigenen Baum ein (doc_user_folders, workspace_folder_mounts), ohne dass der Eigentümer etwas davon merkt.
  • Änderungen erreichen offene Fenster über den Weckruf DOC_SEQ und anschließenden Sync; Notizlisten über DOC_UPDATED (websocket.md).

Grenzen

  • Keine gleichzeitige Mehrbenutzerbearbeitung, keine Cursor-Anzeige, keine Versionshistorie.
  • Keine Virtualisierung langer Dokumente; sehr große Notizen können auf Mobilgeräten träge werden (nicht gemessen).
  • Suche (/search) erfasst nur Titel und Inhalt eigener Notizen (FLAW-18).