Phase 1 of the collaboration plan (server side):
- internal/collab: block tree with parent IDs and fractional order keys,
operations with conflict rules (version check, block leases, conflict
copies instead of lost text, restore on late edits, cycle checks),
in-memory leases/sessions and long-poll notifier.
- Storage: per-note lock + transaction, append-only effect log (doc_ops),
idempotent results per opId (doc_op_results), snapshot, log paging,
central DocRole. Old flat block data is converted to the tree.
- The existing whole-document save (PUT/PATCH) runs as an adapter through
the same engine, so the current editor keeps working and writes to the log.
- API: GET /docs/{id}/snapshot, POST /docs/{id}/sync, GET /docs/{id}/changes
(long poll), POST /docs/{id}/leave; DOC_SEQ poke for WebSocket/SSE rooms.
- Backend accepts editor (write) shares for notes and folders; the forced
read-only migration is gone. The share dialog still offers read only.
- Tests: conflict matrix, order keys, leases, storage adapter round trip,
idempotency, API protocol incl. long poll, and a randomized simulation
(4 clients, lost/duplicated requests and responses, offline phases,
lease expiry) checking convergence, no lost text and exactly-once results.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 0 of the collaboration plan:
- Remove BroadcastToAll; task, task list and workspace folder events now
only reach users who can see the resource. Task list events carry only
the list ID, clients reload with their own permissions.
- Reject unauthenticated WebSocket/SSE connections (401). Every room join
(URL room, JOIN_ROOM, SSE rooms) is checked via a room authorizer;
/events/rooms requires login and only accepts the caller's own sseId.
- Reorder rejects tasks the caller cannot access or edit (IDOR).
- Lift the server WriteTimeout for SSE streams so they are not cut after 30s.
- Fix folder share removal sending DOC_DELETED to the share ID.
- Tests for all of the above; docs and flaw list updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server-authoritative operation log with per-block versions and 20s
block leases, conflict copies instead of data loss, IndexedDB queue
for offline use, HTTP-based sync with WebSocket/SSE/long-poll wakeups,
unified note/folder permissions, and per-user undo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add vitest, jsdom and Testing Library as dev dependencies,
replace the placeholder test:run script with vitest run.
- Add outliner tests for Backspace merging and caret placement on click.
- Run the frontend tests in the Dockerfile before the Vite build.
- Update docs (README, architecture, FLAW-19).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Clicking into a bullet places the caret where the mouse was, mapped
from the rendered markdown layer back to the raw text, instead of
always jumping to the end.
- Remove the grey background on focused and hovered rows and on the
bullet handle.
- Collapse/expand chevrons are only shown while hovering the row.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The merge only applied to a fixed list of block types, so legacy blocks
without a type were ignored, and blocks with children were rejected.
Now only code/divider/table/progress are excluded and children move up
under the previous block. The focused bullet dot is also neutral now.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Backspace at the start of a non-empty bullet appends its text to the
previous visible bullet (skipped for blocks with children and for
code/divider/table/progress blocks).
- Hashtags are rendered inline as clickable chips instead of a badge row
below the text, so lines no longer grow taller.
- Targeted/highlighted bullets use a neutral background instead of accent.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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>
Task list shares now carry a permission (editor/viewer). The server rejects
writes from viewers with 403, and the UI hides or disables edit controls
for read-only lists.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>