103 lines
4.1 KiB
Markdown
103 lines
4.1 KiB
Markdown
---
|
|
id: TASK-47
|
|
title: Implement System Clock / Heartbeat Service for rSpace canvas
|
|
status: Done
|
|
assignee: []
|
|
created_date: '2026-02-18 22:30'
|
|
updated_date: '2026-03-11 23:19'
|
|
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
|
|
|
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
|
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
|
|
<!-- SECTION:DESCRIPTION:END -->
|
|
|
|
## Acceptance Criteria
|
|
<!-- AC:BEGIN -->
|
|
- [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
|
|
<!-- AC:END -->
|
|
|
|
## Implementation Notes
|
|
|
|
<!-- SECTION:NOTES:BEGIN -->
|
|
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.
|
|
<!-- SECTION:NOTES:END -->
|