rspace-online/MODULE_SPEC.md

5.6 KiB

rSpace — Collaborative Canvas Platform

Module ID: rspace Domain: rspace.online Version: 0.1.0 Framework: Bun / Hono / Automerge CRDT / Vite Status: Active

Purpose

Real-time collaborative canvas where groups can create, arrange, and interact with shapes representing different tools — notes, polls, maps, budgets, itineraries. The foundation layer for the r*.online ecosystem. Subdomain-based routing creates ephemeral or persistent community spaces.

Data Model

CRDT Document (Automerge)

interface CommunityDoc {
  meta: CommunityMeta;
  shapes: { [id: string]: ShapeData };
}

interface CommunityMeta {
  name: string;
  slug: string;
  createdAt: string;
  visibility: SpaceVisibility;
  ownerDID: string | null;
}

interface ShapeData {
  type: string;        // 'folk-note', 'folk-itinerary', 'demo-poll', etc.
  id: string;
  x: number;
  y: number;
  width: number;
  height: number;
  rotation: number;
  content?: string;
  sourceId?: string;   // For arrows/connections
  targetId?: string;
  [key: string]: unknown;  // Shape-specific properties
}

Storage

  • Primary: Automerge binary files at data/communities/{slug}.automerge
  • Fallback: JSON at data/communities/{slug}.json (auto-migrated)
  • In-memory cache with debounced saves (2s)

Permission Model

Space Integration

  • SpaceVisibility: All four levels (public, public_read, authenticated, members_only)
  • Default role for open spaces: PARTICIPANT (everyone can add shapes)

Capabilities

Capability Required SpaceRole AuthLevel Description
view_canvas VIEWER BASIC See canvas shapes and layout
add_shapes PARTICIPANT STANDARD Create new shapes on canvas
edit_own_shapes PARTICIPANT STANDARD Modify/delete own shapes
edit_any_shape MODERATOR STANDARD Modify/delete any user's shapes
delete_any_shape MODERATOR STANDARD Remove any shape
configure_space ADMIN ELEVATED Change visibility, name, settings

Module-Specific Overrides

Currently uses a boolean readOnly flag on WebSocket connections:

  • readOnly=true if visibility is public_read and user is unauthenticated
  • No per-shape ownership tracking yet (all authenticated users can edit all shapes)

Current Auth Implementation

  • EncryptID token verification via verifyEncryptIDToken()
  • evaluateSpaceAccess() at WebSocket upgrade and HTTP routes
  • extractToken() from Authorization header
  • authenticateWSUpgrade() for WebSocket connections

API Endpoints

HTTP Routes

Method Path Auth Required Capability Description
POST /api/communities Yes configure_space Create community
GET /api/communities/:slug Depends view_canvas Get community metadata
GET /api/communities/:slug/shapes Depends view_canvas Export shapes as JSON
POST /api/communities/:slug/shapes Yes add_shapes Add shapes via API
POST /api/communities/demo/reset Reset demo data (rate-limited)

WebSocket Protocol

Message Type Direction Purpose
sync Bidirectional Automerge binary sync messages
snapshot Server→Client Full JSON state (JSON mode clients)
presence Bidirectional Cursor/user presence updates
ping/pong Bidirectional Keep-alive heartbeat
update Client→Server Legacy shape update (JSON mode)
delete Client→Server Legacy shape deletion (JSON mode)
error Server→Client Auth/permission errors

Dual sync modes: Automerge (binary) for rich clients, JSON snapshot for simple clients.

Canvas Integration

rSpace IS the canvas. Other modules embed as shapes:

Shape Type Module Description
demo-poll rVote Embedded voting widget
folk-note rNotes Editable note card
folk-itinerary rTrips Trip timeline
folk-destination rMaps Map location marker
folk-budget rFunds Budget tracker
demo-expense rFunds Expense with split tracking
demo-cart-item rCart Shopping item
folk-token-mint rWallet Token issuance
folk-token-ledger rWallet Token distribution
folk-packing-list rTrips Checklist
folk-notebook rNotes Notebook container
folk-arrow Visual connection between shapes

Cross-Module Dependencies

Module Integration
All modules Shapes from every module render on the rSpace canvas
EncryptID Identity, authentication, DID-based ownership
rNetwork Community membership graph

Local-First / Offline Support

  • CRDT strategy: Automerge documents. Full offline editing supported.
  • Conflict resolution: Automerge's built-in LWW semantics. No manual conflict resolution needed.
  • Sync protocol: Custom WebSocket relay. Clients exchange Automerge sync messages via the server. Server maintains per-peer sync state.
  • Offline → online: On reconnect, client sends accumulated changes. Server merges and broadcasts.

Migration Plan

  1. Add members map to CommunityMeta for inline CRDT membership
  2. Replace boolean readOnly with SpaceRole in WebSocket connection data
  3. Use resolveSpaceRole() at WS upgrade to determine role
  4. Add hasCapability() checks in WS message handler before accepting writes
  5. Add per-shape createdBy DID tracking for own-vs-any permission distinction
  6. Add encryptIDSpaceRoleAuth() Hono middleware to HTTP API routes