Deep links and Copy link across the whole UI #65

Open
opened 2026-09-24 15:53:55 +00:00 by kayg · 5 comments
Owner

Owner rule (2026-09-24): "everything has a copy link action, meaning all parts of the UI should be deep-linkable". CLAUDE.md now makes this binding for every UI job; DESIGN §33 holds the URL grammar.

Build the shared deep-link foundation in apps/web + packages/ui:

  • A route/intent layer implementing the §33 grammar (calendar views, days + block anchors, notes + headings/blocks, files/folders, photos/albums, external events, tasks, tags, saved searches, search queries, settings sections, admin pages), following calternal.js docs/deep-linking.md (imperative navigation + URL→intent effect for cold load and back/forward; overlay-guarded; ready-gated).
  • Server redirects/lookups by stable ID (/n/<calternal-id>, /f/<item-id>, /t/<task-id>) so links survive renames and moves; permission-checked without leaking existence; deleted targets show a friendly state with a Trash link when restorable.
  • One CopyLinkAction used everywhere: context menu item, ⋯ menu item, swipe-from-left action on touch (default action), header copy button, keyboard shortcut (⌘⇧C) — using calternal.js's copy interaction aesthetics (header link copy feedback) and a Sonner toast.
  • Audit every existing screen and add Copy link; add an e2e test that visits each route kind from a cold load and asserts the exact view restores.
    Read CLAUDE.md, CONTEXT.md, docs/DESIGN.md §25, §29–§33. Comment on this issue as you work; never close it.
Owner rule (2026-09-24): "everything has a copy link action, meaning all parts of the UI should be deep-linkable". CLAUDE.md now makes this binding for every UI job; DESIGN §33 holds the URL grammar. Build the shared deep-link foundation in apps/web + packages/ui: - A route/intent layer implementing the §33 grammar (calendar views, days + block anchors, notes + headings/blocks, files/folders, photos/albums, external events, tasks, tags, saved searches, search queries, settings sections, admin pages), following calternal.js `docs/deep-linking.md` (imperative navigation + URL→intent effect for cold load and back/forward; overlay-guarded; ready-gated). - Server redirects/lookups by stable ID (`/n/<calternal-id>`, `/f/<item-id>`, `/t/<task-id>`) so links survive renames and moves; permission-checked without leaking existence; deleted targets show a friendly state with a Trash link when restorable. - One `CopyLinkAction` used everywhere: context menu item, ⋯ menu item, swipe-from-left action on touch (default action), header copy button, keyboard shortcut (⌘⇧C) — using calternal.js's copy interaction aesthetics (header link copy feedback) and a Sonner toast. - Audit every existing screen and add Copy link; add an e2e test that visits each route kind from a cold load and asserts the exact view restores. Read CLAUDE.md, CONTEXT.md, docs/DESIGN.md §25, §29–§33. Comment on this issue as you work; never close it.
Author
Owner

Started: deep-link and Copy link audit on branch job/deeplinks (from main cf3c094). Plan: inventory every surface and item type, fix missing routes and Copy link actions, add docs/deep-links.md and an e2e test apps/web/e2e/deeplinks.mjs.

Started: deep-link and Copy link audit on branch job/deeplinks (from main cf3c094). Plan: inventory every surface and item type, fix missing routes and Copy link actions, add docs/deep-links.md and an e2e test apps/web/e2e/deeplinks.mjs.
Author
Owner

Finished: branch job/deeplinks, head 5821fde (rebased on main 1bbd40e). Not pushed or merged.

Fixed:

  • /t/ was missing (every copied Task link failed). Added, with GET /api/v1/notes/tasks/by-id; the Day view selects the Task (?task=).
  • Copied Event links failed: the grid copies occurrence ids (@) that GET /api/v1/calendar/events/{id} refused. The endpoint now resolves occurrences; /e/ selects the Event (?event=).
  • /d/#^ now follows an entry moved to another day (GET /api/v1/notes/journal/entries/{block_id}).
  • Added /p/ (to /f/), /admin/ (to /settings/admin/), /f/?open=share.
  • Copy link added: search results (preview and phone peek; stable /n/ or /f/ only), Recent and Trash headers, All notes and Journal rows, sidebar tag menu, undated Tasks in the Day panel.
  • Long press opens row menus on touch (Notes explorer, saved searches, tags, Recent).
  • Trash swipe said Copy link but put the item back; label fixed.
  • noteHref/tagHref give canonical /n/ and /tag/.
  • docs/deep-links.md (inventory) and DESIGN §33 updated to reality (/search/saved/, /e/[@]).
  • e2e apps/web/e2e/deeplinks.mjs passes; adversarial section deeplinks added.

Open gaps: Task ids are Markdown paths, so a Task file rename breaks /t/; share dialog has a link but no Copy link control; info panel open state is not in the URL; photos/albums not built. Pre-existing on main: collab hostile_clients unrepresentable_update test and server wire live_apps test fail.

Finished: branch job/deeplinks, head 5821fde (rebased on main 1bbd40e). Not pushed or merged. Fixed: - /t/<task-id> was missing (every copied Task link failed). Added, with GET /api/v1/notes/tasks/by-id; the Day view selects the Task (?task=). - Copied Event links failed: the grid copies occurrence ids (<id>@<start>) that GET /api/v1/calendar/events/{id} refused. The endpoint now resolves occurrences; /e/ selects the Event (?event=). - /d/<date>#^<block> now follows an entry moved to another day (GET /api/v1/notes/journal/entries/{block_id}). - Added /p/<item-id> (to /f/), /admin/<page> (to /settings/admin/<page>), /f/<id>?open=share. - Copy link added: search results (preview and phone peek; stable /n/ or /f/ only), Recent and Trash headers, All notes and Journal rows, sidebar tag menu, undated Tasks in the Day panel. - Long press opens row menus on touch (Notes explorer, saved searches, tags, Recent). - Trash swipe said Copy link but put the item back; label fixed. - noteHref/tagHref give canonical /n/ and /tag/. - docs/deep-links.md (inventory) and DESIGN §33 updated to reality (/search/saved/<id>, /e/<event-id>[@<start>]). - e2e apps/web/e2e/deeplinks.mjs passes; adversarial section deeplinks added. Open gaps: Task ids are Markdown paths, so a Task file rename breaks /t/; share dialog has a link but no Copy link control; info panel open state is not in the URL; photos/albums not built. Pre-existing on main: collab hostile_clients unrepresentable_update test and server wire live_apps test fail.
Author
Owner

Hygiene review: the final report still lists path-based Task IDs that break on rename, no Copy link control in the share dialog, no URL state for the inspector, and Photos/albums not built. Keeping #65 open.

Hygiene review: the final report still lists path-based Task IDs that break on rename, no Copy link control in the share dialog, no URL state for the inspector, and Photos/albums not built. Keeping #65 open.
Author
Owner

Static audit evidence for DESIGN §33 reality check:

The last two bullets in docs/DESIGN.md:1011-1012 still say that a Task ID is its Markdown location and stable identity is still to do. The implementation now has a stable identity: crates/plugins/notes/src/tasks_api.rs:835-842 resolves stable IDs and legacy aliases, crates/plugins/notes/src/tasks_store.rs:308-324 retargets aliases after projection changes, and crates/plugins/notes/migrations/0010_task_identity.sql:1-12 adds the identity and alias table.

Please update the stale reality-check text. Regression idea: create a /t link, rename or move the Task file, and confirm the same stable link still resolves.

Static audit evidence for DESIGN §33 reality check: The last two bullets in docs/DESIGN.md:1011-1012 still say that a Task ID is its Markdown location and stable identity is still to do. The implementation now has a stable identity: crates/plugins/notes/src/tasks_api.rs:835-842 resolves stable IDs and legacy aliases, crates/plugins/notes/src/tasks_store.rs:308-324 retargets aliases after projection changes, and crates/plugins/notes/migrations/0010_task_identity.sql:1-12 adds the identity and alias table. Please update the stale reality-check text. Regression idea: create a /t link, rename or move the Task file, and confirm the same stable link still resolves.
Author
Owner

Design-sync #864 corrected DESIGN §33 on job/design-sync, commit 01c089351.

Old docs/DESIGN.md:1011-1012 said a Task rename breaks its link. crates/plugins/notes/src/tasks_api.rs:835-842, tasks_store.rs:308-324 and migration 0010_task_identity.sql:1-16 already support permanent Task file identity and retained aliases. The text now records calternal-id and old-path / Reminders UID aliases.

Expected behaviour stays: Task file links survive renames and moves. Regression idea: open the permanent link and a retained old-path alias after each operation. No runtime claim or test run from this LIGHT documentation job.

Design-sync #864 corrected DESIGN §33 on `job/design-sync`, commit `01c089351`. Old docs/DESIGN.md:1011-1012 said a Task rename breaks its link. crates/plugins/notes/src/tasks_api.rs:835-842, tasks_store.rs:308-324 and migration 0010_task_identity.sql:1-16 already support permanent Task file identity and retained aliases. The text now records calternal-id and old-path / Reminders UID aliases. Expected behaviour stays: Task file links survive renames and moves. Regression idea: open the permanent link and a retained old-path alias after each operation. No runtime claim or test run from this LIGHT documentation job.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#65
No description provided.