Users pulling the image without authentication get "unauthorized" because
ghcr.io packages default to private under an organization. Add a step in
both release workflows to explicitly set the container package to public.
https://claude.ai/code/session_01QovQeW26KfEEmU1KdFfCPU
Concurrent edits to shared notes (e.g., one user checks a shopping list
item while another adds an item) were lost because the sync system used
whole-document Last-Write-Wins. This replaces it with a 3-way line-level
content merge using node-diff3, so changes to different lines are
preserved from both users.
Key changes:
- Add node-diff3 for 3-way line-level content merging
- Remove the timestamp gate in processSyncPush that rejected entire
offline sync pushes when another user had updated the note
- Add content merge to both the sync push path and the PATCH endpoint,
using version snapshots as the merge base
- Send baseVersion from the client so the server can find the correct
common ancestor for 3-way merge
- Protect pending local fields during client pull merge by reading
the sync queue and preserving queued-but-unpushed changes
- Add comprehensive tests for content merge, server sync, and CRDT merge
https://claude.ai/code/session_01FNpVBBjM6vKzfR8y9NM9Ci
The editor card's onpointerdown stopPropagation prevented the
FormattingToolbar's document-level pointerdown listener from
detecting clicks outside the dropdown. Since both overlay handlers
already use e.target === e.currentTarget to ignore bubbled events,
no stopPropagation is needed on the card.
https://claude.ai/code/session_018DYwSysqysMmaRi5XkqTpo
Pointer events are never synthetically re-dispatched from touch
(unlike mouse events), so the tap that opened the editor cannot
ghost-click the overlay. This eliminates the mobile first-load bug
without relying on an arbitrary delay.
Both pointerdown and pointerup must target the overlay itself to
trigger close, which also handles the text-selection-outside-editor
edge case.
https://claude.ai/code/session_018DYwSysqysMmaRi5XkqTpo
On first page load on mobile, the synthetic mousedown from a tap can
arrive ~300ms after the touch event — well after a single
requestAnimationFrame (~16ms). Replace the rAF-based overlayReady
guard with a 400ms timestamp check from mount time to reliably
ignore stale synthetic events on slow first loads.
https://claude.ai/code/session_018DYwSysqysMmaRi5XkqTpo
Send an email to collaborators when they are added to a shared note.
Uses nodemailer with optional SMTP configuration (auto-enabled when
SMTP_HOST is set). Users can opt out via the notifyOnShare preference.
https://claude.ai/code/session_01P4HSMr7QvKw9TMNikUJD9e
Add more vertical padding (py-1 → py-1.5) to checklist items for better
readability. Add min-w-0 to the text input so long text is constrained
within the flex container instead of overflowing out of the note.
https://claude.ai/code/session_0163L1u9MfL1C6Rv3yAw8RKs
- Replace `truncate` with `break-words min-w-0` so long checklist text
wraps visibly instead of being clipped
- Increase vertical spacing between items (space-y-1 → space-y-2)
- Add bottom margin (mb-6) to prevent action buttons overlapping content
- Align checkboxes to top of multi-line items (items-start + mt-0.5)
https://claude.ai/code/session_01UVNA5wucVEjRQzwRxMhTZ9
On mobile, tapping a NoteCard to open the editor produces synthetic mouse
events (mousedown → mouseup → click) at the original touch coordinates.
If those coordinates land on the overlay backdrop rather than the editor
card, the mousedown sets mousedownOnOverlay = true and the click
immediately closes the editor — causing a brief flicker.
Guard against this by deferring overlay readiness to the next animation
frame after mount, so any synthetic events from the originating tap are
ignored.
https://claude.ai/code/session_011C8bfgShjDSmDr3rUCb2gw
On touch devices, hover states don't work, so the pin/archive/delete
buttons were invisible. Now they're always visible on screens below the
md breakpoint and only hover-toggled on desktop.
https://claude.ai/code/session_013DdAk1yj6r3VF6Ze4ycidp