Covers 19 test cases: space CRUD, member add by username, role changes
(viewer/member/moderator/admin), email invites, removal, auth guards.
Run with: ./e2e/tests/space-members-api.sh <AUTH_TOKEN>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mailcow rejects noreply@rspace.online because the authenticated user
is noreply@rmail.online. Updated all SMTP_FROM and SMTP_USER defaults
to use rmail.online consistently: spaces invites, rSplat notifications,
EncryptID auth emails, and rCart payment receipts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
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>
The result fetch was constructing its own URL instead of using the
response_url returned by fal.ai's status poll. This caused 422 errors.
Now captures response_url from poll and uses it for result retrieval.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The spaces module was defaulting to http://localhost:3000 for EncryptID
API calls, which resolves to the rspace container itself (both run on
port 3000). Changed to http://encryptid:3000 matching server/index.ts.
Also improved error surfacing in /members/add endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phone photos (3-4MB, 4000px+) were failing with "Invalid image" on
fal.ai Hunyuan3D. Now resizes to max 1024px JPEG with sharp before
submitting, and uses PUBLIC_ORIGIN HTTPS URL instead of data URI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the floating action button toggle with the same collapse/expand
behavior as desktop. Toolbar sits as a compact icon column on the left,
panels open to the right, and corner tools move to bottom-right.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two race conditions caused closed tabs to resurrect:
1. syncTabsFromServer() fetch completing after a local close, merging
the stale server response back in
2. Debounced PUT killed by page navigation when closing the active tab,
so the server never learned about the close
Fix: track closed moduleIds per session to skip during merge, and flush
server PUT with keepalive:true before navigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The publicUrl helper was generating http:// URLs (x-forwarded-proto from
Traefik), causing fal.ai to fail with "Invalid image" 422 errors. Now
reads the staged image from disk and sends as base64 data URI for
reliable delivery. Also bumps poll timeout from 5 to 8 minutes and
surfaces actual fal.ai error messages to the client.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Peer-to-peer RV/camper rentals within community trust networks.
Forked from rBnb with vehicle-specific concepts: specs, mileage
policies, pickup/dropoff locations, and dry humor throughout.
4 seed vehicles, full CRUD API, Leaflet map with pickup/dropoff
markers, rental request flow, endorsement tags including
"suspiciously_clean" and "smells_like_adventure".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The communitySlug derivation was parsing path segments (e.g. /rcal) as
part of the space name instead of using the subdomain. On
jeff.rspace.online/rcal, this caused communitySlug to be "rcal" instead
of "jeff", making tab navigation redirect to rcal.rspace.online.
Now: on subdomain hosts, space always comes from the subdomain. Path
segments are only parsed for the space on localhost.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add four reminder scheduling affordances to the canvas:
- Floating 📅 icon on selected shapes toggles the reminder widget
- Right-click "Schedule a reminder" context menu option
- Drag-to-calendar compact mode (shows after 200ms of shape movement)
- Email notification via EncryptID on reminder creation
Closes TASK-122
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Hide CrowdSurf from app switcher (hidden: true) since it's now a
sub-tab of rChoices
- Replace dead outputPaths (Polls/Results with no routes) with actual
tabs: Spider Chart, Ranking, Voting, CrowdSurf
- Add /:tab route handler so sub-nav pills link to working URLs
- Component reads tab attribute for initial tab selection
- Remove internal .demo-tabs (shell sub-nav replaces them)
- Bump JS cache version to v=6
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Replace CrowdSurf tab placeholder with working swipe-card interface
populated from rChoices session data (or demo fallback). Uses seeded
PRNG (mulberry32 + djb2 hash) for deterministic daily sortition per
user, preventing position bias. Right-swipe = approve (casts vote via
local-first client), left-swipe = skip. Swipe state persists in
localStorage across page reloads. Includes summary view with
session-grouped approvals and reset functionality.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fal.ai needs to download the staged image. Using hardcoded PUBLIC_ORIGIN
(rspace.online) fails because Cloudflare redirects /data/ paths and the
subdomain (jeff.rspace.online) isn't matched. Now derives the public URL
from the request's Host header. Added logging for staged image URLs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cloudflare/Traefik 301-redirects /data/ paths to data.rspace.online, which
fal.ai can't follow. Staged images now served at /api/files/generated/ which
passes through correctly. Added route alias for backwards compat.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
In-memory gen3dJobs are lost on container restart. The poll was silently
swallowing 404s and looping forever. Now stops after 3 consecutive 404s
with a clear "server restarted" message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds margin-top to demo-tabs to prevent overlap with shell nav.
Hides tab labels on narrow screens (<=480px), showing only icons
so all 4 tabs fit. Bumps JS cache to v=4.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
activeLayerId was being written to the shared Automerge CRDT on every tab
switch, causing all open windows/devices to follow. Now active tab is
local-only. Adds REST API + server-side storage so authenticated users'
tab lists persist across sessions and devices.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Also fix canvas.html null reference crash when share-badge is stripped
by extractCanvasContent() header removal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a fourth sub-tab linking to the CrowdSurf module with teaser content.
Bumps JS cache version to v=3.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Browser ignores importmap when a <script type="module"> appears before it,
breaking Three.js imports and causing the 3D gen UI to hang at staging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GLB models now render inline 3D previews using Google's <model-viewer> web
component with auto-rotate. AI-generated models show source image thumbnails.
Fixed fal.ai result fetch with retry logic and detailed logging for diagnosis.
Save flow now uses save-generated API with thumbnail_url passthrough.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Defer initThreeViewer to next animation frame so the DOM has laid out
before reading container dimensions. Fall back to viewport size instead
of hardcoded 800x600 when container reports zero dimensions. Add proper
MIME types for GLB/GLTF file serving.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the Crowdsurfing protocol (gospelofchange/Crowdsurfing) as an
rSpace module with full local-first Automerge CRDT sync. Users propose
activities with commitment thresholds, others swipe to join and declare
contributions, and activities trigger when enough people commit.
Module includes schemas, local-first client, swipe UI dashboard with
pointer gesture detection, landing page, seed template data, and
Vite build integration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The canvas header is stripped when served via renderShell (extractCanvasContent),
removing the #share-badge button. The JS then crashes on shareBadge.addEventListener
which prevents all canvas interaction. Add null guards for all share panel elements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap formData() in try/catch with logging to diagnose Content-Type
issues through Cloudflare tunnel. Also fix client-side error handling
to clear progress timer and show actual error message on failure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default upload tab is now "Generate from Image"
- Entire dotted drop area is clickable to open file browser
- Update process3DGenJob to use Hunyuan3D v2.1 via fal.ai queue API
(was still using old Trellis endpoint)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default upload mode is now "Generate from Image" instead of splat upload
- Clicking anywhere in the dotted drop area opens the file browser
(not just the "browse" link)
- Add cursor: pointer to upload mode areas
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
- Switch to fal.ai queue API (submit/poll/result) with 5-min deadline
to avoid synchronous timeout on long-running textured mesh generation
- Bump controls z-index to 100 so buttons aren't obscured by the
GaussianSplats3D canvas overlay
- Update progress phases for Hunyuan3D timing (60-180s)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Synchronous fal.run endpoint times out for textured mesh generation.
Switch to queue.fal.run submit/poll/result pattern with 5-minute
deadline. Update client progress phases for longer generation time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SAM 3D was designed for object segmentation, not full-scene
reconstruction — failed on arbitrary images. Hunyuan3D v2.1 produces
high-quality textured GLB meshes from any single image reliably.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Text prompts require Grounding DINO to detect specific objects, which
fails on arbitrary images. Using a full-image bounding box bypasses
text detection entirely and reconstructs the whole scene as a Gaussian
splat.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- rtube: 4 live-split proxy routes (start/status/stop/hls), new "360 Live"
mode in folk-video-player with HLS.js multi-view grid player
- rmeets: ?api=1 route for Jitsi External API mode, new folk-jitsi-room
web component with 360° Director panel (canvas captureStream)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SAM 3D uses Grounding DINO which needs real noun classes, not abstract
terms. Use broad multi-class prompt with very low threshold (0.05) to
detect objects in any image type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SAM 3D requires a segmentation prompt — default "car" fails on
non-car images. Use "everything" with low threshold (0.2) to capture
full scenes including people and backgrounds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SAM 3D outputs native Gaussian splat .ply files (rendered via existing
initSplatViewer) instead of GLB meshes, with full-scene support including
people and backgrounds. Faster generation (5-30s vs 45-75s), $0.02/gen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server-side proxy routes (POST /api/360split, GET status, POST import) fetch
video from R2, submit to video360-splitter, and import results back. Frontend
adds Split 360° button with settings modal, progress polling, and library import.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>