Post detail overlay now renders content as a tweet chain:
- Each tweet is a spine-connected row (dot + connecting line) with
tweet number, per-platform char counter, and inline textarea in
edit mode
- [+ Add tweet] button at the bottom appends a new empty tweet to
the chain; × per tweet removes it (hidden when only one tweet)
- Save writes threadPosts[] when len > 1, else plain content (and
clears threadPosts), so single drafts stay flat
- View mode shows tweets stacked vertically reading top-to-bottom,
edit mode keeps the same layout with editable boxes
- Per-platform limits (x/twitter 280, bluesky 300, threads 500, li
3000, ig 2200, yt 5000) drive live char counters; over-limit
goes red bold
- Grid cards gain a 🧵 N badge when threadPosts.length > 1
- Fix FLIP animation replaying on every re-render (now guarded with
an instance flag, plays once per open)
Bump folk-thread-gallery cache to v=5.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Clicking a post card expands it into a FLIP-animated detail overlay
instead of navigating away. Overlay has two modes:
View mode — full post content, schedule, hashtags, campaign, char
count. Actions: Open in Campaign (external link), Edit.
Edit mode — textarea for content, status picker (Draft/Scheduled/
Published), datetime-local for scheduled date, space-separated
hashtag input. Saves via offline runtime changeDoc so the post list
updates live everywhere else the doc is subscribed. Hashtag strings
are auto-prefixed with # if missing. ESC cancels edit; ESC again
(or backdrop click) closes the overlay. Backdrop blur + smooth
translate+scale entry from the clicked card's rect.
Threads still use the dedicated thread-editor since they have
multi-tweet rich editing. Card anchors become buttons with
data-post-id; cursor/focus-visible styling preserved. Cache bump
folk-thread-gallery to v=4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Remove the top-right Campaigns / Campaign Canvas / Newsletter sub-nav
from /rsocials landing. Gallery filter chips become the primary toggle:
Drafts / Scheduled / Published only (no "All"), centered above the grid.
Default filter is drafts. Threads render alongside published posts.
Bump folk-thread-gallery cache to v=3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
/rsocials now lands on the content gallery instead of the nav hub.
Gallery surfaces all campaign posts (not just drafts/scheduled) and
adds filter chips for All / Drafts / Scheduled / Published with live
count badges. Last-selected filter persists in localStorage. Cards use
per-status left-border accent (amber/blue/green) and a published badge.
Top-right sub-nav keeps Campaigns / Campaign Canvas / Newsletter one
click away. Bump folk-thread-gallery cache to v=2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Align /rsocials/campaign canvas with main rspace canvas behavior:
two-finger scroll now pans; Ctrl/Cmd+wheel or trackpad pinch
(ctrlKey) zooms at cursor. Previously any wheel event zoomed.
Sibling folk-campaign-workflow.ts already used this pattern.
Bump asset cache to v=4.
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>
Postiz's POST /public/v1/posts response shape doesn't reliably include the
new post's id (varies by version). When parsing fails, query listPosts in a
narrow window right after create and match by integration+content to recover
the real id. Without this, reconcile can't find queued posts back in Postiz.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Earlier version only skipped when postizPostId was set. If a send attempt
failed (no postizPostId but postizStatus='failed'), the sweep retried every
60s and hammered Postiz's throttler. Retries now require the user to clear
postizStatus — same gate as a fresh node.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Postiz's /public/v1/posts expects a nested envelope:
{ type, date, shortLink, tags, posts: [{ integration:{id}, value:[{content}], settings:{__type} }] }
The earlier shim's flat {content, integrationIds, type, scheduledAt} was
rejected with "All posts must have an integration id" (the field is named
integration, not integrationIds; it's a nested object, not an array of strings).
Also: Postiz treats PostItem.value[] as thread segments, so createThread now
sends ONE request with multiple value entries rather than N grouped posts.
Callers now pass full {id, identifier} tuples so settings.__type is set
correctly (otherwise Postiz can't route to the provider handler).
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>
- rsocials: collapse dead "posts" outputPath into "threads" entry (💬 Posts)
so the sub-nav shows one button linking to the thread gallery + builder
- spaces GET /:slug/modules: redact settingsSchema fields of type 'password'
to '********' for non-owner callers; PATCH preserves existing password
when the sentinel is sent back unchanged
Closes the leak where unauth'd GET returned Listmonk/Postiz credentials in plaintext.
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>
Audit and fix ~60 violations across 47 files where URLs were constructed
as /{space}/moduleId instead of /moduleId (subdomain provides the space).
- Add getModuleApiBase() helper to shared/url-helpers.ts
- Fix client components: use getModuleApiBase() for fetch URLs,
rspaceNavUrl() for navigation
- Fix server routes: use c.get("isSubdomain") for redirects and
JSON response URLs
- Fix OAuth callbacks (notion, google, clickup): subdomain-aware redirects
- Fix email notification URLs (rvote): use {space}.rspace.online format
- Fix webhook registration (rtasks/clickup): subdomain-aware endpoint URL
- Replace broken #getSpaceSlug() methods in folk-feed, folk-splat
- Replace NODE_ENV checks with proper isSubdomain checks (rdata, rnetwork)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Modules now declare their canvas shapes and AI tools (canvasShapes/canvasToolIds
on RSpaceModule), creating a single source of truth that the canvas enforces:
- Phase 1: Extended RSpaceModule + ModuleInfo, added moduleId to CanvasToolDefinition
with getToolsForModules() filter, added moduleOf() to ShapeRegistry, populated
declarations in 9 modules, fixed 8 ungated toolbar buttons (rchoices, rwallet, rsocials)
- Phase 2: AI prompt sends enabledModules, server filters Gemini tool declarations
- Phase 3: folk-commitment-pool and folk-task-request show lock overlay when rtime disabled
- Phase 4: Extracted MODULE_META into shared lib/module-display.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 120s AbortController timeout to apiFetch so wizard can't hang
forever on slow networks (shows "Request timed out" instead of stuck)
- Switch content generation from gemini-2.5-pro to gemini-2.5-flash
to avoid Cloudflare/Traefik proxy timeouts (pro model took 30-60s+)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add GET /api/threads, /api/threads/:id, /api/campaigns, /api/campaigns/:id
REST endpoints so other rApps can fetch rsocials data
- Register folk-social-thread/campaign/newsletter in MI triage panel,
tool schema, system prompt, and KNOWN_TRIAGE_SHAPES
- Add rsocials MODULE_PORTS (threads-out, campaigns-out, post-published,
campaign-data) and WIDGET_API to folk-rapp for embed/widget mode
- Add rsocials to folk-feed FEED_ENDPOINTS (threads, campaigns, newsletter)
and normalize response arrays (threads, campaigns, drafts)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Space invites: Convert both username-add and email-invite (existing user)
paths from direct-add to invite flow — creates space_invite via EncryptID,
sends invite email with Accept button, dispatches space_invite notification
with Accept/Decline buttons in the notification bell. No one gets forcefully
added to a space anymore.
rSocials content linking: All generated campaign content now links through
to actual editable content. Draft post cards in thread gallery are clickable
(thread editor or campaign view). Campaign manager post cards expand on click
and thread badges link to thread editor. Wizard success screen shows
individual thread links. CampaignPost schema gains threadId field, stored on
commit so posts maintain their thread association.
Also includes canvas social media tools, social shape components
(folk-social-thread, folk-social-campaign, folk-social-newsletter),
and MI context-aware suggestion registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Gemini Flash agentic loop that converts natural language prompts
into real MCP tool call sequences for PCB design (KiCad) and parametric
CAD (FreeCAD). Dynamic schema conversion from MCP tools to Gemini
function declarations, 8-turn/60s loop with real execution and result
feedback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidates token verification into server/auth.ts, removing the
external SDK dependency. All modules now import from the local module.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Newsletter campaigns now require N-of-M team member approval via rInbox
before Listmonk starts sending. The send-newsletter workflow node creates
a draft campaign and gates it through the team inbox; a manual submit-
approval route is also available. The multisig email UI shows a green
"Newsletter Approval" badge with campaign ID for newsletter approvals.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Progressive approval workflow: paste brief → AI extracts structure →
AI generates per-platform posts → review with per-post regen →
commit (saves campaign, creates threads, drafts newsletters, builds workflow DAG).
Includes MI integration for Cmd+K campaign creation and vite build entry.
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>
Full campaign editor with HTML body textarea, live iframe preview,
list selector with subscriber counts, save draft, send now, and
schedule send. Added edit/delete actions on draft campaigns and
GET/PUT/DELETE single-campaign proxy routes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename "Threads" to "Posts & Threads" in hub nav, route title, and subPageInfos.
Thread gallery now shows draft/scheduled posts from campaigns alongside threads.
Add Postiz API client (postiz-client.ts) with settings schema for URL + API key.
Proxy routes: /api/postiz/status, integrations, posts, threads.
Wire workflow executor to call real Postiz API for post/thread/cross-post nodes.
Add "Send to Postiz" button in thread builder (editor + readonly views).
Add approval queue: PendingApproval schema (v5), GET/POST /api/approvals routes,
wait-approval workflow node creates pending approvals and pauses execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Declarative onboardingActions on RSpaceModule lets each rApp define its
own onboarding cards (import, upload, link, create). renderOnboarding()
renders them as a responsive card grid with upload handling. Adds ICS
import endpoint to rCal (POST /api/import-ics). 15 modules wired up.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The thread gallery already has a "New Thread" button linking to the editor,
so a separate hub button and subnav pill for the editor is redundant.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New gallery landing page at /campaigns showing all campaign workflows as
cards with miniature SVG previews. Click a card to open the editor at
?workflow=<id>. Editor gains back-link to dashboard and workflow attribute
for deep-linking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add types/hono.d.ts declaring effectiveSpace, spaceRole, and isOwner
on Hono's ContextVariableMap. Remove 127 "as any" casts across 18
files. Fix ParticipantStatus type in rmaps SyncMessage union.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Listmonk newsletter management proxy API with role-based auth,
newsletter manager component, password setting type support, and
new backlog task files. Update newsletter subscribe URL.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The /campaigns route was serving folk-campaign-manager (simple list view)
instead of folk-campaign-planner (the drag-and-drop flow canvas). The
planner was fully built but had no route.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rsocials had defaultScope: "global" but client components passed the raw
space slug, creating threads in space-specific docs (e.g. commonshub).
Server routes then looked in the non-existent "global" doc → 404.
Changed to defaultScope: "space" to match how client actually works.
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>
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>
Phase 1 — Fix scope system: new scope-resolver.ts resolves global vs
space-scoped docId prefixes. Server middleware sets effectiveSpace on
Hono context. All 18 modules updated to use dataSpace for Automerge
doc access while keeping space for display. Client runtime gets
setModuleScopes() and resolveDocSpace() for local-first scope
resolution.
Phase 2 — Seamless cross-space navigation: TabCache now tracks panes
per space:module key. OfflineRuntime maintains lazy WebSocket
connections per space. Space-switcher dispatches space-switch event
handled client-side with history.pushState instead of full reload.
Phase 3 — Spaces as layers: Layer type extended with spaceSlug and
spaceRole. Tab bar gains "Add Space Layer" picker. Canvas renders
cross-space shapes with visual indicators. Space layers persisted as
SpaceRefs via nesting API. Runtime provides getAllActiveSpaces() and
subscribeModuleAcrossSpaces() for module-level data aggregation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace infographic/typography prompts with atmospheric abstract art
prompts. Images now use flowing gradients, organic shapes, and moody
lighting to evoke the tweet's theme without any text or typography.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace generic "dark themed, minimal" prompts with detailed
infographic-style prompts that generate bold, shareable visuals
with typography overlays, iconic symbols, and data-viz elements.
Add try/catch error handling around fal.ai calls to prevent
unhandled network errors from crashing the request handler.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>