Commit Graph
100 Commits
Author SHA1 Message Date
sandrodachandClaude Opus 5.5 6c154af251 fix(workspace): single scroll area, drag cleanup, thin note titles with bundled Inter
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m18s
- the workspace fills the window; only the note scrolls (also on phones, where the
  sideways scroll area used to scroll on its own)
- clear drag state on dragend, calmer sidebar toggle when collapsed
- ship Inter as variable font, light and larger note titles; header shows the
  title only after the big title scrolled away and stays one row on phones
- main builds show the package version without -dev

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 18:58:55 +01:00
sandrodachandClaude Opus 5.5 ad4829796c fix(settings): let the profile section use the full width
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m9s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 18:36:50 +01:00
sandrodachandClaude Opus 5.5 2542e0e7b8 fix(themes): white editor and grey sidebar in light theme
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m1s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 18:03:46 +01:00
sandrodachandClaude Opus 5.5 1b0c8ba18f chore(release): v0.9.0
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m9s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:51:32 +01:00
sandrodachandClaude Opus 5.5 5ff99c5434 fix(workspace): ignore formatting shortcuts in read-only notes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:51:14 +01:00
sandrodachandClaude Opus 5.5 8ecde4872d Merge branch 'feat/editor-polish' into dev
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:46:10 +01:00
sandrodach 07d86a0e2f docs(readme): add daily summary to features list 2026-10-30 16:23:26 +01:00
sandrodach a317ce0fee feat(workspace): add formatting shortcuts for bold, italic, and links in outliner 2026-10-30 16:22:55 +01:00
sandrodach 1d6863824b feat(workspace): add line numbers and horizontal scrolling to code block editor 2026-10-30 16:17:17 +01:00
sandrodach 108ac6621c fix(themes): improve contrast for code blocks and callouts in light theme 2026-10-30 16:12:36 +01:00
sandrodachandClaude Opus 5.5 e15b028171 Merge branch 'docs/review' into dev
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 7s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 15:25:36 +01:00
sandrodach 6952ae15e3 docs(env): fix typo in comment 2026-10-30 13:38:56 +01:00
sandrodach e8c7c55dd5 docs(changelog): note group-shared task lists in daily summary for 0.8.0 2026-10-30 13:38:21 +01:00
sandrodach 57de85d530 docs(readme): update feature list, version badge to v0.8.0, and config options 2026-10-30 13:38:06 +01:00
sandrodach d86623f2c9 docs(websocket): document DEMO_RESET event 2026-10-30 13:36:42 +01:00
sandrodach e83c1ae7dd docs(flaws): strike implemented images/audio feature idea 2026-10-30 13:36:27 +01:00
sandrodach 6ae4fbc2bf docs(sharing): complete sentence pointing to flaws.md 2026-10-30 13:36:08 +01:00
sandrodach 4a3ee2c570 docs(ui-patterns): update voice input description in HoldToRecordFab 2026-10-30 13:35:59 +01:00
sandrodach f5f21e1c9c docs(triage): update speech input description to useVoiceInput 2026-10-30 13:35:37 +01:00
sandrodach f2df3f8d86 docs(tasks): add task watchers and granular notifications documentation 2026-10-30 13:35:24 +01:00
sandrodach b5e89d6bd7 docs(workspace): update slash commands, extract/merge behavior, permissions, and link fix 2026-10-30 13:34:51 +01:00
sandrodach ad6a8ead61 docs(database): update schema columns, migrations 3-7, and remove obsolete statements 2026-10-30 13:33:51 +01:00
sandrodach b9df907ead docs(architecture): add missing env variables to configuration table 2026-10-30 13:32:58 +01:00
sandrodach e6ea8155e4 docs(api): fix routes in rest.md to match server.go 2026-10-30 13:32:18 +01:00
sandrodachandClaude Opus 5.5 6100d339f1 chore(release): v0.8.0
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m16s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 10:00:09 +01:00
sandrodach 4f5da9507f Merge branch 'feat/gemini-workspace' into dev
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	CHANGELOG.md
2026-10-30 09:54:30 +01:00
sandrodachandClaude Opus 5.5 6b3c32a370 fix(notify): daily summary includes lists shared through a group
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:54:10 +01:00
sandrodachandClaude Opus 5.5 a69bcbaf10 feat(notify): bundled notifications, task watchers, daily summary
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m4s
- Per-user routing (own mail / own Discord webhook) for task alarms
  (sent at once), shares, completed shared tasks and watched tasks;
  settings as JSON on the user (GET /auth/me, PATCH /auth/settings).
- Everything but alarms is queued and sent as one message per user
  after NOTIFY_DIGEST_MINUTES (default 5); mails now multipart with an
  HTML version, Discord as one embed. Three failed attempts drop it.
- Own changes never notify the actor, except on watched tasks when
  asked for; "paused" stops everything including alarms.
- Task watchers: POST/DELETE /tasks/{id}/watch, isWatching on tasks.
- Daily summary at a chosen time: overdue, today, tomorrow, plus the
  count of the next 7 days; nothing due, nothing sent.
- Migration 7; jobs do not run in the demo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:49:13 +01:00
sandrodach 5f27e7ca9c feat(workspace): move status pills to tab bar and add undo/redo and actions menu to note header 2026-10-30 09:41:02 +01:00
sandrodach fc7b2b3a2c Merge remote-tracking branch 'origin/dev' into feat/gemini-workspace
# Conflicts:
#	CHANGELOG.md
2026-10-30 09:33:23 +01:00
sandrodach d2afcf49df feat(notifications): add channel routing matrix, daily summary, and task watch button 2026-10-30 09:32:52 +01:00
sandrodach 6795edbf4b feat(voice): live dictation with browser pause restart and server audio chunking 2026-10-30 09:27:30 +01:00
sandrodach 446f8e4649 fix(workspace): tighten link preview card, slash menu matching/scrolling, and Enter on last empty bullet 2026-10-30 09:21:29 +01:00
sandrodachandClaude Opus 5.5 362dd3b4c6 fix(workspace): extract replaces the branch in the editor, with undo
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m2s
The server only creates the new note and returns the link; the editor
swaps the branch for it as an ordinary own edit through the sync engine.
No more clash with unsent typing (conflict copies), the link shows at
once also with polling, and Strg+Z restores the branch. Undoing (toast or
Strg+Z) puts the new note into the trash via POST /extract/undo. The
sidebar gets the new note right away and opens its folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:18:25 +01:00
sandrodachandClaude Opus 5.5 02ce554c02 chore(release): v0.7.0
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 9s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 00:26:26 +01:00
sandrodachandClaude Opus 5.5 4d1b37c956 feat(workspace): turn a branch into its own note, merge notes
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m56s
- Extract: button on the bullet (desktop) or /extract (/notiz). The bullet
  becomes the title (hashtags stay at the link), its children the content
  of a new note in the same folder with the source's shares (a foreign
  source owner gets write access); the branch becomes [[title]] through
  the operation log, so open editors follow.
- Merge: drop a note onto another in the sidebar or use "Mit anderer
  Notiz zusammenführen…" in the note header. The own source is appended
  as an h2 section with its bullets below and goes to the trash; the toast
  offers a complete undo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 00:25:46 +01:00
sandrodachandClaude Opus 5.5 4c26eb2960 feat(workspace): link previews above bullets with a web address (M5)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m52s
- GET /link-preview?url= fetches the page on the server (https only,
  SSRF-guarded like webhooks), reads Open Graph/Twitter tags, title,
  description and icon from the head, loads picture and icon (no SVG) and
  keeps them in link_previews (migration 6) for 7 days; readers' browsers
  never contact the page. Off in the demo; 300 fetches per address in
  15 minutes.
- Compact card above the bullet (icon, site, title, one line, small
  picture); the duplicate link badge is left out.
- ✕ turns the address into [title](url), so hiding syncs with the note;
  "Link-Vorschauen anzeigen" under appearance switches all off per device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 00:06:05 +01:00
sandrodachandClaude Opus 5.5 83408d120d fix(workspace): more room for notes on phones
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m57s
Almost no side margin, 14 px indent per level (22 px from tablet width
on), zoom and delete buttons only take width in the active row. Very deep
rows keep about 14rem and the note scrolls sideways instead of squeezing
the text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:55:00 +01:00
sandrodachandClaude Opus 5.5 56c1fa02e6 feat(mail): sender display name (SMTP_FROM_NAME, default MindSift)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m54s
A bare SMTP_FROM address gets the display name in the From header; a name
already in SMTP_FROM wins, the envelope keeps the bare address. Also a
field in the admin mail settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:47:38 +01:00
sandrodachandClaude Opus 5.5 1632dd22c4 fix(workspace): English slash commands, short texts, wider menu
/image replaces /bild (aliases bild/foto keep working), shorter
descriptions for /link, /image, /audio, /diktat; the menu is wider, the
command never wraps and long descriptions are cut off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:47:38 +01:00
sandrodachandClaude Opus 5.5 1f63e08a73 feat(media): images and recordings in backups, exports and imports (M6)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m52s
- Backup ZIP (download and automatic per-user server backups) carries the
  files of the user's own notes as media/<id><ext>; restoring creates
  them with new IDs and rewrites the blocks.
- Markdown archive puts them under attachments/ and embeds them relative
  to each note (![caption](../attachments/…)); re-importing turns them
  back into image/audio blocks.
- Obsidian import takes images and audio a note embeds on its own
  (![[file.png]], ![](path/file.png)); unused or invalid files appear as
  skipped in the preview instead of vanishing.
- Format detection and file paths moved into storage for this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:41:26 +01:00
sandrodachandClaude Opus 5.5 3f2bc96732 feat(workspace): dictation via /diktat (M4)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m59s
/diktat (only in an empty bullet, only with voice input available)
listens right away; the bullet becomes one button with the live wave
across it and a translucent "Stopp" on top. A tap ends it and the
recognised text lands in the bullet as plain text. Uses the configured
speech recognition (own Whisper server or the browser); Esc cancels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:30:15 +01:00
sandrodachandClaude Opus 5.5 3f5e3b2ac1 feat(workspace): voice notes via /audio (M3)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m10s
- /audio (only in an empty bullet) shows a recording bubble: green round
  button starts, it turns red with a live wave and timer on its left, a
  tap saves the recording as an inline audio player. An audio file can be
  uploaded instead; Esc/✕ restores the empty bullet.
- Chrome's WebM recordings get their length measured, so the player shows
  the total time and seeking works.
- With the own Whisper server "Transkribieren" turns the recording into
  the (searchable) caption.
- Loaded files keep their Blob, as the CSP rightly blocks fetch() on blob:
  URLs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:23:54 +01:00
sandrodachandClaude Opus 5.5 e8fa14a4cb feat(workspace): image blocks via /bild (M2)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m18s
- /bild (only in an empty bullet) turns the bullet into an inline picker:
  file, camera on phones, drag & drop, paste, or an https link the server
  copies. Esc/✕ restores the empty bullet; nothing is synced before the
  upload succeeded.
- Photos are shrunk to 2048 px and stored as WebP (JPEG fallback); the
  re-encoding drops EXIF data such as the location.
- Image block: loaded with the login as blob URL, click opens full
  screen, optional caption kept in the block content
  (![caption](media:id)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:14:08 +01:00
sandrodachandClaude Opus 5.5 177fa49363 feat(media): storage for images and audio in notes (M1)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m4s
- Table media (migration 5), files in $DATA_DIR/media/<docId>/.
- POST /documents/{id}/media (write access), POST .../media/fetch copies an
  external https image (SSRF-guarded, not in the demo), GET /media/{id}
  with range requests for readers of a note that shows the file.
- Format detected from the content (no SVG); own sandbox CSP on answers.
- Blocks point to files through their content (media:<id>), so the note
  sync needs no change; compaction removes files no block mentions any
  more after a day. Demo reset and demo start clear the folder.
- Limits MEDIA_MAX_IMAGE_MB, MEDIA_MAX_AUDIO_MB, MEDIA_QUOTA_MB,
  MEDIA_DEMO_MAX_MB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:57:59 +01:00
sandrodachandClaude Opus 5.5 e385a44fb9 chore(docker): explanations in .env.example, whisper as commented block
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 8s
- docker-compose.yml only maps variables; every variable is explained in
  .env.example (German, with defaults, units and choices).
- The whisper service is a commented block to switch on instead of a
  compose profile.
- TZ, TRUSTED_PROXIES, LOGIN_PROTECTION, DEMO_RESET_MINUTES and
  LEGAL_*_CONTENT are now passed through (they had no effect from .env).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:51:57 +01:00
sandrodachandClaude Opus 5.5 d396d42acf docs(changelog): hold-to-record cancels by dragging up
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 7s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:49:32 +01:00
sandrodachandClaude Opus 5.5 d52992afd2 Merge branch 'changelog_backlog' into dev
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 8s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:49:02 +01:00
sandrodachandClaude Opus 5.5 cc68d3f334 fix(workspace): keep the cursor in a block that turns into a code block
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m58s
Converting via /code or ``` swapped the text field for the code editor's
and left the focus nowhere, so further typing triggered app shortcuts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:48:35 +01:00
sandrodach b624093980 docs(changelog): backfill release history from v0.1 to v0.5.2 2026-10-29 22:42:43 +01:00
sandrodachandClaude Opus 5.5 9124809f54 Merge branch 'feat/code-block' into dev
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:37:17 +01:00
sandrodachandClaude Opus 5.5 a9d0e49159 Merge branch 'feat/sidebar-explorer' into dev
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:37:17 +01:00
sandrodachandClaude Opus 5.5 7fa21e485b feat(voice): all microphone buttons use the server's speech recognition
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m56s
- New useVoiceInput hook (lib/voice.ts): "server" records with MediaRecorder
  and sends to /voice/transcribe, "browser" keeps the live recognition,
  "off" or missing browser support hides the microphone.
- Quick dump bar, mobile capture sheet and hold-to-record use it; live
  waves from the real input level (VoiceWave) and "Wird erkannt…".
- Recordings stop after STT_MAX_SECONDS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:23:48 +01:00
sandrodach ff53f06991 feat(workspace): code block with language picker and live highlighting 2026-10-29 22:18:03 +01:00
sandrodachandClaude Opus 5.5 7801cd13b9 feat(voice): self-hosted speech recognition via Whisper (STT_*)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m49s
- STT_URL switches voice input to an OpenAI-compatible Whisper server
  (e.g. speaches); without it the browser's recognition stays. Configured
  by environment only, with limits for upload size, parallel jobs, hourly
  budget per user and timeout. The demo always uses the browser.
- POST /voice/transcribe forwards recordings and returns the text; nothing
  is stored. On startup MindSift waits for the server and asks it to
  download the model if missing.
- Admin card shows the active mode and server state, with a test recording.
- docker-compose: optional "whisper" service (speaches 0.8.3 CPU, profile
  "whisper", models in ./whisper).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:12:57 +01:00
sandrodach 9f3c78dde0 feat(workspace): sidebar as a plain file explorer 2026-10-29 22:08:35 +01:00
sandrodachandClaude Opus 5.5 6a5e82431f chore(release): v0.6.1
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m6s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:20:00 +01:00
sandrodachandClaude Opus 5.5 fbc404fea1 fix(notes): no self-conflicts when typing in a rhythm
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m51s
Several unsent text changes of one block were applied one by one to the
local view, numbering local versions ahead of the server, which folds them
into one change (formBatch). The focused field kept the inflated version as
base, so the next edit after a sync conflicted with the user's own text.
The local view now applies pending ops as they will be sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:13:02 +01:00
sandrodachandClaude Opus 5.5 b55334b163 chore(release): v0.6.0
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m8s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 20:40:59 +01:00
sandrodachandClaude Opus 5.5 090d11d4c3 refactor(capture): memoize writable lists in the capture bar
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 20:40:59 +01:00
sandrodachandClaude Opus 5.5 ef16778ef5 Merge branch 'feat/single-list-shortcut' into dev
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 20:36:11 +01:00
sandrodachandClaude Opus 5.5 9d9698186c fix(security): demo sends nothing, hidden SMTP password, body limits (FLAW-33..38)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m52s
- Demo: senders for mail, Discord and webhooks refuse, no alarm ticker;
  test alarm, SMTP test, server settings, backups, account and session
  changes of the shared demo accounts answer 403; the session list only
  shows the own device. The UI shows the notices and disables the controls.
- SMTP password is never sent back (smtpPassSet), empty keeps it.
- ?token= on webhook ingest accepts only API keys.
- Request bodies capped at 2 MB (sync 8 MB, imports 101 MB).
- Deleting an account removes its server backups.
- Backup downloads, exports and import uploads get 30 minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 19:43:23 +01:00
sandrodachandClaude Opus 5.5 3709282a4f fix(auth): longer IDs and invite codes, register limits, single-use invites (FLAW-32, FLAW-39, FLAW-40)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m2s
- NewID uses 96 random bits; invite codes get their own 100 bits in Base32.
- Registration and forgot-password are limited per address via loginGuard.
- The invite is claimed atomically before the account is created and
  released again when the account cannot be created.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 19:28:09 +01:00
sandrodachandClaude Opus 5.5 1af3a6e90a feat(auth): server-side sessions and current password for account changes (FLAW-30, FLAW-31)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m52s
- Every login is a session (device, IP, last use); the token's jti is its ID.
  Sessions end on logout, per device from the profile, or after 30 idle days.
- Tokens older than a day are renewed via the X-Session-Token header.
- Changing password or login e-mail needs the current password; a new
  password logs out all other devices and mails the old address.
- Demo reset keeps the demo visitors' sessions.
- revoked_tokens is replaced by sessions (migration 4); everyone is logged
  out once after the upgrade.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 19:25:22 +01:00
sandrodachandClaude Opus 5.5 b2ecda9896 fix(security): safe links and security headers (FLAW-28, FLAW-29)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m48s
safeHref lets only http, https and mailto become links (Markdown viewer,
outliner, legal links); javascript: and friends show as text. A
middleware sets a Content-Security-Policy (scripts only from MindSift,
no framing, connections only to this server), X-Frame-Options,
nosniff, Referrer-Policy and a Permissions-Policy. The two inline
scripts of index.html moved to files so script-src stays 'self'.

The second inline script also deleted every cache on each page load,
which undermined the offline start; it is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 19:02:13 +01:00
sandrodachandClaude Opus 5.5 3ca4ff7bce chore: Semantic Versioning and a changelog from now on
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m50s
Tags become three-part (v0.6.0), the header shows the full version and
pre-release tags no longer move :stable. CHANGELOG.md (Keep a Changelog)
starts with an Unreleased section; older versions will be added from the
history. The quantity field opens the number keypad on phones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 18:55:32 +01:00
sandrodach 3a27a37acb feat(triage): skip list selector when only one writable list exists 2026-10-29 18:49:35 +01:00
sandrodachandClaude Opus 5.5 ff27d07aa3 docs(flaws): FLAW-33 covers outgoing alarms of a public demo
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 9s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 18:39:20 +01:00
sandrodachandClaude Opus 5.5 6cbfedd013 fix(lists): typing into the shopping list on phones
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m1s
The + button and the menu entry focused the new-item field 60 ms after
the tap; iOS only opens the keyboard for focus() inside the user gesture,
so the field was selected but nothing could be typed. Focus now happens
right in the tap. The list inputs use 16px on phones, so iOS no longer
zooms in and pushes the field under the keyboard. Version 0.5.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 17:28:43 +01:00
sandrodachandClaude Opus 5.5 3c31a22ba0 fix(capture): + button opens the capture sheet again in triage and tasks
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m59s
Hold-to-record opened the sheet on pointerup; the click the browser sends
right after landed on the new sheet's backdrop and closed it at once.
Lists and notes have no such backdrop and kept working. A short tap now
opens on the click itself (as before), and after a hold that click is
ignored. Tests send the real pointerup + click sequence. Version 0.5.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 17:12:03 +01:00
sandrodachandClaude Opus 5.5 fcdf44a0ad docs: fresh review – new flaw list (FLAW-28 to 41) and feature ideas
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 8s
The old list (FLAW-01 to 27) was done and is removed; references to it
in other documents are gone or replaced by the content. New findings
from a review after v0.5, among them a high one: javascript: links in
task notes run on click (Markdown viewer), which with the session in
localStorage allows taking over accounts through a shared task list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 17:02:02 +01:00
sandrodachandClaude Opus 5.5 13a7c9f08d release: v0.5 – security hardening, backups, demo reset, API key scopes, hold-to-record
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 16:54:09 +01:00
sandrodachandClaude Opus 5.5 373987292f fix(capture): hold-to-record works by keyboard, confirms only after saving; drop FLAW-16
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m43s
The + button lost its click handler for pointer events, so keyboard,
VoiceOver and switch control could no longer open the capture sheet; a
click without pointer (detail 0) now taps. "Im Quick Dump gespeichert"
appears after the save succeeded, and the cancel state uses an existing
border color. FLAW-16 (setup open until the first account, demo
accounts) is removed from the list: intended behaviour, not a flaw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 16:35:26 +01:00
sandrodachandClaude Opus 5.5 ac2d9e1412 Merge branch 'feat/hold-to-record' into dev: hold the + button to record a thought
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 16:31:29 +01:00
sandrodachandClaude Opus 5.5 64e077dd57 feat(backup): admin and account UI for server backups, import by section
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m44s
Admin settings: switch, time, retention, list with download and a
"Jetzt sichern" button. Account settings: own server backups with
download and restore (replace or add, for chosen sections, replace needs
a second tap). The MindSift import gets the same section picker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 16:11:49 +01:00
sandrodachandClaude Opus 5.5 c97765e08e feat(backup): daily server and user backups, restore by section (backend)
Admins switch automatic backups on, pick the time and the retention
(default 03:00, 3 days). Each run writes a gzip snapshot of the whole
database (VACUUM INTO, consistent while others write) and one MindSift
backup ZIP per active user below $DATA_DIR/backups, then deletes files
past the retention. A restart after the time catches up on that day.
Admins list, download and trigger runs; users list, download and restore
their own backups.

Import and restore can be limited to sections (notes, tasks, lists,
inbox, themes): restore only empties the chosen sections. Export and
import now carry custom themes. File names are checked against a fixed
pattern, so no other file can be fetched through the API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 15:10:06 +01:00
sandrodachandClaude Opus 5.5 cab5a79f6d refactor(storage): one definition of task list access (FLAW-20)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m56s
accessibleTaskListsSQL in tasklists.go defines which task lists a user
can see; GetTaskLists, GetTaskListByID and the task queries use it
instead of three copies of the same subquery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 15:05:05 +01:00
sandrodachandClaude Opus 5.5 0fdf46635b test(frontend): task dialog, sharing avatars, trash, API key scopes, passwords (FLAW-19)
Covers opening and closing the task dialog (the former hook-order bug),
date/time fields and the view-only mode for viewer lists, the avatar
stack of shared items, the two-tap delete in the trash, scope selection
and badges of API keys, and the shared password rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 15:03:54 +01:00
sandrodachandClaude Opus 5.5 4c50d15915 chore(frontend): real ESLint instead of a placeholder; fix hook order (FLAW-19)
eslint.config.js with the recommended JS/TypeScript rules and the React
hooks rules; npm run lint runs ESLint and is part of the image build.
Errors fail the build, the 24 exhaustive-deps findings stay warnings.

It found two real bugs: TaskDetailModal and ManageColumnsModal called
their hooks after 'if (!isOpen) return null', so the hook count changed
whenever the dialog opened or closed. Both are now a thin wrapper plus a
content component. Also removes unused imports and dead code (old task
list share handlers, an unused realtime status, an unused rollup).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 15:02:52 +01:00
sandrodachandClaude Opus 5.5 6b56a33500 fix(db): report write errors, multi-step changes all or nothing (FLAW-14)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m4s
Store.execInTx runs related statements in one transaction and returns
the first error. Used for deleting and moving folders (with the trash),
shared folders, folder shares and mounts, deleting task lists and
accounts, pinning, and the password reset (new password and the end of
all other links together). Writes whose success the API reports now
pass their error to the client (logout, new password, setup, sharing
mode, new group, restore, unlinking a note block), follow-up tasks and
alarm markers log failures. Remaining ignored writes are listed as
intentional in flaws.md.

Found on the way: DeleteTaskList unlinked all tasks before checking
ownership, so a stranger with the list ID could empty it; viewers could
unlink tasks from note blocks. Both fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:59:23 +01:00
sandrodachandClaude Opus 5.5 792ca946f8 fix(db): transactions wait for the write lock instead of failing (FLAW-23)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 58s
A load test with 16 concurrent writers lost 12 of 480 writes with
SQLITE_BUSY: transactions that read before writing cannot be helped by
busy_timeout once another connection writes. _txlock=immediate makes
every transaction take the write lock at BEGIN, so it queues instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:51:01 +01:00
sandrodachandClaude Opus 5.5 dc44f8250c fix(db): numbered migrations that run once and fail loudly (FLAW-13)
schema_migrations records every applied step; the former migrate() is
step 3, the baseline that builds the v0.4.1 schema and repairs older
databases. Columns are only added when missing, so every other error now
stops the start with a clear message instead of being swallowed, and the
cleanup statements no longer run on each start. migrations/001_init.sql
was never read and is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:49:35 +01:00
sandrodachandClaude Opus 5.5 f57a9884d1 fix(security): stream tickets instead of session tokens in URLs (FLAW-22)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m32s
WebSocket and EventSource put the 30-day session token into the URL,
where proxies log it. The app now gets a one-time ticket right before
connecting (POST /auth/stream-ticket, 60 s, bound to the token version);
?token= is no longer accepted for streams, non-browser clients may use
the Authorization header.

With BASE_URL set, CORS allows only that origin and WebSocket upgrades
only it or the requested host; credentials are off (no cookies exist).
Logout, ending all sessions, a new password and deactivation close all
live streams of the account; clients with a valid session reconnect
with a fresh ticket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:46:58 +01:00
sandrodachandClaude Opus 5.5 5c711c2cf7 feat(api-keys): scopes for triage, tasks and list items (FLAW-07)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m33s
Keys get scopes when created (webhook:triage, webhook:task,
webhook:list; default triage, old keys become triage). The webhook
ingest learns target task (optional task list) and list_item (needs a
list the owner may write to); /inbox checks the scope of its target as
well; a missing scope answers 403. Keys can no longer open live streams,
which carried all of the owner's events.

The visible key UI lived in the account settings while EcosystemView
was never rendered; it is replaced by ApiKeysPanel in the settings with
scope chips, scope badges per key and a simulator for all three
targets. Examples send the key as X-API-Key header, not in the URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:36:17 +01:00
sandrodachandClaude Opus 5.5 3900c6104e fix(security): list items need write access to their list (FLAW-27)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 59s
Creating, checking, editing, deleting, reordering and clearing list
items did not check the list at all: any logged-in user with a list or
item ID could change it, viewers of shared lists as well. All item
endpoints and converting a thought into a list item now require owner
or editor rights and that the item belongs to the list (404 without
access, 403 for viewers).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:28:39 +01:00
sandrodach eabb018c64 feat(capture): hold mobile + button to record voice thoughts directly to inbox 2026-10-29 14:27:42 +01:00
sandrodachandClaude Opus 5.5 11c14fa9ff feat(auth): lock logins after repeated failures, trust proxies explicitly (FLAW-09)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 59s
Failed logins are counted per account+address (3), per account (20) and
per address (30) within 15 minutes; a full bucket answers 429 with
Retry-After for 15 minutes. Locking the account+address bucket first
means an attacker cannot lock the owner out from elsewhere. Unknown
names count like accounts. Success clears the account buckets, a
password reset (mail or admin) lifts the lock. LOGIN_PROTECTION=false
switches it off.

chi's RealIP believed X-Forwarded-For from anyone. The client address
now comes from the headers only when the connection is from a trusted
proxy: TRUSTED_PROXIES=private (default: loopback, Docker, LAN), all
(old behaviour), none, or CIDRs. A proxy that sends no client address
is logged once and per-address limits are skipped for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:26:02 +01:00
sandrodachandClaude Opus 5.5 6b9eb62caf feat(demo): reset the demo instance every 20 minutes with a countdown
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m34s
DEMO_RESET_MINUTES (default 20, 0 = off) resets the database to the
sample data. Demo accounts get fixed IDs so sessions survive; requests
hold a read lock so the reset never runs under a half-finished request
(streams excluded). DEMO_RESET goes to every connection, /auth/status
announces the next reset. The app shows "✨ Demo · Reset in MM:SS" in
place of the version, then clears cached answers, remounts the views,
reloads in the background and shows a short notice; if no event
arrives (long polling) it asks the server after the countdown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:22:06 +01:00
sandrodachandClaude Opus 5.5 afd3b0347c fix(ui): rounded-full wins over the theme radius on framed panels
The global rule giving .bg-panel.border the theme's card radius made the
round search button square in themes with 0px corners. Elements that ask
for rounded-full now stay round in every theme. Also marks FLAW-21 as
fixed (Unlicense is in the repository).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 14:16:31 +01:00
sandrodachandClaude Opus 5.5 6d6a35d28d fix(ui): tab counters 4px lower and further right
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m32s
Corner counters on tabs (header, task lists, lists, workspace) sat on
the tab's top border and close to the text; now -top-0.5 -right-2 with
pr-3 on the label. The mobile bottom bar keeps its icon placement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:46:26 +01:00
sandrodachandClaude Opus 5.5 e7851f1257 feat(workspace): sidebar search opens the global search
The sidebar filter only matched titles and tags, never the bullets. It
is replaced by a search-field-like button that opens the command palette
(full-text search over all notes and bullets).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:44:40 +01:00
sandrodachandClaude Opus 5.5 4bf060b97e feat(ui): workspace tabs use the shared counter
To-Dos and Hashtags show a CountBadge on the label like all other tabs;
Notizen has no counter any more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:44:07 +01:00
sandrodachandClaude Opus 5.5 c4fc455850 feat(ui): open list items counter on Listen, none on Workspace
New stat listItemsOpenCount: unchecked items in all lists the user sees
(own, shared directly or through a group), shown as accent counter on
Listen in the header and the mobile bottom bar. Workspace loses its
counter. Stats refresh on list events and after deleting an item.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:43:56 +01:00
sandrodachandClaude Opus 5.5 6d720c0c36 feat(ui): round icon-only search button in the title bar
The shortcut moves from the visible ⌘K badge into the tooltip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:42:25 +01:00
sandrodachandClaude Opus 5.5 d1982816c1 fix(alarms): give up after three runs without delivery (FLAW-12)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m34s
New column alarm_failures counts ticker runs in which no channel
delivered; at three the alarm is marked as done and a warning is logged
instead of retrying every minute forever. Success, a new due date or
reopening the task starts over with three attempts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:22:13 +01:00
sandrodachandClaude Opus 5.5 b5f926bcf7 fix(auth): new passwords need at least 8 characters (FLAW-09)
auth.ValidatePassword checks every way a password is set: setup,
registration, profile, admin create and reset, reset by mail. Same rule
in the browser before sending (lib/password.ts), with our own German
message instead of the browser popup. Existing shorter passwords still
log in. Profile and admin reset no longer trim the password, which made
passwords with surrounding spaces unusable for login.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:20:46 +01:00
sandrodachandClaude Opus 5.5 f8989d0c44 fix(theme): readable text on the Polarized teal accent
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m34s
White on #14b8a6 reaches only 2.5:1; dark teal #042f2e gives 5.8:1 for
primary buttons, counters and active filters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 11:08:39 +01:00
sandrodachandClaude Opus 5.5 ee60a03e8c Merge branch 'theme/polarized-teal' into dev: Polarized in green/teal
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m36s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 11:04:31 +01:00
sandrodach 51a41df14b feat(theme): revise Polarized to classic green/teal dark palette 2026-10-29 09:15:20 +01:00
sandrodachandClaude Opus 5.5 82a5b6c4ad feat(demo): deeply nested sample note to try out zooming
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 59s
"Hausrenovierung 2027" in Privat goes down seven levels (floor → room →
topic → appointment → variants → details) with tasks and hashtags mixed
in, so zooming into a branch and back via the breadcrumb shows something
realistic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 09:14:31 +01:00