- 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>
Phase 4 of the collaboration plan:
- The sync engine listens for DOC_SEQ in the note's realtime room and syncs
right away. Without WebSocket/SSE it long-polls /docs/{id}/changes (25 s);
after three failures it falls back to polling every 3 s and retries long
polling when the browser comes back online.
- With push or long polling the engine only syncs every 7 s while holding
leases (renewal), otherwise every 30 s as a safety net. Focusing a block
announces its lease immediately (otherwise it could take up to 30 s).
- Realtime connection: SSE counts as connected only after its first event;
a stream that stays silent for 5 s (buffering proxy) switches SSE off for
the tab. App-level PING/PONG detects WebSockets that are accepted but
forward nothing and switches to SSE after 35 s.
- The editor shows the active channel for shared notes.
- Tests: engine channel tests (push, heartbeat, lease on focus, long
polling, interval fallback, switching), realtime fallback tests with fake
WebSocket/EventSource, Go tests for PONG and DOC_SEQ delivery, and
e2e/channels.e2e.mjs measuring latency behind six simulated proxy setups
(0.2-0.3 s on all live channels, ~3 s with plain polling).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 3 of the collaboration plan:
- Blocks held by someone else show a lock with the name and are read-only;
Enter in such a block adds a new block below. Delete, merge, indent and
drag are not started when a involved block (or one in its branch) is
locked; a short notice explains why (fixes FLAW-25).
- Presence: the editor header lists who else has the note open.
- Conflict copies are highlighted ("Konflikt – Version von …") with
Übernehmen (replaces the original or the title) and Verwerfen. Both check
the locks of the original and of the copy first.
- Undo/redo of own changes (Ctrl/Cmd+Z, Ctrl+Shift+Z, Ctrl+Y, beforeinput
history events): typing is grouped per block until a 1 s pause, up to 200
steps per tab; a step is skipped with a notice if someone else changed or
holds the block meanwhile. New clearConflict props patch on the server.
- New blocks get focus synchronously on mount (fixes FLAW-26).
- Fix: after reopening a note from local storage the engine polled every
30 s instead of 3 s until the next change, because the delay was decided
before the first response told it the note is shared.
- Tests: undo/conflict engine tests, lock/undo/conflict UI tests and
e2e/lock.e2e.mjs (two browsers); all three browser tests pass against a
freshly built image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The share dialog for notes and shared folders now offers "Bearbeiten" and
"Nur Lesen" and stores write/read accordingly. Editors already edit through
the sync engine since phase 2.
Adds e2e/share.e2e.mjs: shares a note as editor through the dialog and checks
that the recipient can edit it; e2e/run.sh runs both browser tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 2 of the collaboration plan:
- frontend/src/lib/docSync: TypeScript port of the block tree, operations,
effects and order keys (kept identical to Go via shared test vectors),
diff from the editor's flat list to operations, IndexedDB persistence,
HTTP transport and DocSyncEngine (one request in flight, idempotent
resends, backoff, 3 s/30 s polling, keepalive flush and leave on exit,
block leases for focus, 20 s grace and new blocks).
- Text changes carry the version the user saw when typing (first change
wins when coalescing; a stale focused field keeps its old base), so a
concurrent edit becomes a conflict copy instead of a silent overwrite.
- DocumentEditor uses the engine instead of the 800 ms whole-document PUT;
editors (not only owners) can edit, remote changes appear live.
- Server: task IDs of linked blocks are delivered again, linked tasks follow
ticked/deleted blocks after sync, note tags are derived, title changes
notify other users; block IDs already used in another note are renamed
(starter content with fixed IDs was empty for every further user).
- Fix: unlinking tasks from blocks wrote to non-existent columns and never
worked (error was swallowed).
- Tests: Go/TS order key vectors, diff round trips, engine races (lost
responses, offline + reload, edits arriving between typing and sending,
stale focused field, duplicate first block), plus a Playwright test with
two browsers against the real image (e2e/run.sh).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>