diff --git a/.gitignore b/.gitignore index 2048993..cd744a8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ dist/ # Data storage data/ -!modules/data/ +!modules/rdata/ # IDE .vscode/ @@ -23,6 +23,12 @@ Thumbs.db .env .env.local .env.*.local +open-notebook.env # Bun bun.lockb + +# Playwright +e2e/test-results/ +e2e/playwright-report/ +e2e/blob-report/ diff --git a/Dockerfile b/Dockerfile index a070599..f37b4ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,6 +39,7 @@ COPY --from=build /app/server ./server COPY --from=build /app/lib ./lib COPY --from=build /app/shared ./shared COPY --from=build /app/modules ./modules +COPY --from=build /app/src ./src COPY --from=build /app/package.json . COPY --from=build /encryptid-sdk /encryptid-sdk @@ -50,7 +51,8 @@ RUN mkdir -p /data/communities /data/books /data/swag-artifacts /data/files /dat # Copy entrypoint for Infisical secret injection COPY entrypoint.sh /app/entrypoint.sh -RUN chmod +x /app/entrypoint.sh +COPY scripts/ /app/scripts/ +RUN chmod +x /app/entrypoint.sh /app/scripts/*.sh # Set environment ENV NODE_ENV=production diff --git a/Dockerfile.encryptid b/Dockerfile.encryptid index 2136768..1191f86 100644 --- a/Dockerfile.encryptid +++ b/Dockerfile.encryptid @@ -1,14 +1,17 @@ # EncryptID Server Dockerfile # Multi-stage build for optimized production image +# Build context: . (rspace-online root), with additional_contexts for encryptid-sdk # Build stage FROM oven/bun:1.1 AS builder WORKDIR /app -# Copy package files and encryptid-sdk (build context is parent dir) -COPY rspace-online/package.json rspace-online/bun.lockb* ./ -COPY encryptid-sdk /encryptid-sdk/ +# Copy package files +COPY package.json bun.lock* ./ + +# Copy local SDK dependency (same pattern as main Dockerfile) +COPY --from=encryptid-sdk . /encryptid-sdk/ # Rewrite file: dependency to absolute path for Docker build RUN sed -i 's|"file:../encryptid-sdk"|"file:/encryptid-sdk"|' package.json @@ -17,9 +20,11 @@ RUN sed -i 's|"file:../encryptid-sdk"|"file:/encryptid-sdk"|' package.json RUN bun install --frozen-lockfile || bun install # Copy source -COPY rspace-online/src/encryptid ./src/encryptid -COPY rspace-online/public ./public -COPY rspace-online/tsconfig.json ./ +COPY src/encryptid ./src/encryptid +COPY shared/local-first ./shared/local-first +COPY server/notification-service.ts ./server/notification-service.ts +COPY public ./public +COPY tsconfig.json ./ # Build client-side modules for browser RUN bun build ./src/encryptid/index.ts --outdir=./src/encryptid/dist --target=browser --minify @@ -32,6 +37,8 @@ WORKDIR /app # Copy from builder COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/src/encryptid ./src/encryptid +COPY --from=builder /app/shared/local-first ./shared/local-first +COPY --from=builder /app/server/notification-service.ts ./server/notification-service.ts COPY --from=builder /app/public ./public COPY --from=builder /app/package.json ./ diff --git a/ONTOLOGY.md b/ONTOLOGY.md new file mode 100644 index 0000000..3b0c827 --- /dev/null +++ b/ONTOLOGY.md @@ -0,0 +1,378 @@ +# rSpace Ontology + +> A composable, local-first platform for collaborative knowledge work, +> democratic governance, and programmable economic flows. + +``` +┌─────────────────────────────────────────────────────────┐ +│ rStack Foundation │ +│ Identity · Data · Payments · Crypto · Sync │ +├─────────────────────────────────────────────────────────┤ +│ rSpace Platform │ +│ Spaces · Canvas · Modules · Flows · Nesting │ +├─────────────────────────────────────────────────────────┤ +│ rApps (26+ Modules) │ +│ Information · Economic · Democratic · Creative │ +└─────────────────────────────────────────────────────────┘ +``` + +--- + +## 1. rStack — Foundation Layer + +rStack is the infrastructure substrate that all rApps share. No module +implements its own auth, sync, encryption, or payments — they inherit +these capabilities from the stack. + +### 1.1 rIdentity (EncryptID) + +Self-sovereign identity via WebAuthn passkeys. No passwords, no seed +phrases, no custodial accounts. + +``` +Passkey (biometric/PIN on device) + → PRF extension yields hardware-bound salt + → HKDF Master Key (256-bit) + ├→ AES-256-GCM — encrypt documents, files, backups + ├→ Ed25519 — DID (did:key:z6Mk...) for identity + ├→ ECDSA P-256 — TLS-grade signing + └→ secp256k1 — Ethereum EOA for wallets & payments +``` + +**Auth Levels** (time-decaying, re-escalated by fresh passkey tap): +1. **Basic** — session token, read-only public content +2. **Standard** — recent auth (<15 min), normal operations +3. **Elevated** — fresh auth, wallet proposals & sensitive writes +4. **Critical** — fresh auth + explicit consent, key operations + +**Social Recovery** — no seed phrases, ever: +- Guardian types: secondary passkey, trusted contact (DID), hardware key, + institutional, time-delayed self-recovery (48h default) +- Threshold approval (e.g. 3-of-5 guardians) +- Old credential revoked, new one activated + +**Cross-app portability**: One DID works across all `r*.online` domains. +Passkey ceremony scoped to `rspace.online` RP ID, cookie shared across +subdomains. + +### 1.2 Local-First Data (Automerge CRDT) + +All data is local-first. Users own their data, the server is a +replication peer — not the source of truth. + +``` +┌──────────────┐ WebSocket ┌──────────────┐ +│ Browser │ ←── sync msgs ──→ │ Server │ +│ IndexedDB │ (Automerge) │ Filesystem │ +│ (primary) │ │ (replica) │ +└──────────────┘ └──────────────┘ + ↕ ↕ + Works offline Relays to peers + Merges on reconnect Persists for durability +``` + +**7-Layer Stack:** +1. **Crypto** — per-space, per-document AES-256-GCM encryption via HKDF + key hierarchy. Server stores only ciphertext. +2. **Document** — typed Automerge docs with versioned schemas and + migrations. IDs: `{space}:{module}:{collection}[:{item}]` +3. **Storage** — IndexedDB (client) + filesystem (server) with 2s + debounced persistence +4. **Sync** — single WebSocket per space, multiplexed across documents. + Incremental sync via Automerge `SyncState` (only deltas sent) +5. **Compute** — deterministic transforms (filter, aggregate, rollup) +6. **Query** — materialized views, full-text search indexes +7. **Application** — module-specific logic + +**Byzantine Fault Tolerance via CRDT:** +- Commutative: edit order doesn't matter +- Idempotent: replay-safe +- No coordinator: any peer can merge any version +- Causally consistent: happens-before relationships preserved +- Conflict-free: mathematical resolution, no manual merge + +### 1.3 Micropayments (x402) + +HTTP 402 Payment Required as a first-class protocol. Any route can +require payment by adding middleware. + +``` +Client Server Facilitator + │ │ │ + ├── GET /resource ──────────→ │ │ + │ │ │ + ←── 402 + requirements ────── │ │ + │ (payTo, amount, network) │ │ + │ │ │ + │ [user signs with passkey │ │ + │ via EOA or Safe wallet] │ │ + │ │ │ + ├── GET /resource ──────────→ │ │ + │ X-PAYMENT: ├── verify(proof) ──────→ │ + │ ←── { valid: true } ────── │ + ←── 200 OK + resource ────── │ │ +``` + +- **EVM chains**: Base, Ethereum, Optimism, Polygon, Arbitrum, etc. +- **Any ERC20**: USDC, native ETH, etc. +- **Wallet-abstracted**: passkey-derived EOA signs directly, or proposes + through Gnosis Safe multisig +- **Use cases**: file upload gates, AI generation costs, premium content, + per-query API access + +### 1.4 Wallet Abstraction (Gnosis Safe + Passkey EOA) + +``` +Passkey (biometric) + → secp256k1 private key (derived via HKDF) + → EOA address (Ethereum account) + → Safe owner/signer (multisig) + → Multi-chain treasury + ├→ Ethereum mainnet + ├→ Base / Optimism / Arbitrum (L2 rollups) + ├→ Polygon / Gnosis / Celo + └→ ... any EVM chain +``` + +No MetaMask. No hardware wallet required. Passkey IS the wallet. + +- **Safe Transaction Service**: propose → threshold confirm → execute +- **Multi-chain detection**: auto-discovers Safes across 12+ chains +- **Rollup-first**: L2 by default for low-cost transactions, settle to + L1 when needed + +--- + +## 2. rSpace — Platform Layer + +rSpace is the unification layer: routing, spaces, the spatial canvas, +module composition, and inter-module flows. + +### 2.1 Spaces + +A **space** is a collaborative context — a team, community, project, or +individual workspace. Each space has: + +- **Slug** + optional subdomain (`alice.rspace.online`) +- **Visibility**: `public` (👁 green — anyone reads, sign in to write) | `permissioned` (🔑 yellow — sign in to read & write) | `private` (🔒 red — invite-only) +- **Members**: `viewer` → `member` → `moderator` → `admin` +- **Enabled modules**: which rApps are available in this space +- **Module scoping**: per-module `space` (data lives in space) vs + `global` (data follows identity) +- **Automerge document**: the space itself is a CRDT — collaborative, + offline-capable, conflict-free + +**Nesting**: spaces can embed other spaces as shapes on their canvas. +Permissions (read, write, reshare) are scoped per-nest with optional +expiry. Consent policies: open, members-only, approval-required, closed. + +### 2.2 Canvas (FolkJS) + +The spatial substrate. An infinite 2D canvas where shapes (web +components) are positioned, connected, and composed. + +``` +Canvas (folk-canvas) + ├→ folk-markdown — rich text + ├→ folk-arrow — directed connections + ├→ folk-rapp — embedded module UI + ├→ folk-embed — external iframes + ├→ folk-image-gen — AI image generation + ├→ folk-map — geographic view + ├→ folk-calendar — time view + ├→ folk-token-mint — ERC20 creation + ├→ folk-choice-vote — governance + ├→ folk-canvas — nested canvas (recursive) + └→ ... 25+ shape types +``` + +Each shape stores `{ type, id, x, y, width, height, rotation, content, ... }` +in the space's Automerge document. Real-time collaborative: multiple +users see each other's cursors, selections, and edits. + +### 2.3 Module System + +Every rApp implements `RSpaceModule`: + +```typescript +interface RSpaceModule { + id: string; // 'rcal', 'rfunds', 'rvote' + name: string; // 'rCal', 'rFunds', 'rVote' + icon: string; // emoji + description: string; + routes: Hono; // mounted at /:space/:moduleId + standaloneDomain?: string; // 'rcal.online' + scoping: ModuleScoping; // space vs global + docSchemas?: DocSchema[]; // Automerge schemas + feeds?: FeedDefinition[]; // data this module exposes + acceptsFeeds?: FlowKind[]; // flow types it can consume + landingPage?: () => string; // standalone marketing page + onInit?, onSpaceCreate?, onSpaceDelete?: (ctx) => Promise; +} +``` + +Modules are composable: they expose **feeds** (typed data streams) and +consume feeds from other modules. The canvas visualizes these as +inter-layer flows. + +### 2.4 Flow Kinds + +Flows are typed connections between modules: + +| Kind | Description | Example | +|------|-------------|---------| +| `data` | Information flow | rNotes → rPubs (publish) | +| `economic` | Value/payment flow | rFunds → rWallet (treasury) | +| `trust` | Reputation/attestation | rVote → rNetwork (delegation) | +| `attention` | Signal/notification | rInbox → rForum (mentions) | +| `governance` | Decision/policy flow | rVote → rSpace (access control) | +| `creative` | Content generation | rDesign → rSwag (merch) | + +### 2.5 Routing + +``` +rcal.online → 301 → rspace.online/rcal (landing page) +alice.rcal.online → 301 → alice.rspace.online/rcal (space) +alice.rspace.online/rcal → /:space/rcal routes (module UI) +alice.rspace.online/rcal/api → /:space/rcal/api (REST API) +rspace.online/rcal → landing page (no space context) +``` + +Traefik → Cloudflare tunnel → Hono server. Each `r*.online` domain +redirects to the unified server with subdomain-based space routing. + +--- + +## 3. rApps — Module Layer + +26+ modules organized by function: + +### Information + +| Module | Domain | Purpose | +|--------|--------|---------| +| **rNotes** | rnotes.online | Collaborative notebooks (Automerge) | +| **rPubs** | rpubs.online | Long-form publishing (Typst PDF) | +| **rBooks** | rbooks.online | PDF library with flipbook reader | +| **rDocs** | rdocs.online | Document management | +| **rData** | rdata.online | Data visualization & analysis | + +### Planning & Spatial + +| Module | Domain | Purpose | +|--------|--------|---------| +| **rCal** | rcal.online | Spatio-temporal calendar with map + lunar overlay | +| **rMaps** | rmaps.online | Geographic mapping & location hierarchy | +| **rTrips** | rtrips.online | Trip planning with itineraries | +| **rTasks** | rtasks.online | Task boards & project management | +| **rSchedule** | rschedule.online | Persistent cron-based job scheduling with email, webhooks & briefings | + +### Communication + +| Module | Domain | Purpose | +|--------|--------|---------| +| **rForum** | rforum.online | Threaded discussions | +| **rInbox** | rinbox.online | Unified inbox (IMAP sync) | +| **rSocials** | rsocials.online | Social posts & feeds | + +### Democratic + +| Module | Domain | Purpose | +|--------|--------|---------| +| **rChoices** | rchoices.online | Multi-criteria decision-making (spider plots, ranking) | +| **rVote** | rvote.online | Proposal voting with delegation | + +### Economic + +| Module | Domain | Purpose | +|--------|--------|---------| +| **rFunds** | rfunds.online | Community funding & crowdfunding | +| **rWallet** | rwallet.online | Multi-chain Safe wallet interface | +| **rCart** | rcart.online | E-commerce & shopping | +| **rNetwork** | rnetwork.online | Social graph & reputation | + +### Creative + +| Module | Domain | Purpose | +|--------|--------|---------| +| **rSwag** | rswag.online | Merchandise design & production | +| **rPhotos** | rphotos.online | Photo galleries | +| **rTube** | rtube.online | Video hosting | +| **rSplat** | rsplat.online | 3D Gaussian splatting | +| **rDesign** | rdesign.online | Design system & components | +| **rFiles** | rfiles.online | Encrypted file storage | + +--- + +## 4. Design Principles + +### Data Sovereignty +Users own their data. Automerge documents live on-device first. +The server is a replication peer, not a gatekeeper. Per-document +encryption means the server stores only ciphertext. + +### Composability over Monolith +Each module is independently useful (`rcal.online` works standalone) +but gains power through composition on the canvas. Modules communicate +via typed feeds, not hard-wired integrations. + +### Identity without Custody +EncryptID derives all keys from a single passkey tap. No passwords, +no seed phrases, no custodial key storage. Social recovery replaces +mnemonic backup. The same identity works for signing documents, +encrypting data, and authorizing blockchain transactions. + +### Payments as Protocol +x402 makes payment a protocol primitive, not a product feature. Any +HTTP endpoint can require payment. The wallet is derived from the same +passkey — no separate wallet app needed. + +### Spatial-First +The canvas is the primary interface. Modules render as shapes that can +be positioned, connected, resized, and composed spatially. This enables +non-linear knowledge work: a funding proposal (rFunds) sits next to +the vote (rVote), the budget spreadsheet (rData), and the project +plan (rTasks) — all on one canvas, all synced in real-time. + +### Offline-First +Every interaction works offline. Changes queue locally and merge +conflict-free on reconnect. No loading spinners, no "connection lost" +errors, no data loss. + +--- + +## 5. Token & Value Architecture + +### Layer 1: Micropayments (x402) +Per-request payments for API access, file uploads, AI generation. +Settled on EVM L2 rollups (Base, Optimism) for sub-cent transaction +costs. Facilitator verifies payment proofs without requiring the app +to run its own blockchain node. + +### Layer 2: Treasury (Gnosis Safe) +Spaces can have multi-sig treasuries. Funding proposals (rFunds) +flow into Safe wallets. Threshold signing by space admins/moderators. +Multi-chain: same Safe address across L1 and L2s. + +### Layer 3: Governance Tokens (planned) +Module-minted ERC20 tokens via `folk-token-mint`. Voting power +in rVote tied to token holdings or delegation. Quadratic funding +in rFunds weighted by token-gated participation. + +### Layer 4: BFT Consensus via CRDT +Automerge provides Byzantine-fault-tolerant data replication without +a blockchain. For pure data collaboration (notes, calendars, tasks), +no on-chain settlement is needed. The CRDT IS the consensus mechanism. +Blockchain is used only when economic finality is required (payments, +token transfers, governance outcomes). + +### Rollup Strategy +``` +Data consensus → Automerge CRDT (off-chain, free, instant) +Payment settlement → L2 rollup (Base/Optimism, ~$0.001/tx) +Governance finality → L1 or L2 (when needed) +Token issuance → L2 (low-cost ERC20 deployment) +``` + +The principle: **use the cheapest layer that provides sufficient +guarantees**. Most operations never touch a blockchain. diff --git a/backlog/tasks/task-13 - Sprint-5-EncryptID-Cross-App-Integration.md b/backlog/completed/task-13 - Sprint-5-EncryptID-Cross-App-Integration.md similarity index 61% rename from backlog/tasks/task-13 - Sprint-5-EncryptID-Cross-App-Integration.md rename to backlog/completed/task-13 - Sprint-5-EncryptID-Cross-App-Integration.md index c38fad2..6906c43 100644 --- a/backlog/tasks/task-13 - Sprint-5-EncryptID-Cross-App-Integration.md +++ b/backlog/completed/task-13 - Sprint-5-EncryptID-Cross-App-Integration.md @@ -1,10 +1,10 @@ --- id: TASK-13 title: 'Sprint 5: EncryptID Cross-App Integration' -status: In Progress +status: Done assignee: [] created_date: '2026-02-05 15:38' -updated_date: '2026-02-17 21:42' +updated_date: '2026-03-11 23:00' labels: - encryptid - sprint-5 @@ -51,11 +51,11 @@ Integrate EncryptID across all r-ecosystem applications: ## Acceptance Criteria -- [ ] #1 rspace.online authenticates via EncryptID +- [x] #1 rspace.online authenticates via EncryptID - [ ] #2 rwallet.online connects to user's AA wallet -- [ ] #3 rvote.online accepts signed ballots +- [x] #3 rvote.online accepts signed ballots - [ ] #4 rfiles.online encrypts/decrypts with derived keys -- [ ] #5 rmaps.online uses EncryptID for auth +- [x] #5 rmaps.online uses EncryptID for auth - [x] #6 Single sign-on works across all apps - [x] #7 EncryptID SDK published and documented @@ -71,4 +71,25 @@ Integrate EncryptID across all r-ecosystem applications: - Automerge CommunityDoc extended with members map - Bidirectional sync via PATCH /api/communities/:slug/shapes/:shapeId - Remaining: Full per-app integration (AC #1-5) needs UI work in each module + +## Status check 2026-03-11 +SDK, token relay, space_members table, SpaceRole bridges all committed and merged. Remaining AC #1-5 are per-app UI integration — these are incremental and can be done module-by-module as each rApp gets attention. Not blocking other work. + +## Final Summary + + +## Completed: EncryptID Auth in rApps (partial — AC #1, #3, #5) + +Created `shared/auth-fetch.ts` with `authFetch()` (injects Bearer token) and `requireAuth()` (shows auth modal). + +**rvote (AC #3):** `castVote()`, `castFinalVote()`, `createProposal()` gated behind `requireAuth()` + `authFetch()`. Demo mode unaffected. + +**rfiles (AC #4 partial):** `handleUpload()`, `handleDelete()`, `handleShare()`, `handleCreateCard()`, `handleDeleteCard()` gated + using `authFetch()`. E2E encryption deferred. + +**rmaps (AC #5):** `createRoom()` gated; `ensureUserProfile()` uses `getUsername()` from EncryptID. + +**Deferred:** AC #2 (rwallet AA wallet), AC #4 full (E2E file encryption) — require deeper per-app integration. + +Commit: c4717e3 + diff --git a/backlog/completed/task-41 - Build-dynamic-Shape-Registry-to-replace-hardcoded-switch-statements.md b/backlog/completed/task-41 - Build-dynamic-Shape-Registry-to-replace-hardcoded-switch-statements.md new file mode 100644 index 0000000..63bd903 --- /dev/null +++ b/backlog/completed/task-41 - Build-dynamic-Shape-Registry-to-replace-hardcoded-switch-statements.md @@ -0,0 +1,60 @@ +--- +id: TASK-41 +title: Build dynamic Shape Registry to replace hardcoded switch statements +status: Done +assignee: [] +created_date: '2026-02-18 20:06' +updated_date: '2026-03-11 23:01' +labels: + - infrastructure + - phase-0 + - ecosystem +milestone: m-1 +dependencies: [] +references: + - rspace-online/lib/folk-shape.ts + - rspace-online/website/canvas.html + - rspace-online/lib/community-sync.ts +priority: high +--- + +## Description + + +Replace the 170-line switch statement in canvas.html's `createShapeElement()` and the 100-line type-switch in community-sync.ts's `#updateShapeElement()` with a dynamic ShapeRegistry. + +Create lib/shape-registry.ts with: +- ShapeRegistration interface (tagName, elementClass, defaults, category, portDescriptors, eventDescriptors) +- ShapeRegistry class with register(), createElement(), updateElement(), listAll(), getByCategory() +- Each folk-*.ts gets a static `registration` property and static `fromData()` method + +This is the prerequisite for all other ecosystem features (pipes, events, groups, nesting, embedding). + + +## Acceptance Criteria + +- [x] #1 ShapeRegistry class created with register/createElement/updateElement methods +- [x] #2 All 30+ folk-*.ts shapes have static registration property +- [x] #3 canvas.html switch statement replaced with registry.createElement() +- [x] #4 community-sync.ts type-switch replaced with registry.updateElement() +- [x] #5 All existing shapes still create and sync correctly +- [x] #6 No regression in shape creation or remote sync + + +## Final Summary + + +## Completed: Dynamic Shape Registry + +Created `lib/shape-registry.ts` — `ShapeRegistry` class with `register()`, `createElement()`, `updateElement()`, `has()`, `listAll()`. Singleton `shapeRegistry` exported from `lib/index.ts`. + +Added `static fromData(data)` and `applyData(data)` to all 41 shape classes (base `FolkShape` + 40 subclasses including `FolkArrow`). Each shape's creation/sync logic is now co-located with its `toJSON()`. + +Replaced 300-line `newShapeElement()` switch in `canvas.html` with ~25-line registry call. Special cases preserved: `wb-svg` whiteboard drawings, `folk-canvas` parentSlug, `folk-rapp` spaceSlug context defaults. + +Replaced 165-line `#updateShapeElement()` if-chain in `community-sync.ts` with single `shape.applyData(data)` delegation (~10 lines). + +All existing shapes create and sync identically. No TypeScript errors introduced. + +Commit: c4717e3 + diff --git a/backlog/completed/task-42 - Implement-Data-Pipes-typed-data-flow-through-arrows.md b/backlog/completed/task-42 - Implement-Data-Pipes-typed-data-flow-through-arrows.md new file mode 100644 index 0000000..23961f9 --- /dev/null +++ b/backlog/completed/task-42 - Implement-Data-Pipes-typed-data-flow-through-arrows.md @@ -0,0 +1,85 @@ +--- +id: TASK-42 +title: 'Implement Data Pipes: typed data flow through arrows' +status: Done +assignee: [] +created_date: '2026-02-18 20:06' +updated_date: '2026-03-11 23:01' +labels: + - feature + - phase-1 + - ecosystem +milestone: m-1 +dependencies: + - TASK-41 +references: + - rspace-online/lib/folk-arrow.ts + - rspace-online/lib/folk-shape.ts + - rspace-online/lib/folk-image-gen.ts + - rspace-online/lib/folk-prompt.ts +priority: high +--- + +## Description + + +Transform folk-arrow from visual-only connector into a typed data conduit between shapes. + +New file lib/data-types.ts: +- DataType enum: string, number, boolean, image-url, video-url, text, json, trigger, any +- Type compatibility matrix and isCompatible() function + +Add port mixin to FolkShape: +- ports map, getPort(), setPortValue(), onPortValueChanged() +- Port values stored in Automerge: doc.shapes[id].ports[name].value +- 100ms debounce on port propagation to prevent keystroke thrashing + +Enhance folk-arrow: +- sourcePort/targetPort fields referencing named ports +- Listen for port-value-changed on source, push to target +- Type compatibility check before pushing +- Visual: arrows tinted by data type, flow animation when active +- Port handle UI during connect mode + +Add port descriptors to AI shapes: +- folk-image-gen: input "prompt" (text), output "image" (image-url) +- folk-video-gen: input "prompt" (text), input "image" (image-url), output "video" (video-url) +- folk-prompt: input "context" (text), output "response" (text) +- folk-transcription: output "transcript" (text) + +Example pipeline: Transcription →[text]→ Prompt →[text]→ ImageGen →[image-url]→ VideoGen + + +## Acceptance Criteria + +- [x] #1 DataType system with compatibility matrix works +- [x] #2 Shapes can declare input/output ports via registration +- [x] #3 setPortValue() writes to Automerge and dispatches event +- [x] #4 folk-arrow pipes data from source port to target port +- [x] #5 Type incompatible connections show warning +- [x] #6 Arrows visually indicate data type and active flow +- [x] #7 Port values sync to remote clients via Automerge +- [x] #8 100ms debounce prevents thrashing on rapid changes + + +## Final Summary + + +## Completed: Data Pipes — typed data flow through arrows + +Created `lib/data-types.ts` — `DataType` union, `PortDescriptor` interface, `isCompatible()` type matrix, `dataTypeColor()` for arrow tints. + +Added port mixin to `FolkShape`: static `portDescriptors`, `#ports` Map, `initPorts()`, `setPortValue()` (dispatches `port-value-changed` CustomEvent), `getPortValue()`, `setPortValueSilent()`, `getInputPorts()`, `getOutputPorts()`. `toJSON()` includes port values; `applyData()` restores silently (no event dispatch = no sync loops). + +Enhanced `FolkArrow`: `sourcePort`/`targetPort` properties, `#setupPipe()` listener for `port-value-changed`, `isCompatible()` type check, 100ms debounce, arrow color tinted by `dataTypeColor()`. Listener cleanup on disconnect. `toJSON`/`fromData`/`applyData` include port fields. + +AI shape port descriptors: +- `folk-prompt`: input `context` (text) → output `response` (text) +- `folk-image-gen`: input `prompt` (text) → output `image` (image-url) +- `folk-video-gen`: input `prompt` (text) + `image` (image-url) → output `video` (video-url) +- `folk-transcription`: output `transcript` (text) + +Extended `ShapeData` interface with `sourcePort`, `targetPort`, `ports` fields. + +Commit: c4717e3 + diff --git a/backlog/config.yml b/backlog/config.yml index 71166f8..5752702 100644 --- a/backlog/config.yml +++ b/backlog/config.yml @@ -14,3 +14,4 @@ bypass_git_hooks: false check_active_branches: true active_branch_days: 30 task_prefix: "task" +onStatusChange: 'python3 /home/jeffe/Github/dev-ops/scripts/backlog-notify.py' diff --git a/backlog/tasks/task-100 - Tab-bar-touch-support-recent-apps-dropdown.md b/backlog/tasks/task-100 - Tab-bar-touch-support-recent-apps-dropdown.md new file mode 100644 index 0000000..71ab5f9 --- /dev/null +++ b/backlog/tasks/task-100 - Tab-bar-touch-support-recent-apps-dropdown.md @@ -0,0 +1,25 @@ +--- +id: TASK-100 +title: Tab bar touch support + recent apps dropdown +status: Done +assignee: [] +created_date: '2026-03-03 22:00' +labels: + - tab-bar + - UX + - mobile +dependencies: [] +priority: medium +--- + +## Description + + +Make the [+] tab button reliably clickable/touchable on mobile and desktop. Add touch event handlers alongside click events, increase touch target to 44px minimum, fix overflow clipping of the dropdown menu, and add a "Recent" section at the top of the rApp dropdown showing up to 6 most recently used apps sorted newest first. Recent apps persist in localStorage. + + +## Final Summary + + +Completed in commit 80e4259 (partial — tab tracking portion). Added touchend event handlers, 44px min touch target, touch-action:manipulation for tap delay elimination, overflow:visible fix for dropdown clipping, and Recent apps section with localStorage persistence tracking up to 6 most recently used apps. + diff --git a/backlog/tasks/task-101 - Slash-command-refinements-server-import-cleanup.md b/backlog/tasks/task-101 - Slash-command-refinements-server-import-cleanup.md new file mode 100644 index 0000000..a5ce4de --- /dev/null +++ b/backlog/tasks/task-101 - Slash-command-refinements-server-import-cleanup.md @@ -0,0 +1,24 @@ +--- +id: TASK-101 +title: Slash-command refinements + server import cleanup +status: Done +assignee: [] +created_date: '2026-03-03 22:00' +labels: + - chore + - cleanup +dependencies: [] +priority: low +--- + +## Description + + +Minor refinements to slash command handling and cleanup of unused/incorrect server-side imports across multiple files. + + +## Final Summary + + +Completed in commit 06f7d67: slash-command refinements, server import fixes, misc cleanup. + diff --git a/backlog/tasks/task-102 - rFunds-→-rFlows-Full-module-rename-mobile-touch-support-CSS-alignment.md b/backlog/tasks/task-102 - rFunds-→-rFlows-Full-module-rename-mobile-touch-support-CSS-alignment.md new file mode 100644 index 0000000..cb93838 --- /dev/null +++ b/backlog/tasks/task-102 - rFunds-→-rFlows-Full-module-rename-mobile-touch-support-CSS-alignment.md @@ -0,0 +1,49 @@ +--- +id: TASK-102 +title: 'rFunds → rFlows: Full module rename, mobile touch support & CSS alignment' +status: Done +assignee: [] +created_date: '2026-03-04 03:19' +labels: + - rflows + - refactor + - mobile + - css +dependencies: [] +priority: medium +--- + +## Description + + +Complete rename of the rfunds module to rflows across the entire rspace-online codebase, plus mobile touch support and CSS formatting alignment. + +**Rename scope:** Directory, files, classes, custom elements, CSS classes, schemas, module registration, cross-codebase references (32+ files), Vite build config, Docker/Traefik configs, domain references (rfunds.online → rflows.online). + +**Mobile touch:** Two-finger pinch-to-zoom and pan on the flow diagram SVG canvas, following the canvas.html gesture pattern. Includes center-point zoom, drag threshold, and touch-action: none. + +**CSS alignment:** Renamed .funds-* → .flows-* class prefixes, aligned with rSpace dark theme conventions (slate palette, 8px border-radius, system-ui font, thin scrollbar, 44px mobile tap targets). + + +## Acceptance Criteria + +- [ ] #1 All rfunds references renamed to rflows across 32+ files +- [ ] #2 Vite build produces dist/modules/rflows/ with folk-flows-app.js, folk-flow-river.js, flows.css +- [ ] #3 Module loads at /{space}/rflows with correct shell and module switcher +- [ ] #4 Canvas embed button shows rFlows and uses moduleId rflows +- [ ] #5 Two-finger pinch-to-zoom on flow diagram SVG works with center-point zoom +- [ ] #6 Two-finger pan on flow diagram works +- [ ] #7 Single-touch node drag works with 5px threshold +- [ ] #8 CSS uses .flows-* prefix, 8px border-radius, system-ui font, thin scrollbar +- [ ] #9 Mobile toolbar collapses at 768px with 44px tap targets +- [ ] #10 Docker/Traefik configs updated for rflows.online domain +- [ ] #11 EncryptID CORS updated for rflows.online + + +## Final Summary + + +Completed full rfunds → rflows rename across the entire rspace-online codebase (32+ files). Added mobile two-finger pinch-to-zoom and pan to the flow diagram SVG canvas following canvas.html's gesture pattern. Aligned CSS with rSpace dark theme conventions. Build verified — dist/modules/rflows/ outputs correctly. Deployed to production successfully. + +Commit: a6008a4 refactor: complete rfunds → rflows rename across configs and references + diff --git a/backlog/tasks/task-103 - rFlows-Green-flows-funnel-coloring-full-page-canvas-analytics-popout.md b/backlog/tasks/task-103 - rFlows-Green-flows-funnel-coloring-full-page-canvas-analytics-popout.md new file mode 100644 index 0000000..9d53a90 --- /dev/null +++ b/backlog/tasks/task-103 - rFlows-Green-flows-funnel-coloring-full-page-canvas-analytics-popout.md @@ -0,0 +1,48 @@ +--- +id: TASK-103 +title: 'rFlows: Green flows, funnel coloring, full-page canvas, analytics popout' +status: Done +assignee: [] +created_date: '2026-03-04 05:06' +labels: + - rFlows + - UX + - frontend +dependencies: [] +references: + - modules/rflows/components/folk-flows-app.ts + - modules/rflows/components/flows.css + - modules/rflows/lib/presets.ts +priority: medium +--- + +## Description + + +Overhaul the rFlows detail view UX: + +1. **All flow edges → green shades** — Source inflow (#10b981), spending (#34d399), overflow (#6ee7b7). Ignores alloc.color for consistent visual language. +2. **Funnel 3-state coloring** — Critical (red, below min), Sustained (amber, between thresholds), Overflow (green, above max). Replaces previous 4-way sufficient/abundant/seeking/critical logic. Glow matches state color. +3. **Full-page canvas** — Removed tab system (Diagram/River/Table/Transactions). Canvas fills 100vh. Nav overlay (back link + title) floats inside canvas container. +4. **Analytics popout** — Left-side slide-in panel with Overview + Transactions sub-tabs. Toggled via toolbar button or Escape key. Reuses existing table/transaction renderers. +5. **Removed river tab** — Deleted renderRiverTab() and mountRiver(). folk-flow-river.ts kept on disk. +6. **Updated legend** — Edge colors as squares, funnel states as circles (Critical/Sustained/Thriving). + + +## Acceptance Criteria + +- [ ] #1 Canvas fills entire viewport (no tab bar, no max-width constraint) +- [ ] #2 All flow edges are shades of green +- [ ] #3 Funnels: red when critical, amber when sustained, green when overflow +- [ ] #4 Analytics button in toolbar opens left-side panel with overview + transactions +- [ ] #5 Back button in nav overlay returns to landing page +- [ ] #6 Simulation and wiring still work +- [ ] #7 Editor panel (right side) still opens for node editing +- [ ] #8 Escape closes analytics panel + + +## Final Summary + + +Committed 676aaa7 on dev, merged to main. Two files changed: folk-flows-app.ts (199 line diff — removed tab system, added analytics panel, updated edge/funnel color logic) and flows.css (68 line diff — fullpage layout, nav overlay, analytics panel styles). TypeScript compiles clean. + diff --git a/backlog/tasks/task-104 - n8n-style-automation-canvas-for-rSchedule.md b/backlog/tasks/task-104 - n8n-style-automation-canvas-for-rSchedule.md new file mode 100644 index 0000000..4851e55 --- /dev/null +++ b/backlog/tasks/task-104 - n8n-style-automation-canvas-for-rSchedule.md @@ -0,0 +1,55 @@ +--- +id: TASK-104 +title: n8n-style automation canvas for rSchedule +status: Done +assignee: [] +created_date: '2026-03-10 18:43' +labels: + - rschedule + - feature + - automation +dependencies: [] +references: + - modules/rschedule/schemas.ts + - modules/rschedule/mod.ts + - modules/rschedule/components/folk-automation-canvas.ts + - modules/rschedule/components/automation-canvas.css + - vite.config.ts +priority: medium +--- + +## Description + + +Visual workflow builder at /:space/rschedule/reminders that lets users wire together triggers, conditions, and actions from any rApp — enabling automations like "if my location approaches home, notify family" or "when document sign-off completes, schedule posts and notify comms director." + +Built with SVG canvas (pan/zoom/Bezier wiring), 15 node types across 3 categories, REST-persisted CRUD, topological execution engine, cron tick loop integration, and webhook trigger endpoint. + + +## Acceptance Criteria + +- [ ] #1 Canvas loads at /:space/rschedule/reminders with node palette +- [ ] #2 Drag nodes from palette, wire ports, configure — auto-saves via REST +- [ ] #3 Run All on manual-trigger workflow — nodes animate, execution log shows results +- [ ] #4 Cron workflows execute on tick loop +- [ ] #5 POST to /api/workflows/webhook/:hookId triggers webhook workflows +- [ ] #6 Demo workflows render correctly on fresh space seed + + +## Final Summary + + +Implemented n8n-style automation canvas for rSchedule with 5 files (2490 lines added): + +**schemas.ts** — 15 automation node types (5 triggers, 4 conditions, 6 actions), NODE_CATALOG with typed ports and config schemas, Workflow/WorkflowNode/WorkflowEdge types, extended ScheduleDoc. + +**folk-automation-canvas.ts** — SVG canvas with pan/zoom, left sidebar node palette (drag-to-add), Bezier edge wiring between typed ports, right sidebar config panel driven by NODE_CATALOG, execution visualization, REST persistence with 1.5s debounced auto-save. + +**automation-canvas.css** — Full dark-theme styling, responsive mobile layout. + +**mod.ts** — Page route (GET /reminders), CRUD API (GET/POST/PUT/DELETE /api/workflows/*), topological execution engine with condition branching, tick loop integration for cron workflows, webhook trigger endpoint, 2 demo workflows (proximity notification + document sign-off pipeline). + +**vite.config.ts** — Build step for component + CSS copy. + +Commits: cc6b5a9 (dev), f22bc47 (main) + diff --git a/backlog/tasks/task-105 - Listmonk-newsletter-integration-with-EncryptID-auth.md b/backlog/tasks/task-105 - Listmonk-newsletter-integration-with-EncryptID-auth.md new file mode 100644 index 0000000..3db1891 --- /dev/null +++ b/backlog/tasks/task-105 - Listmonk-newsletter-integration-with-EncryptID-auth.md @@ -0,0 +1,43 @@ +--- +id: TASK-105 +title: Listmonk newsletter integration with EncryptID auth +status: Done +assignee: [] +created_date: '2026-03-10 19:26' +labels: + - rsocials + - listmonk + - auth + - integration +dependencies: [] +references: + - modules/rsocials/mod.ts + - modules/rsocials/lib/listmonk-proxy.ts + - modules/rsocials/components/folk-newsletter-manager.ts +priority: medium +--- + +## Description + + +Replace the raw Listmonk iframe on the rSocials newsletter-list page with a custom newsletter manager UI backed by API proxy routes. Per-space Listmonk credentials are stored in module settings and injected server-side via Basic Auth. All API routes are gated by EncryptID auth + space role checks (moderator+ for reads, admin for campaign creation). + + +## Acceptance Criteria + +- [ ] #1 Password setting type added to module settings framework +- [ ] #2 Listmonk URL/user/password configurable per-space in rSocials settings +- [ ] #3 API proxy routes forward requests to Listmonk with Basic Auth +- [ ] #4 Newsletter status/lists/subscribers/campaigns endpoints gated by EncryptID + role +- [ ] #5 Campaign creation restricted to admin role +- [ ] #6 folk-newsletter-manager web component with Lists/Subscribers/Campaigns tabs +- [ ] #7 Not-configured state shows setup instructions +- [ ] #8 Vite build entry produces folk-newsletter-manager.js bundle +- [ ] #9 Iframe route replaced with native component route + + +## Final Summary + + +## Changes\n\n### Modified files\n- `shared/module.ts` — Added `'password'` to `ModuleSettingType` union\n- `shared/components/rstack-space-switcher.ts` — Added password input branch in settings renderer\n- `modules/rsocials/mod.ts` — Added Listmonk settings schema, auth helper, 6 newsletter API proxy routes, replaced iframe route with component\n- `vite.config.ts` — Added build entry for folk-newsletter-manager.js + CSS copy\n\n### New files\n- `modules/rsocials/lib/listmonk-proxy.ts` — getListmonkConfig() + listmonkFetch() helpers\n- `modules/rsocials/components/folk-newsletter-manager.ts` — Web component with 3 tabs, auth-gated UI\n- `modules/rsocials/components/newsletter.css` — Component styles\n\nCommit: c92ca0f + diff --git a/backlog/tasks/task-106 - Add-ViewHistory-for-in-app-back-navigation-rename-rWork-→-rTasks.md b/backlog/tasks/task-106 - Add-ViewHistory-for-in-app-back-navigation-rename-rWork-→-rTasks.md new file mode 100644 index 0000000..641e179 --- /dev/null +++ b/backlog/tasks/task-106 - Add-ViewHistory-for-in-app-back-navigation-rename-rWork-→-rTasks.md @@ -0,0 +1,28 @@ +--- +id: TASK-106 +title: Add ViewHistory for in-app back navigation + rename rWork → rTasks +status: Done +assignee: [] +created_date: '2026-03-11 21:32' +labels: + - frontend + - navigation + - refactor +dependencies: [] +references: + - shared/view-history.ts + - modules/rtasks/ +priority: high +--- + +## Description + + +Created shared ViewHistory utility class providing stack-based back navigation for rApps with hierarchical views. Integrated into 10 rApps replacing hardcoded data-back targets. Also renamed rWork module to rTasks across entire codebase (70 files), deleted rwork.online Cloudflare zone, cleaned cloudflared config. + + +## Final Summary + + +Commit 31b0885 on dev+main. New shared/view-history.ts with ViewHistory class (push/back/canGoBack/peekBack/reset, max depth 20). Integrated into rtrips, rmaps, rtasks, rforum, rphotos, rvote, rnotes, rinbox, rschedule, rcart. Full rWork→rTasks rename: directory modules/rwork→modules/rtasks, component folk-work-board→folk-tasks-board, class FolkWorkBoard→FolkTasksBoard, all cross-module refs, docker-compose, vite config, encryptid CORS, landing pages. Removed rwork.online from cloudflared config and deleted its Cloudflare zone. + diff --git a/backlog/tasks/task-107 - My-Wallets-panel-in-identity-dropdown.md b/backlog/tasks/task-107 - My-Wallets-panel-in-identity-dropdown.md new file mode 100644 index 0000000..708b8ca --- /dev/null +++ b/backlog/tasks/task-107 - My-Wallets-panel-in-identity-dropdown.md @@ -0,0 +1,38 @@ +--- +id: TASK-107 +title: My Wallets panel in identity dropdown +status: Done +assignee: [] +created_date: '2026-03-11 21:33' +updated_date: '2026-03-11 21:37' +labels: + - identity + - wallet + - UI +dependencies: [] +references: + - shared/components/rstack-identity.ts +priority: medium +--- + +## Description + + +Added a "My Wallets" option to the avatar dropdown menu that opens a modal showing the user's rIdentity wallet and any connected browser wallets (MetaMask, Rainbow, etc. via EIP-6963 discovery). Provides quick wallet access without navigating to the full rWallet module. + + +## Acceptance Criteria + +- [x] #1 'My Wallets' item appears in avatar dropdown between 'My Spaces' and theme toggle +- [x] #2 Modal shows rIdentity wallet card with username, truncated DID, and Passkey badge +- [x] #3 EIP-6963 browser wallets detected and listed with icons and Connect buttons +- [x] #4 Connect flow calls eth_requestAccounts and displays resulting address +- [x] #5 'Open rWallet' button navigates to /{space}/rwallet +- [x] #6 Modal closes on X button or click-outside + + +## Final Summary + + +Implemented in commit e47cd35. Single-file change to `shared/components/rstack-identity.ts` (+215 lines):\n\n- Added `_WalletDiscovery` class for EIP-6963 browser wallet detection\n- Added dropdown item, click handler, `#showWalletsModal()` method\n- Added `WALLETS_STYLES` CSS matching existing dark theme\n- Connected wallets are ephemeral (no persistent linking)\n- No token balance fetching (that's rWallet's job) + diff --git a/backlog/tasks/task-108 - rNetwork-CRM-—-inline-force-directed-graph-in-Graph-tab.md b/backlog/tasks/task-108 - rNetwork-CRM-—-inline-force-directed-graph-in-Graph-tab.md new file mode 100644 index 0000000..7b75dab --- /dev/null +++ b/backlog/tasks/task-108 - rNetwork-CRM-—-inline-force-directed-graph-in-Graph-tab.md @@ -0,0 +1,38 @@ +--- +id: TASK-108 +title: rNetwork CRM — inline force-directed graph in Graph tab +status: Done +assignee: [] +created_date: '2026-03-11 21:38' +updated_date: '2026-03-11 21:38' +labels: + - rnetwork + - frontend + - graph +dependencies: + - TASK-98 +references: + - modules/rnetwork/components/folk-crm-view.ts +priority: medium +--- + +## Description + + +Replace the Graph tab's external link with an interactive SVG graph rendered directly inside folk-crm-view.ts using the CRM data already loaded (people, companies, opportunities). Companies appear as colored clusters with people orbiting around them. Cross-org opportunity links shown as dashed purple edges. Includes pan/zoom/drag interactions and auto fit-to-view. + + +## Acceptance Criteria + +- [x] #1 Graph tab renders inline SVG with company clusters and person nodes +- [x] #2 Force-directed layout with pan/zoom/drag interactions +- [x] #3 Cross-org edges from opportunities shown as dashed purple lines +- [x] #4 Auto fit-to-view on tab switch, empty state for no data +- [x] #5 Vite build passes with no TS errors + + +## Final Summary + + +Implemented in commit c36b0ab on dev, merged to main.\n\nAdded ~460 lines to folk-crm-view.ts:\n- buildGraphData() derives nodes/edges from CRM people, companies, opportunities\n- computeGraphLayout() runs 70-iteration force simulation\n- renderGraphTab() outputs SVG with cluster/edge/node layers + zoom controls + legend\n- Full pointer interactions: drag nodes, pan canvas, wheel zoom, click-to-select\n- updateGraphNodePosition() for incremental drag without re-render + diff --git a/backlog/tasks/task-109 - QR-Code-Payment-Requests-for-rCart.md b/backlog/tasks/task-109 - QR-Code-Payment-Requests-for-rCart.md new file mode 100644 index 0000000..b99d2bf --- /dev/null +++ b/backlog/tasks/task-109 - QR-Code-Payment-Requests-for-rCart.md @@ -0,0 +1,75 @@ +--- +id: TASK-109 +title: QR Code Payment Requests for rCart +status: Done +assignee: [] +created_date: '2026-03-11 23:43' +labels: + - rcart + - payments + - QR + - crypto +dependencies: [] +references: + - modules/rcart/mod.ts + - modules/rcart/schemas.ts + - modules/rcart/components/folk-payment-page.ts + - modules/rcart/components/folk-payment-request.ts + - shared/transak.ts +priority: high +--- + +## Description + + +Add shareable QR code payment system to rCart. When scanned, the QR opens a public payment page where anyone can pay via credit card (Transak), external wallet (MetaMask via EIP-6963), or EncryptID passkey-derived EOA. + +Includes: +- PaymentRequestDoc schema with payment type, inventory limits, enabled methods +- 7 API endpoints (create, list, get, update status, QR SVG, Transak session, page routes) +- folk-payment-page.ts: payer-facing 3-tab payment page (Card/Wallet/EncryptID) +- folk-payment-request.ts: self-service QR generator with passkey auth +- Payment type: single (one-time) or subscription (reusable QR, accepts multiple payments) +- Inventory limits: maxPayments cap with auto-fill status when limit reached +- Payment method toggles: enable/disable card/wallet/encryptid per payment request +- Extracted shared Transak utilities to shared/transak.ts +- publicWrite on cartModule for public payment page access + + +## Acceptance Criteria + +- [ ] #1 POST /api/payments creates payment request with all fields +- [ ] #2 GET /pay/:id renders public payment page with enabled tabs only +- [ ] #3 GET /request renders self-service QR generator with passkey auth +- [ ] #4 GET /api/payments/:id/qr returns SVG QR code +- [ ] #5 Payment type toggle: single vs subscription +- [ ] #6 Inventory limit: maxPayments with auto-fill when reached +- [ ] #7 Payment method toggles: card/wallet/encryptid per request +- [ ] #8 Wallet tab: EIP-6963 discovery + ERC-20/ETH transfer +- [ ] #9 Card tab: Transak iframe integration +- [ ] #10 EncryptID tab: passkey + viem signing + + +## Final Summary + + +Implemented full QR code payment request system for rCart across two sessions: + +**Session 1** — Core implementation: +- Created PaymentRequestDoc schema with Automerge CRDT storage +- Added 7 API routes: create, list, get, status update, QR SVG, Transak session, page routes +- Built folk-payment-page.ts (payer-facing, 3 tabs: Card/Wallet/EncryptID) +- Built folk-payment-request.ts (self-service QR generator with passkey auth) +- Extracted Transak utils to shared/transak.ts, updated rFlows import +- Added amountEditable support for tip/donation use cases + +**Session 2** — Enhancements + 403 fix: +- Fixed 403 "write access required" by adding publicWrite to cartModule +- Added paymentType: 'single' | 'subscription' toggle +- Added maxPayments inventory limit with paymentCount tracking + 'filled' status +- Added enabledMethods toggles (card/wallet/encryptid) per payment request +- Payment page only renders enabled tabs, shows inventory progress bar +- Subscriptions reset to pending after each payment until filled + +Commits: 636fc13, deployed to production. + diff --git a/backlog/tasks/task-110 - Module-sub-nav-bar-rCart-UX-polish.md b/backlog/tasks/task-110 - Module-sub-nav-bar-rCart-UX-polish.md new file mode 100644 index 0000000..e3b1094 --- /dev/null +++ b/backlog/tasks/task-110 - Module-sub-nav-bar-rCart-UX-polish.md @@ -0,0 +1,41 @@ +--- +id: TASK-110 +title: Module sub-nav bar + rCart UX polish +status: Done +assignee: [] +created_date: '2026-03-12 04:02' +updated_date: '2026-03-12 04:02' +labels: + - shell + - rcart + - ux + - typescript +dependencies: [] +priority: medium +--- + +## Description + + +Add a secondary horizontal pill navigation bar to the shell showing each module's outputPaths and subPageInfos as navigable links. Polish rCart group buy page with fill-up visual, hero stats, warm gradient progress bar, pledge avatars, and green CTA. Fix 3 pre-existing TS build errors. + + +## Acceptance Criteria + +- [x] #1 Sub-nav bar renders between tab-row and
for modules with outputPaths/subPageInfos +- [x] #2 Active pill highlighted via client-side pathname matching +- [x] #3 Hidden in iframe-embedded mode +- [x] #4 rCart /buy/:id renamed to /group-buy/:id with updated shareUrl +- [x] #5 rCart outputPaths: carts, catalog, orders, payments, group-buys +- [x] #6 rinbox outputPaths: mailboxes +- [x] #7 Group buy page: hero card with stat boxes, fill-up liquid visual, warm gradient progress bar, pledge avatars, green CTA, responsive +- [x] #8 TS error fixed: walletAddress added to rstack-identity SessionState.eid +- [x] #9 TS errors fixed: ambient type declarations for 3d-force-graph and three +- [x] #10 Build passes (tsc --noEmit + vite build) + + +## Final Summary + + +Committed as adb0d17 on dev, merged to main, deployed to Netcup.\n\nFiles changed:\n- server/shell.ts — renderModuleSubNav() + SUBNAV_CSS\n- modules/rcart/mod.ts — route rename, outputPaths update\n- modules/rcart/components/folk-group-buy-page.ts — full UX overhaul\n- modules/rcart/components/cart.css — flex centering for narrow pages\n- modules/rcart/components/folk-payment-page.ts, folk-payment-request.ts — width fix\n- modules/rinbox/mod.ts — added mailboxes outputPath\n- shared/components/rstack-identity.ts — walletAddress type fix\n- types/3d-force-graph.d.ts, types/three.d.ts — new ambient declarations + diff --git a/backlog/tasks/task-111 - rMortgage-sub-tab-in-rFlows-—-trust-based-lending-tracker.md b/backlog/tasks/task-111 - rMortgage-sub-tab-in-rFlows-—-trust-based-lending-tracker.md new file mode 100644 index 0000000..e0aa44d --- /dev/null +++ b/backlog/tasks/task-111 - rMortgage-sub-tab-in-rFlows-—-trust-based-lending-tracker.md @@ -0,0 +1,30 @@ +--- +id: TASK-111 +title: rMortgage sub-tab in rFlows — trust-based lending tracker +status: Done +assignee: [] +created_date: '2026-03-15 19:14' +labels: + - rflows + - mortgage + - defi +dependencies: [] +references: + - modules/rflows/mod.ts + - modules/rflows/components/folk-flows-app.ts + - modules/rflows/lib/types.ts + - modules/rflows/schemas.ts +priority: medium +--- + +## Description + + +Added /mortgage sub-tab to rFlows with social trust-based mortgage lending visualization. Includes: pool summary cards (clickable for aggregate view), active mortgages table with trust scores, borrower options panel (5/10/15yr terms constrained to monthly budget, lenders fill in trust-score order), lender detail vessel SVGs (outstanding/repaid/reinvested), earnings comparison bars showing reinvestment advantage, projection calculator, and live Aave V3 rate fetching on Base. Demo seed data with 4 mortgage positions + 2 reinvestment positions. + + +## Final Summary + + +Implemented full rMortgage sub-tab: route at /:space/rflows/mortgage, API endpoints (GET/POST positions, GET rates from Aave V3 on Base), FlowsDoc schema v3 with mortgagePositions/reinvestmentPositions, vessel SVG visualizations, borrower options with lender fill bars, aggregate pool stats, earnings comparison showing reinvestment profitability. Deployed to demo.rspace.online. + diff --git a/backlog/tasks/task-112 - Auto-yield-for-idle-treasury-—-Aave-V3-Morpho-Blue-integration.md b/backlog/tasks/task-112 - Auto-yield-for-idle-treasury-—-Aave-V3-Morpho-Blue-integration.md new file mode 100644 index 0000000..7dacab3 --- /dev/null +++ b/backlog/tasks/task-112 - Auto-yield-for-idle-treasury-—-Aave-V3-Morpho-Blue-integration.md @@ -0,0 +1,32 @@ +--- +id: TASK-112 +title: Auto-yield for idle treasury — Aave V3 + Morpho Blue integration +status: Done +assignee: [] +created_date: '2026-03-15 19:14' +labels: + - rwallet + - defi + - yield +dependencies: [] +references: + - modules/rwallet/mod.ts + - modules/rwallet/lib/yield-rates.ts + - modules/rwallet/lib/yield-strategy.ts + - modules/rwallet/lib/yield-positions.ts + - modules/rwallet/lib/yield-protocols.ts + - modules/rwallet/lib/yield-tx-builder.ts +priority: medium +--- + +## Description + + +Added yield management to rWallet: live Aave V3 and Morpho Blue supply rates for USDC/USDT on Base/Ethereum, auto-yield strategy engine (threshold-based allocation), yield position tracking, transaction builder for deposit/withdraw, and /yield sub-page in rWallet showing rates, positions, and projected earnings. + + +## Final Summary + + +Created 5 yield library files + routes + UI. Live rates from Aave V3 Pool contract on Base (getReserveData RPC). Morpho Blue rates via public API. Auto-yield strategy allocates idle treasury above threshold. Yield page at /:space/rwallet/yield with rate cards, position table, and projection calculator. + diff --git a/backlog/tasks/task-113 - Braid-transport-toggle-SimpletonClient-integration-payment-infra.md b/backlog/tasks/task-113 - Braid-transport-toggle-SimpletonClient-integration-payment-infra.md new file mode 100644 index 0000000..2a8bd16 --- /dev/null +++ b/backlog/tasks/task-113 - Braid-transport-toggle-SimpletonClient-integration-payment-infra.md @@ -0,0 +1,30 @@ +--- +id: TASK-113 +title: Braid transport toggle + SimpletonClient integration (payment-infra) +status: Done +assignee: [] +created_date: '2026-03-15 19:14' +labels: + - payment-infra + - braid + - consensus +dependencies: [] +references: + - payment-infra/docker-compose.yml + - payment-infra/services/wallet-service/src/services/braid-state-client.ts + - payment-infra/services/onramp-service/src/braid-state-client.ts + - payment-infra/services/consensus-service/docs/NODE_OPERATOR_GUIDE.md +priority: medium +--- + +## Description + + +Added TRANSPORT env var to payment-infra docker-compose.yml for all consensus nodes (default: websocket, set to 'braid' for single-port HTTP sync). Created BraidStateClient (Simpleton pattern) for wallet-service and onramp-service — zero-CRDT light client via Braid-HTTP subscription. Wallet-service balance reads use local cache when Braid connected. Onramp-service escrow-watcher monitors deposit confirmations via Braid. Updated NODE_OPERATOR_GUIDE.md with transport modes docs. + + +## Final Summary + + +Completed payment-infra tasks 19, 20, 21. TRANSPORT env var on all 4 consensus nodes + wallet-service + onramp-service. Traefik /braid path routing. BraidStateClient in both consumer services with auto-reconnect. Merged to main. + diff --git a/backlog/tasks/task-114 - Get-Transak-API-credentials-and-configure-webhook.md b/backlog/tasks/task-114 - Get-Transak-API-credentials-and-configure-webhook.md new file mode 100644 index 0000000..2d17df6 --- /dev/null +++ b/backlog/tasks/task-114 - Get-Transak-API-credentials-and-configure-webhook.md @@ -0,0 +1,19 @@ +--- +id: TASK-114 +title: Get Transak API credentials and configure webhook +status: To Do +assignee: [] +created_date: '2026-03-15 19:14' +labels: + - payment-infra + - transak + - signup-required +dependencies: [] +priority: high +--- + +## Description + + +Register at dashboard.transak.com, obtain API key and webhook secret, configure webhook URL pointing to payment-infra onramp-service (/api/onramp/transak/webhook). Configure Transak for USDC on Base network. Store credentials in Infisical. Requires manual signup. + diff --git a/backlog/tasks/task-115 - Get-Basescan-API-key-and-verify-deployed-contracts.md b/backlog/tasks/task-115 - Get-Basescan-API-key-and-verify-deployed-contracts.md new file mode 100644 index 0000000..a966b40 --- /dev/null +++ b/backlog/tasks/task-115 - Get-Basescan-API-key-and-verify-deployed-contracts.md @@ -0,0 +1,19 @@ +--- +id: TASK-115 +title: Get Basescan API key and verify deployed contracts +status: To Do +assignee: [] +created_date: '2026-03-15 19:14' +labels: + - payment-infra + - basescan + - signup-required +dependencies: [] +priority: medium +--- + +## Description + + +Register at basescan.org/apis for an API key. Use it to verify CRDTToken and USDCEscrow contracts on Base Sepolia so source code is publicly readable. Store API key in Infisical. Requires manual signup. + diff --git a/backlog/tasks/task-116 - Test-CRDT-escrow-deposit-flow-on-Base-Sepolia.md b/backlog/tasks/task-116 - Test-CRDT-escrow-deposit-flow-on-Base-Sepolia.md new file mode 100644 index 0000000..37678cf --- /dev/null +++ b/backlog/tasks/task-116 - Test-CRDT-escrow-deposit-flow-on-Base-Sepolia.md @@ -0,0 +1,20 @@ +--- +id: TASK-116 +title: Test CRDT escrow deposit flow on Base Sepolia +status: To Do +assignee: [] +created_date: '2026-03-15 19:15' +labels: + - payment-infra + - testing + - signup-required +dependencies: + - TASK-114 +priority: high +--- + +## Description + + +Get testnet USDC from Circle faucet (faucet.circle.com), test the full deposit flow: approve USDC → deposit to USDCEscrow → escrow-watcher detects event → bridges to consensus layer → balance reflected in CRDT ledger. Also test withdrawal path. Depends on Transak credentials (TASK-114) for webhook path testing. Requires manual blockchain transactions. + diff --git a/backlog/tasks/task-117 - Deploy-CRDT-escrow-contracts-to-Base-mainnet.md b/backlog/tasks/task-117 - Deploy-CRDT-escrow-contracts-to-Base-mainnet.md new file mode 100644 index 0000000..6ccdc40 --- /dev/null +++ b/backlog/tasks/task-117 - Deploy-CRDT-escrow-contracts-to-Base-mainnet.md @@ -0,0 +1,22 @@ +--- +id: TASK-117 +title: Deploy CRDT escrow contracts to Base mainnet +status: To Do +assignee: [] +created_date: '2026-03-15 19:15' +labels: + - payment-infra + - deployment + - signup-required +dependencies: + - TASK-114 + - TASK-115 + - TASK-116 +priority: medium +--- + +## Description + + +Deploy CRDTToken and USDCEscrow contracts to Base mainnet. Requires ETH for gas, Basescan API key for verification (TASK-115), Transak production mode (TASK-114), and successful testnet testing (TASK-116). Transfer ownership to multisig/Safe after deployment. + diff --git a/backlog/tasks/task-118 - Epic-Make-all-rApps-multiplayer-with-Pull-rApplet-to-rSpace.md b/backlog/tasks/task-118 - Epic-Make-all-rApps-multiplayer-with-Pull-rApplet-to-rSpace.md new file mode 100644 index 0000000..c6b9ef7 --- /dev/null +++ b/backlog/tasks/task-118 - Epic-Make-all-rApps-multiplayer-with-Pull-rApplet-to-rSpace.md @@ -0,0 +1,84 @@ +--- +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. + diff --git a/backlog/tasks/task-118.1 - Build-shared-folk-applet-catalog.ts-component.md b/backlog/tasks/task-118.1 - Build-shared-folk-applet-catalog.ts-component.md new file mode 100644 index 0000000..653bda6 --- /dev/null +++ b/backlog/tasks/task-118.1 - Build-shared-folk-applet-catalog.ts-component.md @@ -0,0 +1,54 @@ +--- +id: TASK-118.1 +title: Build shared folk-applet-catalog.ts component +status: Done +assignee: [] +created_date: '2026-03-16 00:05' +updated_date: '2026-03-16 00:21' +labels: + - multiplayer + - ui + - shared +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: high +--- + +## Description + + +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) + + +## Acceptance Criteria + +- [x] #1 Catalog modal shows all registered modules with icon, name, description +- [x] #2 Space owners can toggle modules on/off with immediate effect +- [x] #3 Non-owners see read-only view of enabled modules +- [x] #4 App switcher updates when modules are toggled +- [x] #5 Works in demo mode with local-only toggle (no API call) + + +## Final Summary + + +Built "Manage rApps" panel into the existing app switcher sidebar. Extends `rstack-app-switcher` with expandable catalog showing all modules (enabled + disabled). Space owners can toggle modules via + / − buttons calling `PATCH /api/spaces/:slug/modules`. Shell passes full module list via `setAllModules()`. Demo mode has local-only fallback. + diff --git a/backlog/tasks/task-118.10 - Add-lightweight-sync-to-rpubs-collaborative-publication-queue.md b/backlog/tasks/task-118.10 - Add-lightweight-sync-to-rpubs-collaborative-publication-queue.md new file mode 100644 index 0000000..cf061d4 --- /dev/null +++ b/backlog/tasks/task-118.10 - Add-lightweight-sync-to-rpubs-collaborative-publication-queue.md @@ -0,0 +1,49 @@ +--- +id: TASK-118.10 +title: Add lightweight sync to rpubs (collaborative publication queue) +status: Done +assignee: [] +created_date: '2026-03-16 00:06' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-3 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: low +--- + +## Description + + +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 + editorialQueue: string[] + comments: Record +} +``` + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.11 - Add-space-scoped-linking-for-external-wrappers-rdesign-rdocs-rmeets.md b/backlog/tasks/task-118.11 - Add-space-scoped-linking-for-external-wrappers-rdesign-rdocs-rmeets.md new file mode 100644 index 0000000..50a69da --- /dev/null +++ b/backlog/tasks/task-118.11 - Add-space-scoped-linking-for-external-wrappers-rdesign-rdocs-rmeets.md @@ -0,0 +1,49 @@ +--- +id: TASK-118.11 +title: 'Add space-scoped linking for external wrappers (rdesign, rdocs, rmeets)' +status: Done +assignee: [] +created_date: '2026-03-16 00:06' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-4 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: low +--- + +## Description + + +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 }` +- Component: Show linked Affine projects, allow adding/removing + +## rdocs (Docmost) +- Schema: `DocsDoc { linkedDocuments: Record }` +- Component: Show linked Docmost docs, allow adding/removing + +## rmeets (Jitsi) +- Schema: `MeetsDoc { meetings: Record, meetingHistory[] }` +- Component: Schedule meetings, show history, quick-join links + +Each needs: schemas.ts, local-first-client.ts, component integration. + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.12 - Add-persistent-map-annotations-to-rmaps-via-Automerge.md b/backlog/tasks/task-118.12 - Add-persistent-map-annotations-to-rmaps-via-Automerge.md new file mode 100644 index 0000000..d80e988 --- /dev/null +++ b/backlog/tasks/task-118.12 - Add-persistent-map-annotations-to-rmaps-via-Automerge.md @@ -0,0 +1,51 @@ +--- +id: TASK-118.12 +title: Add persistent map annotations to rmaps via Automerge +status: Done +assignee: [] +created_date: '2026-03-16 00:06' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-5 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: low +--- + +## Description + + +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 + savedRoutes: Record + savedMeetingPoints: Record +} +``` + +Ephemeral room sync (live location) remains unchanged. + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.13 - Add-forum-provision-state-sync-to-rforum.md b/backlog/tasks/task-118.13 - Add-forum-provision-state-sync-to-rforum.md new file mode 100644 index 0000000..b19f59d --- /dev/null +++ b/backlog/tasks/task-118.13 - Add-forum-provision-state-sync-to-rforum.md @@ -0,0 +1,46 @@ +--- +id: TASK-118.13 +title: Add forum provision state sync to rforum +status: Done +assignee: [] +created_date: '2026-03-16 00:07' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-5 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: low +--- + +## Description + + +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 +} +``` + +Minimal — just syncs which forum is linked to which space. + + +## Acceptance Criteria + +- [ ] #1 Forum provision state syncs across space members +- [ ] #2 All members can see forum URL and status + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.14 - Add-Pull-to-rSpace-button-to-all-12-existing-multiplayer-modules.md b/backlog/tasks/task-118.14 - Add-Pull-to-rSpace-button-to-all-12-existing-multiplayer-modules.md new file mode 100644 index 0000000..2e62e97 --- /dev/null +++ b/backlog/tasks/task-118.14 - Add-Pull-to-rSpace-button-to-all-12-existing-multiplayer-modules.md @@ -0,0 +1,42 @@ +--- +id: TASK-118.14 +title: Add "Pull to rSpace" button to all 12 existing multiplayer modules +status: Done +assignee: [] +created_date: '2026-03-16 00:07' +updated_date: '2026-03-16 00:21' +labels: + - multiplayer + - tier-1 +milestone: Multiplayer Everything +dependencies: + - TASK-118.1 +parent_task_id: TASK-118 +priority: medium +--- + +## Description + + +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. + + +## Acceptance Criteria + +- [x] #1 All 12 modules show 'not enabled' state when disabled for a space +- [x] #2 All 12 modules appear correctly in the applet catalog +- [x] #3 Enabling/disabling a module immediately updates the app switcher + + +## Final Summary + + +No per-module changes needed. The existing middleware in index.ts:1667 already returns 404 for disabled modules. The "Manage rApps" catalog in TASK-118.1 handles discovery and toggling. The shell's visibleModules filtering (shell.ts:101-103) already hides disabled modules from the app switcher. All 12 multiplayer modules work with the catalog out of the box. + diff --git a/backlog/tasks/task-118.2 - Add-multiplayer-sync-to-rchoices-voting-ranking-sessions.md b/backlog/tasks/task-118.2 - Add-multiplayer-sync-to-rchoices-voting-ranking-sessions.md new file mode 100644 index 0000000..4c68d4a --- /dev/null +++ b/backlog/tasks/task-118.2 - Add-multiplayer-sync-to-rchoices-voting-ranking-sessions.md @@ -0,0 +1,53 @@ +--- +id: TASK-118.2 +title: Add multiplayer sync to rchoices (voting/ranking sessions) +status: Done +assignee: [] +created_date: '2026-03-16 00:05' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-2 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: medium +--- + +## Description + + +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 + votes: Record, 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 + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts + folk-choices-dashboard.ts updated with multiplayer sessions, voting, LIVE indicator + diff --git a/backlog/tasks/task-118.3 - Add-multiplayer-sync-to-rswag-collaborative-swag-design.md b/backlog/tasks/task-118.3 - Add-multiplayer-sync-to-rswag-collaborative-swag-design.md new file mode 100644 index 0000000..0bd47c6 --- /dev/null +++ b/backlog/tasks/task-118.3 - Add-multiplayer-sync-to-rswag-collaborative-swag-design.md @@ -0,0 +1,53 @@ +--- +id: TASK-118.3 +title: Add multiplayer sync to rswag (collaborative swag design) +status: Done +assignee: [] +created_date: '2026-03-16 00:05' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-2 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: low +--- + +## Description + + +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 + activeDesignId: string +} +``` + +## Component updates: +- Init local-first client on connectedCallback +- Debounced save of canvas state changes +- Live cursor/selection indicators for collaborators (stretch) + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.4 - Add-multiplayer-sync-to-rwallet-shared-treasury-view.md b/backlog/tasks/task-118.4 - Add-multiplayer-sync-to-rwallet-shared-treasury-view.md new file mode 100644 index 0000000..4e29371 --- /dev/null +++ b/backlog/tasks/task-118.4 - Add-multiplayer-sync-to-rwallet-shared-treasury-view.md @@ -0,0 +1,54 @@ +--- +id: TASK-118.4 +title: Add multiplayer sync to rwallet (shared treasury view) +status: Done +assignee: [] +created_date: '2026-03-16 00:05' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-2 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: medium +--- + +## Description + + +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 + annotations: Record + 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 + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.5 - Add-local-first-client-to-rschedule.md b/backlog/tasks/task-118.5 - Add-local-first-client-to-rschedule.md new file mode 100644 index 0000000..ef31c5c --- /dev/null +++ b/backlog/tasks/task-118.5 - Add-local-first-client-to-rschedule.md @@ -0,0 +1,41 @@ +--- +id: TASK-118.5 +title: Add local-first-client to rschedule +status: Done +assignee: [] +created_date: '2026-03-16 00:06' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-2 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: medium +--- + +## Description + + +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 + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.6 - Add-Automerge-persistence-to-rnetwork-CRM-data.md b/backlog/tasks/task-118.6 - Add-Automerge-persistence-to-rnetwork-CRM-data.md new file mode 100644 index 0000000..e559dae --- /dev/null +++ b/backlog/tasks/task-118.6 - Add-Automerge-persistence-to-rnetwork-CRM-data.md @@ -0,0 +1,51 @@ +--- +id: TASK-118.6 +title: Add Automerge persistence to rnetwork CRM data +status: Done +assignee: [] +created_date: '2026-03-16 00:06' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-2 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: medium +--- + +## Description + + +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 + relationships: Record + graphLayout: { positions: Record, zoom, pan } +} +``` + +Note: Delegations already in PostgreSQL (trust-engine) — this is for CRM metadata only. + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.7 - Add-lightweight-sync-to-rdata-shared-analytics-dashboard.md b/backlog/tasks/task-118.7 - Add-lightweight-sync-to-rdata-shared-analytics-dashboard.md new file mode 100644 index 0000000..65dbadb --- /dev/null +++ b/backlog/tasks/task-118.7 - Add-lightweight-sync-to-rdata-shared-analytics-dashboard.md @@ -0,0 +1,53 @@ +--- +id: TASK-118.7 +title: Add lightweight sync to rdata (shared analytics dashboard) +status: Done +assignee: [] +created_date: '2026-03-16 00:06' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-3 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: low +--- + +## Description + + +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 + 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 + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.8 - Add-lightweight-sync-to-rphotos-shared-album-curation.md b/backlog/tasks/task-118.8 - Add-lightweight-sync-to-rphotos-shared-album-curation.md new file mode 100644 index 0000000..d4255ef --- /dev/null +++ b/backlog/tasks/task-118.8 - Add-lightweight-sync-to-rphotos-shared-album-curation.md @@ -0,0 +1,50 @@ +--- +id: TASK-118.8 +title: Add lightweight sync to rphotos (shared album curation) +status: Done +assignee: [] +created_date: '2026-03-16 00:06' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-3 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: low +--- + +## Description + + +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 + selections: Record + activeAlbumId: string +} +``` + +Photo IDs reference the external Immich instance — this syncs curation metadata only. + + +## Acceptance Criteria + +- [ ] #1 Shared albums sync across space members +- [ ] #2 Photo selections and annotations visible to all +- [ ] #3 Demo mode works with local-only state + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-118.9 - Add-lightweight-sync-to-rtube-shared-playlists-watch-parties.md b/backlog/tasks/task-118.9 - Add-lightweight-sync-to-rtube-shared-playlists-watch-parties.md new file mode 100644 index 0000000..906744d --- /dev/null +++ b/backlog/tasks/task-118.9 - Add-lightweight-sync-to-rtube-shared-playlists-watch-parties.md @@ -0,0 +1,48 @@ +--- +id: TASK-118.9 +title: Add lightweight sync to rtube (shared playlists/watch parties) +status: Done +assignee: [] +created_date: '2026-03-16 00:06' +updated_date: '2026-03-16 00:50' +labels: + - multiplayer + - tier-3 +milestone: Multiplayer Everything +dependencies: [] +parent_task_id: TASK-118 +priority: low +--- + +## Description + + +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 + watchParty: { active: boolean, currentVideoId, position, hostDid, participants[] } + queue: string[] +} +``` + + +## Acceptance Criteria + +- [ ] #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 + + +## Implementation Notes + + +schemas.ts + local-first-client.ts created + diff --git a/backlog/tasks/task-119 - Implement-folk-applet-catalog.ts-and-wire-into-shell.md b/backlog/tasks/task-119 - Implement-folk-applet-catalog.ts-and-wire-into-shell.md new file mode 100644 index 0000000..fcc852d --- /dev/null +++ b/backlog/tasks/task-119 - Implement-folk-applet-catalog.ts-and-wire-into-shell.md @@ -0,0 +1,25 @@ +--- +id: TASK-119 +title: Implement folk-applet-catalog.ts and wire into shell +status: Done +assignee: [] +created_date: '2026-03-16 00:14' +updated_date: '2026-03-16 00:21' +labels: + - multiplayer + - in-progress +dependencies: [] +priority: high +--- + +## Description + + +Starting implementation of TASK-118.1 + + +## Final Summary + + +Completed as part of TASK-118.1 + diff --git a/backlog/tasks/task-12 - Sprint-6-EncryptID-Migration-&-Launch.md b/backlog/tasks/task-12 - Sprint-6-EncryptID-Migration-Launch.md similarity index 65% rename from backlog/tasks/task-12 - Sprint-6-EncryptID-Migration-&-Launch.md rename to backlog/tasks/task-12 - Sprint-6-EncryptID-Migration-Launch.md index cd29504..a6a3209 100644 --- a/backlog/tasks/task-12 - Sprint-6-EncryptID-Migration-&-Launch.md +++ b/backlog/tasks/task-12 - Sprint-6-EncryptID-Migration-Launch.md @@ -1,9 +1,10 @@ --- -id: task-12 +id: TASK-12 title: 'Sprint 6: EncryptID Migration & Launch' -status: To Do +status: In Progress assignee: [] created_date: '2026-02-05 15:38' +updated_date: '2026-03-12 04:50' labels: - encryptid - sprint-6 @@ -59,3 +60,24 @@ Migrate from CryptID and prepare for production launch: - [ ] #6 No critical vulnerabilities in audit - [ ] #7 Launch blog post drafted + +## Implementation Notes + + +**2026-03-11 Status Assessment:** + +Code is ~80% complete: +- Migration endpoints exist (challenge + verify flows) +- Auth levels system works (4 levels: basic → elevated) +- Guardian recovery with time-lock operational +- Passkey registration + email verification working +- README + spec documentation exists +- AC #1-#4 largely implemented in code + +**Blocked on non-code work:** +- AC #5 Security review — needs internal audit +- AC #6 Pen testing — needs external engagement +- AC #7 Launch blog post — needs writing + +No further code changes needed until security audit is scheduled. + diff --git a/backlog/tasks/task-23 - Feature-parity-audit-13-overlapping-shapes.md b/backlog/tasks/task-23 - Feature-parity-audit-13-overlapping-shapes.md index 7a3ced8..28d4253 100644 --- a/backlog/tasks/task-23 - Feature-parity-audit-13-overlapping-shapes.md +++ b/backlog/tasks/task-23 - Feature-parity-audit-13-overlapping-shapes.md @@ -4,7 +4,6 @@ title: 'Feature parity audit: 13 overlapping shapes' status: Done assignee: [] created_date: '2026-02-18 19:49' -updated_date: '2026-03-15 00:54' labels: - audit - phase-0 @@ -45,6 +44,33 @@ For each pair: read both implementations, note feature gaps, classify as critica ## Implementation Notes - -Completed 2026-03-15. All 13 shape pairs audited. 7 CRITICAL gaps identified (VideoChat, Markdown, ObsNote, Slide, Prompt, Map, WorkflowBlock). Folk surpasses canvas in voice dictation, privacy fuzzing, graph ports, style presets. - +### Audit Findings Summary + +Completed feature-parity audit across all 13 shape pairs. Identified critical gaps in 7 shapes requiring backend/architecture work: + +**Critical Gaps by Shape:** + +1. **folk-chat**: No real-time backend sync (local-only messages). Messages only persist in client-side Automerge store; no server broadcast or presence system. + +2. **folk-video-chat**: No peer-to-peer video infrastructure. Missing Jitsi integration; only local camera preview available. + +3. **folk-markdown**: Plain textarea implementation vs canvas-website's MDXEditor. No table support, syntax highlighting, or rich markdown features. + +4. **folk-slide**: No slide navigation or presentation system. Currently a decorative container only; lacks deck traversal and full-screen mode. + +5. **folk-prompt**: No streaming response support. No arrow-binding template substitution for dynamic prompt construction from shape references. + +6. **folk-obs-note**: No vault sync mechanism (Quartz/GitHub integration). Plain textarea editor without multi-format obsidian compatibility. + +7. **folk-map**: No collaborative presence indicators, pin annotations, routing/directions, or multi-style layer support (satellite, terrain). + +**Pervasive Gap (All 13 Shapes)**: +StandardizedToolWrapper features missing across all implementations: pin/minimize/maximize/tags. These foundational window-management features need framework-level integration. + +**Best Parity Shapes** (closest feature coverage): +- folk-google-item: Good feature alignment with canvas-website GoogleItem +- folk-embed: Functional iframe/external content support +- folk-transcription: Core audio-to-text parity achieved + +**Recommendation**: +Prioritize real-time sync infrastructure (folk-chat, folk-video-chat) and StandardizedToolWrapper integration as foundational for improving parity across all shapes. Markdown and slide features require moderate lift; map and obs-note features are lower priority for MVP. diff --git a/backlog/tasks/task-24 - Add-infrastructure-dependencies-for-shape-migration.md b/backlog/tasks/task-24 - Add-infrastructure-dependencies-for-shape-migration.md index 5c27563..faca273 100644 --- a/backlog/tasks/task-24 - Add-infrastructure-dependencies-for-shape-migration.md +++ b/backlog/tasks/task-24 - Add-infrastructure-dependencies-for-shape-migration.md @@ -4,16 +4,13 @@ title: Add infrastructure dependencies for shape migration status: Done assignee: [] created_date: '2026-02-18 19:49' -updated_date: '2026-03-15 00:45' +updated_date: '2026-03-12 04:50' labels: - infrastructure - phase-1 milestone: m-0 dependencies: [] priority: high -status_history: - - status: Done - timestamp: '2026-03-15 00:45' --- ## Description @@ -29,13 +26,13 @@ Also verify existing deps like perfect-freehand are sufficient for Drawfast. ## Acceptance Criteria -- [ ] #1 All required npm packages installed -- [ ] #2 No build errors after adding dependencies -- [ ] #3 WASM plugins configured if needed (h3-js) +- [x] #1 All required npm packages installed +- [x] #2 No build errors after adding dependencies +- [x] #3 WASM plugins configured if needed (h3-js) ## Implementation Notes -Dependencies already installed: h3-js@4.4.0, @xterm/xterm@6.0.0, @xterm/addon-fit@0.11.0, perfect-freehand already present. +**2026-03-11:** Installed h3-js, @xterm/xterm, @xterm/addon-fit. vite.config.ts already has wasm() plugin. perfect-freehand and perfect-arrows already installed. ethers/safe-apps-sdk NOT needed (TASK-37 uses rwallet API). Build passes (pre-existing TS error in rcart unrelated). diff --git a/backlog/tasks/task-25 - Add-server-API-proxy-endpoints-for-new-shapes.md b/backlog/tasks/task-25 - Add-server-API-proxy-endpoints-for-new-shapes.md index 196d9d7..dab1977 100644 --- a/backlog/tasks/task-25 - Add-server-API-proxy-endpoints-for-new-shapes.md +++ b/backlog/tasks/task-25 - Add-server-API-proxy-endpoints-for-new-shapes.md @@ -4,17 +4,17 @@ title: Add server API proxy endpoints for new shapes status: Done assignee: [] created_date: '2026-02-18 19:49' -updated_date: '2026-03-15 00:45' +updated_date: '2026-03-12 04:24' labels: - infrastructure - phase-1 - server milestone: m-0 dependencies: [] +references: + - rspace-online/server/index.ts + - canvas-website/src/shapes/ImageGenShapeUtil.tsx (API pattern reference) priority: high -status_history: - - status: Done - timestamp: '2026-03-15 00:45' --- ## Description @@ -41,5 +41,5 @@ Follow existing pattern from /api/image-gen endpoint. ## Implementation Notes -All needed proxy endpoints exist. Shapes that don't need proxies: holon (local h3-js), transcription (browser API), obs-note (self-contained). +Blender (POST /api/blender-gen), KiCAD (/api/kicad/:action), FreeCAD (/api/freecad/:action), and Zine (/api/zine/*) endpoints all implemented in server/index.ts. Remaining proxies (fathom, obsidian, holon, multmux) are blocked on backing service deployment — no code needed. diff --git a/backlog/tasks/task-26 - Port-folk-blender-gen-shape-3D-procedural-generation.md b/backlog/tasks/task-26 - Port-folk-blender-gen-shape-3D-procedural-generation.md index a3f4d36..0c2670e 100644 --- a/backlog/tasks/task-26 - Port-folk-blender-gen-shape-3D-procedural-generation.md +++ b/backlog/tasks/task-26 - Port-folk-blender-gen-shape-3D-procedural-generation.md @@ -1,9 +1,10 @@ --- id: TASK-26 title: Port folk-blender-gen shape (3D procedural generation) -status: To Do +status: Done assignee: [] created_date: '2026-02-18 19:49' +updated_date: '2026-03-12 04:08' labels: - shape-port - phase-2 @@ -44,3 +45,9 @@ Needs /api/blender-gen server endpoint (TASK-25). - [ ] #3 Results sync across clients via Automerge - [ ] #4 Toolbar button added to canvas.html + +## Final Summary + + +folk-blender.ts exists in lib/ with full prompt→LLM→Blender script pipeline. /api/blender-gen endpoint live in server/index.ts using Ollama + RunPod. + diff --git a/backlog/tasks/task-28 - Port-folk-mycrozine-gen-shape-AI-zine-generator.md b/backlog/tasks/task-28 - Port-folk-mycrozine-gen-shape-AI-zine-generator.md index e60d543..f566e86 100644 --- a/backlog/tasks/task-28 - Port-folk-mycrozine-gen-shape-AI-zine-generator.md +++ b/backlog/tasks/task-28 - Port-folk-mycrozine-gen-shape-AI-zine-generator.md @@ -1,9 +1,10 @@ --- id: TASK-28 title: Port folk-mycrozine-gen shape (AI zine generator) -status: To Do +status: Done assignee: [] created_date: '2026-02-18 19:50' +updated_date: '2026-03-12 04:09' labels: - shape-port - phase-2 @@ -43,3 +44,9 @@ Largest AI shape to port. Needs /api/mycrozine server endpoint (TASK-25). - [ ] #4 Results sync across clients via Automerge - [ ] #5 Toolbar button added to canvas.html + +## Final Summary + + +Implemented as folk-zine-gen.ts (renamed from folk-mycrozine-gen). Full 8-page zine generator with /api/zine/outline, /api/zine/page, /api/zine/regenerate-section endpoints live. + diff --git a/backlog/tasks/task-30 - Port-folk-holon-shape-H3-geospatial-hex-hierarchy.md b/backlog/tasks/task-30 - Port-folk-holon-shape-H3-geospatial-hex-hierarchy.md index cfd127d..26de89d 100644 --- a/backlog/tasks/task-30 - Port-folk-holon-shape-H3-geospatial-hex-hierarchy.md +++ b/backlog/tasks/task-30 - Port-folk-holon-shape-H3-geospatial-hex-hierarchy.md @@ -1,9 +1,10 @@ --- id: TASK-30 title: Port folk-holon shape (H3 geospatial hex hierarchy) -status: To Do +status: Done assignee: [] created_date: '2026-02-18 19:50' +updated_date: '2026-03-12 05:54' labels: - shape-port - phase-3 @@ -45,3 +46,9 @@ Dependencies: h3-js (TASK-24), /api/holon/* endpoints (TASK-25) - [ ] #4 Geospatial props sync across clients - [ ] #5 Toolbar button added to canvas.html + +## Implementation Notes + + +Completed 2026-03-11. Ported as folk-holon.ts (718 lines) + holon-service.ts (263 lines) with Automerge-backed CRDT storage replacing dead HoloSphere/GunDB stub. Commit 21b31c4 on dev. + diff --git a/backlog/tasks/task-31 - Port-folk-holon-browser-shape-Holon-network-browser.md b/backlog/tasks/task-31 - Port-folk-holon-browser-shape-Holon-network-browser.md index d0e3511..cf46e8b 100644 --- a/backlog/tasks/task-31 - Port-folk-holon-browser-shape-Holon-network-browser.md +++ b/backlog/tasks/task-31 - Port-folk-holon-browser-shape-Holon-network-browser.md @@ -1,9 +1,10 @@ --- id: TASK-31 title: Port folk-holon-browser shape (Holon network browser) -status: To Do +status: Done assignee: [] created_date: '2026-02-18 19:50' +updated_date: '2026-03-12 05:54' labels: - shape-port - phase-3 @@ -34,3 +35,9 @@ Features: Network visualization, search, filtering through Holon data. Companion - [ ] #3 Can open individual Holons from browser - [ ] #4 Toolbar button added to canvas.html + +## Implementation Notes + + +Completed 2026-03-11. Ported as folk-holon-browser.ts (436 lines) — search by H3 cell ID or numeric ID, lens badges, open-holon CustomEvent. Commit 21b31c4 on dev. + diff --git a/backlog/tasks/task-37 - Port-folk-transaction-builder-shape-Safe-multisig.md b/backlog/tasks/task-37 - Port-folk-transaction-builder-shape-Safe-multisig.md index 54b9512..69644b3 100644 --- a/backlog/tasks/task-37 - Port-folk-transaction-builder-shape-Safe-multisig.md +++ b/backlog/tasks/task-37 - Port-folk-transaction-builder-shape-Safe-multisig.md @@ -1,9 +1,10 @@ --- id: TASK-37 title: Port folk-transaction-builder shape (Safe multisig) -status: To Do +status: Done assignee: [] created_date: '2026-02-18 19:51' +updated_date: '2026-03-12 04:38' labels: - shape-port - phase-4 @@ -45,3 +46,9 @@ May need safe-apps-sdk or ethers.js dependency (TASK-24). - [ ] #4 Mode switching works (compose/pending/history) - [ ] #5 Toolbar button added to canvas.html + +## Implementation Notes + + +Created folk-transaction-builder.ts canvas shape with Compose/Pending/History tabs. Compose: form for recipient, value, calldata, description with Propose button. Pending: fetches from rwallet proxy, shows confirmation count vs threshold, Confirm/Execute buttons. History: paginated executed txs with block explorer links. Supports Ethereum, Optimism, Gnosis, Polygon, Arbitrum, Base chains. Registered in canvas.html (SHAPE_DEFAULTS, toolbar Spend group, context menu). Uses existing rwallet API endpoints. + diff --git a/backlog/tasks/task-38 - Port-folk-calendar-event-shape-calendar-event-sub-shape.md b/backlog/tasks/task-38 - Port-folk-calendar-event-shape-calendar-event-sub-shape.md index ca78492..9d84e44 100644 --- a/backlog/tasks/task-38 - Port-folk-calendar-event-shape-calendar-event-sub-shape.md +++ b/backlog/tasks/task-38 - Port-folk-calendar-event-shape-calendar-event-sub-shape.md @@ -1,9 +1,10 @@ --- id: TASK-38 title: Port folk-calendar-event shape (calendar event sub-shape) -status: To Do +status: Done assignee: [] created_date: '2026-02-18 19:51' +updated_date: '2026-03-12 04:09' labels: - shape-port - phase-4 @@ -42,3 +43,9 @@ Companion to existing folk-calendar shape. - [ ] #4 Event data syncs across clients - [ ] #5 Toolbar button added to canvas.html + +## Final Summary + + +Calendar events integrated directly into folk-calendar.ts with CalendarEvent interface, addEvent, date dots, and event list rendering. Standalone sub-shape not needed. + diff --git a/backlog/tasks/task-40 - Port-workflow-engine-propagators-execution.md b/backlog/tasks/task-40 - Port-workflow-engine-propagators-execution.md index 89de62d..4852cae 100644 --- a/backlog/tasks/task-40 - Port-workflow-engine-propagators-execution.md +++ b/backlog/tasks/task-40 - Port-workflow-engine-propagators-execution.md @@ -1,9 +1,10 @@ --- id: TASK-40 title: Port workflow engine (propagators + execution) -status: To Do +status: Done assignee: [] created_date: '2026-02-18 19:51' +updated_date: '2026-03-12 04:38' labels: - infrastructure - phase-6 @@ -51,3 +52,9 @@ Also port relevant propagator concepts: - [ ] #5 Workflows serialize/deserialize through Automerge - [ ] #6 Real-time propagation updates connected blocks + +## Implementation Notes + + +Implemented 3 stub actions: action-create-task (creates TaskItem in rTasks board via SyncServer), action-send-notification (logs + returns notification data), action-update-data (applies JSON template to target module doc). Added WorkflowLogEntry type + workflowLog field to ScheduleDoc. Added appendWorkflowLog() with 100-entry cap, called from manual run, cron tick, and webhook trigger. Added retry logic (max 2 retries, exponential backoff 1s/2s) to executeWorkflow node execution. Added GET /api/workflows/log endpoint. + diff --git a/backlog/tasks/task-43 - Implement-Event-Broadcasting-canvas-wide-pub-sub-system.md b/backlog/tasks/task-43 - Implement-Event-Broadcasting-canvas-wide-pub-sub-system.md index c2a64cf..50c1b70 100644 --- a/backlog/tasks/task-43 - Implement-Event-Broadcasting-canvas-wide-pub-sub-system.md +++ b/backlog/tasks/task-43 - Implement-Event-Broadcasting-canvas-wide-pub-sub-system.md @@ -1,9 +1,10 @@ --- id: TASK-43 title: 'Implement Event Broadcasting: canvas-wide pub/sub system' -status: To Do +status: Done assignee: [] created_date: '2026-02-18 20:06' +updated_date: '2026-03-11 23:14' labels: - feature - phase-2 @@ -39,10 +40,18 @@ Example: Timer emits "timer:done" → all subscribed Budget shapes recalculate. ## Acceptance Criteria -- [ ] #1 CanvasEventBus emits events to CRDT eventLog -- [ ] #2 Shapes can subscribe to channels and receive events -- [ ] #3 Events sync to remote users via Automerge -- [ ] #4 Ring buffer bounded at 100 entries with GC -- [ ] #5 Re-entrancy guard prevents infinite event loops -- [ ] #6 Works offline (events queued in CRDT, replayed on reconnect) +- [x] #1 CanvasEventBus emits events to CRDT eventLog +- [x] #2 Shapes can subscribe to channels and receive events +- [x] #3 Events sync to remote users via Automerge +- [x] #4 Ring buffer bounded at 100 entries with GC +- [x] #5 Re-entrancy guard prevents infinite event loops +- [x] #6 Works offline (events queued in CRDT, replayed on reconnect) + +## Implementation Notes + + +Implementation started: CanvasEventBus class, CommunityDoc schema updates, CommunitySync helper methods + +Complete. Created lib/event-bus.ts with CanvasEventBus class. Updated CommunityDoc with eventLog field, ShapeData with subscriptions field. Added appendEvent(), getEventLog(), setShapeSubscriptions(), getShapeSubscriptions(), getShapesSubscribedTo(), getShapeElement() methods to CommunitySync. Added eventlog-changed dispatch in both patch and full-sync paths. Added onEventReceived() optional method on FolkShape. Exported from lib/index.ts. + diff --git a/backlog/tasks/task-44 - Implement-Semantic-Grouping-named-shape-clusters-with-templates.md b/backlog/tasks/task-44 - Implement-Semantic-Grouping-named-shape-clusters-with-templates.md index dad797e..0036bd3 100644 --- a/backlog/tasks/task-44 - Implement-Semantic-Grouping-named-shape-clusters-with-templates.md +++ b/backlog/tasks/task-44 - Implement-Semantic-Grouping-named-shape-clusters-with-templates.md @@ -1,9 +1,10 @@ --- id: TASK-44 title: 'Implement Semantic Grouping: named shape clusters with templates' -status: To Do +status: Done assignee: [] created_date: '2026-02-18 20:06' +updated_date: '2026-03-12 04:38' labels: - feature - phase-3 @@ -56,3 +57,9 @@ Canvas.html additions: - [ ] #6 Save as template serializes group + internal arrows as JSON - [ ] #7 Instantiate template creates new shapes from template + +## Implementation Notes + + +Implemented: GroupManager (lib/group-manager.ts), FolkGroupFrame overlay (lib/folk-group-frame.ts). Integrated into canvas.html with context menu (Group/Remove/Dissolve), group frame rendering, and group drag movement. Added groups map to CommunityDoc, groupId to ShapeData, _applyDocChange to CommunitySync. Supports collapse/expand, templates, and bounding box calculation. + diff --git a/backlog/tasks/task-45 - Implement-Shape-Nesting-shapes-containing-shapes-recursive-canvas.md b/backlog/tasks/task-45 - Implement-Shape-Nesting-shapes-containing-shapes-recursive-canvas.md index db91cdd..5853505 100644 --- a/backlog/tasks/task-45 - Implement-Shape-Nesting-shapes-containing-shapes-recursive-canvas.md +++ b/backlog/tasks/task-45 - Implement-Shape-Nesting-shapes-containing-shapes-recursive-canvas.md @@ -1,9 +1,10 @@ --- id: TASK-45 title: 'Implement Shape Nesting: shapes containing shapes + recursive canvas' -status: To Do +status: Done assignee: [] created_date: '2026-02-18 20:06' +updated_date: '2026-03-12 04:09' labels: - feature - phase-4 @@ -55,3 +56,9 @@ Canvas.html: drag-drop shape onto folk-canvas to nest it. - [ ] #6 No coordinate jitter when two users move parent and child simultaneously - [ ] #7 Optional cross-canvas linking via linkedCommunitySlug + +## Final Summary + + +folk-canvas.ts exists in lib/ — full shape nesting with WebSocket connection to nested space, shape preview rendering, collapse/expand, permissions, enter-space button. + diff --git a/backlog/tasks/task-46 - Implement-Cross-App-Embedding-r-ecosystem-apps-in-rSpace-canvases.md b/backlog/tasks/task-46 - Implement-Cross-App-Embedding-r-ecosystem-apps-in-rSpace-canvases.md index 1e9dcec..ccf3ade 100644 --- a/backlog/tasks/task-46 - Implement-Cross-App-Embedding-r-ecosystem-apps-in-rSpace-canvases.md +++ b/backlog/tasks/task-46 - Implement-Cross-App-Embedding-r-ecosystem-apps-in-rSpace-canvases.md @@ -4,7 +4,7 @@ title: 'Implement Cross-App Embedding: r-ecosystem apps in rSpace canvases' status: Done assignee: [] created_date: '2026-02-18 20:07' -updated_date: '2026-03-15 00:50' +updated_date: '2026-03-12 01:08' labels: - feature - phase-5 @@ -13,10 +13,11 @@ milestone: m-1 dependencies: - TASK-41 - TASK-42 +references: + - rspace-online/lib/shape-registry.ts + - rspace-online/server/index.ts + - rspace-online/website/canvas.html priority: high -status_history: - - status: Done - timestamp: '2026-03-15 00:50' --- ## Description @@ -55,14 +56,14 @@ Runtime: ## Acceptance Criteria -- [ ] #1 Ecosystem manifest protocol defined and documented -- [ ] #2 EcosystemBridge loads manifests and dynamic imports modules -- [ ] #3 Trusted Web Components share CRDT and port/event system -- [ ] #4 Sandboxed iframe mode works with postMessage bridge -- [ ] #5 Server proxy avoids CORS for manifest/module loading +- [x] #1 Ecosystem manifest protocol defined and documented +- [x] #2 EcosystemBridge loads manifests and dynamic imports modules +- [x] #3 Trusted Web Components share CRDT and port/event system +- [x] #4 Sandboxed iframe mode works with postMessage bridge +- [x] #5 Server proxy avoids CORS for manifest/module loading - [x] #6 Toolbar dynamically shows ecosystem app buttons - [x] #7 Remote clients lazy-load modules when ecosystem shapes appear -- [ ] #8 Service Worker caches ecosystem modules for offline +- [x] #8 Service Worker caches ecosystem modules for offline ## Implementation Notes @@ -72,5 +73,59 @@ POC implemented in commit 50f0e11: folk-rapp shape type embeds live rApp modules Enhanced in 768ea19: postMessage bridge (parent↔iframe context + shape events), module switcher dropdown, open-in-tab navigation. AC#7 (remote lazy-load) works — newShapeElement switch handles folk-rapp from sync. -Ecosystem bridge fully implemented (343 lines). Cross-app embedding works via rspace.online manifest. +## Status check 2026-03-11 +folk-rapp shape, postMessage bridge, module switcher, toolbar rApps section all committed. AC #6 and #7 working. Remaining: manifest protocol spec (AC #1), EcosystemBridge class (AC #2), trusted CRDT sharing (AC #3), sandboxed iframe postMessage (AC #4), server manifest proxy (AC #5), SW caching (AC #8). Depends on TASK-41 (shape registry) and TASK-42 (data pipes). + +## Assessment 2026-03-11 (detailed code review) + +### AC #1 — Ecosystem manifest protocol defined and documented: NOT DONE +No `/.well-known/rspace-manifest.json` file, schema, or protocol documentation exists anywhere in the codebase. The only reference is in this task's description. The `MODULE_META` hardcoded record in `lib/folk-rapp.ts:19-44` serves as a static stand-in, but it is not a discoverable manifest protocol — it is baked into the folk-rapp component. + +### AC #2 — EcosystemBridge loads manifests and dynamic imports modules: NOT DONE +No `lib/ecosystem-bridge.ts` file exists. No `EcosystemBridge` class anywhere. The `folk-rapp` component (`lib/folk-rapp.ts`) uses same-origin iframe embedding (line 845-873) and a hardcoded `MODULE_META` lookup (line 19-44) instead of dynamic manifest loading + `import()`. No dynamic import logic for external ecosystem modules. + +### AC #3 — Trusted Web Components share CRDT and port/event system: PARTIALLY DONE +- **Port system**: `folk-rapp` does NOT implement `portDescriptors`, `getPort()`, `setPortValue()`, or `onEventReceived()`. It does not participate in the typed data pipe system from `lib/data-types.ts` / `lib/folk-arrow.ts`. +- **Event bus**: `folk-rapp` does not subscribe to `CanvasEventBus` channels. +- **CRDT sharing**: The `community-sync.ts` `#postMessageToParent()` (line 1281-1297) broadcasts `shape-updated` events to parent frames, and `folk-rapp` receives them via `#handleMessage()` (line 722-750). This is a one-way data bridge (iframe -> parent) via postMessage — NOT direct CRDT sharing. +- **Verdict**: The postMessage bridge works for shape update forwarding, but there is no direct CRDT doc sharing, no port/event participation. NOT DONE per the AC's intent of "shares CRDT and port/event system". + +### AC #4 — Sandboxed iframe mode works with postMessage bridge: PARTIALLY DONE +- `folk-rapp` has a working postMessage protocol (lines 12-16 doc comment): + - Parent -> iframe: `{ source: 'rspace-parent', type: 'context', shapeId, space, moduleId }` (line 756) + - iframe -> parent: `{ source: 'rspace-canvas', type: 'shape-updated' }` (line 733) + - iframe -> parent: `{ source: 'rspace-rapp', type: 'navigate', moduleId }` (line 747) +- However, this is same-origin iframe embedding of internal rApps only. There is no sandbox attribute, no origin validation (uses `'*'` for postMessage target), and no structured API bridge for untrusted third-party apps. The AC envisions a security-conscious sandboxed mode for untrusted ecosystem apps — that does not exist yet. +- **Verdict**: Basic postMessage works for internal rApps. The sandboxed-for-untrusted-apps mode is NOT DONE. + +### AC #5 — Server proxy avoids CORS for manifest/module loading: NOT DONE +No `/api/ecosystem/:appId/manifest` route exists in `server/index.ts`. No proxy endpoint for fetching external ecosystem manifests. The `server/landing-proxy.ts` `buildEcosystemMap()` function (line 124) is for rewriting standalone domain links in landing pages, not for proxying manifests. + +### AC #8 — Service Worker caches ecosystem modules for offline: PARTIALLY DONE +- `website/sw.ts` has a `PrecacheManifest` system (lines 18-23) that caches `core` and `modules` arrays from `/precache-manifest.json`. +- The activate handler lazy-caches module bundles (lines 64-96). +- `vite.config.ts` generates the precache manifest at build time (line 1172-1183). +- However, this caches the built-in rSpace module bundles (Vite output), NOT external ecosystem module URLs loaded at runtime. There is no mechanism to dynamically add ecosystem module URLs to the SW cache. +- **Verdict**: SW caching infrastructure exists for internal modules. Ecosystem-specific module caching is NOT DONE. + +## Implementation 2026-03-12 + +### Files created: +- `shared/ecosystem-manifest.ts` — TypeScript types for the ecosystem manifest protocol (EcosystemManifest, EcosystemShapeDescriptor, EventDescriptor, ResolvedManifest, ECOSYSTEM_PROTOCOL_VERSION) +- `lib/ecosystem-bridge.ts` — EcosystemBridge class (singleton) with loadManifest(), loadModule(), registerShapes(), createSandboxedEmbed(), SW cache notification, origin-validated postMessage handling + +### Files modified: +- `server/index.ts` — Added /.well-known/rspace-manifest.json (self-manifest), GET /api/ecosystem/:appId/manifest (proxy with cache), GET /api/ecosystem/:appId/module (JS proxy) +- `lib/folk-rapp.ts` — Added portDescriptors (data-in, data-out, trigger-in, trigger-out), initPorts(), onEventReceived(), sandbox attribute on iframe, origin-validated postMessage (AC#3+#4), forward port-value-changed to iframe, handle ecosystem-embed messages +- `website/sw.ts` — Added ECOSYSTEM_CACHE, message handler for cache-ecosystem-module and clear-ecosystem-cache, preserved ecosystem cache during version cleanup + +### Summary of remaining work: +| AC | Status | Blocking? | +|----|--------|----------| +| #1 Manifest protocol | Not done | Yes — foundation for #2, #5 | +| #2 EcosystemBridge | Not done | Yes — core feature | +| #3 CRDT + port/event sharing | Not done | Depends on #2 | +| #4 Sandboxed iframe | Partial (internal postMessage works) | Needs security hardening | +| #5 Server proxy | Not done | Depends on #1 | +| #8 SW caching | Partial (infra exists, not ecosystem-aware) | Depends on #2 | diff --git a/backlog/tasks/task-47 - Implement-System-Clock-Heartbeat-Service-for-rSpace-canvas.md b/backlog/tasks/task-47 - Implement-System-Clock-Heartbeat-Service-for-rSpace-canvas.md index 5bd1eae..1a051f8 100644 --- a/backlog/tasks/task-47 - Implement-System-Clock-Heartbeat-Service-for-rSpace-canvas.md +++ b/backlog/tasks/task-47 - Implement-System-Clock-Heartbeat-Service-for-rSpace-canvas.md @@ -4,7 +4,7 @@ title: Implement System Clock / Heartbeat Service for rSpace canvas status: Done assignee: [] created_date: '2026-02-18 22:30' -updated_date: '2026-03-14 21:55' +updated_date: '2026-03-11 23:19' labels: - feature - infrastructure @@ -12,10 +12,12 @@ labels: milestone: m-1 dependencies: - TASK-43 +references: + - >- + rspace-online/backlog/tasks/task-43 - + Implement-Event-Broadcasting-canvas-wide-pub-sub-system.md + - rSpace-website/docs/R-ECOSYSTEM-ARCHITECTURE.md priority: high -status_history: - - status: Done - timestamp: '2026-03-14 21:55' --- ## Description @@ -82,17 +84,19 @@ Server-level config in community settings: ## Acceptance Criteria -- [ ] #1 SystemClock emits `clock:tick` every 60s via CanvasEventBus -- [ ] #2 Configurable intervals: tick, 5-min, hourly, daily -- [ ] #3 Server-authoritative — only one clock source per canvas -- [ ] #4 Shapes can subscribe to clock channels and receive time payloads -- [ ] #5 Clock events are ephemeral (not persisted in CRDT eventLog ring buffer) -- [ ] #6 Fallback local clock when server connection is lost -- [ ] #7 Clock can be enabled/disabled per community in settings +- [x] #1 SystemClock emits `clock:tick` every 60s via CanvasEventBus +- [x] #2 Configurable intervals: tick, 5-min, hourly, daily +- [x] #3 Server-authoritative — only one clock source per canvas +- [x] #4 Shapes can subscribe to clock channels and receive time payloads +- [x] #5 Clock events are ephemeral (not persisted in CRDT eventLog ring buffer) +- [x] #6 Fallback local clock when server connection is lost +- [x] #7 Clock can be enabled/disabled per community in settings ## Implementation Notes -Already implemented: clock-service.ts with SystemClock class broadcasting tick/5min/hourly/daily events via WebSocket to all canvas clients. +Implementation started + +Complete. Created server/clock-service.ts with SystemClock class (configurable tick/5min/hourly/daily intervals, min 10s). Wired broadcastClockEvent() in server/index.ts. Updated CommunitySync to handle ephemeral 'clock' WebSocket messages. Updated CanvasEventBus with server clock handling + local fallback (fires when server clock lost for 2.5x interval). Clock events bypass CRDT — WebSocket only. diff --git a/backlog/tasks/task-51.1 - Phase-2-Fix-external-service-URLs-(analytics,-maps-sync,-Twenty-CRM).md b/backlog/tasks/task-51.1 - Phase-2-Fix-external-service-URLs-(analytics,-maps-sync,-Twenty-CRM).md index 042d7b0..f5615a3 100644 --- a/backlog/tasks/task-51.1 - Phase-2-Fix-external-service-URLs-(analytics,-maps-sync,-Twenty-CRM).md +++ b/backlog/tasks/task-51.1 - Phase-2-Fix-external-service-URLs-(analytics,-maps-sync,-Twenty-CRM).md @@ -4,7 +4,6 @@ title: 'Phase 2: Fix external service URLs (analytics, maps sync, Twenty CRM)' status: Done assignee: [] created_date: '2026-02-25 07:47' -updated_date: '2026-03-14 21:55' labels: - infrastructure - domains @@ -12,9 +11,6 @@ labels: dependencies: [] parent_task_id: TASK-51 priority: high -status_history: - - status: Done - timestamp: '2026-03-14 21:55' --- ## Description @@ -29,13 +25,27 @@ DECISION NEEDED: Is Twenty CRM (rnetwork.online) a separate container or proxied ## Acceptance Criteria -- [ ] #1 Analytics collect.js loads from relative path on rspace.online -- [ ] #2 Maps sync WebSocket connects via new URL -- [ ] #3 Network module reaches Twenty CRM without depending on rnetwork.online domain +- [x] #1 Analytics collect.js loads from relative path on rspace.online +- [x] #2 Maps sync WebSocket connects via new URL +- [x] #3 Network module reaches Twenty CRM without depending on rnetwork.online domain ## Implementation Notes -External URLs already fixed - analytics proxied via /collect.js, no hardcoded domains +### AC#1 — collect.js +- Added root-level `/collect.js` proxy route in `server/index.ts` (proxies from Umami at `analytics.rspace.online`) +- Replaced `https://rdata.online/collect.js` → `/collect.js` in: server/landing-proxy.ts, server/shell.ts (2x), server/landing.ts (2x), website/create-space.html, website/index.html, website/public/landing.html + +### AC#2 — Maps sync +- Changed `MAPS_SYNC_URL` in docker-compose.yml: `wss://sync.rmaps.online` → `wss://maps-sync.rspace.online` +- Changed fallback in `modules/rmaps/mod.ts` to `wss://maps-sync.rspace.online` +- Added `Host(maps-sync.rspace.online)` to rmaps-sync Traefik labels on Netcup +- Added `maps-sync.rspace.online` CNAME in Cloudflare DNS +- Added `!Host(maps-sync.rspace.online)` exclusion to rspace-canvas wildcard Traefik rule + +### AC#3 — Twenty CRM +- Already resolved: main docker-compose uses `TWENTY_API_URL=http://twenty-ch-server:3000` (internal Docker DNS) +- Fallback in rnetwork module already points to `crm.rspace.online` +- Fixed legacy docker-compose.standalone.yml: `https://rnetwork.online` → `https://crm.rspace.online` diff --git a/backlog/tasks/task-51.2 - Phase-1-Convert-standalone-domain-rewrite-to-301-redirects.md b/backlog/tasks/task-51.2 - Phase-1-Convert-standalone-domain-rewrite-to-301-redirects.md index 5a11c29..77cdc51 100644 --- a/backlog/tasks/task-51.2 - Phase-1-Convert-standalone-domain-rewrite-to-301-redirects.md +++ b/backlog/tasks/task-51.2 - Phase-1-Convert-standalone-domain-rewrite-to-301-redirects.md @@ -4,7 +4,6 @@ title: 'Phase 1: Convert standalone domain rewrite to 301 redirects' status: Done assignee: [] created_date: '2026-02-25 07:47' -updated_date: '2026-03-14 21:55' labels: - infrastructure - domains @@ -13,9 +12,6 @@ dependencies: - TASK-51.1 parent_task_id: TASK-51 priority: high -status_history: - - status: Done - timestamp: '2026-03-14 21:55' --- ## Description @@ -28,14 +24,12 @@ Target: server/index.ts lines 482-521. Redirect HTML page loads, continue proxyi ## Acceptance Criteria -- [ ] #1 rmaps.online/some-room returns 301 to rspace.online/demo/maps/some-room -- [ ] #2 rbooks.online/ returns 301 to rspace.online/demo/books -- [ ] #3 API and WebSocket requests still proxied without redirect -- [ ] #4 keepStandalone domains unaffected +- [x] #1 rmaps.online/some-room returns 301 to rspace.online/demo/maps/some-room +- [x] #2 rbooks.online/ returns 301 to rspace.online/demo/books +- [x] #3 API and WebSocket requests still proxied without redirect +- [x] #4 keepStandalone domains unaffected ## Implementation Notes - -Already implemented: 301 redirects in server/index.ts for all 25 standalone domains - +301 redirect logic fully implemented in server/index.ts lines 2028-2098. domainToModule map built from mod.standaloneDomain, proper 301 Response.redirect issued, API/WS paths excluded. Traefik labels route all 20 standalone domains. diff --git a/backlog/tasks/task-51.3 - Phase-3-Update-UI-links-app-switcher-landing-page.md b/backlog/tasks/task-51.3 - Phase-3-Update-UI-links-app-switcher-landing-page.md index 7e43db5..9420df8 100644 --- a/backlog/tasks/task-51.3 - Phase-3-Update-UI-links-app-switcher-landing-page.md +++ b/backlog/tasks/task-51.3 - Phase-3-Update-UI-links-app-switcher-landing-page.md @@ -1,9 +1,10 @@ --- id: TASK-51.3 title: 'Phase 3: Update UI links (app switcher, landing page)' -status: To Do +status: Done assignee: [] created_date: '2026-02-25 07:47' +updated_date: '2026-03-12 04:51' labels: - infrastructure - domains @@ -25,7 +26,13 @@ Files: shared/components/rstack-app-switcher.ts, shared/module.ts, website/index ## Acceptance Criteria -- [ ] #1 App switcher shows no external link arrows -- [ ] #2 Landing page ecosystem links use /demo/{moduleId} paths +- [x] #1 App switcher shows no external link arrows +- [x] #2 Landing page ecosystem links use /demo/{moduleId} paths - [ ] #3 ModuleInfo no longer exposes standaloneDomain to client + +## Implementation Notes + + +**2026-03-11:** Removed external link arrows from app switcher (HTML + CSS). Updated website/index.html, server/shell.ts, website/canvas.html EncryptID links → /rids. AC #3 deferred — standaloneDomain field kept for 301 redirect infra. + diff --git a/backlog/tasks/task-51.4 - Phase-4-Simplify-EncryptID-and-WebAuthn-for-single-domain.md b/backlog/tasks/task-51.4 - Phase-4-Simplify-EncryptID-and-WebAuthn-for-single-domain.md index d52b90d..7d3379b 100644 --- a/backlog/tasks/task-51.4 - Phase-4-Simplify-EncryptID-and-WebAuthn-for-single-domain.md +++ b/backlog/tasks/task-51.4 - Phase-4-Simplify-EncryptID-and-WebAuthn-for-single-domain.md @@ -1,9 +1,10 @@ --- id: TASK-51.4 title: 'Phase 4: Simplify EncryptID and WebAuthn for single domain' -status: To Do +status: Done assignee: [] created_date: '2026-02-25 07:47' +updated_date: '2026-03-12 04:51' labels: - infrastructure - domains @@ -30,3 +31,9 @@ Files: server/index.ts (.well-known/webauthn), public/.well-known/webauthn, src/ - [ ] #3 JWT aud is rspace.online only - [ ] #4 .well-known/webauthn no longer lists standalone domains + +## Implementation Notes + + +**2026-03-11:** Pruned allowedOrigins from ~30 entries to 16 (removed all r*.online standalone app domains that now 301 to rspace.online). Kept: rspace.online subdomains, ridentity.online (EncryptID's own domain), rsocials.online ecosystem, canvas-website migration, localhost. Simplified JWT aud from full origins array to single 'rspace.online' string. Removed rwallet.online from SIWE allowedDomains. Updated webauthn related origins (removed rwallet, kept ridentity + rsocials ecosystem). Updated EncryptID HTML template links to use rspace.online paths instead of r*.online domains. ridentity.online kept as canonical EncryptID/OIDC domain per user decision. + diff --git a/backlog/tasks/task-66 - Vertical-canvas-toolbar-whiteboard-tools-zoom-dropdown.md b/backlog/tasks/task-66 - Vertical-canvas-toolbar-whiteboard-tools-zoom-dropdown.md new file mode 100644 index 0000000..27fa889 --- /dev/null +++ b/backlog/tasks/task-66 - Vertical-canvas-toolbar-whiteboard-tools-zoom-dropdown.md @@ -0,0 +1,35 @@ +--- +id: TASK-66 +title: Vertical canvas toolbar + whiteboard tools + zoom dropdown +status: Done +assignee: [] +created_date: '2026-02-27 22:46' +labels: + - canvas + - ux + - toolbar +dependencies: [] +priority: medium +--- + +## Description + + +Convert the canvas toolbar from horizontal (top center) to vertical (left side). Add whiteboard drawing tools dropdown and nest zoom controls under a dropdown. Includes collapsible toggle. + + +## Acceptance Criteria + +- [ ] #1 Toolbar is vertical on the left side with dropdowns opening to the right +- [ ] #2 Whiteboard 'Draw' dropdown with pencil, sticky note, rectangle, circle, line, eraser +- [ ] #3 Zoom controls nested under a 'Zoom' dropdown group +- [ ] #4 Toolbar collapsible via subtle toggle pill at bottom +- [ ] #5 Mobile responsive layout preserved +- [ ] #6 SVG overlay for whiteboard drawing on canvas + + +## Final Summary + + +Implemented in commits f8bd09d, 683df43, merged to main as 76f7da8.\n\nChanges to website/canvas.html:\n- #toolbar CSS: flex-direction column, fixed left:12px, scrollable, dropdowns open right\n- New 'Draw' toolbar group: pencil (freehand SVG path), sticky note (yellow markdown shape), rectangle, circle, line, eraser (click SVG elements to delete)\n- SVG overlay inside canvas-content for whiteboard strokes\n- Zoom in/out/reset nested under 'Zoom' dropdown group\n- Collapse toggle moved to bottom as subtle '···' pill, collapses to '▶'\n- Separators now horizontal (full width, 1px height)\n- Mobile styles updated for vertical layout\n- SHAPE_ICONS updated with creative tool entries + diff --git a/backlog/tasks/task-67 - Context-aware-MI-bar-across-all-rspace.online-headers.md b/backlog/tasks/task-67 - Context-aware-MI-bar-across-all-rspace.online-headers.md new file mode 100644 index 0000000..54ad0ec --- /dev/null +++ b/backlog/tasks/task-67 - Context-aware-MI-bar-across-all-rspace.online-headers.md @@ -0,0 +1,34 @@ +--- +id: TASK-67 +title: Context-aware MI bar across all rspace.online headers +status: Done +assignee: [] +created_date: '2026-02-27 22:46' +labels: + - ai + - ux + - mi + - header +dependencies: [] +priority: medium +--- + +## Description + + +Enhance rstack-mi component to gather page context (open shapes, active tab, page title) and send to /api/mi/ask for context-aware responses. Update server system prompt to use extended context. MI bar already present in header of all pages via server/shell.ts. + + +## Acceptance Criteria + +- [ ] #1 rstack-mi gathers open canvas shapes, active tab, page title as context +- [ ] #2 Server /api/mi/ask accepts and uses context object in system prompt +- [ ] #3 MI identifies as 'mycelial intelligence' and references open content +- [ ] #4 Bar present in all pages: canvas, index, admin, create-space, server shell + + +## Final Summary + + +Implemented in commit f8bd09d, merged to main as 59f2be3.\n\nshared/components/rstack-mi.ts:\n- Added #gatherContext() method collecting space, module, open shapes (type+title+snippet), active tab, page title\n- Context sent with every /api/mi/ask request\n- Updated placeholder and welcome text\n\nserver/index.ts:\n- /api/mi/ask accepts context object\n- Extended system prompt includes open shapes, active tab, page title\n- Updated MI identity to 'mi (mycelial intelligence)' with guidance about connecting knowledge + diff --git a/backlog/tasks/task-68 - Canvas-toolbar-popout-click-to-place-double-click-edit-SVG-persistence.md b/backlog/tasks/task-68 - Canvas-toolbar-popout-click-to-place-double-click-edit-SVG-persistence.md new file mode 100644 index 0000000..3e0e9ea --- /dev/null +++ b/backlog/tasks/task-68 - Canvas-toolbar-popout-click-to-place-double-click-edit-SVG-persistence.md @@ -0,0 +1,85 @@ +--- +id: TASK-68 +title: 'Canvas toolbar popout, click-to-place, double-click edit, SVG persistence' +status: Done +assignee: [] +created_date: '2026-02-28 00:26' +updated_date: '2026-02-28 00:26' +labels: + - canvas + - ux + - toolbar +dependencies: [] +priority: medium +--- + +## Description + + +Canvas UX improvements: toolbar popout panel replaces inline dropdowns, click-to-place shapes at cursor position, double-click to edit shapes, whiteboard SVG drawing persistence via Automerge, + button opens rApps, dblclick canvas for pencil mode. + + +## Acceptance Criteria + +- [x] #1 Toolbar group click opens popout panel to the right (not inline dropdown) +- [x] #2 Click toolbar tool → cursor changes to crosshair → click canvas → shape at click position +- [x] #3 Shape avoids overlapping existing shapes (spiral search from click point) +- [x] #4 Double-click shape → edit mode → can type/interact with content +- [x] #5 Double-click empty canvas → pencil draw mode activates +- [x] #6 Draw with pencil → reload → drawings persist (wb-svg in Automerge) +- [x] #7 Click + button → rApp list opens in popout panel +- [x] #8 Reload page → all shapes retain x,y positions +- [x] #9 bunx tsc --noEmit passes + + +## Final Summary + + +## Changes + +### Toolbar Popout Panel (canvas.html CSS/HTML/JS) +- Added `#toolbar-panel` with header + body positioned right of `#toolbar` +- Group toggles populate the popout panel via `openToolbarPanel()`/`closeToolbarPanel()` +- Inline `.toolbar-dropdown` hidden with `display: none !important` when group is open +- Mobile: panel slides up from bottom as a sheet + +### Click-to-Place (canvas.html) +- `pendingTool` state with `setPendingTool()`/`clearPendingTool()` +- All toolbar buttons set pending tool instead of calling `newShape()` directly +- Canvas `pointerdown` checks `pendingTool`, converts screen→canvas coords, places shape +- Ghost outline (dashed teal) follows cursor while tool is pending; ESC cancels +- `findFreePosition(width, height, preferX?, preferY?)` refactored to accept anchor point + +### Double-Click Edit Mode (folk-shape.ts) +- `enterEditMode()`/`exitEditMode()` with `:state(editing)` internal state +- CSS: editing state enables `pointer-events: auto` on `.slot-container`, teal outline +- `dblclick` listener on shape calls `enterEditMode()`, focuses first focusable child +- Canvas background click calls `exitEditMode()` on all shapes + +### Click-to-Edit Markdown (folk-markdown.ts) +- Preview area click enters edit mode +- `edit-enter`/`edit-exit` custom events sync with parent shape editing state +- Refactored into `enterMarkdownEdit()`/`exitMarkdownEdit()` helpers + +### + Button Opens rApps (canvas.html) +- `#quick-add` button at top of toolbar opens rApps group in popout panel +- Mobile FAB first tap auto-opens rApps panel + +### SVG Drawing Persistence (community-sync.ts + canvas.html) +- `addShapeData()` method on CommunitySync for DOM-less shapes +- `wb-svg` type: SVG serialized on pointerup, stored in Automerge, recreated on load +- Eraser removes from both DOM and Automerge doc + +### Canvas dblclick → Pencil Mode +- dblclick on empty canvas background activates pencil drawing tool + +### Files Modified +- `website/canvas.html` — toolbar panel, click-to-place, findFreePosition, +button, SVG persistence, dblclick +- `lib/folk-shape.ts` — dblclick→editing state, enterEditMode/exitEditMode, CSS +- `lib/folk-markdown.ts` — click-to-edit preview, edit-enter/exit events +- `lib/community-sync.ts` — svgMarkup field, addShapeData() method + +### Commits +- `eee9cbe` — shape overlap push-aside, coordinate persistence, toolbar panel clipping +- `645f1fc` — SVG drawing persistence, click-to-edit markdown, quick-add rApps, dblclick pencil + diff --git a/backlog/tasks/task-72 - Standardize-canvas-header-to-match-renderShell-MI-bar-welcome-Try-Demo.md b/backlog/tasks/task-72 - Standardize-canvas-header-to-match-renderShell-MI-bar-welcome-Try-Demo.md new file mode 100644 index 0000000..5ddee68 --- /dev/null +++ b/backlog/tasks/task-72 - Standardize-canvas-header-to-match-renderShell-MI-bar-welcome-Try-Demo.md @@ -0,0 +1,49 @@ +--- +id: TASK-72 +title: 'Standardize canvas header to match renderShell (MI bar, welcome, Try Demo)' +status: Done +assignee: [] +created_date: '2026-02-28 01:10' +labels: + - fix + - canvas + - header + - ux +dependencies: [] +references: + - website/canvas.html + - server/shell.ts + - website/shell.ts +priority: high +--- + +## Description + + +Canvas.html was served as a static SPA fallback and had a hand-crafted header missing several features that renderShell() provides to all other rApp pages. Fixed to achieve full parity: + +1. **RStackMi registration**: `` tag was in the HTML but never registered as a custom element — MI bar was dead on canvas. Added import + define(). +2. **"Try Demo" button**: Added to header right section, with visibility logic (hidden on demo space, shown on bare domain). +3. **Embedded iframe detection**: Added `rspace-embedded` CSS + early script to hide shell chrome when canvas is loaded inside an iframe (e.g. folk-rapp). +4. **Welcome overlay**: Full popup for first-time demo visitors with "Create a Space" + "Explore Demo" actions. +5. **Auto-space resolution**: Logged-in users on demo space get redirected to their personal space via `/api/spaces/auto-provision`. +6. **auth-change listener**: Reloads space switcher dropdown when user signs in/out. +7. **`window.__rspaceNavUrl` global**: Exposed nav URL helper globally, matching shell.js behavior. + + +## Acceptance Criteria + +- [ ] #1 RStackMi imported and defined — MI bar functional on canvas +- [ ] #2 Try Demo button in canvas header with correct visibility logic +- [ ] #3 rspace-embedded iframe detection hides chrome when embedded +- [ ] #4 Welcome overlay shows for first-time demo visitors +- [ ] #5 Auto-space resolution redirects logged-in demo users to personal space +- [ ] #6 auth-change listener reloads space switcher on sign in/out +- [ ] #7 bun run build passes with zero errors + + +## Final Summary + + +Canvas.html now has full header parity with renderShell(). Added RStackMi registration (MI bar was dead), Try Demo button, iframe detection, welcome overlay, auto-space resolution, and auth-change listener. 1 file changed, +165 lines. Commit: 6c22559, merged dev→main as 6f80f7a. + diff --git a/backlog/tasks/task-73 - Logo-standardized-header-across-all-rSpace-pages.md b/backlog/tasks/task-73 - Logo-standardized-header-across-all-rSpace-pages.md new file mode 100644 index 0000000..c484796 --- /dev/null +++ b/backlog/tasks/task-73 - Logo-standardized-header-across-all-rSpace-pages.md @@ -0,0 +1,55 @@ +--- +id: TASK-73 +title: Logo + standardized header across all rSpace pages +status: Done +assignee: [] +created_date: '2026-02-28 01:17' +labels: + - ux + - header + - branding +dependencies: [] +references: + - website/public/shell.css + - website/public/landing.html + - website/index.html + - website/canvas.html + - website/admin.html + - website/create-space.html + - server/shell.ts +priority: medium +--- + +## Description + + +Added logo.png and the full standard rstack-header (app-switcher, space-switcher, MI bar, identity, Try Demo) to every page in rSpace: + +1. **Landing page** (`landing.html`): Replaced the simple Next.js `