rspace-online/MODULE_SPEC.md

151 lines
5.6 KiB
Markdown

# 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)
```typescript
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