Skip to content

Handoff: node links route through owning app with side peek, BUILT (awaiting review/merge)

URL: https://mkdocs.justinsforge.com/memory/handoffs/creatortrack-node-link-app-routing-2026-07-06/

Date: 2026-07-06 Branch: feat/node-link-app-routing (1 commit 45611af off main @ 3065fa7). NOT merged, NOT deployed. Dev slot: worktree /home/justinwieb/forge-suite-wt/feat/node-link-app-routing, DB ct_feat_node_link_app_routing, live preview http://100.97.43.104:3064 Origin: FOLLOW-UP flagged in creatortrack-cockpit-and-tasks-controls-built-2026-07-06: every /n/{id} link opened the bare chrome-less node page.

What it does

  • New lib/node-app-routing.ts: resolveAppPeekPath walks a database_row node's parent chain (row -> database -> app node via isAppNode, depth-capped) and, when the owning app is registered in APP_PEEK_PARAM, returns pagePath(ws, appNode)?peek={rowId} with the caller's query string carried through.
  • Wired in app/(suite)/[ws]/[page]/page.tsx after the canonical-slug redirect, as a temporary redirect(). Legacy /n/{id} inherits it for free (it 308s into the canonical route). No migration; read-only routing.
  • APP_PEEK_PARAM = { tasks: "peek" } today; add entries as apps gain URL-driven peek support (crm/sales candidates).
  • ?full=1 bypass renders the plain full row page. Peek's expand button (Peek.tsx) and CRM PersonPanel's "Open notes page" now link /n/{id}?full=1.
  • Beneficiaries with zero changes: NotificationsBell reminder deep links, UpdatesPanel ?hl= chips, BlockRenderer child-page links, any external /n/{id} permalink (Telegram bots).

Verified (dev slot, end-to-end)

  • /n/5660 (task row) -> 200 at /justin/tasks-5657?peek=5660 (Tasks app, task peeked).
  • /n/5660?full=1 -> 200 at the pretty full row page, no redirect.
  • Plain doc /n/5622 -> 200 at its pretty page, untouched.
  • tsc clean.
  • Note: slot DB needed forge_workspace_migrate.py (clone base predated cockpit's core.list_workspace_members fn); forge_creatortrack_dev_base.sh refresh is due.

Review pointers

  • Redirect loop safety: target is the app node (type="tasks", not database_row), so the redirected page never re-enters the helper.
  • Parent walk is one getNode per hop (<=6, RLS-scoped); trees are 2 hops in practice.
  • Merge is ONCE via integrator; teardown slot after (dev-slot reaper or forge_creatortrack_agent_teardown.sh).

[Claude Code]