Skip to content

Codebase refactor#42

Merged
CRIMSONHydra merged 9 commits into
mainfrom
refactor
Jun 10, 2026
Merged

Codebase refactor#42
CRIMSONHydra merged 9 commits into
mainfrom
refactor

Conversation

@CRIMSONHydra

@CRIMSONHydra CRIMSONHydra commented Jun 10, 2026

Copy link
Copy Markdown
Member

Test framework, type-checking, docs, tooling & bug fixes

Hardens Waves for production: adds full test suites and CI-style checks to both packages, introduces backend type-checking, consolidates configuration, writes a docs/ reference set, ports the .claude/ agent tooling, and fixes several latent bugs surfaced along the way.

Branch: refactormain · 57 files changed (+10,875 / −408)


Why

The app shipped to production with no automated tests, no backend linting or type-checking, duplicated/drifted configuration, and a handful of latent bugs. This PR puts a verifiable safety net under the codebase and documents how it actually behaves today.

What changed

🧪 Testing (new)

  • Backend — Vitest + Supertest + mongodb-memory-server. 68 tests covering every controller (auth, room, message), all three models, the auth middleware, generateToken, the shared CORS origins module, and the Socket.IO / WebRTC signaling relay (real client connections). ~88% statement coverage (100% on models/routes/utils).
  • Frontend — Vitest + React Testing Library + jsdom. 63 tests covering App routing, JoinRoom, CustomRoom, Documentation, and Chat (axios / socket.io-client / RTCPeerConnection / toastify mocked). 100% on CustomRoom/Documentation, ~97% JoinRoom, ~81% Chat.
  • Single-test commands documented; coverage output is git-ignored.

🔎 Backend lint + type-checking (new)

  • ESLint flat config (matching the frontend) and tsc --checkJs over src/**/*.js with JSDoc — type safety with no runtime change and no TypeScript migration.
  • New scripts: lint, typecheck, test, test:watch, test:coverage, and check (lint + typecheck + test).

🧱 Refactor & config consolidation

  • Extracted Express app wiring out of index.js into src/app.js (the single source of app configuration; what tests import). index.js is now a thin entry point (listen + connectDB).
  • CORS origins consolidated into src/libs/allowedOrigins.js (previously duplicated across app.js and socket.js and drifted). Extensible per-deployment via the CLIENT_ORIGINS env var; src/libs/env.js guarantees .env loads first. Documented in .env.example.

📚 Documentation (new docs/)

ARCHITECTURE, BACKEND_STRUCTURE, FRONTEND_STRUCTURE, DATABASE_SCHEMA, API, REALTIME, TESTING, and a README index with a doc-ownership map. CLAUDE.md updated with the new commands, conventions, and tooling notes.

🛠️ .claude/ tooling

  • block-destructive-git PreToolUse hook (guards against destructive git verbs).
  • CodeRabbit workflow: coderabbit-fixer agent + /fix-coderabbit command + auto-delegation hook, with per-file locking (session-lock.sh), background Monitor progress, and a SendMessage drip-feed concurrency model.

🐛 Bug fixes

Bug Fix
Chat.jsx subscribed to user-left; server emits userLeft → handler never fired Client subscribes to userLeft
login returned { id } while signup/check return { _id } login returns _id; frontend readers updated
protectedRoute returned 500 for an expired/invalid token Now returns 401
Socket.IO transports was nested inside cors (ignored) Moved to the top-level server option
Unmount cleanup captured socketRef.current synchronously (null) → socket never disconnected Cleanup reads the socket at cleanup time; emits leave + disconnects
Dead code: p2pSent (sent, ignored) + unused image schema field; 6 unused-var lint errors Removed

Verification

  • Backend: cd backend && npm run check → lint ✓ · typecheck ✓ · 68 tests ✓
  • Frontend: cd frontend && npm run lint (0 errors) · npm test → 63 tests ✓

Summary by CodeRabbit

  • New Features

    • Configurable CORS origins via env var; richer realtime/WebRTC signaling improvements.
  • Bug Fixes

    • Auth responses now return user id as _id.
    • Invalid/expired tokens return 401 (not 500).
    • Improved message deduplication and WebRTC disconnect cleanup.
  • Documentation

    • Added comprehensive repo and API docs.
  • Tests

    • Expanded backend and frontend test suites; added CI workflow.
  • Chores

    • Added git-safety pre-check and CI/audit automation.

fix: typechecker warnings
…move unused imports and enhance error handling
- Created comprehensive test suites for Chat, CustomRoom, and Documentation components to ensure proper rendering and functionality.
- Implemented tests for JoinRoom component, covering both anonymous and registered user flows.
- Added setup file for Vitest to configure testing environment and mock necessary browser APIs.
- Updated Vite configuration to include testing setup and coverage reporting.
…structure, database schema, frontend structure, real-time messaging, and testing procedures
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@CRIMSONHydra, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 47 minutes and 20 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7567c74f-5d22-4434-9e6e-c390eb152fc4

📥 Commits

Reviewing files that changed from the base of the PR and between fc91001 and 625aa51.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • CLAUDE.md
  • backend/tests/setup.js
  • backend/tests/socket.test.js
  • docs/FRONTEND_STRUCTURE.md
  • docs/TESTING.md
📝 Walkthrough

Walkthrough

This PR adds Claude automation and safety hooks, refactors backend app/CORS/env wiring and some contracts, implements extensive backend and frontend test infra and suites, updates frontend chat/join runtime flows, and adds comprehensive documentation and CI configuration.

Changes

Integrated backend, frontend, tooling, and docs update

Layer / File(s) Summary
Claude automation, locking, and safety guardrails
.claude/*, .claude/hooks/*, .claude/lib/*, .claude/scripts/*, .claude/settings.json, .claude/.gitignore
Adds CodeRabbit fixer agent docs/command, destructive-git PreToolUse hook, filesystem session lock with TTL, agent progress monitor, Claude settings, and per-file concurrency/locking rules.
Backend env, CORS, app wiring, and server bootstrap
backend/src/libs/env.js, backend/src/libs/allowedOrigins.js, backend/src/app.js, backend/src/index.js, backend/.env.example
Centralizes dotenv loading, introduces allowedOrigins derived from CLIENT_ORIGINS, extracts Express app into app.js with CORS and cookie middleware, and reduces index.js to a thin server bootstrap.
Backend auth/message/room contract adjustments
backend/src/controllers/*, backend/src/middleware/*, backend/src/models/*
Login responses now emit _id, image removed from Message schema, JWT verification errors return 401, and a few JSDoc callsite casts were added.
Backend lint/typecheck/test infrastructure
backend/eslint.config.js, backend/package.json, backend/tsconfig.json, backend/vitest.config.js
Adds ESLint flat config, TypeScript check-js config, Vitest config (serial, setup, timeouts, v8 coverage), and scripts/devDependencies for lint/typecheck/test.
Backend test environment helpers and setup
backend/tests/setup.js, backend/tests/helpers/index.js
In-memory MongoDB Vitest setup, per-test cleanup, and helpers to create users and produce auth cookies for tests.
Backend endpoint, model, utils, and socket tests
backend/tests/*.test.js
Comprehensive Vitest + Supertest suites for auth, messages, rooms, middleware, models, token/cookie generation, allowedOrigins parsing, and Socket.IO signaling/join/leave behaviors.
Frontend runtime updates
frontend/src/App.jsx, frontend/src/components/Chat.jsx, frontend/src/components/JoinRoom.jsx, frontend/package.json, frontend/vite.config.js, frontend/eslint.config.js
Removes parent join-state coupling, updates Chat to userLeft and ref snapshot cleanup, simplifies P2P send payloads, aligns JoinRoom to use backend _id, and updates frontend scripts/tooling/Vite test config.
Frontend test tooling and component tests
frontend/src/test/setup.js, frontend/src/**/*.test.jsx, frontend/src/components/*.test.jsx
Adds Vitest test setup with WebRTC/clipboard/UUID shims, ESLint test globals, and extensive component + integration tests for App, Chat, JoinRoom, CustomRoom, and Documentation.
Documentation and CI
docs/*, CLAUDE.md, .coderabbit.yaml, .github/workflows/ci.yml, .gitignore
Adds architecture, API, realtime, DB schema, backend/frontend structure, testing docs, CLAUDE guidance, coderabbit config, and a GitHub Actions CI workflow.

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor

- downgraded @tailwindcss/vite and tailwindcss to version 4.3.0
- updated @vitejs/plugin-react to version 6.0.2
- updated @vitest/coverage-v8 to version 4.1.8
- updated vite to version 8.0.16
- updated vitest to version 4.1.8
@CRIMSONHydra

Copy link
Copy Markdown
Member Author

@coderabbitai its been 5 hours and your still processing changes, any issues?

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the PR status and review comments
gh pr view 42 --repo wavey-waves/waves --json state,title,reviews,comments,updatedAt,createdAt

# Also check for any check runs / status
gh pr checks 42 --repo wavey-waves/waves 2>/dev/null || echo "No checks available"

Length of output: 7910



@CRIMSONHydra — apologies for the trouble! The review run (c0d9357d-7cb4-4ce4-a25c-185df7cc3cbe) does appear to be stuck — it's been processing for over 5 hours with no output, which is definitely not normal even for a large PR like this one (55 files, ~11k lines).

The best fix is to kick off a fresh review. I'll trigger one now:

(´• ω •`) ごめんなさい 🐇

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/ARCHITECTURE.md (1)

117-117: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Inconsistent env loading documentation.

Line 117 states environment variables are "Loaded via dotenv.config() in app.js", but according to the review stack context and BACKEND_STRUCTURE.md, environment loading is handled by libs/env.js which is imported first. The statement should reference libs/env.js as the centralized environment loader.

📝 Suggested fix
-`PORT`, `MONGODB_URI`, `JWT_SECRET`, `NODE_ENV`. Loaded via `dotenv.config()` in `app.js`.
+`PORT`, `MONGODB_URI`, `JWT_SECRET`, `NODE_ENV`. Loaded via `libs/env.js` (which calls `dotenv.config()` and is imported by `app.js` and `index.js`).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/ARCHITECTURE.md` at line 117, Update the statement on line 117 to
reference the centralized environment loader instead of app.js: replace the
claim that env vars are "Loaded via dotenv.config() in app.js" with text
indicating they are loaded via libs/env.js (the module responsible for loading
and exposing process env), and ensure any mention of dotenv is tied to
libs/env.js rather than app.js so documentation matches the actual bootstrap
sequence where libs/env.js is imported first.
🧹 Nitpick comments (8)
docs/BACKEND_STRUCTURE.md (2)

45-52: ⚡ Quick win

Add language identifier to fenced code block.

The request lifecycle diagram should have a language identifier for consistency.

📝 Suggested fix
-```
+```text
 HTTP request
   → app.js middleware: express.json → request-ip → cookieParser → cors
   → router (/api/auth | /api/messages | /api/rooms)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/BACKEND_STRUCTURE.md` around lines 45 - 52, Add a language identifier to
the fenced code block that starts with "HTTP request" so the block is rendered
consistently; locate the triple-backtick block containing the HTTP request
lifecycle (lines beginning "HTTP request → app.js middleware: express.json →
request-ip → cookieParser → cors") and change the opening fence to include a
language tag such as "text" (e.g., ```text) to ensure proper formatting.

Source: Linters/SAST tools


7-29: ⚡ Quick win

Add language identifier to fenced code block.

The directory tree should have a language identifier for proper syntax highlighting.

📝 Suggested fix
-```
+```text
 backend/src/
 ├── index.js                      # entry point: listens + connectDB
 ├── app.js                        # configures the shared Express app (middleware, routes, prod static, error handler)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/BACKEND_STRUCTURE.md` around lines 7 - 29, The fenced code block in
BACKEND_STRUCTURE.md lacks a language identifier; update the opening fence for
the directory tree (the block showing backend/src/ and the file list including
index.js, app.js, libs/socket.js, etc.) to include a language identifier such as
"text" (e.g., change ``` to ```text) so the tree renders with proper syntax
highlighting.

Source: Linters/SAST tools

docs/ARCHITECTURE.md (2)

9-17: ⚡ Quick win

Add language identifier to fenced code block.

The code block should specify a language for proper syntax highlighting and tooling support.

📝 Suggested fix
-```
+```text
 waves/
 ├── frontend/        # React 19 + Vite + Tailwind v4 (separate npm package)
 ├── backend/         # Express + Socket.IO, ES modules (separate npm package)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/ARCHITECTURE.md` around lines 9 - 17, Update the fenced code block in
docs/ARCHITECTURE.md that contains the "waves/" directory tree to include a
language identifier for proper highlighting (e.g., change the opening ``` to
```text or ```bash); locate the block that starts with the lines showing
"waves/" and the tree entries ("frontend/", "backend/", "docs/", etc.) and
replace the fence accordingly so the snippet is ```text ... ``` (no other
changes).

Source: Linters/SAST tools


54-82: ⚡ Quick win

Add language identifier to fenced code block.

The ASCII diagram should have a language identifier for consistency and tooling support.

📝 Suggested fix
-```
+```text
    Sender (Chat.jsx)                                  Receiver (Chat.jsx)
    ─────────────────                                  ───────────────────
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/ARCHITECTURE.md` around lines 54 - 82, The fenced ASCII diagram block in
ARCHITECTURE.md lacks a language identifier; update the opening triple-backtick
for the diagram in the shown block to include a language token (e.g., ```text)
so tooling and linters treat it correctly. Locate the ASCII diagram block (the
triple-backtick that precedes "Sender (Chat.jsx)                                
Receiver (Chat.jsx) …") and change it to include the language identifier,
ensuring the closing triple-backtick remains unchanged; no other content
modifications are needed.

Source: Linters/SAST tools

frontend/src/App.jsx (1)

385-392: ⚡ Quick win

Dead state can be removed entirely.

The user and roomType state (lines 385-387) and handleJoinRoom (389-392) appear unused: ChatRoute manages its own local user state (line 254) and doesn't read from App-level state, and no other component consumes these values. Consider removing both the state declarations and handleJoinRoom, then updating Home to no longer expect an onJoinRoom prop.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/App.jsx` around lines 385 - 392, Remove the dead App-level state
and handler: delete the useState declarations that define the unused setters
(const [, setUser] = useState(null); const [, setRoomType] = useState(null);)
and remove the handleJoinRoom function; then update where App passes props to
Home to stop supplying onJoinRoom and remove any references to
setUser/setRoomType or handleJoinRoom. Confirm ChatRoute still manages its own
user state (ChatRoute) and that no other components consume the removed
App-level values before committing.
frontend/src/test/setup.js (1)

46-61: ⚖️ Poor tradeoff

WebRTC fake's localDescription behavior differs from the real API.

The fake sets localDescription immediately in the constructor (Line 49), but real RTCPeerConnection has it as null until setLocalDescription() is called. Additionally, the fake's setLocalDescription method (Line 56) doesn't update the localDescription property.

This could mask bugs where production code reads localDescription before calling setLocalDescription. However, for testing basic signaling flows (offer/answer/ICE) where the fake methods return resolved promises, this should be adequate.

💡 Optional enhancement for more realistic behavior

If you want the fake to more closely match real WebRTC:

 class FakeRTCPeerConnection {
   constructor() {
     this.connectionState = 'new'
-    this.localDescription = { type: 'offer', sdp: 'fake-sdp' }
+    this.localDescription = null
     this.onicecandidate = null
     this.onconnectionstatechange = null
     this.ondatachannel = null
     this.createDataChannel = vi.fn((label) => new FakeDataChannel(label))
     this.createOffer = vi.fn(() => Promise.resolve({ type: 'offer', sdp: 'fake-offer' }))
     this.createAnswer = vi.fn(() => Promise.resolve({ type: 'answer', sdp: 'fake-answer' }))
-    this.setLocalDescription = vi.fn(() => Promise.resolve())
+    this.setLocalDescription = vi.fn((desc) => {
+      this.localDescription = desc || { type: 'offer', sdp: 'fake-sdp' }
+      return Promise.resolve()
+    })
     this.setRemoteDescription = vi.fn(() => Promise.resolve())
     this.addIceCandidate = vi.fn(() => Promise.resolve())
     this.close = vi.fn()
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/test/setup.js` around lines 46 - 61, FakeRTCPeerConnection
currently initializes localDescription in the constructor and never updates it;
change it so localDescription is initialized to null and update the
setLocalDescription method on FakeRTCPeerConnection to assign the passed
description (e.g., the argument to setLocalDescription) to this.localDescription
before resolving its promise; this preserves current promise behavior but makes
reads of localDescription match real RTCPeerConnection semantics.
backend/src/index.js (1)

14-14: 💤 Low value

Inconsistent semicolon style.

Line 14 is missing a semicolon after the closing brace, while other statements in the file use semicolons consistently. Consider adding it for style consistency, although this is purely cosmetic.

📝 Proposed fix
   connectDB();
-})
+});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/index.js` at line 14, The file ends with a closing brace and
parenthesis token "})" missing a trailing semicolon; add a semicolon after that
token (change "})" to "});") to match the file's semicolon style and run the
project's linter/Prettier to ensure consistency across statements (locate the
final closing "})" in backend/src/index.js where the callback/block ends).
backend/tests/socket.test.js (1)

83-97: Add isolation coverage tests for webrtc-answer and webrtc-ice-candidate

The webrtc-answer and webrtc-ice-candidate relay handlers in backend/src/libs/socket.js already gate on room sharing before emitting to the target, but backend/tests/socket.test.js currently only asserts the “no relay across different rooms” behavior for webrtc-offer (no tests mention webrtc-answer / webrtc-ice-candidate). Add analogous isolation tests for those events to cover the full guideline set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/socket.test.js` around lines 83 - 97, Add two new tests
mirroring the existing "does NOT relay signaling between peers that share no
room" case for the events 'webrtc-answer' and 'webrtc-ice-candidate': use
connect() to create sockets a and b, have a join 'room-a' and b join 'room-b',
await once(a,'existing-room-users') and once(b,'existing-room-users'), create
guards with never(b,'webrtc-answer') and never(b,'webrtc-ice-candidate'), emit
a.emit('webrtc-answer', { answer: {...}, to: b.id }) and
a.emit('webrtc-ice-candidate', { candidate: {...}, to: b.id }) respectively, and
assert await expect(guard).resolves.toBeUndefined(); finally disconnect a and
b—this will exercise the room-sharing gate implemented in the relay handlers in
backend/src/libs/socket.js.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/agents/coderabbit-fixer.md:
- Around line 60-78: The GraphQL query relying on reviewThreads.nodes and
reviewThreads.nodes.comments.nodes must handle schema differences where
databaseId may be missing/deprecated; update the code that processes
reviewThreads, comments, and Step 7 to fall back from comments.nodes.databaseId
to other available identifiers (e.g., comment.id or
PullRequestReviewComment.fullDatabaseId / node.id) and detect presence of
PullRequestReviewComment fields (path, line) before using them; specifically,
adjust the comment-filtering and ID-capture logic that references reviewThreads,
comments, databaseId, PullRequestReviewComment, and Step 7 so it accepts either
databaseId or alternative IDs and skips reply-posting for cover-letter review
bodies without databaseId.

In @.claude/commands/fix-coderabbit.md:
- Around line 21-25: The lock key generation currently pipes the file path
through `sha1sum` which can fail on systems without that tool; update the lock
acquisition logic used by session-lock.sh (the `acquire` invocation) to compute
the hash portably by trying `sha1sum`, then `shasum -a 1`, then `openssl dgst
-sha1` (or similar fallbacks) and only error if none are available, or
alternatively add a short doc note listing required tooling; modify the code
that builds the `"cr-fixer:$(printf '%s' '<path>' | sha1sum | cut -c1-12)"`
token to use the chosen fallback sequence so `session-lock.sh acquire` receives
a valid opaque gate on all platforms.

In @.claude/hooks/block-destructive-git.js:
- Around line 56-72: The existing FORBIDDEN entry that matches git config only
catches explicit write flags but misses the two-argument write form (e.g., git
config user.name "Alice"); update the FORBIDDEN array by adding a second rule
after the current /\bgit\s+config\s+(--global|...)\b/ entry that detects the
simple write pattern (match commands like git config <key> <value> but not
options starting with -); use a regex such as /\bgit\s+config\s+[^\s-][^\s]*\s+/
with the same human-friendly message like "git config (write)" so simple
key/value writes are blocked alongside the existing flag-based rule.

In `@backend/src/libs/allowedOrigins.js`:
- Around line 16-18: The allowedOrigins array in allowedOrigins.js currently
contains bare IP strings (e.g., '13.228.225.19', '18.142.128.26',
'54.254.162.138') which won't match browser Origin headers; update those entries
to include the scheme (e.g., 'https://13.228.225.19' and/or
'http://13.228.225.19') or replace the array with a regex/function-based origin
matcher used by the CORS/Socket.IO config (locate the exported allowedOrigins
array or the origin-checking function in allowedOrigins.js and adjust the
entries/logic accordingly).

---

Outside diff comments:
In `@docs/ARCHITECTURE.md`:
- Line 117: Update the statement on line 117 to reference the centralized
environment loader instead of app.js: replace the claim that env vars are
"Loaded via dotenv.config() in app.js" with text indicating they are loaded via
libs/env.js (the module responsible for loading and exposing process env), and
ensure any mention of dotenv is tied to libs/env.js rather than app.js so
documentation matches the actual bootstrap sequence where libs/env.js is
imported first.

---

Nitpick comments:
In `@backend/src/index.js`:
- Line 14: The file ends with a closing brace and parenthesis token "})" missing
a trailing semicolon; add a semicolon after that token (change "})" to "});") to
match the file's semicolon style and run the project's linter/Prettier to ensure
consistency across statements (locate the final closing "})" in
backend/src/index.js where the callback/block ends).

In `@backend/tests/socket.test.js`:
- Around line 83-97: Add two new tests mirroring the existing "does NOT relay
signaling between peers that share no room" case for the events 'webrtc-answer'
and 'webrtc-ice-candidate': use connect() to create sockets a and b, have a join
'room-a' and b join 'room-b', await once(a,'existing-room-users') and
once(b,'existing-room-users'), create guards with never(b,'webrtc-answer') and
never(b,'webrtc-ice-candidate'), emit a.emit('webrtc-answer', { answer: {...},
to: b.id }) and a.emit('webrtc-ice-candidate', { candidate: {...}, to: b.id })
respectively, and assert await expect(guard).resolves.toBeUndefined(); finally
disconnect a and b—this will exercise the room-sharing gate implemented in the
relay handlers in backend/src/libs/socket.js.

In `@docs/ARCHITECTURE.md`:
- Around line 9-17: Update the fenced code block in docs/ARCHITECTURE.md that
contains the "waves/" directory tree to include a language identifier for proper
highlighting (e.g., change the opening ``` to ```text or ```bash); locate the
block that starts with the lines showing "waves/" and the tree entries
("frontend/", "backend/", "docs/", etc.) and replace the fence accordingly so
the snippet is ```text ... ``` (no other changes).
- Around line 54-82: The fenced ASCII diagram block in ARCHITECTURE.md lacks a
language identifier; update the opening triple-backtick for the diagram in the
shown block to include a language token (e.g., ```text) so tooling and linters
treat it correctly. Locate the ASCII diagram block (the triple-backtick that
precedes "Sender (Chat.jsx)                                  Receiver (Chat.jsx)
…") and change it to include the language identifier, ensuring the closing
triple-backtick remains unchanged; no other content modifications are needed.

In `@docs/BACKEND_STRUCTURE.md`:
- Around line 45-52: Add a language identifier to the fenced code block that
starts with "HTTP request" so the block is rendered consistently; locate the
triple-backtick block containing the HTTP request lifecycle (lines beginning
"HTTP request → app.js middleware: express.json → request-ip → cookieParser →
cors") and change the opening fence to include a language tag such as "text"
(e.g., ```text) to ensure proper formatting.
- Around line 7-29: The fenced code block in BACKEND_STRUCTURE.md lacks a
language identifier; update the opening fence for the directory tree (the block
showing backend/src/ and the file list including index.js, app.js,
libs/socket.js, etc.) to include a language identifier such as "text" (e.g.,
change ``` to ```text) so the tree renders with proper syntax highlighting.

In `@frontend/src/App.jsx`:
- Around line 385-392: Remove the dead App-level state and handler: delete the
useState declarations that define the unused setters (const [, setUser] =
useState(null); const [, setRoomType] = useState(null);) and remove the
handleJoinRoom function; then update where App passes props to Home to stop
supplying onJoinRoom and remove any references to setUser/setRoomType or
handleJoinRoom. Confirm ChatRoute still manages its own user state (ChatRoute)
and that no other components consume the removed App-level values before
committing.

In `@frontend/src/test/setup.js`:
- Around line 46-61: FakeRTCPeerConnection currently initializes
localDescription in the constructor and never updates it; change it so
localDescription is initialized to null and update the setLocalDescription
method on FakeRTCPeerConnection to assign the passed description (e.g., the
argument to setLocalDescription) to this.localDescription before resolving its
promise; this preserves current promise behavior but makes reads of
localDescription match real RTCPeerConnection semantics.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8a7ed168-dda8-46db-a427-eb73bcdae061

📥 Commits

Reviewing files that changed from the base of the PR and between 0dc54e0 and e6bd65e.

⛔ Files ignored due to path filters (2)
  • backend/package-lock.json is excluded by !**/package-lock.json
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (55)
  • .claude/.gitignore
  • .claude/agents/coderabbit-fixer.md
  • .claude/commands/fix-coderabbit.md
  • .claude/hooks/block-destructive-git.js
  • .claude/lib/session-lock.sh
  • .claude/scripts/agent-progress-monitor.sh
  • .claude/settings.json
  • .gitignore
  • CLAUDE.md
  • backend/.env.example
  • backend/eslint.config.js
  • backend/package.json
  • backend/src/app.js
  • backend/src/controllers/auth.controller.js
  • backend/src/controllers/message.controller.js
  • backend/src/controllers/room.controller.js
  • backend/src/index.js
  • backend/src/libs/allowedOrigins.js
  • backend/src/libs/env.js
  • backend/src/libs/socket.js
  • backend/src/middleware/auth.middleware.js
  • backend/src/models/message.model.js
  • backend/src/models/room.model.js
  • backend/tests/allowedOrigins.test.js
  • backend/tests/auth.controller.test.js
  • backend/tests/auth.middleware.test.js
  • backend/tests/helpers/index.js
  • backend/tests/message.controller.test.js
  • backend/tests/models.test.js
  • backend/tests/room.controller.test.js
  • backend/tests/setup.js
  • backend/tests/socket.test.js
  • backend/tests/utils.test.js
  • backend/tsconfig.json
  • backend/vitest.config.js
  • docs/API.md
  • docs/ARCHITECTURE.md
  • docs/BACKEND_STRUCTURE.md
  • docs/DATABASE_SCHEMA.md
  • docs/FRONTEND_STRUCTURE.md
  • docs/README.md
  • docs/REALTIME.md
  • docs/TESTING.md
  • frontend/eslint.config.js
  • frontend/package.json
  • frontend/src/App.jsx
  • frontend/src/App.test.jsx
  • frontend/src/components/Chat.jsx
  • frontend/src/components/Chat.test.jsx
  • frontend/src/components/CustomRoom.test.jsx
  • frontend/src/components/Documentation.test.jsx
  • frontend/src/components/JoinRoom.jsx
  • frontend/src/components/JoinRoom.test.jsx
  • frontend/src/test/setup.js
  • frontend/vite.config.js
💤 Files with no reviewable changes (1)
  • backend/src/models/message.model.js

Comment thread .claude/agents/coderabbit-fixer.md
Comment thread .claude/commands/fix-coderabbit.md
Comment thread .claude/hooks/block-destructive-git.js
Comment thread backend/src/libs/allowedOrigins.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
docs/TESTING.md (1)

54-54: ⚡ Quick win

Consider adding caution about npm audit fix behavior.

The guidance suggests running npm audit fix to address vulnerabilities, but this command can introduce breaking changes by updating to newer major versions. Consider revising to recommend reviewing npm audit output first and testing changes after applying fixes.

Suggested addition: "triage by reviewing npm audit output, then run npm audit fix and test thoroughly (as it may introduce breaking changes) or manually bump the offending dependency."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/TESTING.md` at line 54, Update the paragraph that recommends "triage by
running `npm audit fix`" to warn that `npm audit fix` can introduce breaking
changes by upgrading major versions: advise first reviewing `npm audit` output,
running `npm audit fix` only after review, testing thoroughly, or manually
bumping the offending dependency; include this guidance in the same block that
references the `security-audit` job and `--audit-level` so readers see the
caution alongside the existing remediation steps.
backend/tests/socket.test.js (1)

36-45: 💤 Low value

Potential socket listener leak in never() helper on success path.

When the timeout resolves (event never arrived), the socket.once() listener is not removed. If the event arrives after never() resolves but before the socket disconnects, the listener callback will execute and call clearTimeout(timer) on an already-fired timer, which is harmless but wasteful. More importantly, this orphaned listener could theoretically interfere with subsequent assertions in the same test if the socket were reused.

Since all tests disconnect sockets immediately after, this is benign in practice—but cleaning up the listener makes the helper robust for future use.

♻️ Suggested fix
 function never(socket, event, window = 400) {
   return new Promise((resolve, reject) => {
-    const timer = setTimeout(resolve, window)
-    socket.once(event, () => {
+    const handler = () => {
       clearTimeout(timer)
       reject(new Error(`unexpectedly received ${event}`))
-    })
+    }
+    const timer = setTimeout(() => {
+      socket.off(event, handler)
+      resolve()
+    }, window)
+    socket.once(event, handler)
   })
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/socket.test.js` around lines 36 - 45, The never() helper leaves
the socket.once listener attached when the timeout resolves; update
never(socket, event, window) to store the listener callback in a variable (e.g.,
handler) and on timeout call socket.off(event, handler) (or
socket.removeListener(event, handler) depending on your socket API) before
resolving, and likewise keep the existing clearTimeout/clear cleanup when the
listener fires so both success and failure paths remove the opposite handler;
update the listener registration in never() to use that handler reference so the
listener is cleaned up on timeout.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 30-33: Replace all mutable action tags in the workflow (e.g., the
uses entries like "actions/checkout@v4" and "actions/setup-node@v4") with their
corresponding immutable full 40-character commit SHAs; update every "uses:" line
throughout the file (including the other occurrences referenced) so each action
reference uses the pinned SHA instead of a floating tag to prevent supply-chain
drift.
- Line 30: The checkout steps using the actions/checkout@v4 action currently
default to persisting credentials; update every checkout step that invokes
actions/checkout@v4 (the steps that currently read "uses: actions/checkout@v4")
to explicitly set persist-credentials: false under the step's with: block so
credentials are not kept for later steps; ensure you add this to each occurrence
of the checkout step in the workflow.

In `@frontend/src/App.jsx`:
- Line 23: Docs still list Home as accepting onJoinRoom but the Home component
signature in App.jsx no longer accepts that prop; update the
FRONTEND_STRUCTURE.md entry for the "/" route to remove onJoinRoom from the Home
props and revise any documented "join-success" callback parameters to reflect
the current Home implementation (match the actual props/state handlers used by
the Home function). Locate references to Home and the route in the docs and
replace the old prop example with the new Home signature and the correct
callback parameter names/shape so the documentation matches the code.

---

Nitpick comments:
In `@backend/tests/socket.test.js`:
- Around line 36-45: The never() helper leaves the socket.once listener attached
when the timeout resolves; update never(socket, event, window) to store the
listener callback in a variable (e.g., handler) and on timeout call
socket.off(event, handler) (or socket.removeListener(event, handler) depending
on your socket API) before resolving, and likewise keep the existing
clearTimeout/clear cleanup when the listener fires so both success and failure
paths remove the opposite handler; update the listener registration in never()
to use that handler reference so the listener is cleaned up on timeout.

In `@docs/TESTING.md`:
- Line 54: Update the paragraph that recommends "triage by running `npm audit
fix`" to warn that `npm audit fix` can introduce breaking changes by upgrading
major versions: advise first reviewing `npm audit` output, running `npm audit
fix` only after review, testing thoroughly, or manually bumping the offending
dependency; include this guidance in the same block that references the
`security-audit` job and `--audit-level` so readers see the caution alongside
the existing remediation steps.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 70fa6c17-c540-4145-94b9-ce2e6f38772b

📥 Commits

Reviewing files that changed from the base of the PR and between e6bd65e and fc91001.

⛔ Files ignored due to path filters (2)
  • backend/package-lock.json is excluded by !**/package-lock.json
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (14)
  • .claude/agents/coderabbit-fixer.md
  • .claude/commands/fix-coderabbit.md
  • .claude/hooks/block-destructive-git.js
  • .coderabbit.yaml
  • .github/workflows/ci.yml
  • backend/package.json
  • backend/src/index.js
  • backend/src/libs/allowedOrigins.js
  • backend/tests/socket.test.js
  • docs/ARCHITECTURE.md
  • docs/BACKEND_STRUCTURE.md
  • docs/TESTING.md
  • frontend/package.json
  • frontend/src/App.jsx
✅ Files skipped from review due to trivial changes (2)
  • docs/BACKEND_STRUCTURE.md
  • docs/ARCHITECTURE.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • backend/src/libs/allowedOrigins.js
  • .claude/commands/fix-coderabbit.md
  • backend/package.json
  • frontend/package.json
  • backend/src/index.js
  • .claude/hooks/block-destructive-git.js
  • .claude/agents/coderabbit-fixer.md

Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread frontend/src/App.jsx
@CRIMSONHydra CRIMSONHydra merged commit ba1425d into main Jun 10, 2026
5 checks passed
@CRIMSONHydra CRIMSONHydra deleted the refactor branch June 10, 2026 21:47
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.

2 participants