Skip to content

feat: real-time live activity feed for platform-wide registrations & claims - #1393

Merged
joelpeace48-cell merged 2 commits into
FinesseStudioLab:mainfrom
springswell:feat/live-activity-feed-1201
Sep 25, 2026
Merged

joelpeace48-cell merged 2 commits into
FinesseStudioLab:mainfrom
springswell:feat/live-activity-feed-1201

Conversation

@springswell

@springswell springswell commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds a real-time, platform-wide live activity feed: a ticker of recent campaign registrations and reward claims, pushed over the existing WebSocket server (#456) instead of polled.

How it works

on-chain event ─▶ eventIndexer (claim / register projected)
                   └─ onActivity(...) ─▶ WebSocketServer.publishActivity()
                                          └─ broadcast to room "activity" ─▶ <LiveActivityFeed />

Backend

  • backend/src/jobs/eventIndexer.js:
    • New optional onActivity callback on createEventIndexer.
    • The claim and register handlers call it through emitActivity() after the event has been projected into the DB.
    • Errors from the callback are caught and logged, so the feed can never stall indexing.
    • When no callback is passed, the indexer behaves as before.
  • backend/src/websocket/server.js:
    • New publishActivity(activity) broadcasts { type: 'activity', id, kind, wallet, campaignId, amount, ledger, timestamp } to the new activity room.
    • Only the registration and claim kinds are accepted.
    • Privacy: wallets are masked server-side as GABC…WXYZ via maskWallet. The message id uses only kind:txHash, so the full address never reaches subscribers.
  • backend/src/index.js: passes onActivity to the indexer. It resolves getWebSocketServer() lazily, because the WS server is attached after the HTTP server starts listening. When WebSockets are disabled, nothing is sent.

Clients opt in with the existing subscribe protocol, { type: 'subscribe', channel: 'activity' }, so there's no protocol change.

Frontend

  • frontend/src/lib/activityFeed.js: pure helpers:
    • normalizeActivity rejects malformed frames defensively;
    • addActivity puts newest first, de-duplicates by id and caps at 20;
    • formatActivityAmount converts stroops to points;
    • describeActivity and formatRelativeTime build the display text.
  • frontend/src/components/LiveActivityFeed.jsx:
    • Uses the existing getWebSocketClient() singleton, whose reconnect/resubscribe logic already existed.
    • Subscribes to activity and shows a Live / Connecting… status indicator.
    • Relative times refresh every 15s.
    • Uses an aria-live list and unsubscribes on unmount.
    • The client can be injected via the client prop for tests or Storybook.
  • frontend/src/components/LiveActivityFeed.css: slide-in and pulse micro-animations, disabled under prefers-reduced-motion. Uses theme tokens with fallbacks, so it follows light and dark themes.

Tests

backend/src/websocket/activity-feed.test.js (node:test) covers:

  • maskWallet;
  • emitActivity mapping for claims and registrations, a missing wallet, a missing callback and a throwing callback;
  • an end-to-end subscribe → publishActivity → receive test, which also asserts the full wallet never appears in the payload;
  • rejection of unknown kinds.

Not done / not verified (raised early on request)

Event indexer gains an onActivity hook fired after claim/register
events are projected; index.js forwards them to the new
WebSocketServer.publishActivity, which broadcasts masked-wallet
'activity' messages to the 'activity' channel.

Refs FinesseStudioLab#1201
Subscribes to the 'activity' WebSocket channel and renders a live,
de-duplicated, capped ticker of registrations and reward claims with
connection status, relative times and reduced-motion-aware animations.

Closes FinesseStudioLab#1201
@drips-wave

drips-wave Bot commented Sep 25, 2026

Copy link
Copy Markdown

@springswell Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@joelpeace48-cell
joelpeace48-cell merged commit 8cbdc38 into FinesseStudioLab:main Sep 25, 2026
11 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment