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

9.4 KiB
Raw Blame History

🧠 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

  • 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.
  • 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).
  • 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.
  • 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 über CSS-Variablen gesteuert:

: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 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), der Frontend-Typecheck, Vite-Build und Go-Unit-Tests (go test -v ./... inkl. internal/api/server_test.go) direkt beim Image-Bau ausführt und bei Erfolg sofort pusht.