Files
MindSift/BRAIN.md
T
sandrodach 5c4e130862
MindSift CI & Docker Release / Build, Test in Container & Push (push) Failing after 38s
fix(sqlite,browser): resolve SQLite connection pool deadlock, disable stale SW cache, and update BRAIN.md
2026-10-24 21:27:51 +02:00

143 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🧠 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.
---
## 📋 0. Aktueller Projektplan & Umsetzungs-Status
### Erledigte Meilensteine
- [x] **CI/CD & Multi-Stage Docker Build (`Dockerfile`, `.gitea/workflows/build-and-publish.yaml`):**
- Alle Frontend-Checks (`tsc --noEmit`, `vite build`) und Backend-Tests (`go test -v ./...`) laufen direkt im Multi-Stage Container-Build ohne doppelte Vorab-Steps.
- Push auf `dev` baut und überschreibt `git.dsit.me/sandrodach/mindsift:dev`.
- [x] **Monochromes, eckiges Desktop-Design & Zentrale CSS-Steuerung (`frontend/src/index.css`, `frontend/tailwind.config.js`):**
- Zentrale CSS-Variablen (`--bg-app`, `--bg-panel`, `--accent-primary`, `--border-color`, `--radius-card: 0px`) in `frontend/src/index.css`.
- Eckige Tabs, eckige Panels/Karten (`0px` Radius), nur die Schnell-Eingabe-Blase oben im Header und Profil-Avatare sind rund (`rounded-full`).
- Untere doppelte Navigationsleiste entfernt; Schnell-Notiz-Blase (`InstantCaptureBar`) sitzt ganz oben im Header über den Tabs.
- Workspace links als eckiger, monochromer Datei-/Ordner-Baum (File Explorer Tree mit Unterordnern).
- [x] **Quick Dump Notes + Triage Swipen + Direkt-Zuordnung (`InstantCaptureBar.tsx`, `TriageDeck.tsx`, `server.go`):**
- **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.
---
## 🎨 1. Design-System & CSS-Architektur (`frontend/src/index.css`)
Alle Farben, Abstände und Radien werden zentral in [`frontend/src/index.css`](file:///home/sandro/Dokumente/git/MindSift/frontend/src/index.css) über CSS-Variablen gesteuert:
```css
:root {
/* Monochromer Hintergrund (Dunkles Schiefer/Anthrazit) */
--bg-app: #121316;
--bg-panel: #1a1c20;
--bg-panel-elevated: #22252a;
--bg-panel-hover: #282c33;
/* Einzige Akzentfarbe + hellere/gedimmte Variante */
--accent-primary: #2563eb;
--accent-hover: #3b82f6;
--accent-dim: rgba(37, 99, 235, 0.14);
--accent-border: rgba(59, 130, 246, 0.45);
/* Kanten & Linien */
--border-color: rgba(255, 255, 255, 0.09);
--border-subtle: rgba(255, 255, 255, 0.05);
/* Eckiges Layout (0px für Karten/Panels, minimal für Inputs) */
--radius-card: 0px;
--radius-btn: 2px;
--radius-input: 2px;
}
```
### Zentrale Komponenten-Klassen
- `.panel-surface` / `.panel-elevated`: Eckige Container mit `1px solid var(--border-color)`.
- `.btn-action`: Monochromer, kompakter Button (`border-radius: var(--radius-btn)`).
- `.btn-primary`: Akzent-Button auf `--accent-primary`.
- `.input-field`: Minimal gerundetes (`2px`) Eingabefeld für Eigenschaften/Optionen.
- `.tab-btn` / `.tab-btn-active`: Eckige, monochrome Header-Tabs.
- `.badge-accent`: Kompaktes Akzent-Badge für Zähler und Tags.
- **Ausnahme für Rundungen (`rounded-full`):** Nur die Schnell-Eingabe-Blase (`InstantCaptureBar`) im Header, der Profil-Avatar und Toggle-Switches sind rund.
---
## ⚙️ 2. State-Machine: Quick Dump, Direkt-Zuordnung & Triage
```
[ HEADER QUICK-CAPTURE BAR ]
│
┌───────────────────────┼───────────────────────┐
│ Standard (Enter) │ Direkt-Option gewählt │
▼ ▼ ▼
status: 'inbox' status: 'converted' status: 'converted'
(Quick Dump Deck) ├── target: 'task' ├── target: 'list_item'
│ └── target: 'document' └── Broadcast via WS
│
├──► Swipe Links / "Wegwerfen" (H / ←) ──► status: 'discarded'
├──► "Später" (Leertaste) ──► ans Ende der lokalen Queue
├──► Swipe Rechts / "Als Aufgabe" (L/→)──► status: 'converted' (type: 'task')
├──► "Mit Termin" (T) ──► status: 'converted' (type: 'task', dueDate)
├──► "Als Notiz" (D) ──► status: 'converted' (type: 'document' + Doc angelegt)
└──► "Auf Liste" ──► status: 'converted' (type: 'list_item' + Item angelegt)
```
### 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'`
- `targetListId`: ID der Zielliste (wenn `target === 'list_item'`)
---
## 🛡️ 3. 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)`
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`:**
- `writeJSON` und der SPA-Fallback setzen `Cache-Control: no-store, no-cache, must-revalidate`, damit Chrome und Firefox nach jedem Container-Update sofort den aktuellen Stand zeigen.
---
## 📡 4. WebSocket Realtime Protocol (Geteilte Listen)
Verbindungs-URL: `ws(s)://<host>/api/v1/ws/spaces/:spaceId?token=<jwt>`
### Events
- `ITEM_CREATED` (auch ausgelöst, wenn ein Gedanke per Direkt-Zuordnung oder Triage auf eine Liste geschoben wird)
- `ITEM_TOGGLED`
- `ITEM_DELETED`
- `LIST_CREATED` / `LIST_DELETED` / `LIST_CLEARED`
- `USER_PRESENCE`
---
## ⌨️ 5. Tastatur-Shortcuts (Desktop)
| Taste | Kontext | Aktion |
| :--- | :--- | :--- |
| `C` oder `/` | Überall | Fokus sofort oben in die Quick-Dump-Eingabeleiste |
| `Enter` | Capture-Leiste | Sofort speichern (Quick Dump oder gewähltes Direkt-Ziel) |
| `Esc` | Capture-Leiste | Eingabe leeren & Dropdown schließen |
| `H` oder `←` | Triage-Deck | Aktiven Quick Dump wegwerfen (`discard`) |
| `L` oder `→` | Triage-Deck | Aktiven Quick Dump sofort zur Aufgabe machen (`task`) |
| `T` | Triage-Deck | Datums-Auswahl für Termin-Aufgabe öffnen |
| `D` | Triage-Deck | Aktiven Quick Dump sofort in Workspace-Notiz umwandeln |
| `Leertaste` | Triage-Deck | Karte überspringen („Später" – ans Ende des Stapels schieben) |
---
## 🚀 6. Gitea CI/CD & Docker Workflow
- **Arbeits-Branch:** `dev` (`origin/dev`)
- **Ziel-Image:** `git.dsit.me/sandrodach/mindsift:dev`
- **Build-Prinzip:** Ein einziger Multi-Stage-Build ([`Dockerfile`](file:///home/sandro/Dokumente/git/MindSift/Dockerfile)), der Frontend-Typecheck, Vite-Build und Go-Unit-Tests (`go test -v ./...` inkl. [`internal/api/server_test.go`](file:///home/sandro/Dokumente/git/MindSift/internal/api/server_test.go)) direkt beim Image-Bau ausführt und bei Erfolg sofort pusht.