Commit Graph

603 Commits

Author SHA1 Message Date
Jeff Emmett d8f9f46515 feat: rFlows visual redesign — HTML card nodes, Sankey widths, smooth drag
- Switch source/outcome nodes from SVG shapes to foreignObject HTML cards
  with white backgrounds, gradient headers, status badges, and progress bars
- Add foreignObject text overlay to funnel nodes (keep SVG tank shape)
- Fix Sankey edge widths: flow-value-relative formula instead of percentage
- Smooth drag: rAF throttle + lightweight edge path patching during drag
- Add dot grid canvas background, arrowhead markers, larger port dots
- Fixed node sizes: source 220x120, outcome 220x180

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:18:06 -08:00
Jeff Emmett 92dff99793 fix: thread image 404 on subdomains + move photo section to top
Pass /data/ paths through subdomain routing without rewriting so
generated image files are accessible on *.rspace.online subdomains.

Move image upload/generate section above the compose textarea in the
thread builder editor layout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:00:58 -08:00
Jeff Emmett 32cab9c67e fix: deep-clone thread before Automerge write to avoid proxy re-insertion
Automerge throws "Cannot create a reference to an existing document
object" when assigning an Automerge proxy object back into the doc.
Now JSON round-trips the thread data before writing, and strips null
fields that should be absent rather than null in the document.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:46:02 -08:00
Jeff Emmett a1b50eb0da fix: Automerge undefined rejection + thread not synced to server
- tweetImages and imageUrl set to null instead of undefined when empty
  (Automerge rejects undefined as invalid JSON)
- Updated ThreadData schema to allow null for optional fields
- This was the root cause of the 404 on image generation: saveDraft
  threw on undefined, so the thread never synced to the server, and
  the server-side route returned "Thread not found"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:14:06 -08:00
Jeff Emmett f9bafc8ef0 fix: Transak modal not opening — namespace querySelector + wallet check
- Use DOM API (createElementNS + createElement) to build foreignObject
  panel instead of innerHTML, ensuring proper HTML namespace for
  querySelector to traverse SVG→HTML boundary
- Query buttons/inputs from HTML panel root instead of SVG overlay
- Remove wallet address requirement for demo mode (use zero address)
- Add console logging and .catch() for Transak widget debugging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:07:28 -08:00
Jeff Emmett 1335c38d48 fix: thread builder offline runtime race + getDoc method name
Two bugs:
- subscribeOffline() bailed if runtime wasn't initialized yet (race with
  shell.ts init). Now waits for runtime to appear, then awaits init().
- getDoc() called runtime.getDoc() which doesn't exist — method is
  runtime.get(). Caused "e.getDoc is not a function" crash in listThreads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:06:47 -08:00
Jeff Emmett 3f19fd9c8e feat: overhaul rFlows funnel visuals — bigger nodes, 3 zones, draggable config
- Increase funnel base size (280×250), source nodes (140-280 dynamic),
  outcome nodes (220×120) for better visibility
- Simplify to 2 threshold lines (Min/Max) and 3 labeled zones:
  Critical (below min), Sufficient (min-max), Overflow (above max)
- Position overflow pipes at max threshold line instead of fixed 55%
- Make drain width proportional to desiredOutflow (physical metaphor)
- Replace popup config panel with draggable handles for funnels:
  valve handle (horizontal drag → outflow rate) and height handle
  (vertical drag → capacity)
- Increase edge stroke widths (3-28px) for more visible flow changes
- Source nodes: tall/thin for small recurring, short/thick for large chunks
- Keep config panel for source/outcome node types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:58:45 -08:00
Jeff Emmett ff5dd8c006 fix: await saveDraft/saveToAutomerge in all image and share handlers
All callers of saveDraft() and saveToAutomerge() in generateImage,
uploadImage, uploadTweetImage, generateTweetImage, removeTweetImage,
and share handler now properly await these async methods. Without await,
runtime.change() fires before the Automerge doc subscription resolves,
causing "Document not open" errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:58:04 -08:00
Jeff Emmett f4edf3b7ae fix: thread API calls 404 on subdomain routing (jeff.rspace.online)
basePath was always returning /{space}/rsocials/ which works for path-based
routing (rspace.online/jeff/rsocials/) but double-prefixes on subdomain
routing (jeff.rspace.online/jeff/rsocials/ → rewritten to /jeff/jeff/rsocials/).

Now detects subdomain hosts (*.rspace.online, *.rsocials.online) and returns
/rsocials/ without the space prefix, since the space is the subdomain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:47:41 -08:00
Jeff Emmett 0abfce2991 fix: thread builder save crash — await Automerge doc open before write
Two bugs fixed:
- attachShadow called unconditionally in connectedCallback, crashing on
  re-insertion ("Shadow root cannot be created on a host which already
  hosts a shadow tree")
- saveToAutomerge/deleteFromAutomerge called runtime.change() before the
  async subscribeOffline() had resolved, causing "Document not open" errors

Now tracks the subscribe promise and awaits it before any write operation.
Also guards shadow root creation in gallery and campaign manager components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:38:50 -08:00
Jeff Emmett 0318f0a7e1 feat: inline config beside node, simplified funnel outflow slider
- Inline config panel now appears beside (right of) the node instead of
  beneath it
- Funnel config simplified to single $/mo outflow slider (0-3000) that
  auto-derives all thresholds: min=1mo, sufficient=4mo, overflow=6mo
- Updated deriveThresholds to 4mo sufficient (was 3mo)
- Demo presets updated to match new 4mo formula

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:32:38 -08:00
Jeff Emmett ecebf84bcc fix: single-click inline editing for rflows nodes
- Single click on a node now opens the inline config panel directly
  (instead of requiring double-click which was broken by pointer capture)
- New nodes from toolbar open inline editor instead of side panel
- Click-outside handler uses shadow root instead of document to avoid
  event retargeting that dismissed the panel on any interaction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:07:31 -08:00
Jeff Emmett bfb1e3d0d7 feat: add Twenty CRM setup scripts for pipeline, fields, and views
Instance-agnostic scripts to configure standalone Twenty CRM instances
(crypto-commons and VOTC) with 7-stage pipeline, custom opportunity/company
fields, and saved views (My Pipeline kanban, Needs Follow-up, Stale Leads).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:06:52 -08:00
Jeff Emmett ce3a3ae0c0 fix: inline editor click-outside handler in shadow DOM
The click-outside handler used event.target at the document level,
which in shadow DOM is retargeted to the host element. Clicking any
input inside the inline config panel (foreignObject) would immediately
dismiss it. Use composedPath() to correctly detect clicks inside the
shadow DOM boundary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 12:44:19 -08:00
Jeff Emmett aff16e647a feat: content-hash cache busting for module/shell assets
Build generates SHA-256 content hashes per asset file and appends
?v=<hash> to all module/shell URLs in rendered HTML automatically.
Eliminates manual ?v=N bumping in mod.ts files. Versioned assets
get Cache-Control: immutable headers, and the service worker cleans
stale entries on activation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 11:50:57 -08:00
Jeff Emmett feabf89137 feat: add MI Content Triage — paste/drop content for AI-powered shape layout
Adds a "dump & layout" feature where users can paste or drag-drop unstructured
content onto the canvas and have Gemini 2.5 Flash analyze it, classify each piece
into the appropriate folk-* shape type, and propose a multi-shape layout with
semantic connections.

- POST /api/mi/triage endpoint with structured JSON output from Gemini
- TriageManager orchestrator (analyze, removeShape, commitAll via MiActionExecutor)
- MiTriagePanel floating preview UI with shape cards, connections, Create All/Cancel
- Canvas drag/drop overlay + paste handler integration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 11:50:44 -08:00
Jeff Emmett 493ae2442c fix: replace broken Postiz reverse proxy with iframe embed
The reverse proxy couldn't work for a Next.js SPA — it caused double
space prefix in redirects and couldn't handle /_next/* static assets.
Switch to iframe approach with demo.rsocials.online directly. Fix
template literal bugs where getSchedulerUrl() was passed as a string
literal instead of being evaluated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 10:20:19 -08:00
Jeff Emmett bb37727f18 feat: reverse-proxy Postiz at /rsocials/scheduler instead of iframe
The rSpace Traefik router catches demo.rsocials.online (priority 120)
before the Postiz container can serve it, making iframe embedding fail.

Replace the iframe approach with a reverse proxy: /rsocials/scheduler/*
proxies to the Postiz container (postiz:5000) on the Docker network.
Rewrites redirect headers to stay within the scheduler path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:36:03 -08:00
Jeff Emmett ea99a83678 fix: use correct Twenty CRM GraphQL endpoint (/graphql)
Twenty CRM exposes data queries at /graphql, not /api or /api/graphql.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:30:06 -08:00
Jeff Emmett 2853e46037 fix: update Postiz URL from social.jeffemmett.com to demo.rsocials.online
The old domain had no DNS record. Postiz is served via Traefik at
demo.rsocials.online.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:26:35 -08:00
Jeff Emmett 2ba2034e3a feat: embed Twenty CRM via iframe on /crm route
Switch /crm and ?view=app from custom folk-crm-view component to
renderExternalAppShell iframe embedding crm.rspace.online. Also fix
twentyQuery endpoint from /api to /api/graphql for the data proxy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:26:16 -08:00
Jeff Emmett 99749d8cf2 refactor: replace ?view= query params with path-based routes in rSocials
/rsocials → canvas view (default)
/rsocials/scheduler → Postiz iframe
/rsocials/feed → demo feed / landing
/rsocials/landing → landing page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:19:27 -08:00
Jeff Emmett bc9f5bcfb4 fix: re-apply rSocials canvas route and vite build entry
The rSocials refactor commit overwrote the canvas route changes.
Re-adds: default canvas view, ?view=feed for old demo feed,
?view=landing for landing page, and vite build entry for
folk-socials-canvas.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:15:06 -08:00
Jeff Emmett 6822ee5b47 Merge branch 'main' into dev 2026-03-04 20:44:30 -08:00
Jeff Emmett 91d414fc88 feat: refactor rSocials from monolith to full rApp
Decompose the 2,116-line mod.ts into a canonical rApp matching the
rFlows/rBooks pattern with Automerge sync, web components, and
extracted CSS.

New files:
- schemas.ts: SocialsDoc, ThreadData, Campaign types + Automerge schema
- local-first-client.ts: browser-side sync client
- lib/types.ts: shared types, DEMO_FEED, PLATFORM_LIMITS
- lib/image-gen.ts: server-only fal.ai + file upload helpers
- components/folk-thread-builder.ts: compose/preview/readonly component
- components/folk-thread-gallery.ts: thread listing grid component
- components/folk-campaign-manager.ts: campaign viewer with import modal
- components/socials.css: all extracted CSS (~550 lines)

mod.ts slimmed to ~616 lines: ensureDoc, image APIs, page routes
injecting <folk-*> web components, file→Automerge migration, seed
template, and module export. Thread/campaign CRUD moved from REST
to Automerge local-first sync.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:44:17 -08:00
Jeff Emmett 831c8b1c24 feat: refactor rSocials from monolith to full rApp
Decompose the 2,116-line mod.ts into a canonical rApp matching the
rFlows/rBooks pattern with Automerge sync, web components, and
extracted CSS.

New files:
- schemas.ts: SocialsDoc, ThreadData, Campaign types + Automerge schema
- local-first-client.ts: browser-side sync client
- lib/types.ts: shared types, DEMO_FEED, PLATFORM_LIMITS
- lib/image-gen.ts: server-only fal.ai + file upload helpers
- components/folk-thread-builder.ts: compose/preview/readonly component
- components/folk-thread-gallery.ts: thread listing grid component
- components/folk-campaign-manager.ts: campaign viewer with import modal
- components/socials.css: all extracted CSS (~550 lines)

mod.ts slimmed to ~616 lines: ensureDoc, image APIs, page routes
injecting <folk-*> web components, file→Automerge migration, seed
template, and module export. Thread/campaign CRUD moved from REST
to Automerge local-first sync.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:42:18 -08:00
Jeff Emmett fff0fd3150 Merge remote-tracking branch 'origin/dev' 2026-03-05 05:34:45 +01:00
Jeff Emmett aa45cabc4e fix: add wasm plugin to folk-flows-app build + add missing rsocials components
The folk-flows-app sub-build imports Automerge which requires WASM support.
Added wasm() plugin, esnext target, and Automerge alias to the sub-build config.

Also adds folk-socials-canvas.ts and socials-canvas.css that were on the server
but missing from git, causing the vite build to fail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:34:32 -08:00
Jeff Emmett cdae6606ab Merge branch 'main' of ssh://gitea.jeffemmett.com:223/jeffemmett/rspace-online 2026-03-05 05:26:42 +01:00
Jeff Emmett 1e7e0f029d Merge remote-tracking branch 'origin/dev' 2026-03-05 05:26:28 +01:00
Jeff Emmett 02c8aa1fb3 fix: disable Twenty multi-workspace to prevent subdomain redirect loop
Multi-workspace mode caused crm.rspace.online to redirect to
admin-crm.crm.rspace.online which doesn't exist. Space-level tenancy
is handled by rSpace's per-space API tokens instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:23:57 -08:00
Jeff Emmett ba3fddc7d4 Merge branch 'dev' 2026-03-04 20:13:27 -08:00
Jeff Emmett 7443f9df9f feat: redesign canvas toolbar with fluid expand and 9-group layout
Toolbar buttons now smoothly widen on hover/click to reveal title text
instead of using CSS tooltips. Reorganized from 7 groups into 9 (Note,
Connect, Media, Embed, AI, Create, Decide, Spend, Travel) with better
categorization. Collapse button uses chevron instead of dots. Mobile
tap targets increased to 48px min-height for accessibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:13:19 -08:00
Jeff Emmett 2bb01c5240 Merge branch 'dev' 2026-03-04 19:36:17 -08:00
Jeff Emmett 991c0ed8a5 chore: remove rDocs and rDesign from module registry
Placeholder modules not yet built out as full rApps. Removes them
from the dropdown/tab bar until they have proper schemas, components,
and local-first support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:36:10 -08:00
Jeff Emmett 3c26addeae fix: defer tab bar active state until switchTo() resolves
The tab bar was setting its `active` attribute synchronously on click,
before TabCache.switchTo() finished fetching and injecting the new pane.
This caused a visual desync where the tab highlighted immediately but
the content area showed a blank flash or stale content.

Now the tab bar dispatches the layer-switch event without changing its
own active state. The shell event handler sets active only after
switchTo() confirms the pane is ready, eliminating the race condition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:32:38 -08:00
Jeff Emmett b28b551ee1 Merge branch 'dev' 2026-03-04 19:20:08 -08:00
Jeff Emmett e1688e8456 feat: canvas-first rFlows with flow storage, retrieval, and management
Open rFlows directly into the interactive canvas instead of the landing
page. Adds a full flow storage system (Automerge for authenticated users,
localStorage for demo/anon) with CRUD operations, auto-save with 1.5s
debounce, flow switching via toolbar dropdown, and a management modal
for rename/duplicate/export/import/delete. Viewport state (zoom/pan)
persists per-flow in localStorage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:19:57 -08:00
Jeff Emmett 02547fbe47 Merge branch 'dev' 2026-03-04 19:16:53 -08:00
Jeff Emmett cbe9fb5103 feat: add interactive canvas to rNetwork + rSocials canvas view
rNetwork: upgrade folk-graph-viewer with pan/zoom/drag, fitView, touch
pinch-zoom, zoom controls, persisted node positions, and incremental
drag updates. rSocials: new folk-socials-canvas component with campaign
and thread card nodes, Postiz slide-out panel, and canvas interactions.
Default / route now renders canvas view; old feed moved to ?view=feed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:16:46 -08:00
Jeff Emmett 741a519a30 fix: add wasm plugin to shell.js build for Automerge runtime
The shell now imports RSpaceOfflineRuntime which transitively pulls in
Automerge WASM. Without the wasm() plugin and esnext target on the
shell build step, vite fails with "ESM integration proposal for Wasm
is not supported".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:16:36 -08:00
Jeff Emmett 798a5edb65 Merge branch 'dev' 2026-03-04 19:12:15 -08:00
Jeff Emmett b2b5644f94 feat: add service worker precaching for cold-start offline support
Generate precache-manifest.json at build time by scanning dist/ for all
cacheable assets. SW fetches the manifest during install and precaches
core shell assets (shell.js, shell.css, theme.css, HTML pages) immediately.
Module JS/CSS bundles are lazy-cached in the background after activation.

Bumps CACHE_VERSION to rspace-v2 to trigger SW update and cache cleanup.
The app can now load fully offline even after browser restart with no network.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:12:05 -08:00
Jeff Emmett afc66ac4c1 Merge branch 'dev' 2026-03-04 19:08:09 -08:00
Jeff Emmett 4cc420d0f6 feat: wire offline-first Automerge sync to all 13 rSpace modules
Add shared RSpaceOfflineRuntime singleton that coordinates IndexedDB
persistence (EncryptedDocStore), WebSocket sync (DocSyncManager), and
in-memory Automerge docs (DocumentManager) for all module web components.

- Phase 0: runtime.ts singleton, shell integration, beforeunload flush
- Phase 1: rstack-offline-indicator status dot in shell header
- Phase 2: service worker stale-while-revalidate for API GETs + offline fallback
- Phase 3: storage-quota.ts with LRU eviction (30d) and quota warnings (70%)
- Phase 4: Tier 1 single-doc modules (rFlows, rCal, rBooks, rSplat)
- Phase 5: Tier 2 multi-doc modules (rNotes, rWork, rInbox, rVote, rTrips, rFiles)
  with doc-list-request/response wire protocol for document discovery
- Phase 6: Tier 3 special cases (rCart hybrid, rForum global doc, rSchedule)

Data now loads instantly from IndexedDB, syncs via WebSocket when online,
and remains browsable offline. rNotes migrated from inline Automerge WS
to shared runtime. All modules fall back to REST when runtime unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:07:59 -08:00
Jeff Emmett b86747d4e1 Merge branch 'dev' 2026-03-04 18:31:36 -08:00
Jeff Emmett f62da0841c feat: redesign rCal timescale bar as bottom spectrum slider
Replace discrete dot-tick zoom controller with a continuous gradient
spectrum slider at the bottom of the calendar. Move lunar overlay and
its toggle to the bottom bar. Add drag + touch support on the slider
thumb for smooth timescale navigation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:28:04 -08:00
Jeff Emmett e9e257cc15 Merge branch 'dev' 2026-03-04 18:14:34 -08:00
Jeff Emmett e827229447 feat: show rSocials landing page on space subdomains
Space subdomain /rsocials now renders the same marketing landing page
as the bare domain, instead of the bare Community Feed placeholder.
Demo space still shows the demo feed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:14:14 -08:00
Jeff Emmett 2428fcdf78 Merge branch 'dev' 2026-03-04 18:03:19 -08:00