--- id: TASK-47 title: 'Implement System Clock / Heartbeat Service for rSpace canvas' status: To Do assignee: [] created_date: '2026-02-18 22:30' labels: - feature - infrastructure - ecosystem 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 --- ## Description Add a server-side System Clock service that broadcasts consistent time signals across the rSpace canvas via the Event Bus (TASK-43). This provides a shared temporal heartbeat that all shapes, modules, and connected r-ecosystem apps can subscribe to. **Why**: Currently there is no shared sense of time passing in rSpace. Individual shapes have no way to trigger time-based behavior (recurring updates, countdowns, reminders, periodic recalculations). A system clock provides the foundational "pulse" that time-aware features depend on. ### Architecture New file `server/clock-service.ts`: - `SystemClock` class running server-side (not per-client) - Emits events on the CanvasEventBus at configurable intervals: - `clock:tick` — every 60 seconds (primary heartbeat) - `clock:minute:5` — every 5 minutes - `clock:hourly` — every hour - `clock:daily` — at midnight UTC (configurable timezone) - Payload includes: `{ timestamp, isoString, hour, minute, dayOfWeek, tickCount }` - Single authoritative source — server emits, clients receive via CRDT sync - Graceful degradation: if server is offline, clients can run a local fallback clock ### Shape Integration Shapes opt in by subscribing to clock channels: ```typescript // In a Budget shape subscriptions: ['clock:hourly'] onEventReceived(channel: 'clock:hourly', payload) { this.recalculate(); } // In a Countdown shape subscriptions: ['clock:tick'] onEventReceived(channel: 'clock:tick', payload) { this.updateRemaining(payload.timestamp); } ``` ### Use Cases - **Timer/Countdown shapes**: Update display every tick - **Budget/Finance shapes**: Recalculate on hourly boundaries - **Calendar shapes**: Highlight "now" marker, trigger reminders - **Presence decay**: Mark users idle after N missed ticks - **Backlog surfacing**: External services can subscribe to clock events to trigger task reviews - **rTime.space foundation**: This clock becomes the temporal primitive that rTime.space builds on - **Workflow triggers**: "Run this workflow every day at 9am" ### Configuration Server-level config in community settings: - `clock.enabled: true` (default true) - `clock.timezone: 'UTC'` (for daily boundary) - `clock.tickInterval: 60` (seconds, minimum 10) - `clock.channels: ['tick', 'minute:5', 'hourly', 'daily']` ### Performance Considerations - Clock events should NOT flood the CRDT eventLog — use a separate lightweight channel or mark as ephemeral (not persisted in ring buffer) - Server-side only emission prevents N clients from emitting N duplicate ticks - Tick events are fire-and-forget, no ack required ## 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