Commit Graph

197 Commits

Author SHA1 Message Date
Jeff Emmett 7618433498 refactor(auth): replace @encryptid/sdk imports with local auth module
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>
2026-03-22 16:41:59 -07:00
Jeff Emmett 29c4f48634 feat(identity): store verified email on profile + show in account modal
Email verification wrote to the `email` column but account status read
from `profile_email` — now setUserEmail writes both. Account modal email
section displays the verified address when collapsed. Tour finale step
triggers identity setup on completion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 15:49:09 -07:00
Jeff Emmett 2de61cd7ad feat(rcal): move zoom/legend below calendar, add multi-day event spans
- Reorder layout: nav → calendar → legend → zoom bars → bottom bar
- Add "Calendar Legend" heading above source badges
- Fix getEventsForDate() to support multi-day range checking
- Render colored span bars across day cells for multi-day events
- Make showAccountModal/isSignedIn public on rstack-identity
- Tour final step triggers identity setup flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 15:10:39 -07:00
Jeff Emmett 466a0305fd fix(spaces): dedup space switcher + restructure into sections
Personal space rename only applies when isPersonal flag is set (not all
private spaces). Demo forced to public visibility. Public spaces no
longer filtered out. Sections: Private → Permissioned → Public →
✦ Discover → Create.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 14:35:07 -07:00
Jeff Emmett fe7157ffe1 fix(shell): position settings/history panels below their buttons
Both panels now use position:fixed with JS-computed coordinates from
getBoundingClientRect(), ensuring they open directly below their
respective header buttons and right-aligned to the button edge.
History panel clamps left edge to prevent off-screen overflow.

Also adds missing click handlers for settings-btn and history-btn
in canvas.html (previously only wired in shell.ts module pages).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 13:59:44 -07:00
Jeff Emmett 63c1b7c1e7 refactor(shell): convert settings & history panels to dropdown menus
Replace full-height slide-in panels with compact dropdowns that appear
beneath header icons. Both icons now grouped in header-right with
mutual exclusion and click-outside-to-close behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 23:17:17 -07:00
Jeff Emmett 6491681e3e fix(auth): force platform authenticator + redirect disabled modules
Force authenticatorAttachment: 'platform' across all WebAuthn registration
flows to prevent USB security key prompts. Redirect browser navigations to
space root when accessing disabled modules instead of returning JSON error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 22:31:13 -07:00
Jeff Emmett cc504d4a86 fix(spaces): make DID resolve endpoint public (no auth needed for profile data)
The resolve-dids endpoint was returning 401 because unsigned fallback tokens
fail HS256 verification. Since username/displayName is public profile data,
remove auth requirement from the endpoint and client call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 18:06:36 -07:00
Jeff Emmett 524356d233 feat(tours+solo): add tours to remaining modules and solo mode toggle
Add guided tours to 6 modules that were missing them:
- Shadow DOM: rsocials dashboard, crowdsurf, rdata (TourEngine)
- Light DOM: rsplat, rbnb, rvnb (new LightTourEngine class)

Add solo mode toggle to collab overlay — click the presence badge
to hide your cursor/presence from others. Persists via localStorage,
dispatches event to canvas PresenceManager.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 17:26:57 -07:00
Jeff Emmett 64f9603e39 fix(spaces): stop module settings selects from polluting scope overrides
Module settings selects (notebook-id, select types) shared the .scope-select
CSS class with actual data-scope selects, causing their values to be sent as
scopeOverrides — triggering "Invalid scope '' for rnotes" on save.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:49:17 -07:00
Jeff Emmett acafe15c4b feat(spaces): resolve member DIDs to usernames in space settings
Add POST /api/users/resolve-dids batch endpoint in EncryptID, proxy
/api/users/* through rspace server, and batch-resolve missing displayNames
in the space settings panel so owners and members show usernames not DIDs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:39:48 -07:00
Jeff Emmett a415d6c308 fix(mi): only minimize on Escape when input empty, fix mobile transform
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:25:06 -07:00
Jeff Emmett b7aadf66cd feat(sync): proxy /api/user/* to EncryptID for cross-session tab state
Adds catch-all proxy route so client tab sync requests (saveTabs/syncTabsFromServer)
reach the EncryptID container. Also fixes rstack-mi panel positioning and
Shadow DOM click-outside handling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:22:37 -07:00
Jeff Emmett b679fc9f1f feat(spaces): bridge email invites with EncryptID identity system
New users get sent to /join for passkey registration + auto-space-join.
Existing users are directly added with in-app + email notification.
Add-by-username now also sends email notification if email is on file.

- Add id to /api/users/lookup response
- Enhance /api/internal/user-email/:userId with recovery + profile email
- Add GET /api/internal/user-by-email for email→DID resolution
- Rewrite POST /:slug/invite to use identity invite flow
- Add email notification to POST /:slug/members/add
- Add success/error feedback to space settings invite UI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:04:22 -07:00
Jeff Emmett ad2120f4fb fix(spaces): keep create-space dropdown open during interaction
The dropdown closed on every click (radio buttons, input focus, etc.)
because a global document click listener removed the "open" class.

- Add menu-level stopPropagation so clicks inside the dropdown don't
  close it
- Only close on clicks outside both trigger and menu
- Preserve form state (name, visibility, open/closed) across
  close/reopen so content isn't lost when accidentally clicking away

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 15:59:31 -07:00
Jeff Emmett f8ab716722 feat(x402): bridge on-chain USDC payments with CRDT token ledger
Connects x402 (on-chain USDC via Base) and CRDT token system (Automerge cUSDC)
in both directions: on-chain payments auto-mint cUSDC to payer's DID, and users
can pay with cUSDC balance via new "crdt" payment scheme. 402 responses now
return both exact and crdt payment options.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 14:23:24 -07:00
Jeff Emmett 4793f9c117 feat(crowdsurf): restore module and add Elo pairwise ranking layer
Restore CrowdSurf as standalone module with full integration (server,
app-switcher, shell favicon, rchoices tab, vite build). Add sortition-
based pairwise Elo ranking: users compare two activities head-to-head,
updating Elo ratings. Includes API endpoints (/api/crowdsurf/pair,
/api/crowdsurf/compare), Rank tab with leaderboard, and Elo badges.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 23:51:24 -07:00
Jeff Emmett d99b85046c feat(rswag): full feature parity — POD clients, dithering, AI gen, fulfillment
8-phase implementation bringing rSwag module to parity with standalone rswag.online:
- Printful v2 + Prodigi v4 API clients with sandbox mode
- 11 dithering algorithms + screen-print color separations
- Gemini AI design generation + user artwork upload
- ~15 new API routes (designs, mockups, storefront, fulfillment, admin)
- 4-tab frontend UI (Browse, Create, HitherDither, Orders)
- Interactive revenue Sankey diagram on landing page
- Fulfillment bridge routing orders to nearest POD provider

Also includes: rChats module scaffold, rVote enhancements, crowdsurf removal,
rchoices cleanup, rwallet tweaks, app-switcher updates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 23:21:53 -07:00
Jeff Emmett d4972453a3 feat(onboarding): add module-specific connect/import/create CTAs
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>
2026-03-20 14:17:19 -07:00
Jeff Emmett df77c9c903 feat(shell): cross-tab sync via BroadcastChannel + keyboard shortcuts & swipe gestures
Add BroadcastChannel for instant same-browser tab sync — opening/closing
tabs in one window propagates immediately to sibling tabs. Extract
reconcileRemoteLayers() helper shared by BroadcastChannel and Automerge,
which cleans up cached DOM panes on remote removal and handles
active-tab-closed scenarios.

Also adds configurable rApp shortcuts (Ctrl/Alt+1-9), header swipe
gestures for rApp cycling, and body data-module-id attr for swipe context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 13:04:31 -07:00
Jeff Emmett 73ad020812 fix(spaces): fix space creation routing and use /rspace URLs
Space creation was broken because the canvas module has id "rspace" but
all navigation URLs used "/canvas". On production subdomain routing this
resulted in 404s after creating a space.

- Switch create-space form from deprecated /api/communities to /api/spaces
- Replace all /canvas navigation URLs with /rspace to match module ID
- Fix DID matching in space listing to check both sub and did:key formats
- Add proper client DID support in EncryptID registration flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 11:07:01 -07:00
Jeff Emmett 39ec09bb3b fix(compat): improve cross-browser support for Firefox, Safari, and older browsers
Add global polyfills for AbortSignal.timeout() (Safari <17, Firefox <122)
and crypto.randomUUID() (Safari <15.4, Firefox <95) in shell HTML templates.
Add -webkit-backdrop-filter prefix across 13 files for older Safari support.
Add Firefox scrollbar (scrollbar-width/scrollbar-color), range input
(::-moz-range-thumb/track), and color-mix() rgba fallbacks. Create shared
compat.ts utility module. Lowers browser floor from Safari 17/Firefox 122
to Safari 15.4/Firefox 95.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 10:43:38 -07:00
Jeff Emmett a736321189 feat(rnotes): add real-time Yjs collaboration, comments, and suggestions
Replace whole-content Automerge sync with character-level Yjs CRDT for
NOTE-type notes. Adds cursor presence, inline comments with threaded
replies, and track-changes suggesting mode.

- Custom Yjs WebSocket provider bridging over existing rSpace WS
- Server-side yjs-sync/yjs-awareness message relay (pure broadcast)
- y-indexeddb for offline persistence, periodic plaintext sync to Automerge
- Comment mark + panel with resolve/reply/delete
- Suggestion insert/delete marks with accept/reject support
- Schema v3→v4 (collabEnabled, comments fields)
- Collab toolbar: comment button, suggesting toggle, peer indicators

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 10:36:09 -07:00
Jeff Emmett 315a29a6d7 fix(shell): hide notification/share/settings icons on mobile, add to identity dropdown
On mobile (<=640px), the header right section was too crowded with icons.
Now hides notification bell, share panel, and settings gear buttons, and
adds equivalent mobile-only items in the identity dropdown menu. Share
uses native navigator.share() when available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:58:52 -07:00
Jeff Emmett 9b81ba70b6 feat(shell): add share button to global header with QR, copy link, email invite
Extract canvas inline share panel into reusable <rstack-share-panel> web component
and add it to the shell header between notification bell and settings gear. Canvas
now uses the component too, removing ~230 lines of inline HTML/CSS/JS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 20:51:21 -07:00
Jeff Emmett e0d976ac92 fix(tabs): track active tab correctly on close + long-press reorder
currentModuleId was a const that never updated on client-side tab
switches, causing close to either do nothing or switch to the wrong
tab. Now uses tabBar.active as source of truth and picks the nearest
remaining tab on close. Also adds touch long-press (400ms) drag
reorder for mobile tabs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:37:24 -07:00
Jeff Emmett 51da13ac46 feat(rbnb): add community hospitality module — trust-based space sharing
New rSpace module for couch surfing and space sharing within community networks.
Gift economy as first-class option, rNetwork trust graph for auto-accept,
messages embedded in CRDTs, endorsements feed back into trust graph.

- schemas.ts: Listing, StayRequest, Endorsement, AvailabilityWindow, SpaceConfig types
- mod.ts: 18 API endpoints (listings, availability, stays, endorsements, search, stats, config)
- landing.ts: Marketing page with warm amber/red/pink palette
- local-first-client.ts: Automerge sync wrapper (BnbLocalFirstClient)
- components: folk-bnb-view (grid+map), folk-listing (card shape), folk-stay-request (detail)
- bnb.css: Economy badges, status indicators, message thread styles
- Registered in server/index.ts, added r🏠 badge to app switcher under "Sharing"
- 6 demo listings (gift couch, exchange farm, suggested tent, sliding loft, gift hub, fixed cabin)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:01:50 -07:00
Jeff Emmett 84c3c318d8 feat: async 3D gen, calendar reminder widget, cross-module drag, subdomain URL fixes
- Make /api/3d-gen async with job queue + email notification on completion
- Add reminder mini-calendar widget to canvas (top-right on shape select)
- Make items draggable across 6 modules (rNotes, rTasks, rFiles, rSplat, rPhotos, rBooks)
- Upgrade rCal drop handler with time-picker popover instead of confirm()
- Show reminder indicators (dots + badges) on calendar days
- Fix subdomain routing: remove space slug from server-rendered sub-nav,
  tab bar, and module links in production (/{moduleId} not /{space}/{moduleId})
- Add buildSpaceUrl() helper for correct external URL generation
- Fix rcart payment URLs for subdomain routing
- Fix rSchedule email links to use subdomain format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:18:51 +00:00
Jeff Emmett bf28e96ae6 Unrestrict 3D layer view camera — full x/y/z orbit
- Add rotateY axis (drag left/right rotates Y, up/down rotates X)
- Shift+drag for Z-axis roll
- Remove 10-80° clamp on rotateX — full ±180° range
- Remove backface-visibility:hidden so layers visible from all angles
- Fix overflow:hidden → overflow:visible for proper 3D perspective
- Increase layer spacing 80→120px for more dramatic depth
- Increase viewport height 340→420px, perspective origin centered

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 13:49:13 -07:00
Jeff Emmett 668c239cf3 feat(shell): add "Manage rApps" catalog to app switcher sidebar
Extends <rstack-app-switcher> with an expandable "Manage rApps" panel
at the bottom of the sidebar. Space owners can:
- See all available modules (enabled + disabled) in one place
- Toggle modules on/off with + / − buttons
- Changes persist via PATCH /api/spaces/:slug/modules
- Local toggle fallback for demo mode
- Busy state disables buttons during API calls

Shell changes:
- renderShell() now builds allModulesJSON with `enabled` flags
- Calls setAllModules() on the app switcher alongside setModules()
- Dispatches 'modules-changed' event for shell reactivity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 17:20:31 -07:00
Jeff Emmett 3b3a642813 fix(routing): remove hardcoded /demo/ path prefix from URLs
demo.rspace.online subdomain already identifies the space, so paths
should not redundantly include /demo/. Replaced 7 occurrences across
rcart, rswag, rpubs, rschedule, and space-switcher with either relative
paths or full demo.rspace.online URLs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 18:48:20 -07:00
Jeff Emmett 357e0bb4c0 refactor(transak): split API keys by environment (staging/production)
Add getTransakApiKey() and getTransakWebhookSecret() helpers that
resolve TRANSAK_API_KEY_STAGING or TRANSAK_API_KEY_PRODUCTION based
on TRANSAK_ENV, with fallback to legacy TRANSAK_API_KEY. All consumers
(rcart, rflows, transak-onramp) now use the shared helpers instead of
reading env vars directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:06:33 -07:00
Jeff Emmett 9d34eca103 fix(transak): default to STAGING environment for all purchases
Switch TRANSAK_ENV default from PRODUCTION to STAGING in shared/transak.ts,
docker-compose.yml, and rflows config endpoint. All card purchases now
route through Transak's staging gateway until production is ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:54:42 -07:00
Jeff Emmett c668d5700c fix(transak): derive referrerDomain from request hostname instead of hardcoding
Resolves T-INF-101 Access Denied when accessing payment links from
subdomains like demo.rspace.online. Adds extractRootDomain() helper
to shared/transak.ts, used by both rcart and rflows onramp adapters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:49:29 -07:00
Jeff Emmett 9091c988ff feat: add subnav outputPaths for rcart, rmeets, rwallet; CRM URL-path tabs
- rcart: add subscriptions outputPath
- rmeets: add rooms + recordings outputPaths
- rwallet: add wallets, tokens, transactions outputPaths
- folk-crm-view: read active tab from URL pathname instead of ?tab=
  query param (with backward compat fallback)
- rstack-app-switcher: rename rtasks category to "Work & Productivity"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 01:37:05 -07:00
Jeff Emmett 0c3d8728a0 fix: graph 3d-force-graph resolution, DID/username display, space role checks
- Switch 3d-force-graph CDN from jsdelivr to esm.sh with bundle-deps
  to resolve missing "three-forcegraph" bare specifier error
- Fix storeCredential() to pass displayName and DID to createUser()
  (prevents NULL did column for credential-first user creation)
- Fix invite acceptance to use claims.did instead of claims.sub for
  space_members.user_did (DID format consistency)
- Fix session refresh to look up username from DB when missing from
  old token (prevents empty username after token refresh)
- Fix resolveCallerRole() in spaces.ts to check both claims.sub and
  claims.did against ownerDID and member keys (auto-provisioned spaces
  store ownerDID as did🔑, API-created as raw userId)
- Refactor CRM route to use URL subpath tabs with renderCrm helper

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 01:31:24 -07:00
Jeff Emmett 8efe18280c feat: consolidate domains, install deps, fix EncryptID types
- TASK-24: Install h3-js, @xterm/xterm, @xterm/addon-fit
- TASK-51.3: Remove app switcher external link arrows, update
  ridentity.online UI links to /rids paths
- TASK-51.4: Prune allowedOrigins (~30 → 16), simplify JWT aud
  to 'rspace.online', remove standalone domains from webauthn,
  update EncryptID HTML template links. Keep ridentity.online as
  canonical EncryptID/OIDC domain.
- Fix EncryptIDClaims type: add username, did fields; update aud
  type to string | string[] — resolves pre-existing TS error
- TASK-12: Update backlog status (80% code-complete, blocked on
  security audit)
- Backlog task updates for TASK-25/37/40/44, new TASK-110

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 21:55:39 -07:00
Jeff Emmett adb0d173d8 feat(shell): add module sub-nav bar + rCart UX polish + fix TS errors
- Add secondary pill navigation bar between tab-row and <main> showing
  each module's outputPaths + subPageInfos as navigable links with
  client-side active highlighting
- Rename rcart /buy/:id route to /group-buy/:id, add payments and
  group-buys outputPaths, rename products → catalog
- Add outputPaths (mailboxes) to rinbox module
- Polish group buy page: hero stat cards, fill-up liquid progress
  visual with tier markers, warm amber→green gradient, pledge avatars,
  green CTA button, price box, responsive improvements
- Fix centering for narrow rcart form pages (flex layout in cart.css)
- Fix TS error: add walletAddress to rstack-identity SessionState type
- Fix TS errors: add ambient type declarations for 3d-force-graph and
  three (dynamically imported in folk-graph-viewer)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:44:45 -07:00
Jeff Emmett 96b77278d4 fix(transak): use direct widget URL instead of broken gateway API
The Transak gateway session API consistently returns 401 despite valid
access tokens. Switch to direct URL construction (query params on
global.transak.com) which Transak still supports and is simpler.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:32:23 -07:00
Jeff Emmett 1460d2b579 feat(ecosystem): implement cross-app embedding protocol (TASK-46)
Add ecosystem manifest protocol, EcosystemBridge class, server proxy
routes, port/event integration for folk-rapp, sandboxed iframe mode
with origin-validated postMessage, and SW caching for ecosystem modules.

Security: no allow-same-origin on sandboxed iframes, redirect: error
on proxy fetches, origin validation on all postMessage handlers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:32:28 -07:00
Jeff Emmett eb00579183 feat(mi): upgrade to community-focused builder with interchangeable AI
Transform MI from a small Ollama-only chat dropdown into a rich builder
panel with swappable AI backends (Gemini, Ollama, Anthropic/OpenAI stubs),
role-based permission gating, and module-spanning content actions.

- Provider abstraction layer (mi-provider.ts) with stream normalization
- Extracted MI endpoints into mi-routes.ts Hono sub-app
- New action types: create/update/delete-content, scaffold, batch
- Module routing map (mi-module-routes.ts) for rApp API integration
- Redesigned panel: fixed 520px, model selector, textarea, minimize pill
- Action confirmation for destructive ops, scaffold progress bar
- Permission validation endpoint with role-based action gating
- Better markdown rendering (headers, code blocks, links, lists)
- Cmd/Ctrl+K keyboard shortcut, collapsible action details

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:29:19 -07:00
Jeff Emmett b8788fa81e refactor: move rcal, rinbox, rnetwork into Connect category
App-switcher: new "Connecting" category with rcal, rinbox, rnetwork.
Canvas toolbar: new "Connect" group with rCal, rInbox, rNetwork
(moved out of Embed dropdown).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:33:48 -07:00
Jeff Emmett c049d7e8df feat(rcart): QR code payment requests with self-service generator
Add shareable QR payment system to rCart:
- PaymentRequestDoc schema with amountEditable support
- Payment API routes (create, list, get, update, QR SVG, Transak session)
- folk-payment-page: 3-tab payer view (Card/Wallet/EncryptID passkey)
- folk-payment-request: self-service QR generator with passkey auth
- Payments tab in folk-cart-shop for managing requests
- Extract Transak utils to shared/transak.ts (used by rFlows + rCart)

Routes: /:space/rcart/request (generator), /:space/rcart/pay/:id (payer)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 16:11:20 -07:00
Jeff Emmett c4717e3c68 feat: auth-fetch, shape registry, and data pipes (TASK-13, TASK-41, TASK-42)
TASK-13: rApp frontends now inject EncryptID bearer tokens via authFetch()
and gate mutations behind requireAuth() — rvote, rfiles, rmaps all protected.
Demo mode unaffected.

TASK-41: Dynamic shape registry replaces 300-line switch in canvas.html and
165-line if-chain in community-sync.ts. All 41 shape classes now co-locate
fromData()/applyData() with their existing toJSON(), making shape creation
and sync fully data-driven.

TASK-42: Data pipes between shapes via typed ports. Shapes declare
input/output PortDescriptors, arrows connect ports with type checking,
100ms debounce, and color tinting. AI shapes (prompt, image-gen, video-gen,
transcription) have initial port descriptors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:59:51 -07:00
Jeff Emmett 8af5f3d0b6 chore: increase recent rApps in dropdown from 3 to 5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:29:33 -07:00
Jeff Emmett e47cd35a34 feat(identity): add My Wallets panel to avatar dropdown
Adds a wallet modal accessible from the identity dropdown showing:
- rIdentity wallet card with username, DID, and passkey badge
- Browser wallet discovery via EIP-6963 (MetaMask, Rainbow, etc.)
- Connect flow with eth_requestAccounts
- Quick link to open the full rWallet module

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:23:00 -07:00
Jeff Emmett 31b088543e feat: add ViewHistory for in-app back navigation, rename rWork to rTasks
Add shared ViewHistory<V> utility class that provides a proper navigation
stack for rApps with hierarchical views. Replaces hardcoded data-back
targets with stack-based back navigation across 10 rApps: rtrips, rmaps,
rtasks, rforum, rphotos, rvote, rnotes, rinbox, rschedule, rcart.

Rename rWork module to rTasks — directory, component (folk-tasks-board),
CSS, exports, domains, and all cross-module references updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 14:04:13 -07:00
Jeff Emmett 2b909becdb fix(shell): move info icon to left of layer toggle in tab bar
Slot the rApp info button into the tab-bar's tab-actions area so it
appears immediately left of the view-toggle (layer icon) instead of
after it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:27:07 -07:00
Jeff Emmett 7177b2882c fix: deduplicate spaces dropdown, group by visibility type
Personal space (slug=username) forced to private so it doesn't appear
as both public and private. Dropdown now groups spaces: Private (red)
at top, Permissioned (yellow) middle, Public (green) bottom.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:00:37 -07:00
Jeff Emmett 8072b250ea feat: canvas background selector — grid, dot, or blank preference
Add user-selectable canvas background style via data-canvas-bg attribute
and CSS custom properties (--rs-canvas-bg-image, --rs-canvas-bg-size).
Three options: grid (default), dot, blank — persisted in localStorage.

- theme.css: new tokens + [data-canvas-bg] selectors
- rstack-identity.ts: Grid/Dot/Blank selector in user dropdown
- canvas.html: CSS vars, zoom-aware scaling, canvas-bg-change listener
- flows.css: use shared bg-image/bg-size vars (fixes rFlows theme bug)
- FOUC prevention in all entry points (shell.ts, create-space.html)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 18:37:50 -07:00
Jeff Emmett 72100c0922 feat: migrate hardcoded colors to --rs-* CSS variables across 18 modules
Replace structural UI colors with theme-aware CSS custom properties so
all rApp modules respond correctly to light/dark theme switching.

Covers: folk-social-post, folk-forum-dashboard, folk-video-player,
folk-video-chat, folk-thread-gallery, folk-campaign-manager,
folk-wallet-viewer, folk-vote-dashboard, folk-swag-designer,
folk-cart-shop, folk-workflow-block, folk-choices-dashboard,
folk-pubs-editor, folk-book-shelf, folk-flows-app, folk-analytics-view,
folk-campaign-planner, and flows.css canvas background.

Intentionally preserved: platform brand colors, chain colors,
data-viz/chart colors, video player black, call action buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 18:34:13 -07:00
Jeff Emmett a7063d24f5 feat: PWA support — installable app, Web Push notifications, app badge
Phase 1: Installable PWA
- Add web app manifest with multi-size icons (192, 512, maskable, apple-touch)
- Add PWA meta tags to all entry points (shell.ts, canvas.html, index.html, create-space.html)
- Register service worker on all pages (previously only canvas.html)
- Add manifest.json to precache core list
- Capture beforeinstallprompt for custom install UX

Phase 2: Web Push Notifications
- Add web-push dependency + push_subscriptions DB table
- VAPID key endpoint, subscribe/unsubscribe routes in notification-routes.ts
- Web Push delivery in notify() with auto-cleanup of expired subscriptions
- SW push + notificationclick event handlers
- Client push subscription flow in notification bell component

Phase 3: Install UX Polish
- App badge (setAppBadge/clearAppBadge) on unread count changes
- "Enable push" button in notification panel header

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 17:35:30 -07:00
Jeff Emmett b2347ec418 feat: per-rApp inline config + module-aware settings panel
Add <rstack-module-setup> component for inline module configuration
(replaces static "Not Configured" instructions). Enhance settings
gear panel to show the current module's settingsSchema at the top.
Pass module-id through shell rendering and tab-cache switching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:45:48 -07:00
Jeff Emmett 53af7fc057 feat(rcal): docked map layout + theme-aware tiles; emoji tab badges
- rCal: default map to docked (side-by-side) layout instead of floating overlay
- rCal: switch map tiles between Voyager (light) and dark_all (dark) based on theme
- rCal: boost dark mode map brightness/contrast for readability
- rCal: watch for theme changes via MutationObserver for live tile swapping
- Tab bar: replace text badges with emoji icons, fix badge colors for light themes
- App switcher: fix badge text color to dark for gradient backgrounds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:13:28 -07:00
Jeff Emmett c92ca0fe05 feat(rsocials): newsletter manager + listmonk proxy + backlog tasks
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>
2026-03-10 12:24:02 -07:00
Jeff Emmett fc65bec9dc feat(app-switcher): emoji badges + recently used section
Replace text abbreviation badges (rN, rPh, etc.) with r+emoji format
(r📝, r📸, etc.), remove duplicate emoji from item rows, and add a
"Recently Used" section at the top of the sidebar persisted via
localStorage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:10:42 -07:00
Jeff Emmett c19142791e feat(rnotes): type-specific notes, voice recording, web clipper, module settings
Phase 1: All 7 note types (NOTE, CODE, BOOKMARK, CLIP, IMAGE, AUDIO, FILE)
with type-specific editors, filter bar, new-note dropdown, and demo notes.
Phase 1.5: Code Snippet and Voice Note slash commands.
Phase 2: Voice recording with 3-tier transcription cascade (server Whisper,
Web Speech API, offline Parakeet TDT), mic button in toolbar, standalone
voice recorder component, upload/transcribe/diarize server routes.
Phase 3: Manifest V3 browser extension (web clipper) retargeted to
rspace.online with slug-based routing, article unlock via Wayback/Google
Cache/archive.ph strategies.
Phase 4: Per-module settings framework — settingsSchema on modules,
moduleSettings in CommunityMeta, gear icon in space settings Modules tab,
rNotes declares defaultNotebookId setting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:39:10 -07:00
Jeff Emmett 1568a5d0dc feat: user dashboard shown when all tabs are closed
When the last tab is closed, a dashboard appears showing the user's
spaces (sorted by most recent visit), notifications, and quick actions.
Clicking any item creates a new tab and hides the dashboard. Browser
back/forward handles dashboard state correctly.

Also adds proper cache headers for HTML and Vite-hashed assets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:55:39 -07:00
Jeff Emmett 5842bd9f9a fix: attachShadow guard, null toggleMemoryBtn, register canvas components
- Add if (!this.shadowRoot) guard in history panel and space settings
  connectedCallback to prevent error on element reconnection
- Null-check toggleMemoryBtn before addEventListener since #toggle-memory
  element was removed
- Import and register RStackSpaceSettings + RStackHistoryPanel in
  canvas.html so settings gear and history panel work on canvas page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:15:57 -07:00
Jeff Emmett 2ecea4ebb8 feat: history panel with author attribution + settings gear relocation
Move settings gear to header right (next to identity) on all pages.
Add history clock button in header left that opens a new slide-out
history panel with Activity feed and Time Machine tabs. Embed author
identity (DID, username, timestamp) in Automerge change messages via
JSON envelope, with backward-compatible parsing for old plain strings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:24:27 -07:00
Jeff Emmett 20c26cd3d7 feat: scope system, cross-space navigation, and spaces-as-layers
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>
2026-03-09 06:33:32 +00:00
Jeff Emmett ef2ac6e74e fix: IDB transaction error and sidebar push desync
- storage.ts: read existing meta from same IDB transaction instead of
  calling getMeta() which opens a separate transaction, causing the
  write transaction to auto-commit before meta put executes
- rstack-app-switcher: track open/close state in #isOpen so re-renders
  don't leave body.rstack-sidebar-open orphaned, add click-outside
  handler, close sidebar on module select, clean up on disconnect

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:02:18 -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 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 3b3eecdddb fix: stop demo→personal space redirect and clean up space switcher
Logged-in users visiting demo.rspace.online were auto-redirected to
their personal space on page load. Now only provisions the space
silently without redirecting. Also removes the redundant "Public
spaces" section from the dropdown and filters the /api/spaces endpoint
to only return demo, user's own spaces, and permissioned spaces.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:02:00 -08:00
Jeff Emmett 57fd1f4913 fix: always show Demo Space at top of space switcher dropdown
Adds a permanent "Demo Space" entry as the first item in the space
switcher dropdown across all rApps. Previously demo only appeared
in the "Public spaces" section (if the API returned it), making it
easy to miss. Now it's always visible at the top with a game
controller icon, followed by the sign-in/personal space CTA.

Also filters demo out of the "Public spaces" section to avoid
showing it twice.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:29:04 -08:00
Jeff Emmett 707d83525b fix: responsive header dropdowns + space switcher on all pages
- Remove overflow:hidden from header__left on mobile (was clipping
  app-switcher and space-switcher triggers)
- Add white-space/overflow/text-overflow to both trigger buttons so
  they truncate gracefully on narrow screens
- Add <rstack-space-switcher> to module landing and sub-page info
  shells so the spaces dropdown always appears next to the rApps dropdown

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:46:40 -08:00
Jeff Emmett e2ebd11d75 style: differentiate rApp tab headers with borders and spacing
Inactive tabs get a subtle background tint, hover/active tabs show
visible borders, active tab uses solid surface background. Wider gap
between tabs and full-width indicator line for clearer separation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:47:20 -08:00
Jeff Emmett 59bdd741be feat: bare-domain sub-pages show info/marketing pages + save-gate
Bare-domain URLs like rspace.online/rsocials/thread now render an info
page with CTAs instead of silently serving the functional app. The
functional app only appears inside a {space} context (e.g.
demo.rspace.online/rsocials/thread). API routes still pass through.

- Add SubPageInfo interface to shared/module.ts
- Add renderSubPageInfo() renderer to server/shell.ts
- Modify bare-domain routing: api/ passthrough → info page → demo fallback
- Add subPageInfos to 8 modules (rsocials, rflows, rnetwork, rtrips,
  rbooks, rphotos, rinbox, rsplat)
- Add window.__rspaceSaveGate() auth prompt on write operations
- Wire save-gate into rsocials Thread Builder save handler

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:16:17 -08:00
Jeff Emmett 1d0e82294b fix: move [+] tab button next to open tabs, style as new-tab shape
- Remove flex:1 from .tabs-scroll so tabs don't stretch across full width
- [+] button sits immediately after last tab instead of far right
- Restyle .tab-add to match .tab shape (same border-radius, padding, hover)
- Push .tab-actions (view toggle) to far right with margin-left: auto
- Dropdown menu follows the button naturally

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:56:51 -08:00
Jeff Emmett 1f071dc4a1 fix: layer flows drag-to-connect, notification 401 spam, /api/meta 404
- Tab bar: replace mouseenter/mouseleave with bounding-rect hit testing
  during drag-to-connect (robust for 3D CSS transforms)
- Tab bar: clean up document mousemove/mouseup listeners on re-render
  to prevent accumulation leak
- Notification bell: stop polling on 401, restart on auth-change
- Space settings: detect subdomain routing to avoid double-prefix on
  /api/meta URL (jeff.rspace.online/jeff/rspace → /jeff/jeff/rspace)
- rSpace module: add GET /api/meta endpoint returning space owner/members

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:12:19 -08:00
Jeff Emmett 7b397b522c fix: [+] tab menu clipped by overflow — move outside scroll container
The add-menu dropdown was inside .tabs-scroll which has overflow-x: auto,
causing the browser to clip overflow-y as well (per CSS spec). Move the
.tab-add-wrap (button + menu) out of .tabs-scroll into .tab-bar directly
so the dropdown renders without clipping, beneath the [+] button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:33:09 -08:00
Jeff Emmett abb3f57ca0 fix: space settings panel hidden behind canvas due to backdrop-filter containment
Move <rstack-space-settings> outside the header element so its position:fixed
is relative to the viewport instead of the 56px header (backdrop-filter creates
a containing block for fixed descendants). Bump panel z-index above all canvas
elements. Also migrate hardcoded colors to CSS theme variables across shell
components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:30:20 -08:00
Jeff Emmett f5260e0817 feat: move dark/light mode toggle to user profile dropdown
Replaced the dark mode checkbox in the My Account modal with a
sun/moon toggle directly in the profile dropdown menu. Sun on the
left, moon on the right, with a colored slider (amber for light,
indigo for dark).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:12:42 -08:00
Jeff Emmett 495baa5935 fix: allow unauthenticated thread builder save/share operations
The space role middleware was blocking all POST/PUT requests from
unauthenticated users with a 403, preventing the thread builder's
save draft and share buttons from working. Added publicWrite module
flag to bypass the role check for modules with public API endpoints.
Also fixed saveDraft() to properly surface server errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:57:59 -08:00
Jeff Emmett a6008a4f2d refactor: complete rfunds → rflows rename across configs and references
Update docker-compose, vite config, Traefik labels, module imports,
and all cross-module references to use the new rflows naming.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:13:14 -08:00
Jeff Emmett cdfe8c5b78 feat: add unified notification system with real-time WS delivery
Persistent, PostgreSQL-backed notification system replacing the in-memory
access request polling. Notifications are created via notify(), persisted
to DB, and delivered in real-time over WebSocket with a 30s polling fallback.

Infrastructure:
- notifications + notification_preferences tables in EncryptID schema
- 10 CRUD functions in db.ts (create, list, count, read, dismiss, etc.)
- notification-service.ts: core notify(), WS registry, notifySpaceAdmins()
- notification-routes.ts: REST API at /api/notifications
- rstack-notification-bell.ts: bell icon component with dropdown panel

Module integration (11 hooks):
- spaces.ts: access_request, access_approved, access_denied, member_joined,
  member_left, role_changed
- index.ts WS handler: ping_user (24h expiry)
- encryptid/server.ts: guardian_accepted, recovery_initiated (owner + guardians),
  recovery_approved

Legacy cleanup:
- Removed access request polling, badge, and approve/deny UI from
  rstack-identity.ts (now handled by notification bell)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 18:59:09 -08:00
Jeff Emmett da2b21cd98 feat: add voice dictation to MI bar, markdown, chat & prompt inputs
Extract Web Speech API logic from folk-transcription into a reusable
SpeechDictation utility, then wire mic buttons into all 4 text input
surfaces. Dictation fills inputs in real-time without auto-submitting.
Hidden gracefully in unsupported browsers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:10:52 -08:00
Jeff Emmett 63ac2a268e perf: parallelize local-first init — batch IDB loads, cache crypto keys, preload sync states
Sequential document loading during init() was the main bottleneck: each cached
doc required a serial IDB read + key derivation + decryption + Automerge.load.
With N documents this meant N× single-doc latency instead of 1×.

Changes:
- Add loadMany() to EncryptedDocStore for parallel Promise.all() batch loading
- Cache derived space/doc CryptoKeys in DocCrypto (one derivation per session)
- Add preloadSyncStates() to DocSyncManager for parallel sync state loading
- Update all 11 module local-first-client init() methods to use batch APIs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:18:55 -08:00
Jeff Emmett 80e42596b3 fix: normalize visibility enums + tab tracking across remaining files
Update remaining references from legacy 4-value visibility model
(public/public_read/authenticated/members_only) to simplified 3-value
model (public/permissioned/private) in rInbox, rVote, identity component,
admin panel, and create-space page. Add tab trackRecent calls in shell.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:29:01 -08:00
Jeff Emmett eb2859d849 refactor: normalize space visibility enums + inline space create form
Align visibility values across server and UI to the canonical set:
public, permissioned, private (replacing public_read, authenticated,
members_only). Add inline space creation form to the space switcher
dropdown and tab bar instead of navigating to /new.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:27:31 -08:00
Jeff Emmett daa6013fd0 fix: add migrateVisibility runtime migration, fix participant→member role label
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:17:53 -08:00
Jeff Emmett 35a5a5f29a feat: workflow template, choice components, space settings, EncryptID vault, UI polish
- Pre-populated 4-node workflow template (trigger→action→condition→output) with blue arrows
- Add folk-choice-vote, folk-choice-rank, folk-choice-spider component libraries
- New rstack-space-settings component
- EncryptID encrypted vault schema and server endpoints
- Space management and community store enhancements
- Shell, landing, and module CSS refinements
- Tab bar, app switcher, identity, and MI component updates
- rNotes app improvements
- rFunds diagram adjustments

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:15:13 -08:00
Jeff Emmett 8bd899d146 fix: persist theme via html[data-theme] + theme.css custom properties
- Blocking <head> script restores canvas-theme from localStorage
  with prefers-color-scheme fallback (no FOUC)
- New theme.css with CSS custom properties for dark/light
- Removed data-theme from body/header/tab-row (now on <html>)
- Theme toggle writes to documentElement instead of body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:56:51 -08:00
Jeff Emmett 4819852b14 fix: extract inline <style> blocks in tab-cache for canvas toolbar rendering
The tab cache's extractContent() only collected <link> stylesheets, missing
inline <style> blocks. The canvas toolbar CSS is entirely inline, causing
unstyled toolbar when switching to the rSpace tab via tab cache.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:51:35 -08:00
Jeff Emmett ebdda1e443 feat: enhanced rinbox multisig approval UI, module landing pages, help guide
- Rinbox: visual multisig approval cards with signer avatars, progress bars,
  email previews, status-colored borders, and compose-for-approval form
- Rinbox: help/guide popout with feature cards, how-it-works steps, use cases
- Rinbox: rich demo data with threaded comments, signer lists, multiple mailboxes
- Module landing pages: improved UX descriptions for rBooks, rCal, rNotes,
  rTrips, rVote, rWork with proper feature descriptions
- Added landingPage support to RSpaceModule interface and server routing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 22:05:08 -08:00
Jeff Emmett 94c5346eda fix: account completion indicators, email verify token type, SW cache
- Add /api/account/status endpoint returning email, multi-device,
  social recovery completion state
- Show red/green status dots on Account modal section headers for
  incomplete vs complete steps (email, device, recovery, data storage)
- Highlight Data Storage section with red warning when using local-only
  storage so users know they're responsible for their own data
- Fix email verification 500 error: change token type from
  'email_verification' to 'email_verify' to match DB check constraint
- Fix service worker: skip non-http(s) schemes to prevent
  chrome-extension:// cache put errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:28:13 -08:00
Jeff Emmett 46c2a0b035 feat: layered local-first data architecture — encrypted backup, relay persistence, at-rest encryption
Implement the 4-layer data model (device → encrypted backup → shared sync → federated):

- Extract shared encryption-utils from community-store (deriveSpaceKey, AES-256-GCM, rSEN format)
- Encrypt module docs at rest when space has meta.encrypted === true
- Fix relay mode persistence: relay-backup/relay-restore wire protocol + .automerge.enc blob storage
- Add backup store + REST API (PUT/GET/DELETE /api/backup/:space/:docId) with JWT auth
- Add client BackupSyncManager with delta-only push, full restore, auto-backup
- Wire backup stubs in encryptid-bridge to BackupSyncManager
- Add rspace-backups Docker volume
- Create docs/DATA-ARCHITECTURE.md design doc with threat model and data flow diagrams

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:09:07 -08:00
Jeff Emmett 9443178d1c feat: Phase 5 — remove PostgreSQL from rForum, rSpace now fully PG-free
Migrate rForum provisioning metadata from shared PG pool to Automerge.
rForum was the last module using PostgreSQL; shared/db/pool.ts is now archived.

- Create modules/rforum/schemas.ts (ForumDoc, ForumInstance, ProvisionLog)
- Rewrite mod.ts: replace sql with Automerge getDoc/changeDoc, add onInit
- Rewrite provisioner.ts: pass SyncServer, logStep/updateInstance via changeDoc
- Fix dashboard snake_case → camelCase field references
- Archive schema.sql and shared/db/pool.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:25:26 -08:00
Jeff Emmett 88d618c1af feat: replace My Account submenu with consolidated popup modal
Consolidates email, device, recovery, postal address, data storage,
and dark mode settings into a single scrollable modal with collapsible
section cards — matching the existing My Spaces modal pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:22:13 -08:00
Jeff Emmett 22db2f439f feat: client-side encryption wiring + space scoping UI (Phase 5+6)
Phase 5 — EncryptID → DocCrypto bridge:
- Add EncryptedDocBridge connecting WebAuthn PRF to document encryption
- Add per-doc relay mode to SyncServer (encrypted spaces bypass participant mode)
- Wire encryption toggle to syncServer.setRelayOnly() on PATCH /:slug/encryption
- Restore relay mode for encrypted spaces on server startup
- Initialize DocBridge from PRF on login, clear on sign-out (both login-button + identity)
- Use bridge helpers for encrypted backup toggle in My Account

Phase 6 — Space scoping UI:
- Add "Modules" tab to Edit Space modal (enable/disable modules, scope toggles, encryption)
- Auto-filter app switcher by space's enabledModules via renderShell()
- Show "G" badge on global-scoped modules in app switcher
- Show lock icon in header for encrypted spaces
- Add getSpaceShellMeta() helper for auto-populating shell options

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:50:16 -08:00
Jeff Emmett b2ea5e04cf feat: unified space lifecycle & module scoping contract (Phase 0+1)
Extend RSpaceModule with scoping, lifecycle hooks (onInit, onSpaceCreate/Delete
with SpaceLifecycleContext, onSpaceEnable/Disable), and DocSchema support.
Add scoping to all 25 modules (8 space, 11 global-configurable, 6 global-fixed).
Consolidate 4 space creation endpoints into shared createSpace() function.
Add enabledModules enforcement middleware and module configuration API
(GET/PATCH /api/spaces/:slug/modules). Deprecation header on /api/communities.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:35:41 -08:00
Jeff Emmett 1f0ef59369 feat: add flow tubes, stable particle animation, and interactive port wiring
Replace invisible particle-only flow visualization with colored 3D tubes
between layers, spread horizontally to avoid overlap. Particles now travel
along tube paths. Add click-to-wire interaction on I/O port chips with
visual feedback (glow/breathe/dim). Prevent animation restart on Automerge
sync by surgically updating flow elements in-place.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:55:16 -08:00
Jeff Emmett 5c21b64a99 feat: add My Account submenu with dark mode + encrypted backup toggles
Reorganize user dropdown into expandable "My Account" submenu containing
account actions (Add Email, Add Device, Recovery) plus Dark Mode and
Encrypted Backup toggle switches. Move theme toggle from toolbar into
account settings, default to dark mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:45:11 -08:00
Jeff Emmett a402caacd8 fix: app-switcher routes through tab system + canvas fills viewport in tab pane
- App-switcher now dispatches module-select event instead of full page navigation
  for same-origin links; shell routes through TabCache for instant tab switching
- Tab pane gets height:100% in canvas-layout mode so #canvas fills the viewport
  (fixes pan/zoom not working on empty canvas background)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:35:38 -08:00
Jeff Emmett be271de7fb feat: add Gnosis Safe + EncryptID passkey wallet abstraction
Derive a deterministic secp256k1 EOA from the passkey's PRF output via
HKDF-SHA256, enabling hardware-backed signing for x402 micropayments and
Safe treasury proposals without storing private keys.

Key changes:
- EOA key derivation with domain-separated HKDF (eoa-derivation.ts)
- Key manager integration with PRF-only EOA path (key-derivation.ts)
- Encrypted client-side wallet store for Safe associations (wallet-store.ts)
- Passkey-backed x402 signer replacing EVM_PRIVATE_KEY (passkey-signer.ts)
- Safe propose/confirm/execute proxy routes in rwallet (mod.ts)
- Wallet capability flag in JWT via users.wallet_address (server.ts)
- Payment operation permissions: x402, safe-propose, safe-execute (session.ts)

Privacy: Safe wallet associations stored client-side only (AES-256-GCM
encrypted localStorage). Server only knows user has wallet capability.

108 tests passing across 5 test suites.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:18:34 -08:00
Jeff Emmett 2a7071edb4 fix: use correct x402 facilitator URL (www.x402.org)
The bare domain x402.org/facilitator returns a 308 redirect that
breaks payment verification. Use www.x402.org/facilitator instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 23:39:07 -08:00
Jeff Emmett 3808b51a64 feat: strip demo pages to show just the interactive component
Demo pages now render the same clean shell as regular spaces — just the
<folk-*> component full-page, no marketing wrapper (hero, feature cards,
CTA). Descriptions belong on landing pages, not demos.

- Remove demo branch from 7 module route handlers (rcal, rcart, rfunds,
  rnotes, rtrips, rtube, rvote)
- Delete 7 demo.ts files (~1200 lines of dead markup)
- Remove renderDemoShell() and DEMO_PAGE_CSS from server/shell.ts
- Remove demoPage field from RSpaceModule interface
- Rename top rApp dropdown item from "rSpace" to "rStack"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:03:46 -08:00
Jeff Emmett a39cf6e1c2 feat: auto-provision personal spaces on first visit + redirect logged-in users from demo
Server-side middleware creates the user's personal space when they visit
{username}.rspace.online for the first time (token in cookie, verified once).
Client-side redirect sends logged-in demo users to their personal space.
"Try Demo" button sets a sessionStorage flag to bypass the redirect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:31:32 -08:00
Jeff Emmett ef1d93d7e9 feat(encryptid): persist login across subdomains via cross-domain cookie
EncryptID sessions were lost when navigating between rspace.online
subdomains (e.g. demo→cca) because localStorage is per-origin. Now
stores a domain-wide cookie (eid_token, domain=.rspace.online, 30 days)
alongside localStorage. On new subdomain visits, the cookie is synced
to localStorage at module load time. Expired tokens are auto-refreshed
via the server before being discarded. Sign-out clears both stores.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:10:36 -08:00