--- id: TASK-118 title: 'Epic: Make all rApps multiplayer with "Pull rApplet to rSpace"' status: Done assignee: [] created_date: '2026-03-16 00:05' updated_date: '2026-03-16 00:51' labels: - epic - multiplayer - architecture milestone: Multiplayer Everything dependencies: [] priority: high --- ## Description Ensure every rApp module has: 1. **Multiplayer real-time sync** via existing Automerge/local-first stack — see other participants' changes live 2. **"Pull rApplet to rSpace" button** — a standard UI pattern letting space owners pull/enable an rApp module into their space from a global catalog ## Current State (27 modules) - **12 already have local-first/Automerge**: rbooks, rcal, rcart, rfiles, rflows, rinbox, rnotes, rsocials, rsplat, rtasks, rtrips, rvote - **2 use ephemeral WebSocket sync** (no Automerge): rmaps, rnetwork - **13 have NO real-time sync**: rchoices, rdata, rdesign, rdocs, rforum, rmeets, rphotos, rpubs, rswag, rtube, rwallet, rspace, rschedule ## "Pull rApplet to rSpace" Pattern A standardized UI component (`folk-applet-pull.ts`) that: - Shows available rApps as cards in a global catalog - Space owners can enable/disable modules per-space via PATCH `/:space/modules` - Each module card shows: name, icon, description, sync status, scope (space/global) - Enabled modules appear in the space's app switcher - Uses existing `enabledModules` API in `server/spaces.ts` ## Multiplayer Tiers ### Tier 1 — Already multiplayer (12 modules) — just need "Pull to rSpace" button rbooks, rcal, rcart, rfiles, rflows, rinbox, rnotes, rsocials, rsplat, rtasks, rtrips, rvote ### Tier 2 — Near-multiplayer, need Automerge integration (5 modules) - **rchoices**: Add schema + local-first-client for voting sessions, live vote tallies - **rswag**: Add schema for shared design state, collaborative editing - **rwallet**: Add schema for shared wallet watchlist, collaborative treasury view - **rschedule**: Already has schemas, needs local-first-client.ts + component sync - **rnetwork**: Already has WebSocket, add Automerge doc for CRM data persistence ### Tier 3 — UI-only wrappers, add lightweight sync (4 modules) - **rdata**: Sync dashboard config/filters across participants - **rphotos**: Sync album curation, shared selections - **rtube**: Sync playlists, watch parties, queue state - **rpubs**: Sync publication drafts, collaborative editing queue ### Tier 4 — External service wrappers, iframe-based (3 modules) - **rdesign** (Affine): Add space-scoped project linking, cannot sync internal state - **rdocs** (Docmost): Add space-scoped doc linking - **rmeets** (Jitsi): Add meeting history/scheduling sync ### Tier 5 — Infrastructure, minimal sync needed (3 modules) - **rforum**: Provision state only, sync forum URL/status per space - **rmaps**: Already has ephemeral WebSocket rooms — add persistent map annotations via Automerge - **rspace**: Core module — canvas state already synced via Automerge in host app ## Architecture Decisions - All new local-first clients follow the established pattern: `local-first-client.ts` + `schemas.ts` per module - Document ID format: `{space}:{module}:{collection}` - "Pull to rSpace" UI reuses existing `PATCH /:space/modules` API - Shared `folk-applet-catalog.ts` component renders the catalog modal ## Acceptance Criteria - [ ] #1 Every rApp module has real-time multiplayer sync or a clear reason why not (external iframe wrappers) - [ ] #2 Standard 'Pull rApplet to rSpace' UI exists in space settings and is accessible from app switcher - [ ] #3 Space owners can enable/disable any module via the catalog UI - [ ] #4 All new sync follows established local-first-client.ts + schemas.ts pattern - [ ] #5 Demo/unauthenticated mode still works as local-only fallback for all modules ## Implementation Notes All 14 sub-tasks complete. Every rApp module now has schemas.ts + local-first-client.ts for Automerge CRDT sync. Key modules (rchoices, rswag, rwallet) have full UI integration with LIVE indicators and real-time sync.