Without JWT_SECRET, or with one of the published placeholders, the server generates 32 random bytes once and keeps them in the data directory (jwt.secret, mode 0600), so tokens cannot be forged and logins survive restarts. Instances that ran on the old default log in once more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
217 lines
11 KiB
Markdown
217 lines
11 KiB
Markdown
<div align="center">
|
||
|
||
# 🧠 MindSift
|
||
### *Der Kopf frei in drei Sekunden.*
|
||
|
||
[](#)
|
||
[](#-schnellstart)
|
||
[](#-deine-daten-gehören-dir)
|
||
[](#-schnellstart)
|
||
|
||
**MindSift** ist eine selbst gehostete Schaltstelle für spontane Gedanken, Aufgaben mit Kanban-Board, hierarchische Outliner-Notizen, die mehrere Personen gleichzeitig bearbeiten können, und gemeinsame Listen. Alles läuft als ein einzelner Container mit eingebetteter SQLite-Datenbank, auf deinem eigenen Server.
|
||
|
||
<p align="center">
|
||
<img src="screenshots/Triage_desktop.png" alt="MindSift Triage Desktop" width="85%" />
|
||
</p>
|
||
|
||
[Philosophie](#-die-philosophie) • [Funktionen](#-funktionen) • [Schnellstart](#-schnellstart) • [Betrieb](#-betrieb--konfiguration) • [Entwicklung](#-entwicklung) • [Dokumentation](#-dokumentation)
|
||
|
||
</div>
|
||
|
||
---
|
||
|
||
## 💡 Die Philosophie
|
||
|
||
Die meisten Notiz- und Aufgaben-Apps verlangen Struktur im falschen Moment: Wenn dir ein Gedanke kommt, willst du keinen Ordner suchen und keine Felder ausfüllen. MindSift trennt deshalb **Erfassen** und **Organisieren**:
|
||
|
||
1. **Abladen:** In die Eingabeleiste tippen, `Enter`, fertig. Wer will, weist den Gedanken gleich einer Aufgabe, Liste oder Notiz zu.
|
||
2. **Sichten (Triage):** Später gehst du den Stapel Karte für Karte durch: verwerfen, zur Aufgabe machen, in eine Notiz oder Liste verwandeln.
|
||
3. **Vertiefen:** Aus losen Ideen werden Aufgaben mit Unteraufgaben, vernetzte Outliner-Notizen oder geteilte Listen für Familie und Team.
|
||
|
||
---
|
||
|
||
## ✨ Funktionen
|
||
|
||
### ⚡ Schnellerfassung & Triage
|
||
|
||
* Eingabeleiste im Kopf der App, jederzeit mit `C` oder `/` fokussierbar; auch per Spracheingabe (Browser-Funktion).
|
||
* Ziel beim Erfassen wählbar: Posteingang, Aufgabe, Listeneintrag oder Notiz.
|
||
* **Triage-Deck:** `H`/`←` verwerfen, `L`/`→` zur Aufgabe, `T` Aufgabe mit Termin, `D` in Notiz verwandeln, Leertaste = später. Auf dem Smartphone per Wischgeste.
|
||
* Papierkorb mit Wiederherstellen.
|
||
|
||
<p align="center">
|
||
<img src="screenshots/Mobile_Triage.png" alt="MindSift Mobile Triage" width="280px" />
|
||
</p>
|
||
|
||
### ✅ Aufgaben & Kanban
|
||
|
||
* Listen- und Kanban-Ansicht, Spalten pro Aufgabenliste frei konfigurierbar.
|
||
* Prioritäten, Fälligkeitsdatum, Hashtags, Unteraufgaben mit Fortschrittsbalken, Markdown-Notizen.
|
||
* Filter, Gruppierung und Sortierung; Drag & Drop in Liste und Board.
|
||
* **Aufgabenlisten teilen** mit Benutzern oder Gruppen, wahlweise als **Bearbeiter** oder **nur lesend**.
|
||
* **Alarme** bei Fälligkeit per E-Mail, Discord oder eigenem Webhook.
|
||
|
||
<p align="center">
|
||
<img src="screenshots/aufgaben_desktop.png" alt="MindSift Aufgaben und Kanban-Board" width="90%" />
|
||
</p>
|
||
|
||
### 📝 Workspace: Outliner-Notizen
|
||
|
||
* Jeder Gedanke ein Bullet: `Enter`, `Tab`/`Shift+Tab`, Ein-/Ausklappen, Drag & Drop ganzer Äste.
|
||
* **Zoom-Fokus** per Klick auf den Bullet, Breadcrumbs zum Zurücknavigieren.
|
||
* Blocktypen und Slash-Befehle: `/todo`, `/link`, `/h1`–`/h3`, `/code` (mit Syntax-Hervorhebung), `/callout`, `/divider`.
|
||
* Wiki-Links `[[Notiz]]`, Links und `#Hashtags`; Tag-Seiten bündeln alle Fundstellen.
|
||
* Ordner, Favoriten, **To-Do-Rollup** über alle Notizen und Export einer Notiz als `.md`.
|
||
* Einfügen von mehrzeiligem Markdown wird in Blöcke zerlegt; `Strg+Z` / `Strg+Umschalt+Z` nimmt eigene Änderungen zurück bzw. stellt sie wieder her.
|
||
* **Teilen:** Notizen und ganze Ordner lassen sich Benutzern oder Gruppen als **Bearbeiter** oder **Leser** freigeben. Empfänger sortieren sie in ihren eigenen Baum ein.
|
||
|
||
#### 🤝 Gemeinsam bearbeiten
|
||
|
||
* **Live:** Mehrere Personen schreiben gleichzeitig in derselben Notiz; Änderungen erscheinen bei den anderen in Bruchteilen einer Sekunde. Der Kopf der Notiz zeigt, wer gerade mitliest.
|
||
* **Kein Überschreiben:** Wer in einem Bullet schreibt, hält ihn kurz für sich; andere sehen ein Schloss mit Namen und arbeiten in den übrigen Bullets weiter. Kommt es doch zu einem Konflikt (z. B. nach Offline-Arbeit), bleibt der zweite Text als markierte Kopie mit „Übernehmen“/„Verwerfen“ erhalten.
|
||
* **Offline-fest:** Jede Eingabe wird zuerst im Browser gesichert und später übertragen, auch nach Neuladen oder Tagen ohne Netz.
|
||
* **Hinter strengen Proxys:** WebSocket → SSE → Long-Polling → Abfrage alle 3 s; MindSift wählt automatisch, was durchkommt. Der aktive Weg steht im Editor („Live“, „Abgleich alle 3 s“).
|
||
|
||
Technik dahinter: [Doku/modules/collaboration.md](Doku/modules/collaboration.md).
|
||
|
||
<p align="center">
|
||
<img src="screenshots/workspace_desktop.png" alt="MindSift Workspace Outliner" width="90%" />
|
||
</p>
|
||
|
||
### 🛒 Geteilte Listen
|
||
|
||
* Einkaufs-, Pack- und Checklisten mit Kategorien per Hashtag (`Hafermilch #Kühlregal`), Mengenangaben und Drag & Drop zwischen Kategorien.
|
||
* Freigabe an Benutzer und Gruppen (Bearbeiter oder Leser); abgehakte Einträge erscheinen bei allen in Echtzeit.
|
||
|
||
<p align="center">
|
||
<img src="screenshots/Listen_desktop.png" alt="MindSift Geteilte Listen" width="90%" />
|
||
</p>
|
||
|
||
### 🏢 Benutzer, Gruppen, Administration
|
||
|
||
* Geführte Ersteinrichtung, Rollen *Admin* und *Mitglied*, Einladungscodes, optional offene Registrierung.
|
||
* Gruppen mit Gruppen-Admins für Freigaben.
|
||
* Admin-Bereich: Benutzer, Einladungen, Instanzname, SMTP, Freigabe-Modus.
|
||
* Vier Themes (Dark, Light, High-Contrast, Soft), installierbar als PWA.
|
||
|
||
### 🔌 Integrationen
|
||
|
||
* **Webhook / API-Key:** `POST /api/v1/webhooks/ingest` legt Aufgaben aus Smarthome, Skripten oder Automationen an.
|
||
* Persönliche API-Keys, Datenexport als JSON.
|
||
|
||
---
|
||
|
||
## 🚀 Schnellstart
|
||
|
||
MindSift läuft als einzelner Container mit Webserver, API, Datenbank und Frontend.
|
||
|
||
### Option 1: Installationsskript
|
||
|
||
```bash
|
||
curl -fsSL https://git.dsit.me/sandrodach/MindSift/raw/branch/dev/install.sh | bash
|
||
```
|
||
|
||
Das Skript legt ein Verzeichnis an, lädt `docker-compose.yml` und `.env.example`, erzeugt ein `JWT_SECRET` und startet den Container.
|
||
|
||
### Option 2: Docker Compose
|
||
|
||
```bash
|
||
mkdir -p mindsift && cd mindsift
|
||
curl -fsSL https://git.dsit.me/sandrodach/MindSift/raw/branch/dev/docker-compose.yml -o docker-compose.yml
|
||
curl -fsSL https://git.dsit.me/sandrodach/MindSift/raw/branch/dev/.env.example -o .env
|
||
# In .env: JWT_SECRET durch einen langen Zufallswert ersetzen!
|
||
docker compose up -d
|
||
```
|
||
|
||
Minimal:
|
||
|
||
```yaml
|
||
services:
|
||
mindsift:
|
||
image: git.dsit.me/sandrodach/mindsift:stable # oder feste Version (:v0.4); :latest = main, :dev = Entwicklungsstand
|
||
restart: unless-stopped
|
||
ports: ["8080:8080"]
|
||
volumes: ["./data:/data"]
|
||
environment:
|
||
- JWT_SECRET=hier-ein-langer-zufaelliger-wert
|
||
- BASE_URL=https://mindsift.example.com
|
||
```
|
||
|
||
### Ersteinrichtung
|
||
|
||
Rufe `http://localhost:8080` auf. Beim ersten Start führt ein Assistent durch das Anlegen des Administrator-Kontos.
|
||
|
||
> ⚠️ **`JWT_SECRET`:** Ohne Angabe (oder mit einem der Platzhalter aus den Beispielen) erzeugt der Server beim ersten Start einen Zufallswert und speichert ihn als `jwt.secret` im Datenverzeichnis. Für Produktion lieber selbst einen langen Zufallswert setzen. Rufe die Instanz außerdem direkt nach dem Start auf, damit kein Fremder das erste Konto anlegt.
|
||
|
||
---
|
||
|
||
## ⚙️ Betrieb & Konfiguration
|
||
|
||
| Variable | Standard | Zweck |
|
||
|---|---|---|
|
||
| `PORT` | `8080` | HTTP-Port |
|
||
| `DATA_DIR` | `/data` (Container) | Ablage der Datenbank `mindsift.db` |
|
||
| `JWT_SECRET` | zufällig erzeugt (`/data/jwt.secret`) | Signaturschlüssel der Anmelde-Tokens; Platzhalter werden ignoriert |
|
||
| `BASE_URL` | `http://localhost:8080` | Öffentliche URL |
|
||
| `ALLOW_REGISTRATION` | `false` | Offene Registrierung (im Admin-UI änderbar) |
|
||
| `LOG_LEVEL` / `DEBUG` | `info` / `false` | Logging |
|
||
| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASS`, `SMTP_FROM`, `SMTP_TLS` | leer | E-Mail-Alarme (auch im Admin-UI) |
|
||
| `SMTP_SKIP_VERIFY` | `false` | Zertifikatsprüfung für interne Mailserver abschalten |
|
||
| `LEGAL_IMPRINT_URL`, `LEGAL_PRIVACY_URL` | leer | Impressum/Datenschutz als externer Link (nur `http(s)`) |
|
||
| `LEGAL_IMPRINT_CONTENT`, `LEGAL_PRIVACY_CONTENT` (oder `…_CONTENT_FILE` mit Dateipfad) | leer | Impressum/Datenschutz als Markdown, angezeigt in einem Lesefenster. Ohne URL und Text bleibt der Link unsichtbar. |
|
||
| `MINDA_DEMO` | `false` | Legt Demo-Konten `admin/admin` (mit Beispieldaten) und `user/user` an; eine Notiz und zwei Listen sind zwischen beiden geteilt, um das gemeinsame Bearbeiten auszuprobieren. **Nie auf öffentlichen Servern!** |
|
||
|
||
* **Reverse-Proxy:** Am besten WebSocket-Upgrade und ungepufferte SSE-Streams durchreichen. Blockiert ein Proxy beides, funktioniert MindSift trotzdem über Long-Polling bzw. regelmäßige Abfragen, nur etwas träger. Beispiele für Nginx, Traefik, Caddy und Cloudflare: [Doku/reverse-proxy.md](Doku/reverse-proxy.md).
|
||
* **Datensicherung:** Alle Daten liegen in `data/mindsift.db` (+ `-wal`/`-shm`). Sichere sie mit `sqlite3 mindsift.db ".backup 'backup.db'"` oder bei gestopptem Container. Zusätzlich gibt es einen JSON-Export pro Benutzer.
|
||
* **Updates:** Neues Image ziehen und Container neu starten (`docker compose pull && docker compose up -d`). Das Schema wird beim Start automatisch angepasst. Die laufende Version steht im Kopf der App unter dem Namen.
|
||
* **Image-Tags:** `:dev` = Stand des Branches `dev`, `:latest` = Stand von `main`, `:stable` = zuletzt veröffentlichte Version. Ein Git-Tag wie `v1.2.0` erzeugt `:v1.2.0` und verschiebt `:stable` darauf.
|
||
|
||
---
|
||
|
||
## 🛠 Entwicklung
|
||
|
||
Voraussetzungen: Go 1.23, Node 22.
|
||
|
||
```bash
|
||
# Backend: Vet und Tests
|
||
go vet ./... && go test ./...
|
||
|
||
# Frontend
|
||
cd frontend
|
||
npm ci
|
||
npm run dev # Vite-Entwicklungsserver
|
||
npx tsc --noEmit # Typprüfung
|
||
npm run test:run # Komponententests (Vitest, jsdom)
|
||
npm run build # Produktions-Build
|
||
cd ..
|
||
e2e/run.sh # Browser-Tests (Playwright, zwei Benutzer) gegen ein frisch gebautes Image
|
||
APP_VERSION=v0.4 e2e/screenshots.sh # Screenshots dieser README neu erzeugen (Demo-Daten)
|
||
```
|
||
|
||
Für das Binary wird das gebaute Frontend nach `cmd/server/dist` kopiert (`go:embed`); das mehrstufige `Dockerfile` erledigt das und führt Typprüfung, Frontend-Tests, Go-Vet und Go-Tests beim Image-Build aus.
|
||
|
||
**Stack:** Go (chi, gorilla/websocket, JWT, modernc SQLite) · React 18, TypeScript, Vite, Tailwind.
|
||
|
||
---
|
||
|
||
## 📚 Dokumentation
|
||
|
||
Die technische Doku liegt unter [Doku/](Doku/README.md): Architektur, Datenbank, REST- und Echtzeit-API, Module (inkl. gemeinsamem Bearbeiten), Freigaben und Berechtigungen, Reverse-Proxy, Themes. Bekannte Schwachstellen und offene Punkte stehen in [Doku/flaws.md](Doku/flaws.md).
|
||
|
||
---
|
||
|
||
## 🔒 Deine Daten gehören dir
|
||
|
||
* Selbst gehostet, keine Telemetrie, keine Fremddienste. Ausgehende Verbindungen gibt es nur zu den Alarm-Zielen, die du selbst einrichtest (SMTP, Discord, Webhook).
|
||
* Alle Inhalte liegen in einer einzigen SQLite-Datei; der ganze Workspace lässt sich als Obsidian-kompatibles Markdown-Archiv (ZIP) exportieren, alle Daten eines Benutzers als JSON.
|
||
|
||
---
|
||
|
||
## 📄 Lizenz
|
||
|
||
MindSift ist gemeinfrei unter [The Unlicense](LICENSE): Du darfst den Code ohne jede Bedingung nutzen, ändern, weitergeben und verkaufen, auch ohne Namensnennung. Es gibt keine Gewährleistung.
|
||
|
||
<div align="center">
|
||
<sub>Gebaut für Klarheit, Geschwindigkeit und digitale Souveränität.</sub>
|
||
</div>
|