feat: complete triage, multi-task lists, kanban, workspace wiki, and admin management
MindSift CI & Docker Release / Build, Test in Container & Push (push) Failing after 16s

This commit is contained in:
sandrodach committed 2026-10-24 22:08:43 +02:00
1 parent 5c4e130862
commit 4ef71b61cd
12 files changed
+3940 -664

No files matched your search

+129 -13
View File
@@ -1,5 +1,5 @@
# 🧠 BRAIN.md — MindSift Internal Dev Cheat Sheet & Architecture Log
> **Zweck:** Zentrales, technisch präzises Nachschlagewerk für Entwicklung, Design-System, Datenbank-Architektur, State-Machines und aktuellen Umsetzungsstand. Wird bei jeder Änderung aktuell gehalten.
> **Zweck:** Zentrales, technisch präzises Nachschlagewerk für Entwicklung, Design-System, Datenbank-Architektur, State-Machines, Backend-APIs und aktuellen Umsetzungsstand. Wird bei jeder Änderung aktuell gehalten.
---
@@ -18,11 +18,29 @@
- **Quick Dump (Standard):** Text oben eingeben + `Enter` wirft den Gedanken sofort als Quick Dump (`status: 'inbox'`) ins Triage-Deck.
- **Direkt-Zuordnung bei der Eingabe:** Über das Auswahl-Menü (`Quick Dump ▾`) in der Eingabeleiste kann ein Eintrag alternativ direkt als **Aufgabe** (`target: 'task'`), direkt auf eine **Geteilte Liste** (`target: 'list_item'`) oder direkt als **Workspace-Notiz** (`target: 'document'`) gespeichert werden.
- **Triage-Entscheidung & Warteschlange:** Im Triage-Deck per Swipe/Klick **Wegwerfen** (`←` / `H`), **Später** (`Leertaste` – ans Ende schieben), **Auf Liste**, **Als Notiz** (`D`), **Mit Termin** (`T`) oder **Als Aufgabe** (`→` / `L`). Inklusive Inline-Textbearbeitung und Warteschlangen-Liste unter der aktiven Karte.
- [x] **Root-Cause Fixes für Browser-Hänger & Cross-Browser-Kompatibilität (Chrome & Firefox):**
- **SQLite Connection-Pool Deadlock behoben (`internal/storage/sqlite.go`):** Vorher war `db.SetMaxOpenConns(1)` aktiv, während `GetAllListsForUser`, `GetListsForSpace` und `GetSpacesForUser` innerhalb von `for rows.Next()` (bei offenem Cursor!) Unterabfragen (`s.GetListItems`, `s.GetSpaceMembers`) aufriefen. Sobald eine Liste existierte, blockierte die einzige DB-Verbindung dauerhaft und alle nachfolgenden Requests (`POST /api/v1/inbox` etc.) hingen bis zum 15-Minuten-TCP-Timeout. Jetzt werden alle `rows` strikt vor jeder Unterabfrage geschlossen (`rows.Close()`), WAL-Pragmas + `busy_timeout(10000)` per DSN übergeben und `MaxOpenConns(8)` gesetzt.
- **Stale JWT User-Auflösung (`internal/api/server.go`):** Wenn nach einem Container-Neustart eine neue SQLite-DB initialisiert wird, löst `authMiddleware` alte Browser-Tokens automatisch auf `EnsureDefaultUser()` (mit `sync.Mutex` gegen Race-Conditions) auf.
- **Service-Worker & Cache-Busting (`frontend/public/sw.js`, `frontend/index.html`, `internal/api/server.go`):** Kein Caching veralteter Bundles in Firefox/Chrome; `Cache-Control: no-store` auf allen `/api/*`-Routen und `index.html`.
- **Optimistisches Input-Clearing & Request-Timeout (`frontend/src/lib/api.ts`, `InstantCaptureBar.tsx`):** Eingabefeld leert sich sofort (<10ms) bei `Enter`, alle Fetch-Calls haben einen 8-Sekunden-`AbortController`-Timeout.
- [x] **Mehrere Aufgabenlisten & Kanban-Board (`TasksView.tsx`, `models.go`, `sqlite.go`):**
- Beliebig viele Aufgabenlisten (z.B. Privat, Arbeit, Homelab) mit eigenem Farb- und Icon-Code.
- Teilen von Aufgabenlisten mit Teams/Spaces.
- Umschalter zwischen kompakter Listenansicht und 3-Spalten-Kanban-Board (`Zu erledigen`, `In Arbeit`, `Erledigt`) mit 1-Klick-Statuswechsel, Fälligkeitsdaten und Notizfeldern.
- [x] **Benutzer- & Rollensteuerung + Admin-Panel (`SettingsModal.tsx`, `server.go`, `sqlite.go`):**
- Benutzerrollen: `admin` und `member`.
- Admin-Verwaltungsbereich zur Erstellung von Accounts, Rollenwechsel, Deaktivierung und Passwort-Reset.
- Server-weite Sharing-Isolations-Modi: `open` (alle finden sich), `teams_only` (nur innerhalb von Teams/Organisationen sichtbar) und `strict_private` (kein Teilen).
- Organisationen & Teams zur Strukturierung von Benutzergruppen.
- [x] **Workspace Markdown-Wiki mit Notion-/Word-Toolbar & Disk-Sync (`WorkspaceView.tsx`, `sqlite.go`):**
- Word-/Notion-artige Formatierungsleiste oben (Fett, Kursiv, Durchgestrichen, Code, Links, Überschriften H1-H3, Checklisten, Aufzählungen, Callouts, Markdown-Tabellen, Fortschrittsbalken).
- Interne Wiki-Links (`[[Dokumenttitel]]`) mit Klick-Navigation und Auto-Erkennung.
- Physische Speicherung auf Festplatte unter `/data/workspace/<user_id>/...` als Standard-`.md`-Dateien zur einfachen Daten-Extraktion, synchronisiert mit SQLite.
- [x] **Webhooks, Alarm-Scheduler & Discord-Integration (`SettingsModal.tsx`, `server.go`):**
- "Webhooks & Export" aus dem Header in das Benutzereinstellungen-Modal verlagert.
- Eigene API-Tokens mit curl-Beispielen für Skripte und externe Alarme.
- Hintergrund-Goroutine im Backend prüft fällige Aufgaben und sendet rechtzeitig (z.B. 15, 30 oder 60 Min. vor Fälligkeit) formatierte Discord-Embeds via Webhook.
- Vollständiger JSON-DB-Export auf Knopfdruck.
- [x] **Cross-Browser & Performance Fixes (Chrome & Firefox):**
- SQLite Connection-Pool Deadlock durch striktes Schließen von `sql.Rows` vor Unterabfragen behoben.
- Stale Token Auto-Resolution via `EnsureDefaultUser()`.
- `Cache-Control: no-store` auf allen API-Routen und `index.html`.
- Optimistisches Leeren des Capture-Inputs und 8-Sekunden-Fetch-Timeout.
---
@@ -66,7 +84,58 @@ Alle Farben, Abstände und Radien werden zentral in [`frontend/src/index.css`](f
---
## ⚙️ 2. State-Machine: Quick Dump, Direkt-Zuordnung & Triage
## 🗄️ 2. Datenbank-Architektur (SQLite Schema & Tabellen)
MindSift speichert alle Daten lokal und hochperformant in SQLite (`/data/mindsift.db`).
### Tabellen-Übersicht
1. **`users`**
- `id TEXT PRIMARY KEY`, `email TEXT UNIQUE`, `password_hash TEXT`, `display_name TEXT`
- `role TEXT DEFAULT 'member'` (`'admin'` | `'member'`)
- `is_active INTEGER DEFAULT 1`
- `discord_webhook_url TEXT DEFAULT ''`
- `notify_before_minutes INTEGER DEFAULT 15`
- `created_at DATETIME`, `updated_at DATETIME`
2. **`thoughts` (Quick Dumps, Triage & Aufgaben)**
- `id TEXT PRIMARY KEY`, `user_id TEXT`, `content TEXT`, `source TEXT`, `priority TEXT`
- `status TEXT` (`'inbox'` | `'converted'` | `'discarded'`)
- `converted_type TEXT` (`'task'` | `'document'` | `'list_item'`)
- `converted_ref_id TEXT` (Referenz auf Document oder ListItem)
- `task_list_id TEXT` (FK auf `task_lists.id`)
- `kanban_status TEXT DEFAULT 'todo'` (`'todo'` | `'in_progress'` | `'done'`)
- `notes TEXT DEFAULT ''` (zusätzliche Aufgabenbeschreibung/Notizen)
- `due_date DATETIME` (Fälligkeitsdatum)
- `alarm_sent INTEGER DEFAULT 0` (Flag für Discord-Benachrichtigung)
- `created_at DATETIME`, `updated_at DATETIME`
3. **`task_lists` (Mehrere Aufgabenlisten)**
- `id TEXT PRIMARY KEY`, `user_id TEXT`, `space_id TEXT` (optional für Team-Sharing)
- `name TEXT NOT NULL`, `color TEXT DEFAULT '#2563eb'`, `icon TEXT DEFAULT 'list'`
- `is_default INTEGER DEFAULT 0`, `created_at DATETIME`, `updated_at DATETIME`
4. **`organizations` & `teams` & `team_members`**
- `organizations`: `id TEXT PRIMARY KEY`, `name TEXT`, `owner_id TEXT`, `created_at DATETIME`, `updated_at DATETIME`
- `teams`: `id TEXT PRIMARY KEY`, `organization_id TEXT`, `name TEXT`, `created_at DATETIME`
- `team_members`: `team_id TEXT`, `user_id TEXT`, `role TEXT DEFAULT 'member'`, `joined_at DATETIME`, `PRIMARY KEY (team_id, user_id)`
5. **`system_settings` (Admin-Konfiguration)**
- `key TEXT PRIMARY KEY`, `value TEXT`, `updated_at DATETIME`
- Wichtige Schlüssel:
- `sharing_isolation_mode`: `'open'` | `'teams_only'` | `'strict_private'`
- `allow_public_registration`: `'true'` | `'false'`
6. **`documents` & `document_blocks` (Workspace & Disk Sync)**
- `documents`: `id TEXT PRIMARY KEY`, `user_id TEXT`, `space_id TEXT`, `title TEXT`, `folder_path TEXT DEFAULT '/'`, `is_archived INTEGER`, `created_at DATETIME`, `updated_at DATETIME`
- `document_blocks`: `id TEXT PRIMARY KEY`, `document_id TEXT`, `block_type TEXT` (`paragraph`, `heading1`, `heading2`, `heading3`, `todo`, `bullet`, `callout`, `code`, `table`, `progress`), `content TEXT`, `order_index INTEGER`, `metadata TEXT`, `updated_at DATETIME`
7. **`spaces`, `space_members`, `shared_lists`, `list_items`, `api_keys`**
- Verwaltung geteilter Einkaufs-/Checklisten und privater Ingestion-Keys.
---
## ⚙️ 3. State-Machine: Quick Dump, Direkt-Zuordnung & Triage
```
[ HEADER QUICK-CAPTURE BAR ]
@@ -87,19 +156,66 @@ Alle Farben, Abstände und Radien werden zentral in [`frontend/src/index.css`](f
```
### API-Endpunkt für Capture (`POST /api/v1/inbox`)
Akzeptiert neben `content`, `priority`, `source`, `dueDate` auch direkt:
- `target`: `'inbox'` (Standard Quick Dump) | `'task'` | `'list_item'` | `'document'`
Akzeptiert:
- `content`: Fließtext des Gedankens
- `priority`: `'low'` | `'medium'` | `'high'`
- `target`: `'inbox'` (Standard) | `'task'` | `'list_item'` | `'document'`
- `taskListId`: ID der Aufgabenliste (wenn `target === 'task'`)
- `targetListId`: ID der Zielliste (wenn `target === 'list_item'`)
- `dueDate`: Optionales ISO-Datum
---
## 🛡️ 3. Kritische Backend-Regeln (SQLite & HTTP)
## 🔔 4. Discord-Alarm-Scheduler & Webhook-Architektur
1. **Hintergrund-Ticker im Go-Backend (`internal/api/server.go`):**
- Ein Hintergrund-Goroutine-Ticker läuft alle 60 Sekunden.
- Fragt `GetDueTasksForAlarm()` ab: Sucht nach offenen Aufgaben (`status = 'converted'`, `converted_type = 'task'`, `kanban_status != 'done'`), deren `due_date` in der Vorwarnzeit liegt (`due_date <= now + notifyBeforeMinutes`) und bei denen `alarm_sent == 0` ist.
- Sendet ein JSON-Embed an die in den Benutzer-Einstellungen hinterlegte `discord_webhook_url`:
```json
{
"username": "MindSift Reminder",
"embeds": [{
"title": "⏰ Aufgabe fällig: <Titel>",
"description": "<Notizen>",
"color": 2450411,
"fields": [
{"name": "Fällig am", "value": "<Datum>", "inline": true},
{"name": "Priorität", "value": "<Prio>", "inline": true}
]
}]
}
```
- Markiert den Gedanken in SQLite mit `MarkTaskAlarmSent(taskID)` als benachrichtigt.
2. **Eingehende Webhooks / Private API-Tokens:**
- Erreichbar unter `POST /api/v1/inbox` mit Header `X-API-Key: ms_...`.
- Ermöglicht direkte Einbindung in Shell-Skripte, Crons oder Drittsysteme via `curl`.
---
## 📝 5. Workspace: Word/Notion-Toolbar, Wiki-Links & Disk-Sync
1. **Formatierungs-Werkzeuge:**
- Markdown-Syntax wird in Echtzeit formatiert und visuell aufbereitet.
- Buttons für H1, H2, H3, Fett (`**`), Kursiv (`*`), Durchgestrichen (`~~`), Code-Blöcke (```` ``` ````), Aufzählungen (`- `), Todos (`- [ ] `), Callouts (`> `), Markdown-Tabellen (`| Spalte 1 | Spalte 2 |`) und Fortschrittsbalken (`[progress:65%]`).
2. **Wiki-Links (`[[Dokumenttitel]]`):**
- Interne Querverweise werden als interaktive Links gerendert.
- Ein Klick auf `[[Dokumenttitel]]` durchsucht die Workspace-Dokumente und öffnet das verlinkte Dokument direkt im Editor.
3. **Physische Speicherung auf Festplatte:**
- Jede Notiz wird zusätzlich zur SQLite-Tabelle als reine `.md`-Datei unter `/data/workspace/<user_id>/<folder_path>/<slug>.md` gespeichert.
- Ermöglicht jederzeitige manuelle Datensicherung, Git-Versionierung oder Backup-Extraktion ohne Datenbank-Abhängigkeit.
---
## 🛡️ 6. Kritische Backend-Regeln (SQLite & HTTP)
1. **NIEMALS verschachtelte Queries bei offenem `sql.Rows`-Cursor ausführen:**
- In [`internal/storage/sqlite.go`](file:///home/sandro/Dokumente/git/MindSift/internal/storage/sqlite.go) muss jede Schleife `for rows.Next()` zuerst alle Zeilen in ein Slice einlesen und sofort `_ = rows.Close()` aufrufen, **bevor** Folgeabfragen (`GetListItems`, `GetSpaceMembers`, `QueryRow` etc.) ausgeführt werden.
2. **SQLite DSN-Pragmas:**
- Jede Verbindung im `sql.DB`-Pool erhält über den DSN automatisch:
`?_pragma=busy_timeout(10000)&_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(1)`
- `MaxOpenConns(8)` und `MaxIdleConns(4)` konfiguriert.
3. **Thread-Safe Default User (`EnsureDefaultUser`):**
- Durch `s.initMu.Lock()` abgesichert, damit parallele Browser-Requests beim ersten Laden niemals in einen `UNIQUE constraint`-Konflikt laufen.
4. **Kein Browser-Caching auf API & `index.html`:**
@@ -107,7 +223,7 @@ Akzeptiert neben `content`, `priority`, `source`, `dueDate` auch direkt:
---
## 📡 4. WebSocket Realtime Protocol (Geteilte Listen)
## 📡 7. WebSocket Realtime Protocol (Geteilte Listen)
Verbindungs-URL: `ws(s)://<host>/api/v1/ws/spaces/:spaceId?token=<jwt>`
@@ -120,7 +236,7 @@ Verbindungs-URL: `ws(s)://<host>/api/v1/ws/spaces/:spaceId?token=<jwt>`
---
## ⌨️ 5. Tastatur-Shortcuts (Desktop)
## ⌨️ 8. Tastatur-Shortcuts (Desktop)
| Taste | Kontext | Aktion |
| :--- | :--- | :--- |
@@ -135,7 +251,7 @@ Verbindungs-URL: `ws(s)://<host>/api/v1/ws/spaces/:spaceId?token=<jwt>`
---
## 🚀 6. Gitea CI/CD & Docker Workflow
## 🚀 9. Gitea CI/CD & Docker Workflow
- **Arbeits-Branch:** `dev` (`origin/dev`)
- **Ziel-Image:** `git.dsit.me/sandrodach/mindsift:dev`