- Setting / REGISTRATION_VERIFY_EMAIL; only with SMTP and BASE_URL; invites skip it
- Hashed one-time tokens (48 h), resend with cooldown, unconfirmed accounts purged
- Approval modes notify admins only after the address is confirmed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Invites: link /?invite=CODE, copy link, send by email, max uses with counter
- Registration modes closed | approval | domain | domain+approval | open, waiting list with approve/reject
- REGISTRATION_MODE / REGISTRATION_DOMAINS lock the admin setting; ALLOW_REGISTRATION=true is honoured
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Kanban on phones/tablets: hold a card, drag it onto a card or column, release; the page scrolls at the edges
- Admin settings: database backups can be deleted (DELETE /api/v1/admin/backups/{name})
- Share message: large Liste/Aufgabe buttons, close button, tap outside closes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- /li lists /link first: name prefix, aliases, name, then description
- link cards about twice as tall; the bare address below becomes an accent
link marker; the link chip bar under bullets is gone, bare web addresses
in text are links themselves
chore(release): v0.14.3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Fjord (new), Polarized Hell and Suri Hell complete the families
Klassik, Fjord, Terrakotta, Polarized, Suri
- settings: family table, follow-system, corners, button frames and an own
accent colour (per device); compact quick picker in the user menus
- code colours in index.css are fallbacks only
chore(release): v0.14.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- dark counterpart of Terrakotta; Soft users move to it
- add tailwindcss-animate: the existing animate-in/fade/slide classes now
run; menus zoom in, sheets slide up, notes slide in on phones
- no animations with reduced motion
chore(release): v0.13.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bold, italic and strikethrough render their inside again, so **`code`**
shows bold code instead of backticks; inline code uses the theme's code
background with the main text colour instead of the accent colour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- focus mode: folders slide in from the left (button, title click, or the
left edge on wide screens); picking a note keeps focus mode
- workspace bar: borderless live/shared/save pills in one style, divider
before the note actions; footer without top line
- journal panel and calendar open with an animation, the view fades in
- paste and markdown import nest a list under the paragraph introducing it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI keeps the 'test once per code state' plan but records commit and
git tree as image labels instead of extra :sha-/:tree- tags, so the
registry only holds dev, latest, vX.Y.Z and stable; the plan test now
asserts the expected decisions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- VAPID keys from VAPID_* or generated once (push_keys, migration 9);
devices in push_subscriptions, forgotten on 404/410 from the push service
- push column for every event (also due tasks) and the daily summary,
bundles as one notification; /push/key, /devices, /subscribe,
/unsubscribe, /test
- settings: switch push on per device, test it, see the devices; the
service worker shows notifications and focuses MindSift on click
- tests decrypt a sent push like a browser (RFC 8291) and check VAPID
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- copy a link to a bullet from its action bubble or pick a bullet in the
link dialog; [[Note#^id|Note › excerpt]] opens the note, jumps to and
highlights the bullet, or says it is gone
- wiki links render inline with their label and are clickable; the
duplicate chip below the text is gone
test(e2e): run each suite with its own container, image tag and port, so
parallel runs from another working copy no longer remove our server
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- the journal opens as a framed panel and closes on a second click,
returning to the previous note; journal state and the last regular note
survive tab switches, the fallback note is never a journal day
- pasted and imported markdown nests content under its heading (H2 below
H1), Enter on a heading creates a child, '- ' / '* ' / '+ ' start a bullet
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- block type 'numbered' (/number): 1., a., i. by nesting, continues on
Enter, an empty item ends the list; markdown export/import as 1.
- pasting: parser moved to lib/pasteOutline with tests; blank lines split
paragraphs, numbered lists keep their type, indentation levels follow
the widths in use (2, 3 or 4 spaces, tabs)
- text that stays in the focused block after pasting (a paragraph with
line breaks) was dropped; the block now takes it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- journal_days (migration 8) maps a person's day to an ordinary note;
GET /journal lists the days, POST /journal/{date} opens or creates one
- the journal sits on top of the notes sidebar: days below each other
(today first, older ones load while scrolling), a calendar with month
and year picker follows the day in view and jumps to any day
- the header shares the day in view; journal notes stay out of the folder
tree; can be switched off per device under Darstellung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The custom webhook could be entered but never switched on since the
notification matrix replaced the old alarm channels. It is now a third
column next to e-mail and Discord for every event and the daily summary;
bundles go out as JSON (event "digest").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
- 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>
- 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>
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>
- /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>
- /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
().
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 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>
- 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>
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>
- 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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>