MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 8s
Remove outdated claims (CRDT, DocRooms, presence, .md files on disk) and document the actual architecture, API, permissions and known flaws. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
84 lines
5.8 KiB
Markdown
84 lines
5.8 KiB
Markdown
# Datenbank
|
|
|
|
SQLite-Datei `mindsift.db` (Standard: `$DATA_DIR/mindsift.db`), geöffnet mit `journal_mode=WAL`, `synchronous=NORMAL`, `foreign_keys=ON`, `busy_timeout=10000` und höchstens 8 Verbindungen. Das Schema entsteht in `Store.migrate()` ([sqlite.go](../internal/storage/sqlite.go)): zuerst `CREATE TABLE IF NOT EXISTS`, danach eine Liste idempotenter `ALTER TABLE`/`CREATE`-Anweisungen für ältere Datenbanken. IDs sind Text mit Präfix (`usr_…`, `th_…`, `tkl_…`, `lst_…`, `tls_…`, `blk_…`, `doc_…`).
|
|
|
|
Die Datei `migrations/001_init.sql` wird vom Code **nicht** gelesen und ist veraltet ([FLAW-13](flaws.md)).
|
|
|
|
## Tabellen
|
|
|
|
### Benutzer und Zugang
|
|
| Tabelle | Zweck | Wichtige Spalten |
|
|
|---|---|---|
|
|
| `users` | Konten | `email` (eindeutig), `username`, `password_hash`, `display_name`, `role` (`admin`/`member`), `is_active`, `token_version`, `alarm_channels` (kommagetrennt), `alarm_email`, `discord_webhook_url`, `custom_webhook_url`, `notify_before_minutes`, `avatar_url` |
|
|
| `user_invites` | Einladungscodes | `code`, `email`, `role`, `team_id`, `expires_at`, `used_by` |
|
|
| `revoked_tokens` | Sperrliste ausgeloggter JWTs | `token_hash`, `expires_at` |
|
|
| `api_keys` | Webhook-/API-Schlüssel | `key_prefix`, `key_hash` (SHA-256), `scopes` (nicht ausgewertet), `last_used_at` |
|
|
| `system_settings` | Schlüssel/Wert für Instanz-Einstellungen | `sharing_mode`, `allow_registration`, `instance_name`, `smtp_*` |
|
|
|
|
### Gedanken und Aufgaben
|
|
| Tabelle | Zweck | Wichtige Spalten |
|
|
|---|---|---|
|
|
| `thoughts` | Gedanken **und** Aufgaben in einer Tabelle | `status` (`inbox`/`kept`/`converted`/`discarded`), `converted_type` (`task`/`document`/`list_item`/`document_block`), `converted_ref_id`, `priority`, `is_completed`, `due_date` (nur Datum), `task_list_id`, `kanban_status`, `notes`, `subtasks` (JSON), `tags` (JSON), `alarm_sent`, `sort_order`, `source` (`manual`, `voice`, `webhook` …) |
|
|
| `task_lists` | Aufgabenlisten | `user_id` (Eigentümer), `team_id` (Altfeld), `title`, `icon`, `color`, `columns` (JSON, Kanban-Spalten) |
|
|
| `task_list_shares` | Freigaben von Aufgabenlisten | `target_type` (`team`/`user`), `target_id`, **`permission`** (`editor`/`viewer`, Standard `editor`) |
|
|
|
|
Eine Aufgabe ist ein `thought` mit `status='kept'` oder `status='converted' AND converted_type='task'`. Aufgaben, die aus einem Notiz-Block entstehen, tragen `converted_type='document_block'` und `converted_ref_id='<docId>:<blockId>'`.
|
|
|
|
### Workspace
|
|
| Tabelle | Zweck |
|
|
|---|---|
|
|
| `documents` | Notizen: `title`, `icon`, `folder_path`, `tags` (JSON), `is_archived`, `markdown_cache`, `shared_folder_id`, `sub_folder_path`, Altspalten `content`, `blocks_json` |
|
|
| `blocks` | Outliner-Blöcke: `document_id`, `type`, `content`, `level`, `position` (REAL), `checked`, `collapsed`, `lang` |
|
|
| `block_tags` | `#Hashtags` je Block (`tag`, `document_id`, `block_id`) |
|
|
| `tag_pages` | Freitext-Notiz je Benutzer und Tag |
|
|
| `doc_pins` | Favoriten je Benutzer |
|
|
| `doc_shares`, `doc_team_shares` | Notiz-Freigaben an Benutzer bzw. Gruppen (`permission` effektiv immer `read`) |
|
|
| `workspace_folders` | Explizit angelegte Ordnerpfade |
|
|
| `workspace_shared_folders` | Geteilte Ordner (Entität mit Eigentümer) |
|
|
| `workspace_folder_shares` | Freigaben geteilter Ordner |
|
|
| `workspace_folder_mounts` | Persönlicher Einhängepfad je Empfänger und geteiltem Ordner |
|
|
| `doc_user_folders` | Persönliche Ablage einer geteilten Einzelnotiz je Empfänger |
|
|
|
|
Blocktypen: `h1`, `h2`, `h3`, `paragraph`, `text`, `todo`, `bullet`, `code`, `callout`, `divider`, `table`, `progress`.
|
|
|
|
### Listen
|
|
| Tabelle | Zweck |
|
|
|---|---|
|
|
| `lists` | Geteilte Listen: `title`, `icon`, `list_type` (`shopping`/`checklist`/`vacation`) |
|
|
| `list_shares` | Freigaben: `target_type`, `target_id`, `role` (`editor`/`viewer`) |
|
|
| `list_items` | Einträge: `content`, `category`, `quantity`, `is_completed`, `completed_by(_name)`, `sort_order` |
|
|
|
|
### Gruppen
|
|
| Tabelle | Zweck |
|
|
|---|---|
|
|
| `teams` | `name`, `description`, `org_id` (Standard `default`) |
|
|
| `team_members` | `team_id`, `user_id`, `role` (`admin`/`member`) |
|
|
| `organizations` | Rudimentär; wird vom UI nicht mehr benötigt ([FLAW-24](flaws.md)) |
|
|
|
|
## Beziehungen
|
|
|
|
```
|
|
users 1─n thoughts thoughts n─1 task_lists (task_list_id, lose)
|
|
users 1─n task_lists task_lists 1─n task_list_shares ─(team|user)→ teams/users
|
|
users 1─n documents 1─n blocks 1─n block_tags
|
|
documents n─n users via doc_shares / doc_team_shares (nur Lesen)
|
|
workspace_shared_folders 1─n workspace_folder_shares / workspace_folder_mounts
|
|
users 1─n lists 1─n list_items; lists 1─n list_shares
|
|
teams 1─n team_members n─1 users
|
|
```
|
|
|
|
`thoughts.task_list_id` ist keine Fremdschlüsselbeziehung; beim Löschen einer Liste setzt der Code die Verweise auf `''`.
|
|
|
|
## Migrationen und Aufräumarbeiten beim Start
|
|
|
|
- Spalten/Tabellen/Indizes werden nachgezogen (`ALTER TABLE … ADD COLUMN`, Fehler werden ignoriert).
|
|
- Veraltete Tabellen werden gelöscht: `spaces`, `space_members`, `space_team_shares`, `document_crdt_state`, `document_crdt_updates`, `document_blocks`, `doc_block_tags`.
|
|
- `users.username` wird aus dem E-Mail-Präfix aufgefüllt.
|
|
- Alle Dokument-, Team- und Ordnerfreigaben werden auf `read` gesetzt (bei **jedem** Start, siehe [FLAW-17](flaws.md)).
|
|
- Standardwerte in `system_settings` (`INSERT OR IGNORE`): `sharing_mode=teams_only`, `allow_registration=false`, `instance_name=MindSift`, SMTP leer.
|
|
- Die Tabelle `teams` wird einmalig ohne Fremdschlüssel auf `organizations` neu aufgebaut.
|
|
|
|
## Sicherung
|
|
|
|
Die gesamte Instanz besteht aus der Datei `mindsift.db` (plus `-wal`/`-shm` im laufenden Betrieb). Konsistent sichern per `sqlite3 mindsift.db ".backup 'backup.db'"` oder durch Stoppen des Containers und Kopieren des `data/`-Verzeichnisses. Benutzerexport: `GET /api/v1/export` (JSON mit Gedanken, Notizen, Listen, Aufgabenlisten).
|