Phase A.5: bring rApp mini-canvases to parity with the main rSpace canvas
on keyboard shortcuts and Space-to-grab behavior, plus ship reusable
primitives for fit-view and zoom chrome.
shared/canvas-interaction.ts — extend CanvasInteractionController:
• enableSpaceToGrab — Space sets grab cursor and flips isSpaceHeld()
• enableKeyboardShortcuts — 0 fit, +/- zoom, arrows pan, Ctrl+Z/Y
undo/redo, Delete/Backspace delete (with shadow-DOM-aware text
input detection so inline editors still work)
• zoomByFactor() helper for chrome +/- buttons
shared/canvas-viewport.ts (new):
• fitViewToRects / fitViewToNodes — standard fit algorithm matching
the main canvas (40px padding, 0.1–1.5 clamp default)
• persistViewport / restoreViewport — localStorage under
rspace_viewport:<key> with finite-value validation
shared/components/rspace-canvas-chrome.ts (new):
• <rspace-canvas-chrome> web component — zoom out/in/fit buttons +
percent indicator + optional grid toggle. Emits canvas-zoom-*
events. Available as drop-in for new/future canvases.
Migrate 8 rApp canvases to opt into space-to-grab + keyboard fit:
rsocials planner (keeps existing isEnabled gate), rsocials workflow,
rminders automation, rflows, rgov circuit, rnetwork CRM graph,
applet-circuit-canvas. rTime skips enableSpaceToGrab because it has
its own Space tracking integrated with node-drag state.
Bump asset cache versions so browsers pick up the new JS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Fix inline post editor: pointerdown + wheel on SVG now bail when
target is inside .cp-inline-config so textarea/select focus and
native scrolling work. Grow post panel to 300×460 with 380px body
so the Done/Delete toolbar isn't clipped.
- Restyle channel palette chips as vertical tldraw-style cards (big
tinted icon, centered label, constraint tags). 2-column grid.
- Add Board view (Drafts / Scheduled / Published) as a 4th switcher
option. Each column toggleable (min one must stay on). Drag a post
card between columns: Drafts→Scheduled opens a date/time picker
modal, Scheduled→Drafts reverts status (blocked if already queued
on Postiz). Published is terminal (no drops). Card shows platform
badge, 3-line preview, char bar + limit, scheduled/published
timestamp, Postiz error badge, release link, Edit button that
jumps back into the canvas editor.
Bump planner assets: css?v=5, js?v=6.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extract the rSpace main canvas wheel + touch interaction model into a
single shared controller (shared/canvas-interaction.ts). Wheel defaults
to pan, Ctrl/Cmd+wheel or trackpad pinch (ctrlKey) zooms at cursor,
two-finger touch pans + pinch-zooms at gesture center.
Migrate 8 rApp mini-canvases to use it, replacing 8 slightly-different
hand-rolled wheel handlers:
- rsocials campaign-planner (the bug report — was zoom-only)
- rsocials campaign-workflow
- rminders automation canvas (was zoom-only)
- rtime timebank weave
- rflows canvas
- rgov circuit
- rnetwork CRM graph (was zoom-only)
- lib/applet-circuit-canvas (was zoom-only)
Fixes the "wheel = zoom" regression everywhere and gives each rApp
canvas two-finger touch pan + pinch for free. Pointer-based pan and
marquee selection remain per-rApp because they depend on per-rApp
hit-testing. Bump asset cache versions for all affected routes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Outbound: forward per-node platformSettings + title through
createPost/createThread via new PostizIntegrationRef.settings/title
merged on top of defaultSettingsFor. Record postizSyncedHash on the
node after each successful send.
Inbound: postizReconcile pulls remote content/publishDate onto queued
and draft nodes when the local hash matches postizSyncedHash, so
Postiz-side edits surface in the planner without clobbering pending
local edits. Published posts always take remote content as final.
Drift→Resync: inline editor shows a yellow "Local edits not yet on
Postiz" row when client SHA-1 (normalized content+title+schedule+tags+
platformSettings) drifts from postizSyncedHash. New
/resync-postiz route deletes the Postiz-side post (via new deletePost
helper, 404-tolerant) then re-creates with current content. Rejected
once published.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extend campaign planner with platform-aware post composition: optional
title (YouTube/TikTok/Reddit/Pinterest), mediaUrls attachments, and
per-platform settings overrides merged into Postiz __type. New
platform-specs.ts library encodes platform constraints. Bump asset
cache version to v=3.
Campaigns dashboard now sends Authorization headers on flow fetch/create
and surfaces 401/403 with a clear message instead of silently failing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per-post "Schedule to Postiz" button on Post nodes (rSpace → Postiz), a 60s
server sweep that auto-pushes Scheduled posts within a 10min lead window,
and a Postiz → rSpace reconcile poll that flips postizStatus to
'published' (or 'failed') and records publishedAt + releaseURL.
- schemas: PostNodeData gains postizPostId, postizIntegrationId,
postizStatus, postizError, postizSentAt, postizCheckedAt,
postizReleaseURL, publishedAt.
- postiz-client: listPosts(startDate, endDate) for reconciliation.
- mod.ts: sendCampaignNodeToPostiz() helper, POST /api/campaign/flows/
:flowId/nodes/:nodeId/send-postiz, postizSweep() + postizReconcile()
wired into onInit via startPostizScheduler.
- folk-campaign-planner: button + status badge in Post inspector,
timeline/table dot colors reflect postizStatus (queued=purple,
published=green, failed=red). Timeline bucket stays by scheduledAt.
- campaign-planner.css: postiz state pill styles.
- Bump campaign-planner JS/CSS to ?v=2 to bust CF cache.
Mock-Postiz smoke against the client lib passes 20/20 assertions.
Live Postiz round-trip pending deploy to Netcup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds e2e/tests/rsocials-campaign-flow.spec.ts — 13 tests covering the
unified campaign flow UX: dashboard → planner navigation, brief canvas
node (+ preview banner), markdown import modal, wizard handoff, and
API shape. 36 passed / 3 AI-skipped across chromium/firefox/mobile.
Bug fixes uncovered by the suite:
- markDownstreamStale only redraws when a node actually flips stale,
so typing in an input node no longer destroys the open inline-edit
overlay.
- executeSave wraps the local-first write in try/catch and nulls the
client on failure, so a half-initialised client (WS down, IDB
unavailable) falls through to localStorage instead of throwing
"Document not open".
- init-failure path also nulls the client so the first save after a
failed subscribe doesn't hit a doc that was never opened.
Test infra:
- server/security.ts + server/index.ts honour DISABLE_RATE_LIMIT=1
(and NODE_ENV=test) to bypass HTTP rate limiter and anon WS-per-IP
cap so the suite can run under 8 parallel workers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expanded folk-campaign-planner with richer live state, styled dashboard
refresh, and schema + mod updates to match the new planner flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Harmonize the two disconnected presence systems into one:
- New shared/collab-presence.ts utility (broadcastPresence, startPresenceHeartbeat)
- Collab overlay now listens to custom presence messages, shows module context in people panel
- Fixed Shadow DOM focus tracking using composedPath() for focus rings through shadow boundaries
- Replaced rNotes custom presence with shared utility (kept sidebar dots)
- Added presence heartbeat to all 27 rApp components with dynamic context strings
- Bumped cache versions in all modified mod.ts files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace manual thread ID entry with select dropdowns in both campaign planner
and workflow components. Server-side publish-thread handler now resolves
linked threadId from Automerge doc when inline content is empty.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add three alternative views to the campaign planner canvas:
- Timeline: horizontal chronological layout with day columns and phase bars
- Platform: kanban columns grouped by platform with post cards
- Table: compact sortable table with status, platform, content, dates
View switcher in toolbar preserves canvas state when switching. Clicking
any post in alt views navigates back to canvas with that node selected
and centered. Keyboard shortcuts guarded to canvas-only view.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously the planner restored a stale zoomed-out viewport from
localStorage, and fitView() could fail silently if the SVG had zero
dimensions during shadow DOM layout. Now: skip viewport restore on
initial load, retry fitView up to 3 rAFs, and clamp min zoom to 50%.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Links on subdomain routing (e.g. jeff.rspace.online) were including
the space in the path (/demo/rsocials/campaigns) instead of just
/rsocials/campaigns. Added basePath getter to all components and
detect subdomain in the server-rendered hub page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pointer-based gesture handling to the calendar for lateral navigation
(drag/swipe left/right) and pinch-to-zoom between temporal layers. Also
fix dark mode across 30+ canvas shape components by replacing hardcoded
white backgrounds and input styles with --rs-* CSS custom property
references (with light-mode fallbacks).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Subdomain routing (demo.rspace.online) already prepends the space,
so links should use /rsocials/... not /demo/rsocials/...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restructure rSocials landing to a hub with navigation cards for Campaigns,
Threads, and Thread Editor. Rename /thread routes to /thread-editor for
clarity. Render campaigns listing inline instead of redirecting. Also
improve rNotes notebook creation to auto-open first note for editing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>