5.6 KiB
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=trueif visibility ispublic_readand 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 routesextractToken()from Authorization headerauthenticateWSUpgrade()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
- Add
membersmap toCommunityMetafor inline CRDT membership - Replace boolean
readOnlywithSpaceRolein WebSocket connection data - Use
resolveSpaceRole()at WS upgrade to determine role - Add
hasCapability()checks in WS message handler before accepting writes - Add per-shape
createdByDID tracking for own-vs-any permission distinction - Add
encryptIDSpaceRoleAuth()Hono middleware to HTTP API routes