Skip to content

Instantly share code, notes, and snippets.

@decagondev
Created February 18, 2026 19:21
Show Gist options
  • Select an option

  • Save decagondev/8376a56d59b86915780493df652c7548 to your computer and use it in GitHub Desktop.

Select an option

Save decagondev/8376a56d59b86915780493df652c7548 to your computer and use it in GitHub Desktop.

CollabBoard Code Audit Report

Date: February 18, 2026 Auditor: Automated code audit Codebase snapshot: main branch at time of audit Total source files: 33 TypeScript/TSX files across 3 packages Total lines of code: ~2,354 (excluding config, tests, and generated files)


1. Executive Summary

CollabBoard is a real-time collaborative whiteboard built with React/Fabric.js on the frontend and Hocuspocus/Yjs on the backend. The codebase is well-structured as a pnpm monorepo with shared TypeScript types, strict linting, and proper separation of concerns between hooks and components.

MVP Verdict: CONDITIONAL PASS

Seven of the nine MVP requirements are cleanly met. Two items have issues that need attention before the MVP can be considered fully passing:

  • Multiplayer cursors have a coordinate-space bug that causes remote cursors to display at incorrect positions after any pan or zoom operation.
  • Object editing is incomplete because individual object deletion is not exposed in the UI despite the underlying function existing in the useBoard hook.
  • Deployment status cannot be verified from the repository alone.

The architecture is sound and follows the Pre-Search document closely. The Yjs CRDT sync layer, Firebase authentication, and Fabric.js canvas rendering are all wired together correctly. The primary risks are in edge-case bugs (cursor coordinates, sync loop timing), missing hardening (no error boundaries, no structured logging, no graceful shutdown), and a documentation mismatch between the planned Fly.io deployment and the actual Render.com configuration.


2. MVP Requirements Checklist

Each requirement is assessed against the CLAUDE.md MVP gate criteria.

2.1 Infinite board with pan/zoom -- PASS

Implementation: packages/client/src/components/Board/Canvas.tsx lines 150-198

  • Pan via Alt+drag or middle mouse button using viewportTransform matrix manipulation
  • Zoom via scroll wheel with zoomToPoint(), clamped to 0.1x-5x range
  • Window resize handler updates canvas dimensions
  • Scene-center calculation accounts for viewport transform and zoom level

Assessment: Fully functional. Zoom centers on cursor position correctly. Pan and zoom compose well together.

2.2 Sticky notes with editable text -- PASS

Implementation:

  • Creation: packages/client/src/hooks/useBoard.ts createStickyNote() (lines 33-55)
  • Rendering: packages/client/src/components/Board/Canvas.tsx createStickyGroup() (lines 56-100)
  • Editing: Canvas.tsx double-click handler (lines 218-252) + textarea overlay (lines 452-482)

Assessment: Sticky notes are created as Fabric.js Groups (Rect background + Textbox). Double-click opens an HTML textarea overlay positioned at screen coordinates. Text saves on blur or Escape. Color is configurable from the toolbar palette. Fixed size (200x200), no rotation/resize on stickies.

2.3 At least one shape type -- PASS

Implementation:

  • Creation: packages/client/src/hooks/useBoard.ts createRectangle() (lines 57-79)
  • Rendering: Canvas.tsx rectangle sync (lines 336-378)

Assessment: Rectangles support creation, movement, resizing (with scale normalization), custom fill/stroke colors. Rotation is disabled. Meets the minimum requirement.

2.4 Create, move, and edit objects -- PARTIAL PASS

Implementation:

  • Create: Toolbar buttons create objects at scene center
  • Move: Fabric.js built-in drag via object:modified event synced to Yjs (lines 255-291)
  • Edit: Text editing via double-click overlay; color changes via toolbar palette
  • Delete: useBoard.deleteObject() exists (lines 96-102) but is never wired to any UI element

Gap: There is no way for a user to delete an individual object. No Delete/Backspace key handler, no right-click context menu, no delete button in the toolbar. The only destructive action available is "Clear All." The deleteObject function works correctly at the data layer but is inaccessible to users.

Recommendation: Wire Delete/Backspace key to deleteObject() for the currently selected Fabric object. This is a small change (~15 lines) that closes the MVP gap.

2.5 Real-time sync between 2+ users -- PASS

Implementation:

  • Yjs provider: packages/client/src/lib/yjs.ts creates HocuspocusProvider with Firebase token auth
  • Board state: Y.Map('objects') keyed by UUID, observed in Canvas.tsx (lines 308-419)
  • Server: packages/server/src/index.ts configures Hocuspocus with SQLite persistence via @hocuspocus/extension-database
  • Loop prevention: isRemoteUpdateRef and isLocalUpdateRef flags prevent Yjs observer / Fabric event infinite loops

Assessment: The sync architecture is correct. Objects created, moved, or edited by one user propagate to all connected clients via Yjs CRDT updates. The object:modified handler updates Yjs on local changes; the objectsMap.observe() handler updates Fabric on remote changes. Tested with real Y.Doc instances in useBoard.test.ts.

2.6 Multiplayer cursors with name labels -- BUG

Implementation:

  • Broadcasting: packages/client/src/hooks/useCursors.ts uses Yjs awareness protocol with 30ms throttle
  • Rendering: packages/client/src/components/Cursors/CursorOverlay.tsx

Bug: CursorOverlay positions remote cursors using raw scene coordinates as CSS left/top pixel values. However, cursor positions are broadcast in scene-space (via canvas.getScenePoint() in Canvas.tsx line 167). When any user pans or zooms, the overlay does not apply the local viewport transform to convert scene coordinates to screen coordinates.

Impact: After any pan or zoom operation, all remote cursors appear at incorrect screen positions. The further the local user pans/zooms from the origin, the more severe the offset. At 2x zoom, cursors are displaced by double their actual offset.

Fix: The CursorOverlay component (or a wrapper) needs access to the current viewportTransform matrix and zoom level. Each remote cursor's scene coordinates must be transformed: screenX = sceneX * zoom + vpt[4], screenY = sceneY * zoom + vpt[5].

2.7 Presence awareness (who's online) -- PASS

Implementation:

  • Hook: packages/client/src/hooks/usePresence.ts reads all Yjs awareness states
  • UI: packages/client/src/components/Presence/PresencePanel.tsx renders avatar + name list

Assessment: Shows online user count, color-coded avatars (photo or initial), and display names. Scrollable list supports multiple users. Presence state includes userId, displayName, photoURL, and color (deterministic hash of userId).

2.8 User authentication -- PASS

Implementation:

  • Client: packages/client/src/lib/firebase.ts (Google OAuth + email/password via Firebase Auth)
  • Auth state: packages/client/src/hooks/useAuth.ts with React Context
  • Route guard: packages/client/src/components/Auth/AuthGuard.tsx redirects to /login
  • Server WebSocket: packages/server/src/hocuspocus/onAuthenticate.ts verifies Firebase JWT via Admin SDK
  • Server HTTP: packages/server/src/middleware/auth.ts verifies Bearer token for API routes

Assessment: Authentication is implemented end-to-end. Both WebSocket (Hocuspocus) and HTTP (Express) connections require valid Firebase JWTs. Token refresh is handled by getIdToken() which waits for auth state on page refresh.

2.9 Deployed and publicly accessible -- UNVERIFIED

Implementation:

  • Frontend: packages/client/vercel.json configures Vercel deployment with SPA rewrites
  • Backend: render.yaml configures Render.com Docker deployment with persistent disk and health check
  • Docker: packages/server/Dockerfile multi-stage build targeting Node 20

Assessment: Deployment configuration exists for both frontend (Vercel) and backend (Render.com), but there is no evidence in the repository (deployment URLs, CI logs, environment configs) that the application has been successfully deployed and tested with two browser windows on a public URL. This must be verified externally.


3. Bugs and Defects

3.1 Critical

ID Bug Location Impact
BUG-001 Remote cursors ignore viewport transform (pan/zoom) CursorOverlay.tsx Remote cursor positions are wrong after any pan/zoom; core multiplayer feature broken
BUG-002 No individual object deletion in UI Toolbar.tsx, Canvas.tsx Users cannot delete specific objects; only "Clear All" available; MVP gap

3.2 Major

ID Bug Location Impact
BUG-003 LoginPage calls navigate() during render LoginPage.tsx:14-16 Violates React rules; may cause "Cannot update during render" warning; could cause redirect loops
BUG-004 isLocalUpdateRef race condition Canvas.tsx:264-289 If Yjs observer fires after flag is cleared (e.g., batched transactions), a feedback loop between Fabric and Yjs could occur
BUG-005 MAX_OBJECTS_PER_BOARD (500) not enforced useBoard.ts, constants.ts Unlimited objects can be created, potentially degrading performance below 60fps target

3.3 Minor

ID Bug Location Impact
BUG-006 Keyboard shortcuts advertised but not implemented Toolbar.tsx tooltips "(V)", "(S)", "(R)" Misleading UX; tooltips promise functionality that does not exist
BUG-007 useRequireAuth is a no-op wrapper useAuth.ts:26-29 Dead code; returns identical result to useAuthState(); unused in the codebase
BUG-008 lib/fabric.ts referenced in CLAUDE.md but does not exist packages/client/src/lib/ Documentation/plan divergence; no functional impact since Canvas.tsx handles setup directly

4. Architecture Review

4.1 Adherence to Pre-Search Architecture

The implementation closely follows the Pre-Search document and CLAUDE.md with a few notable deviations:

Planned Actual Assessment
Fly.io backend hosting Render.com (render.yaml) Significant deviation; Render starter plan has 15-min cold starts
lib/fabric.ts helper module Canvas setup inline in Canvas.tsx Minor; all logic works but is less modular
router.tsx separate file Routes inline in App.tsx Acceptable simplification
onChange Hocuspocus hook Not implemented No server-side validation of object changes
CORS middleware module Inline in index.ts Acceptable for 2-endpoint surface

4.2 Strengths

Monorepo structure: Clean three-package layout (client, server, shared) with pnpm workspaces. The @collabboard/shared package provides a single source of truth for board object types and constants.

Type system: Discriminated union BoardObject type with exhaustive type guards (isStickyNote, isRectangleShape, etc.). BaseBoardObject interface enforces consistent metadata fields. TypeScript strict mode with noUncheckedIndexedAccess catches undefined access on Yjs map reads.

Sync architecture: The Yjs/Fabric binding follows the correct pattern: local Fabric events update Yjs, Yjs observers update Fabric, and boolean ref flags prevent infinite loops. The object:modified handler normalizes Fabric scale back to 1 after saving actual dimensions, which prevents compounding scale drift.

Separation of concerns: Hooks (useYjs, useBoard, useCursors, usePresence) encapsulate all data logic. Components are purely presentational. BoardPage composes hooks and passes callbacks between components.

4.3 Weaknesses

Sticky note recreation: Every remote update to a sticky note destroys the existing Fabric Group and creates a new one (Canvas.tsx:324-335). With many stickies and frequent updates (e.g., rapid text editing by a remote user), this triggers full Group layout passes repeatedly. An in-place update strategy (updating sub-object properties) would be more performant but requires careful handling of Fabric.js Group layout internals.

Monolithic Canvas component: Canvas.tsx at 485 lines handles initialization, pan/zoom, object creation, object sync, text editing overlay, and selection tracking all in one component. This makes it the hardest file to maintain and test.

No error boundaries: A runtime error in any component (Canvas, Toolbar, CursorOverlay) will crash the entire React tree with a white screen. No ErrorBoundary wrapper exists.

Inline styles everywhere: All styling is done via React.CSSProperties objects. No CSS modules, Tailwind, or styled-components. This works but makes responsive design, hover states, and theme consistency harder to maintain.


5. Code Quality

5.1 TypeScript Configuration

  • strict: true with noUncheckedIndexedAccess: true -- excellent
  • ESLint @typescript-eslint/strict-type-checked -- highest strictness level
  • @typescript-eslint/no-explicit-any: "error" -- enforced
  • @typescript-eslint/consistent-type-imports: "error" -- enforced
  • Prettier configured with single quotes, trailing commas, 100 char width

ESLint suppressions: Two eslint-disable-next-line react-hooks/exhaustive-deps in Canvas.tsx (lines 304 and 418). Both are for effects that intentionally run only on mount or when objectsMap changes. These are acceptable patterns for imperative Fabric.js integration but should carry documentation explaining the rationale.

5.2 Testing

Test files found:

  • packages/client/src/hooks/useBoard.test.ts (289 lines, 14 test cases)
  • packages/server/src/hocuspocus/database.test.ts (94 lines, 6 test cases)

Coverage assessment:

  • Board CRUD operations: well tested with real Y.Doc instances
  • Yjs sync between two docs: tested (create, update, delete sync)
  • SQLite persistence: tested (load, store, overwrite, empty, large data)
  • Authentication hooks/middleware: not tested
  • Canvas rendering/sync: not tested (difficult without DOM/canvas mocking)
  • Cursor/presence hooks: not tested
  • AI handler: not tested (stub implementation)

Testing approach: Follows the CLAUDE.md guidance of "never mock Yjs" correctly. Both test files use real in-memory instances (Y.Doc, BetterSqlite3 :memory:). Test framework is Vitest.

Gap: The Pre-Search document targets "95%+ on the critical path" but actual coverage is limited to two files. The Yjs-to-Fabric binding functions in Canvas.tsx (identified as "most complex, most bug-prone") have zero test coverage.

5.3 Documentation

No JSDoc, Docstring, or structured documentation exists on any function, hook, component, or module. Interface types are self-documenting to a degree, but complex functions like syncObjectToCanvas, createStickyGroup, and the Canvas initialization effect have no documentation explaining their behavior, parameters, or side effects.

5.4 Code Style Consistency

  • Naming conventions followed: PascalCase components/types, camelCase hooks/utilities
  • UPPER_SNAKE_CASE for constants in shared/constants.ts
  • Event handlers use handle prefix internally
  • File naming: PascalCase for components, camelCase for hooks/lib (consistent with CLAUDE.md)
  • No any types found in the codebase

6. Security Assessment

6.1 Authentication -- Good

  • WebSocket: Hocuspocus onAuthenticate verifies Firebase JWT via firebase-admin SDK. Connections without valid tokens are rejected. User metadata (uid, displayName, photoURL, email) attached to connection context.
  • HTTP: Express authMiddleware extracts Bearer token and verifies via Firebase Admin SDK. Attaches userId and displayName to request.
  • Client: Firebase Auth SDK handles token lifecycle, refresh, and persistence.

6.2 Authorization -- Weak

  • No board-level authorization: Any authenticated user can access any board by navigating to /board/<boardId>. Board IDs are URL path segments (the default is literally "default"). While the Pre-Search document describes this as intentional ("anyone with the link can edit"), there is no mechanism to prevent enumeration of board IDs.
  • No Hocuspocus onConnect or onChange validation: The server does not validate that a user should have access to a specific board document. All authenticated users have full read/write access to all boards.

6.3 Input Validation -- Weak

  • AI endpoint: Checks for command and boardId existence only. No type validation, length limits, or sanitization.
  • Board objects: Data written to Y.Map('objects') is not validated against the BoardObject schema. A malicious client could inject arbitrary JSON into the map, potentially crashing other clients' canvas rendering.
  • Express body size: express.json() is called without a limit option. Default is 100KB which is reasonable, but should be explicitly set.

6.4 Secrets Management -- Acceptable

  • .env.example documents required variables without values
  • .gitignore excludes .env files
  • render.yaml marks secrets with sync: false
  • Firebase service account loaded from environment variable (JSON string or file path)
  • ANTHROPIC_API_KEY is server-side only

6.5 Security Headers -- Missing

No security headers middleware (Helmet or equivalent). Missing headers:

  • Strict-Transport-Security (HSTS)
  • Content-Security-Policy (CSP)
  • X-Content-Type-Options
  • X-Frame-Options
  • X-XSS-Protection (legacy but harmless)

Canvas rendering is inherently XSS-safe (draws pixels, not DOM), but the login page and any future HTML-rendered user content would benefit from CSP.

6.6 Rate Limiting -- Partial

  • AI endpoint: 10 requests/minute/IP via express-rate-limit -- good
  • WebSocket connections: no rate limiting -- a single IP could open unlimited connections
  • Board object creation: no rate limiting -- could flood the Yjs document

7. Robustness Evaluation

7.1 Error Handling

Area Status
Firebase auth errors Caught and displayed to user in LoginPage
WebSocket disconnect Connection banner shown; Hocuspocus auto-reconnects
Yjs sync errors No explicit handling; relies on Hocuspocus provider defaults
Canvas rendering errors No error boundary; crash = white screen
Server startup errors Will crash process; no retry logic
SQLite errors No try/catch around DB operations in database.ts
AI endpoint errors Stub returns placeholder; no real error handling yet

7.2 Logging

All logging uses console.log with tag prefixes:

  • [SERVER] in index.ts
  • [DB] in database.ts
  • [AUTH] in firebaseAdmin.ts
  • [YJS] in client yjs.ts and useYjs.ts

No structured logging library, no log levels, no request correlation IDs, no production log aggregation. The Pre-Search document recommends structured tagged logging with [HOCUS] and [AI] prefixes, which is partially followed.

7.3 Health Check

/api/health returns { status: 'ok' } unconditionally. It does not verify:

  • SQLite database connectivity
  • Hocuspocus server state
  • Memory/disk usage

For Render.com health checks, this means the service will appear healthy even if the database is corrupt or Hocuspocus has crashed internally.

7.4 Graceful Shutdown

No SIGTERM or SIGINT handler exists in index.ts. When Render.com sends SIGTERM during deploys or scaling:

  • In-flight WebSocket connections are terminated abruptly
  • SQLite writes may be interrupted (WAL mode provides some protection)
  • Yjs documents in memory are lost without a final persistence flush

7.5 Reconnection Resilience

  • Hocuspocus provider handles WebSocket reconnection automatically
  • UI shows "Reconnecting..." banner when disconnected
  • Yjs buffers local changes during disconnect and syncs on reconnect
  • No exponential backoff or user-facing retry button

8. Deployability Assessment

8.1 Documentation Mismatch

The CLAUDE.md file and Pre-Search document consistently reference Fly.io as the backend hosting platform. The actual deployment configuration uses Render.com (render.yaml). No fly.toml exists in the repository.

This is a significant documentation debt. Any developer (or evaluator) following CLAUDE.md instructions for deployment will encounter mismatched guidance.

8.2 Docker Configuration

Dockerfile (packages/server/Dockerfile):

  • Multi-stage build: builder stage compiles TypeScript, production stage copies built artifacts
  • Base image: node:20-slim
  • pnpm installed globally in both stages
  • /data directory created for SQLite persistent volume

Issues:

  • Runs as root (no USER node directive). Running containers as root is a security risk.
  • No HEALTHCHECK instruction. Container orchestrators cannot distinguish a healthy container from an unhealthy one without this.
  • pnpm install --frozen-lockfile --prod in production stage installs all workspace prod deps, including client deps that are not needed on the server.

8.3 Render.com Configuration

render.yaml services:

  1. collabboard-server: Docker web service with /api/health health check, 1GB persistent disk at /data
  2. collabboard-client: Static site built with pnpm, published from packages/client/dist

Issues:

  • starter plan spins down after 15 minutes of inactivity. WebSocket connections require an always-on server. Users connecting to a cold-started instance will experience a 30-60 second delay before the WebSocket server is ready.
  • ANTHROPIC_API_KEY is not listed in render.yaml environment variables (needed when AI handler is implemented).
  • No PORT environment variable listed (Render injects it automatically for Docker services, but explicit documentation would help).

8.4 Vercel Configuration

vercel.json (packages/client/vercel.json):

  • Build command chains: install -> build shared -> build client
  • SPA rewrite rule (/* -> /index.html)
  • Framework: Vite

Assessment: Standard Vercel SPA deployment. Should work correctly.

8.5 CI/CD

No CI/CD pipeline exists. No GitHub Actions, no Render.com auto-deploy hooks visible in the repo. The Pre-Search document notes "manual deploy" for the backend and "auto-deploy on push" for Vercel, which is likely configured outside the repository.


9. Hardening Phase Recommendations

Prioritized by impact and effort. Items marked (MVP-blocking) should be done before declaring MVP complete.

Priority 1: MVP-Critical Fixes

Item Effort Description
Fix cursor coordinate transform ~1 hour Pass viewportTransform and zoom from Canvas to CursorOverlay; transform scene coords to screen coords: screenX = sceneX * zoom + vpt[4]. (MVP-blocking, BUG-001)
Add individual object deletion ~30 min Add Delete/Backspace keydown listener on Canvas; call board.deleteObject(id) for the selected object. (MVP-blocking, BUG-002)
Fix LoginPage render-time navigation ~10 min Replace the if (user) { navigate(...) } block with a useEffect or <Navigate> component. (BUG-003)

Priority 2: Robustness (High Impact)

Item Effort Description
Add React error boundary ~30 min Wrap BoardPage in an ErrorBoundary component that catches canvas/rendering errors and shows a recovery UI instead of a white screen.
Add graceful shutdown handler ~30 min Listen for SIGTERM/SIGINT in index.ts; flush Hocuspocus documents to SQLite; close HTTP server; close DB connection.
Enforce MAX_OBJECTS_PER_BOARD ~20 min Check objectsMap.size before creating new objects in useBoard; show user feedback when limit reached.
Add Express body size limit ~5 min Pass { limit: '100kb' } to express.json().
Deep health check ~30 min Make /api/health verify SQLite read and Hocuspocus document count. Return 503 if unhealthy.

Priority 3: Security Hardening

Item Effort Description
Add security headers ~15 min Install helmet and add as Express middleware. Covers HSTS, CSP, X-Content-Type-Options, etc.
Add Yjs data validation ~1 hour Validate board objects against the BoardObject schema when received from Yjs observers. Reject/ignore malformed data.
Add non-root Docker user ~10 min Add RUN addgroup --system app && adduser --system --ingroup app app and USER app to Dockerfile.
Board-level access control ~2 hours Optional: add board creator tracking and invite-based access. Low priority for demo/evaluation use case.

Priority 4: Code Quality

Item Effort Description
Add JSDoc to all hooks and key functions ~2 hours Document parameters, return values, side effects, and usage for useBoard, useYjs, useCursors, syncObjectToCanvas, createStickyGroup, etc.
Implement keyboard shortcuts ~1 hour Add keydown listener for V (select), S (sticky), R (rectangle), Delete/Backspace (delete selected). Remove misleading tooltips or make them functional.
Extract Canvas sub-modules ~2 hours Split Canvas.tsx (485 lines) into: pan/zoom handler, object sync observer, text editing overlay, and selection manager.
Add error boundary tests ~1 hour Test that rendering errors in child components are caught and displayed.
Remove dead code ~10 min Remove useRequireAuth (unused, no-op wrapper).

Priority 5: Deployment Hardening

Item Effort Description
Update CLAUDE.md for Render.com ~30 min Replace all Fly.io references with Render.com; document actual deployment commands and configuration.
Add Docker HEALTHCHECK ~5 min Add `HEALTHCHECK CMD wget -q --spider http://localhost:$PORT/api/health
Upgrade Render plan for always-on ~5 min Switch from starter to a paid plan that does not spin down, or implement a keep-alive ping. Cold starts break WebSocket-dependent applications.
Add ANTHROPIC_API_KEY to render.yaml ~5 min Add the env var entry (with sync: false) for when AI handler is implemented.
Add CI pipeline ~2 hours GitHub Actions workflow: install -> typecheck -> lint -> test -> build. Block merges on failure.

Priority 6: Performance

Item Effort Description
In-place sticky note updates ~2 hours Instead of destroying/recreating the Fabric Group on every remote update, update sub-object properties in place. Requires careful handling of Fabric.js Group layout.
Add structured logging ~1 hour Replace console.log with a lightweight logger (e.g., pino) with log levels, timestamps, and structured JSON output.
Add WebSocket connection limits ~30 min Limit concurrent connections per IP or per user to prevent resource exhaustion.

10. Appendix: File Inventory

packages/client/src/ (Frontend)

File Lines Purpose
main.tsx 12 React entry point, mounts App to DOM
App.tsx 26 React Router setup with auth-guarded routes
vite-env.d.ts 1 Vite type declarations
components/Auth/AuthProvider.tsx 12 React Context provider for auth state
components/Auth/AuthGuard.tsx 25 Route guard; redirects unauthenticated users to /login
components/Auth/LoginPage.tsx 147 Login UI with Google OAuth and email/password forms
components/Board/BoardPage.tsx 83 Main board container; composes all hooks and components
components/Board/Canvas.tsx 485 Fabric.js canvas: init, pan/zoom, object sync, text editing
components/Cursors/CursorOverlay.tsx 68 SVG cursor rendering overlay for remote users
components/Presence/PresencePanel.tsx 95 Online users panel with avatars and names
components/Toolbar/Toolbar.tsx 170 Tool selection, color palette, clear board button
hooks/useAuth.ts 29 Firebase auth state hook and AuthContext
hooks/useYjs.ts 43 Yjs document and Hocuspocus provider lifecycle
hooks/useBoard.ts 132 Board CRUD operations against Yjs Y.Map
hooks/useCursors.ts 87 Cursor position broadcasting/receiving via awareness
hooks/usePresence.ts 35 Online users list from awareness state
hooks/useBoard.test.ts 289 Unit tests for board CRUD and Yjs sync
lib/firebase.ts 61 Firebase app/auth initialization and auth methods
lib/yjs.ts 41 Yjs provider factory with token auth

packages/server/src/ (Backend)

File Lines Purpose
index.ts 65 Entry point: HTTP server + WebSocket upgrade + Hocuspocus
hocuspocus/onAuthenticate.ts 26 Firebase JWT verification for WebSocket connections
hocuspocus/firebaseAdmin.ts 32 Firebase Admin SDK singleton initialization
hocuspocus/database.ts 39 SQLite document persistence (load/store)
hocuspocus/database.test.ts 94 SQLite persistence unit tests
ai/handler.ts 26 AI command handler (stub, returns placeholder)
middleware/auth.ts 30 Express Bearer token verification middleware
middleware/rateLimit.ts 12 Express rate limiter factory (10 req/min/IP)

packages/shared/src/ (Shared Types)

File Lines Purpose
index.ts 2 Re-exports types and constants
types.ts 115 BoardObject discriminated union, type guards, cursor/presence types
constants.ts 48 Colors, dimensions, limits, rate-limit config

Configuration Files

File Purpose
package.json (root) Workspace scripts, shared devDependencies
pnpm-workspace.yaml Workspace package paths
tsconfig.base.json Base TypeScript config (strict, ES2022)
.eslintrc.json ESLint strict-type-checked + Prettier
.prettierrc Code formatting rules
render.yaml Render.com deployment (server + client)
packages/client/vercel.json Vercel frontend deployment
packages/server/Dockerfile Multi-stage Docker build
.env.example Environment variable documentation

End of audit report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment