Skip to content

Feat/add collab mode#20

Merged
Kripu77 merged 62 commits intomainfrom
feat/add-collab-mode
Mar 1, 2026
Merged

Feat/add collab mode#20
Kripu77 merged 62 commits intomainfrom
feat/add-collab-mode

Conversation

@Kripu77
Copy link
Owner

@Kripu77 Kripu77 commented Mar 1, 2026

Summary by CodeRabbit

  • New Features

    • Introduced real-time collaboration enabling multiple users to work on boards simultaneously
    • Added live cursor tracking to display remote user positions on shared boards
    • Implemented collaboration status bar showing online users and connection state
    • Added board sharing functionality via URL generation for inviting others
    • Introduced user nickname management and presence indicators
    • Added connection status display (connected, reconnecting, disconnected)
  • Tests

    • Added comprehensive test coverage for collaboration functionality

Kripu77 and others added 16 commits February 28, 2026 16:58
* feat: add PostHog analytics with reverse proxy

- Initialize PostHog client in instrumentation-client.ts
- Add server-side client with session ID support
- Configure /ingest reverse proxy for ad-blocker resilience
- Enable performance monitoring, error tracking, console logs

* feat: add server-side PostHog tracking to AI API routes

- Track ai_chat_requested and ai_structure_requested events
- Use session-based distinct IDs for anonymous tracking

* feat: add PostHog tracking to toolbar components

- Track undo/redo actions with stack sizes
- Track zoom changes (in/out/fit/reset) with zoom levels
- Track selection formatting (fill, stroke, width, style changes)

* feat: add PostHog tracking to board interactions

- Track grid type, spacing, and major grid changes
- Track pencil mode toggle
- Track image insertions (source, target, dimensions) and fullscreen views
- Track element deletions via eraser tool

* feat: add PostHog tracking to image, eraser, and app actions

- Track image insertions (source, target, dimensions)
- Track image fullscreen views
- Track element deletions via eraser tool
- Track board lifecycle (created, deleted, renamed, switched)
- Track file operations (save, open, export, clear)

* chore: update gitignore and Next.js env types

* chore: add .claude/ to .gitignore

* fix: improve PostHog initialization safety and configuration

- Validate POSTHOG_KEY before initialization to prevent crashes
- Fix invalid defaults value (2026-01-30 -> 2025-11-30)
- Make console log recording environment-aware (dev only)
- Register process-level shutdown handlers instead of per-request
- Batch events with flushAt: 10 and flushInterval: 5000ms
- Handle missing PostHog key gracefully with warning

* fix: extract duplicated model name resolution and handle null PostHog

- Create shared resolveModelName utility function
- Handle null PostHog client gracefully in API routes

* fix: correct telemetry placement and state consistency

- Move tool_selected capture after board null check
- Fix toggleHanddrawn to use newMode in setState
- Add resulting zoom level to zoom_fit_to_screen event
- Add @liveblocks/client, @liveblocks/react, @liveblocks/node for real-time collaboration
- Add @dicebear/core, @dicebear/avataaars for avatar generation
- Add unique-names-generator for anonymous user nicknames
- Add posthog-js, posthog-node for product analytics
- Add provider-agnostic collaboration types (CollaborationUser, Cursor, UserPresence)
- Add CollaborationProvider abstraction wrapping Liveblocks
- Add hooks: useCollaborationContext, useRoomPresence, usePresence, useCursorTracking
- Add cursor overlay and avatar components
- Add user identity generation with DiceBear avatars and unique nicknames
- Add cursor manager for presence tracking
- Uses peerDependencies for React, Liveblocks to avoid duplication
- Define Presence types for cursor, selection, viewport, user
- Define Storage schema for Plait elements
- Define UserMeta for user info (name, color, avatar)
- POST /api/collaboration/auth authenticates users for room access
- Validates required fields (userId, userName, userColor)
- Creates Liveblocks session with full access to specified room
- Returns authorized session token
- Add Room component with Liveblocks RoomProvider and ClientSideSuspense
- Add CollaborativeBoard with cursor overlay and board sync
- Add CollaborationStatusBar showing online users and share button
- Integrate with @thinkix/collaboration package hooks and components
- Add server-side PostHog client with environment detection
- Add instrumentation for PostHog initialization on server start
- Support both client-side (posthog-js) and server-side (posthog-node)
- Add RemoteSyncHandler component for collaboration sync
- Listen for thinkix:remote-elements-change custom events
- Use Plait's useListRender to update board from remote changes
- Dispatch thinkix:local-elements-change on local board changes
- Add collaboration prop for showing online status and controls
- Add share board, change nickname, leave collaboration actions
- Add nickname dialog for changing user name
- Show collaboration options on mobile when enabled
- Add room detection from URL params (?room=xxx)
- Add collaboration toggle with enable/disable functions
- Wrap board in Room provider when collaboration enabled
- Show Collaborate button and CollaborationStatusBar
- Use Suspense boundary for useSearchParams
- Add @thinkix/collaboration to paths in tsconfig
- Update vitest config to include collaboration package paths
- Add cursor manager unit tests for presence tracking
- Add user identity tests for avatar and nickname generation
- Add cursor collaboration integration tests
- Add vitest snapshots for avatar generation
…ations

- Add Yjs adapter package with Y.Map-based element storage
- Replace O(n) findIndex operations with O(1) map lookups
- Use transaction origin tracking to prevent sync echo loops
- Add isLocalChange flag to distinguish local vs remote updates
- Update collaborative-board.tsx to use new YjsProvider
- Add yjs and @liveblocks/yjs dependencies
- Integrate getVisibleCursors to only render cursors in viewport
- Add getActiveCursors to filter out idle cursors
- Add maxCursors limit (default 50) to prevent DOM overload
- Export cursor utilities from hooks index
- Export CollaborationErrorBoundary from components
- Add CollaborationErrorBoundary class component
- Add ConnectionIndicator for connection status display
- Provides retry functionality on connection errors
- Add BoardLayoutSlots for positioned toolbar containers
- Add CollaborateButton as standalone component
- Add CollaborativeAppMenu to wrap AppMenu with collaboration context
- Simplify page.tsx to only orchestrate components
- Slots now render inside BoardCanvas for proper positioning context
@vercel
Copy link

vercel bot commented Mar 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
thinkix Ready Ready Preview, Comment Mar 1, 2026 10:39am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 1, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces a complete real-time collaboration system with Liveblocks and Yjs integration. Adds a new @thinkix/collaboration package providing room-based multi-user synchronization, presence tracking with remote cursor visualization, avatar display, authentication handling, and comprehensive hooks/components. Integrates collaboration into the main board application with conditional rendering based on collaboration state. Updates dependencies, API route for auth, and test coverage across all new features.

Changes

Cohort / File(s) Summary
Collaboration Package Core
packages/collaboration/package.json, packages/collaboration/tsconfig.json, packages/collaboration/src/index.ts, packages/collaboration/src/types.ts, packages/collaboration/src/user-identity.ts, packages/collaboration/src/sync-bus.ts, packages/collaboration/src/cursor-manager.ts
Establishes the collaboration package infrastructure with comprehensive type definitions, user identity generation via DiceBear avatars and unique-names-generator, a pub/sub sync bus for local/remote element changes, and cursor state management with viewport transforms and idle timeout handling.
Collaboration Providers & Hooks
packages/collaboration/src/adapter/yjs-provider.tsx, packages/collaboration/src/adapter/collaboration-context.tsx, packages/collaboration/src/adapter/index.ts, packages/collaboration/src/providers/liveblocks/*, packages/collaboration/src/hooks/use-*.ts
Integrates Yjs and Liveblocks with React context for room state, presence updates, sync status, and element mutations. Provides hooks for board synchronization, cursor tracking, collaboration state persistence, and viewport coordinate transformations. Manages connection status, user presence, and bidirectional sync between local and remote peers.
Collaboration UI Components
packages/collaboration/src/components/cursor-overlay.tsx, packages/collaboration/src/components/avatars.tsx, packages/collaboration/src/components/ui.tsx, packages/collaboration/src/components/error-boundary.tsx, packages/collaboration/src/components/index.ts
Renders remote user cursors with document-to-screen coordinate conversion, live avatar strips with overflow indicators, presence status (connected/reconnecting/disconnected), nickname dialog, share button, collaboration panel toggle, and error boundary with retry logic.
Board Collaboration Integration
features/collaboration/components/collaborative-board.tsx, features/collaboration/components/room.tsx, features/collaboration/components/collaborative-app-menu.tsx, features/collaboration/components/collaborate-button.tsx, features/collaboration/index.ts
Wraps board with Yjs/Liveblocks providers, syncs element mutations bidirectionally via sync bus, applies remote cursor tracking, displays collaboration status bar with user count and connection state, integrates nickname/share dialogs, and toggles collaborative UI based on room state.
Board Layout & Canvas Updates
features/board/components/BoardLayoutSlots.tsx, features/board/components/BoardCanvas.tsx, features/board/components/index.ts
Introduces BoardLayoutSlots for flexible slot-based UI composition (topLeft, bottomLeft, topRight), and extends BoardCanvas with RemoteSyncHandler to listen for remote element changes and apply them to local board state via the sync bus.
Main App & Navigation
app/page.tsx
Restructures app with Suspense boundaries, URL-based room parameter handling via useSearchParams, conditional collaboration state checks, and dual rendering paths: collaborative mode with Room, CollaborativeBoard, and collaborative slots vs. standard mode with regular BoardCanvas and slots. Integrates CollaborateButton and CollaborationStatusBar into the UI.
API & Authentication
app/api/collaboration/auth/route.ts, liveblocks.config.ts
Adds POST endpoint that validates userId, userName, userColor, constructs Liveblocks session with user info, optionally grants room FULL_ACCESS, and returns authorization token. Defines global Liveblocks type augmentation for Presence, Storage, UserMeta, and RoomInfo.
Toolbar & Configuration
features/toolbar/components/AppMenu.tsx, eslint.config.mjs, tsconfig.json, vitest.config.mts
Extends AppMenu with collaboration prop containing user, userCount, roomId, and callbacks for share/nickname/leave; renders NicknameDialog and collaboration actions conditionally. Updates ESLint to ignore coverage/ and include collaboration components. Adds TypeScript and Vitest path aliases for the new collaboration package.
Dependencies & Build Config
package.json, lib/posthog-server.ts
Adds @liveblocks/node@3.14.1 and yjs@13.6.29 dependencies. Fixes posthog-server to call crypto.randomUUID() inline instead of importing randomUUID, avoiding runtime errors.
Patches
patches/@plait+draw+0.92.3.patch
Refactors shape rendering calls to avoid explicit fillStyle: 'solid' spreading and removes some fill properties, standardizing how options are passed to drawing primitives.
Comprehensive Test Coverage
tests/components/*.test.tsx, tests/unit/*.test.ts, tests/e2e/collaboration.test.ts, tests/__mocks__/setup.mts
Adds ~1500+ lines of unit, integration, and end-to-end tests covering: collaboration components (avatars, dialogs, panels), cursor management with coordinate transforms and idle timeouts, collaboration state/context/hooks, Yjs provider integration, API authentication, sync bus, user identity generation, viewport utilities, timing helpers, and multi-user scenarios via Playwright.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client/Browser
    participant Auth as Auth Endpoint
    participant Liveblocks as Liveblocks Service
    participant Yjs as Yjs Sync
    participant Peer as Remote Peer

    Client->>Auth: POST /api/collaboration/auth<br/>(userId, userName, userColor, room)
    Auth->>Liveblocks: authorizeWithToken(sessionInfo)
    Liveblocks-->>Auth: authorization token
    Auth-->>Client: token response

    Client->>Liveblocks: connectToRoom(roomId, token)
    Client->>Yjs: initializeYjsDoc()
    Yjs->>Liveblocks: subscribeLiveblocks
    Client->>Client: renderRoom with YjsProvider + RoomProvider

    Peer->>Yjs: updateRemoteElements
    Yjs-->>Client: remoteElementsChanged
    Client->>Client: updateLocalBoard(remoteElements)
    Client->>Client: triggerRemoteSyncHandler

    Client->>Client: localBoardChange
    Client->>Yjs: emitLocalChange(elements)
    Yjs->>Peer: broadcastUpdate
    Peer->>Peer: applyRemoteChange

    Client->>Client: pointerMove
    Client->>Liveblocks: updatePresence(cursor)
    Liveblocks->>Peer: broadcastPresenceUpdate
    Peer->>Peer: renderRemoteCursor
Loading
sequenceDiagram
    participant Board as Local Board
    participant SyncBus as Sync Bus
    participant RemoteSync as RemoteSyncHandler
    participant Elements as Element State

    Board->>Board: handleChange(newElements)
    Board->>SyncBus: emitLocalChange(newElements)
    SyncBus->>RemoteSync: notifyLocalChangeSubscribers
    RemoteSync->>RemoteSync: onRemoteChange(newElements)
    RemoteSync->>Elements: updateElements(newElements)
    Elements->>Board: rerender(updatedElements)

    rect rgba(100, 150, 200, 0.5)
        Note over SyncBus,Elements: Remote peer emits change
    end
    
    RemoteSync->>SyncBus: subscribeToRemoteChanges
    SyncBus->>RemoteSync: notifyRemoteChangeSubscribers
    RemoteSync->>Elements: applyRemoteElements
    Elements->>Board: refreshWithRemoteData
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • PR #19: Modifies lib/posthog-server.ts to change randomUUID() import and usage pattern, directly related to the posthog-server fix in this PR.
  • PR #16: Modifies features/board/components/BoardCanvas.tsx for cursor class logic, while this PR extends the same file with RemoteSyncHandler and sync bus integration.

Poem

🐰 Hopping into rooms with cursors bright,
Yjs and Liveblocks dance through the night,
Remote peers syncing, presence so fine,
Multi-user magic, now boards align!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Feat/add collab mode' directly reflects the main objective of adding collaboration functionality, which is extensively implemented across the changeset with new collaboration components, hooks, providers, and integration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/add-collab-mode

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Mar 1, 2026

⚠️ Test Results

Metric Coverage
Lines 0%
Functions 96.32%
Branches 84.91%
Statements 94.82%
Average 69.0%

📦 Download Coverage Report

How to view coverage report
  1. Download the coverage artifact from the link above
  2. Extract the ZIP file
  3. Open index.html in your browser

Commit: 04b6082ad6bbc225e90dbf29d686c5da8ee96d26

Kripu77 added 8 commits March 1, 2026 15:45
- Add viewport utilities (getViewport, screenToDocument, documentToScreen)
- Add timing utilities (debounce, throttle)
- Add SyncBus for type-safe event communication replacing window events
- Update CursorManager to use shared Viewport type
- Update useCursorTracking to use shared getViewport function
- Remove duplicate coordinate conversion code
- Debounce viewport recalculations (100ms default) for better performance
- Reduce main thread blocking with 100+ cursors
- Add configurable visibilityDebounceMs prop
- Use type-safe SyncBus pub/sub pattern instead of window.dispatchEvent
- Improves testability and removes global event pollution
- Enables proper cleanup with unsubscribe functions
- Export getSyncBus, resetSyncBus, and SyncBus type
- Export utils module for direct access
- Add tsconfig paths for @thinkix/collaboration/* sub-modules
- Update imports to use new sub-path exports
- Fix assertions to use screenX/screenY instead of x/y
- Align with shared viewport utilities
Replace removed 'randomUUID' import from 'crypto' with built-in
crypto.randomUUID() which is available in modern Node.js
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/unit/liveblocks-hooks.test.ts`:
- Around line 4-22: Replace the static mock with a shared configurable mockState
and stable spy functions so tests can both mutate state per test and assert
calls: create a module-level mockState object holding myPresence, users,
connectionStatus, userCount and isConnected and expose stable spies for
updateCursor, updateSelection, updateViewport and updateUserInfo; have the
mocked hooks (usePresence, useRoomPresence, useRoomConnection) return values
that read from mockState and return the stable spy functions so vi.fn()
instances are not recreated; in tests reset mockState and call
vi.clearAllMocks() in beforeEach to restore defaults and allow verifying call
counts and different connection/user scenarios.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebf178d and ad71c7b.

📒 Files selected for processing (3)
  • tests/unit/collaboration-context.test.tsx
  • tests/unit/liveblocks-hooks.test.ts
  • tests/unit/use-cursor-tracking.test.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/unit/use-cursor-tracking.test.tsx
  • tests/unit/collaboration-context.test.tsx

- Introduce new unit tests for the useBoardSync hook, covering initialization, remote elements, and syncToRemote functionality
- Update vitest configuration to include path aliases for collaboration-related files
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Add error isolation in sync-bus to prevent subscriber failures from propagating
- Replace noop assertions with real verifications in liveblocks-hooks and collaboration-context tests
- Use shared mock state for configurable test scenarios
- Replace waitForTimeout with explicit Playwright wait conditions
- Fix weak assertions to properly verify expected behavior
Kripu77 added 4 commits March 1, 2026 20:18
…ider

- Remove redundant CollaborationProvider (duplicated YjsProvider logic)
- Merge RoomProvider into provider.tsx
- Delete room-provider.tsx
- Update exports to use consolidated provider

This reduces code duplication and simplifies the provider hierarchy.
- Replace unsafe `as (patch: object) => void` casts with typed Parameters<typeof>
- Use proper type inference for updateMyPresence calls
- Add explicit PresenceUpdate type for clarity

This eliminates 8 unsafe type casts while maintaining Liveblocks compatibility.
- Replace `as (patch: unknown) => void` with Parameters<typeof> pattern
- Add PresencePatch type for presence updates
- Centralize type assertions at call sites

Reduces unsafe casts from 15+ to 4 controlled assertions at Liveblocks boundaries.
…mance

Offline handling:
- Queue local changes when disconnected
- Show warning banner 'Changes will sync when reconnected'
- Auto-sync queued changes on reconnection
- Prevents data loss during network drops

Performance improvement:
- Replace JSON.stringify comparison with hash-based approach
- generateElementsHash only hashes element IDs and types
- ~1000x less memory allocation on large boards
- Prevents GC pressure with 100+ collaborating users
…dling

- Introduce PresenceJson type for improved clarity in presence updates
- Replace unsafe type casts with structured conversion functions (toCursor, toViewport, toUser)
- Update presence handling logic to utilize new type definitions, reducing type assertion risks
- Refactor presence mapping in useRoomPresence and useYjsPresence for consistency and safety
@Kripu77 Kripu77 merged commit e622163 into main Mar 1, 2026
9 checks passed
@Kripu77 Kripu77 deleted the feat/add-collab-mode branch March 1, 2026 10:45
@coderabbitai coderabbitai bot mentioned this pull request Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant