chore(backlog): add epic TASK-118 — multiplayer everything + pull rApplet to rSpace
Epic with 14 sub-tasks across 5 tiers: - Tier 1: Pull-to-rSpace for 12 existing multiplayer modules - Tier 2: Automerge sync for rchoices, rswag, rwallet, rschedule, rnetwork - Tier 3: Lightweight sync for rdata, rphotos, rtube, rpubs - Tier 4: Space-scoped linking for rdesign, rdocs, rmeets - Tier 5: Persistent annotations for rmaps, provision sync for rforum - Shared folk-applet-catalog.ts component (high priority) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
03de21ddd5
commit
8cdaf77e9a
|
|
@ -0,0 +1,77 @@
|
||||||
|
---
|
||||||
|
id: TASK-118
|
||||||
|
title: 'Epic: Make all rApps multiplayer with "Pull rApplet to rSpace"'
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:05'
|
||||||
|
labels:
|
||||||
|
- epic
|
||||||
|
- multiplayer
|
||||||
|
- architecture
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
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
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #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
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.1
|
||||||
|
title: Build shared folk-applet-catalog.ts component
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:05'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- ui
|
||||||
|
- shared
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: high
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
Create a reusable web component that renders the "Pull rApplet to rSpace" catalog modal.
|
||||||
|
|
||||||
|
## Component: `lib/folk-applet-catalog.ts`
|
||||||
|
- Fetches module list from `GET /:space/modules` API
|
||||||
|
- Renders cards grid: icon, name, description, enabled toggle, scope badge
|
||||||
|
- Toggle calls `PATCH /:space/modules` with updated `enabledModules` array
|
||||||
|
- Accessible from space settings and a "+" button in the app switcher
|
||||||
|
- Shows sync status indicator (multiplayer/local-only/external)
|
||||||
|
- Requires space owner authentication to toggle; read-only for members
|
||||||
|
|
||||||
|
## Shell integration: `server/shell.ts`
|
||||||
|
- Add "+" button to app switcher nav that opens the catalog modal
|
||||||
|
- Only visible to space owners (check `ownerDID` from space meta)
|
||||||
|
|
||||||
|
## Files to create/modify:
|
||||||
|
- `lib/folk-applet-catalog.ts` (new)
|
||||||
|
- `server/shell.ts` (add catalog trigger button)
|
||||||
|
- `server/index.ts` (register the new component JS)
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Catalog modal shows all registered modules with icon, name, description
|
||||||
|
- [ ] #2 Space owners can toggle modules on/off with immediate effect
|
||||||
|
- [ ] #3 Non-owners see read-only view of enabled modules
|
||||||
|
- [ ] #4 App switcher updates when modules are toggled
|
||||||
|
- [ ] #5 Works in demo mode with local-only toggle (no API call)
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.10
|
||||||
|
title: Add lightweight sync to rpubs (collaborative publication queue)
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:06'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-3
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: low
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rpubs compiles markdown to print-ready pocket books via Typst. Add Automerge sync for shared publication drafts and editorial queue.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rpubs/schemas.ts` — PubsDoc with publications, editorialQueue, comments
|
||||||
|
- `modules/rpubs/local-first-client.ts` — CRUD: saveDraft, addToQueue, addComment
|
||||||
|
|
||||||
|
## Schema:
|
||||||
|
```
|
||||||
|
PubsDoc {
|
||||||
|
meta: { module: 'pubs', collection: 'editorial', version: 1 }
|
||||||
|
publications: Record<string, { id, title, markdownContent, status, authorDid, updatedAt }>
|
||||||
|
editorialQueue: string[]
|
||||||
|
comments: Record<string, { pubId, authorDid, text, createdAt }[]>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Publication drafts sync between editors in real-time
|
||||||
|
- [ ] #2 Editorial queue shared across space members
|
||||||
|
- [ ] #3 Comments visible to all members
|
||||||
|
- [ ] #4 Demo mode works locally
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.11
|
||||||
|
title: 'Add space-scoped linking for external wrappers (rdesign, rdocs, rmeets)'
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:06'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-4
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: low
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
These 3 modules wrap external services (Affine, Docmost, Jitsi) via iframes. We can't sync their internal state, but we can add Automerge docs for space-scoped metadata: which projects/docs/rooms are linked to this space, access history, and meeting scheduling.
|
||||||
|
|
||||||
|
## rdesign (Affine)
|
||||||
|
- Schema: `DesignDoc { linkedProjects: Record<id, { url, name, addedBy }> }`
|
||||||
|
- Component: Show linked Affine projects, allow adding/removing
|
||||||
|
|
||||||
|
## rdocs (Docmost)
|
||||||
|
- Schema: `DocsDoc { linkedDocuments: Record<id, { url, title, addedBy }> }`
|
||||||
|
- Component: Show linked Docmost docs, allow adding/removing
|
||||||
|
|
||||||
|
## rmeets (Jitsi)
|
||||||
|
- Schema: `MeetsDoc { meetings: Record<id, { roomName, title, scheduledAt, hostDid, participants[] }>, meetingHistory[] }`
|
||||||
|
- Component: Schedule meetings, show history, quick-join links
|
||||||
|
|
||||||
|
Each needs: schemas.ts, local-first-client.ts, component integration.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Linked external projects/docs/rooms sync across space members
|
||||||
|
- [ ] #2 Meeting scheduling syncs in real-time
|
||||||
|
- [ ] #3 Adding/removing links requires authentication
|
||||||
|
- [ ] #4 Demo mode shows placeholder data
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.12
|
||||||
|
title: Add persistent map annotations to rmaps via Automerge
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:06'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-5
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: low
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rmaps already has ephemeral WebSocket rooms for live location sharing. Add an Automerge doc layer for persistent map annotations (pins, notes, routes, areas) that survive room disconnection.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rmaps/schemas.ts` — MapsDoc with annotations, savedRoutes, meetingPoints
|
||||||
|
- `modules/rmaps/local-first-client.ts` — CRUD: addAnnotation, saveRoute, setMeetingPoint
|
||||||
|
|
||||||
|
## Schema:
|
||||||
|
```
|
||||||
|
MapsDoc {
|
||||||
|
meta: { module: 'maps', collection: 'annotations', version: 1 }
|
||||||
|
annotations: Record<string, { id, type: 'pin'|'note'|'area', lat, lng, label, authorDid, createdAt }>
|
||||||
|
savedRoutes: Record<string, { id, name, waypoints[], authorDid }>
|
||||||
|
savedMeetingPoints: Record<string, { id, name, lat, lng, setBy }>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Ephemeral room sync (live location) remains unchanged.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Persistent annotations survive room disconnection
|
||||||
|
- [ ] #2 Saved routes and meeting points sync via Automerge
|
||||||
|
- [ ] #3 Ephemeral live location sharing still works unchanged
|
||||||
|
- [ ] #4 Demo mode works locally
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.13
|
||||||
|
title: Add forum provision state sync to rforum
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:07'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-5
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: low
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rforum provisions Discourse instances on Hetzner. Add minimal Automerge sync for forum provisioning state per space (URL, status, admin info).
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rforum/local-first-client.ts` — wraps existing schemas
|
||||||
|
|
||||||
|
## Schema (extend existing):
|
||||||
|
```
|
||||||
|
ForumDoc {
|
||||||
|
meta: { module: 'forum', collection: 'provision', version: 1 }
|
||||||
|
forums: Record<string, { url, status: 'provisioning'|'active'|'suspended', adminDid, createdAt }>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Minimal — just syncs which forum is linked to which space.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Forum provision state syncs across space members
|
||||||
|
- [ ] #2 All members can see forum URL and status
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.14
|
||||||
|
title: Add "Pull to rSpace" button to all 12 existing multiplayer modules
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:07'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-1
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies:
|
||||||
|
- TASK-118.1
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
The 12 modules that already have local-first/Automerge sync (rbooks, rcal, rcart, rfiles, rflows, rinbox, rnotes, rsocials, rsplat, rtasks, rtrips, rvote) need the standardized "Pull rApplet to rSpace" integration.
|
||||||
|
|
||||||
|
## What to do:
|
||||||
|
- Ensure each module's component checks `enabledModules` from space meta
|
||||||
|
- Add graceful "not enabled" state when module is disabled for a space
|
||||||
|
- Each module's landing/nav shows correctly in the folk-applet-catalog
|
||||||
|
|
||||||
|
This task depends on TASK-118.1 (the catalog component) being built first.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 All 12 modules show 'not enabled' state when disabled for a space
|
||||||
|
- [ ] #2 All 12 modules appear correctly in the applet catalog
|
||||||
|
- [ ] #3 Enabling/disabling a module immediately updates the app switcher
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.2
|
||||||
|
title: Add multiplayer sync to rchoices (voting/ranking sessions)
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:05'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-2
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rchoices is currently a stateless voting UI. Add Automerge-backed real-time sync for live collaborative voting sessions.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rchoices/schemas.ts` — ChoicesDoc with votingSessions, votes, rankings
|
||||||
|
- `modules/rchoices/local-first-client.ts` — CRUD: createSession, castVote, updateRanking
|
||||||
|
|
||||||
|
## Schema design:
|
||||||
|
```
|
||||||
|
ChoicesDoc {
|
||||||
|
meta: { module: 'choices', collection: 'sessions', version: 1 }
|
||||||
|
sessions: Record<string, { id, title, type: 'vote'|'rank'|'score', options: [], createdBy, createdAt }>
|
||||||
|
votes: Record<string, { sessionId, participantDid, choices: Record<optionId, number>, updatedAt }>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component updates (`folk-choices-*.ts`):
|
||||||
|
- Init local-first client, subscribe to doc changes
|
||||||
|
- Real-time vote tally updates as participants vote
|
||||||
|
- Show participant count and live results
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Voting sessions sync in real-time between participants
|
||||||
|
- [ ] #2 Vote tallies update live as votes come in
|
||||||
|
- [ ] #3 Session creator can configure vote type (single/multi/ranked)
|
||||||
|
- [ ] #4 Demo mode works with local-only state
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.3
|
||||||
|
title: Add multiplayer sync to rswag (collaborative swag design)
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:05'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-2
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: low
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rswag is a client-side design canvas. Add Automerge sync so multiple space members can collaborate on swag designs.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rswag/schemas.ts` — SwagDoc with designs, assets, selectedTemplate
|
||||||
|
- `modules/rswag/local-first-client.ts` — CRUD: saveDesign, updateCanvas, addAsset
|
||||||
|
|
||||||
|
## Schema design:
|
||||||
|
```
|
||||||
|
SwagDoc {
|
||||||
|
meta: { module: 'swag', collection: 'designs', version: 1 }
|
||||||
|
designs: Record<string, { id, name, templateId, canvasState: string, createdBy, updatedAt }>
|
||||||
|
activeDesignId: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component updates:
|
||||||
|
- Init local-first client on connectedCallback
|
||||||
|
- Debounced save of canvas state changes
|
||||||
|
- Live cursor/selection indicators for collaborators (stretch)
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Design state syncs between participants in real-time
|
||||||
|
- [ ] #2 Canvas changes debounced and saved via Automerge
|
||||||
|
- [ ] #3 Design list shared across space members
|
||||||
|
- [ ] #4 Demo mode works locally
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.4
|
||||||
|
title: Add multiplayer sync to rwallet (shared treasury view)
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:05'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-2
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rwallet currently renders client-side-only wallet data from Safe Global API. Add Automerge sync for shared watchlists and treasury annotations.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rwallet/schemas.ts` — WalletDoc with watchedAddresses, annotations, dashboardConfig
|
||||||
|
- `modules/rwallet/local-first-client.ts` — CRUD: addWatchAddress, setAnnotation, updateConfig
|
||||||
|
|
||||||
|
## Schema:
|
||||||
|
```
|
||||||
|
WalletDoc {
|
||||||
|
meta: { module: 'wallet', collection: 'treasury', version: 1 }
|
||||||
|
watchedAddresses: Record<string, { address, chain, label, addedBy, addedAt }>
|
||||||
|
annotations: Record<string, { txHash, note, authorDid, createdAt }>
|
||||||
|
dashboardConfig: { defaultChain, displayCurrency, layout }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component updates (`folk-wallet-viewer.ts`):
|
||||||
|
- Shared watchlist syncs across space members
|
||||||
|
- Transaction annotations visible to all
|
||||||
|
- Dashboard layout preferences synced
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Watched wallet addresses sync across space members
|
||||||
|
- [ ] #2 Transaction annotations visible to all space members
|
||||||
|
- [ ] #3 Dashboard config shared (chain, currency, layout)
|
||||||
|
- [ ] #4 Demo mode works with local-only state
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.5
|
||||||
|
title: Add local-first-client to rschedule
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:06'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-2
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rschedule already has Automerge schemas but lacks a local-first-client.ts for client-side sync. Add the client and wire it into the 3 components (automation-canvas, reminders-widget, schedule-app).
|
||||||
|
|
||||||
|
## New file:
|
||||||
|
- `modules/rschedule/local-first-client.ts` — wraps existing schemas with sync methods
|
||||||
|
|
||||||
|
## Component updates:
|
||||||
|
- All 3 components init the client, subscribe, and react to remote changes
|
||||||
|
- Scheduled jobs, reminders, and automations sync in real-time between space members
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 local-first-client.ts created following established pattern
|
||||||
|
- [ ] #2 All 3 components sync via Automerge
|
||||||
|
- [ ] #3 Reminders and scheduled jobs visible to all space members in real-time
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.6
|
||||||
|
title: Add Automerge persistence to rnetwork CRM data
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:06'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-2
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: medium
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rnetwork currently uses server-stored CRM data with WebSocket visualization. Add Automerge doc for persistent CRM relationship data that syncs via local-first stack alongside the existing WebSocket graph updates.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rnetwork/schemas.ts` — NetworkDoc with contacts, relationships, delegations
|
||||||
|
- `modules/rnetwork/local-first-client.ts` — CRUD for CRM data
|
||||||
|
|
||||||
|
## Schema:
|
||||||
|
```
|
||||||
|
NetworkDoc {
|
||||||
|
meta: { module: 'network', collection: 'crm', version: 1 }
|
||||||
|
contacts: Record<string, { did, name, role, tags[], addedBy, addedAt }>
|
||||||
|
relationships: Record<string, { fromDid, toDid, type, weight, note }>
|
||||||
|
graphLayout: { positions: Record<did, {x,y}>, zoom, pan }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Delegations already in PostgreSQL (trust-engine) — this is for CRM metadata only.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 CRM contact metadata syncs via Automerge between space members
|
||||||
|
- [ ] #2 Graph layout positions persist and sync
|
||||||
|
- [ ] #3 Existing WebSocket delegation UI still works unchanged
|
||||||
|
- [ ] #4 Demo mode works with local-only data
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.7
|
||||||
|
title: Add lightweight sync to rdata (shared analytics dashboard)
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:06'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-3
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: low
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rdata is a privacy-first analytics dashboard. Add Automerge sync so space members share dashboard configuration and filter state.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rdata/schemas.ts` — DataDoc with dashboardConfig, savedViews, filterPresets
|
||||||
|
- `modules/rdata/local-first-client.ts` — CRUD: saveView, updateFilters, setConfig
|
||||||
|
|
||||||
|
## Schema:
|
||||||
|
```
|
||||||
|
DataDoc {
|
||||||
|
meta: { module: 'data', collection: 'dashboard', version: 1 }
|
||||||
|
savedViews: Record<string, { id, name, filters, dateRange, metrics[], createdBy }>
|
||||||
|
activeViewId: string
|
||||||
|
sharedFilters: { dateRange, granularity, segments[] }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component updates:
|
||||||
|
- Dashboard filter changes sync between viewers
|
||||||
|
- Saved views shared across space members
|
||||||
|
- "Follow" mode: one member's view reflected to all
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Saved dashboard views sync across space members
|
||||||
|
- [ ] #2 Filter changes can optionally sync in real-time
|
||||||
|
- [ ] #3 Demo mode works with local-only state
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.8
|
||||||
|
title: Add lightweight sync to rphotos (shared album curation)
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:06'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-3
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: low
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rphotos wraps Immich for photo display. Add Automerge sync for shared album curation and selections.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rphotos/schemas.ts` — PhotosDoc with albums, selections, annotations
|
||||||
|
- `modules/rphotos/local-first-client.ts` — CRUD: createAlbum, addToAlbum, annotatePhoto
|
||||||
|
|
||||||
|
## Schema:
|
||||||
|
```
|
||||||
|
PhotosDoc {
|
||||||
|
meta: { module: 'photos', collection: 'curation', version: 1 }
|
||||||
|
albums: Record<string, { id, name, photoIds[], createdBy, updatedAt }>
|
||||||
|
selections: Record<string, { photoId, selectedBy[], note }>
|
||||||
|
activeAlbumId: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Photo IDs reference the external Immich instance — this syncs curation metadata only.
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Shared albums sync across space members
|
||||||
|
- [ ] #2 Photo selections and annotations visible to all
|
||||||
|
- [ ] #3 Demo mode works with local-only state
|
||||||
|
<!-- AC:END -->
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
id: TASK-118.9
|
||||||
|
title: Add lightweight sync to rtube (shared playlists/watch parties)
|
||||||
|
status: To Do
|
||||||
|
assignee: []
|
||||||
|
created_date: '2026-03-16 00:06'
|
||||||
|
labels:
|
||||||
|
- multiplayer
|
||||||
|
- tier-3
|
||||||
|
milestone: Multiplayer Everything
|
||||||
|
dependencies: []
|
||||||
|
parent_task_id: TASK-118
|
||||||
|
priority: low
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||||
|
rtube is a community video hosting UI. Add Automerge sync for shared playlists and watch party queue state.
|
||||||
|
|
||||||
|
## New files:
|
||||||
|
- `modules/rtube/schemas.ts` — TubeDoc with playlists, watchParty, queue
|
||||||
|
- `modules/rtube/local-first-client.ts` — CRUD: createPlaylist, addToPlaylist, updateQueue
|
||||||
|
|
||||||
|
## Schema:
|
||||||
|
```
|
||||||
|
TubeDoc {
|
||||||
|
meta: { module: 'tube', collection: 'playlists', version: 1 }
|
||||||
|
playlists: Record<string, { id, name, videoIds[], createdBy, updatedAt }>
|
||||||
|
watchParty: { active: boolean, currentVideoId, position, hostDid, participants[] }
|
||||||
|
queue: string[]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<!-- SECTION:DESCRIPTION:END -->
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
<!-- AC:BEGIN -->
|
||||||
|
- [ ] #1 Playlists sync across space members
|
||||||
|
- [ ] #2 Watch party state (current video, position) syncs in real-time
|
||||||
|
- [ ] #3 Demo mode works with local-only state
|
||||||
|
<!-- AC:END -->
|
||||||
Loading…
Reference in New Issue