Skip to content

Conversation

@ARCoder181105
Copy link
Contributor

@ARCoder181105 ARCoder181105 commented Dec 6, 2025

Description

This PR resolves critical compilation errors that are currently preventing the backend server from building and starting. It addresses struct naming collisions, duplicate configuration fields, and unresolved merge conflicts found in the codebase.

Note to Maintainers:
This PR focuses strictly on fixing the build. I have identified further runtime errors and areas for refactoring (such as the Gemini service logic and WebSocket handlers), but I am submitting this first to establish a stable, compilable baseline. I plan to address the remaining logic/runtime issues in subsequent PRs once this is merged.

Fixes

Fixes #128

Changes

  • config/config.go: Removed a duplicate Redis struct definition that was causing redeclaration errors.
  • models/admin.go: Renamed the Comment struct to AdminComment to resolve a namespace collision with the main Comment model in models/comment.go.
  • db/db.go: Added the missing "log" import required for Redis connection logging.
  • websocket/team_websocket.go: Resolved git merge conflict markers (<<<< HEAD), removed duplicate function definitions, and consolidated helper functions.
  • services/gemini.go: Fixed the Gemini client implementation to correctly initialize the global client variable and use the correct method signatures for the SDK.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Verification

  • go mod tidy run successfully.
  • go build ./... passes without errors.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed team capacity validation and corrected open-team filtering.
    • Resolved spectator initialization for new live connections.
  • Improvements

    • Real-time team notifications now target only relevant participants.
    • Updated AI content generation integration for more consistent outputs.
    • Renamed admin comment type to avoid naming collisions.
  • Chores

    • Reworked email/SMTP configuration structure and replaced legacy production config with a new sample configuration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 6, 2025

Walkthrough

Resolves backend build and merge issues: restructures Config (adds SMTP, YAML tags, removes inline Redis/SMTP), removes prod YAML, renames Comment→AdminComment, updates Gemini usage, tightens websocket broadcasts to per-recipient snapshots, fixes imports and team capacity/BSON logic.

Changes

Cohort / File(s) Summary
Config & samples
backend/config/config.go, backend/config/config.prod.yml, backend/config/config.prod.sample.yml
Reworked Config layout: added SMTP struct with yaml:"smtp", annotated JWT with yaml:"jwt", removed inline anonymous SMTP and inline Redis, switched ioutil.ReadFileos.ReadFile. Deleted config.prod.yml and added config.prod.sample.yml.
Models
backend/models/admin.go
Renamed exported CommentAdminComment to avoid collision with models/comment.go.
WebSocket refactor
backend/websocket/team_websocket.go, backend/websocket/websocket.go, backend/websocket/debate_spectator.go
Replaced all-client broadcasts with snapshotTeamRecipients(room, exclude) (removed snapshotAllTeamClients); omitted initializing Client.IsSpectator on new connect; changed package to websocket in spectator file.
Controllers & handlers
backend/controllers/team_controller.go, backend/controllers/auth.go, backend/controllers/admin_controller.go, backend/controllers/transcript_controller.go
Team: default non-positive MaxSize to 4 in JoinTeam and use bson.A in GetAvailableTeams. Auth: added log import. Admin: accumulate models.AdminComment. Transcript: capture returned email to avoid discard.
DB & server wiring
backend/db/db.go, backend/cmd/server/main.go
Added log and github.com/redis/go-redis/v9 imports; switched Redis config usage from cfg.Redis.URLcfg.Redis.Addr with default localhost:6379; referenced websocket handler symbol from package.
Gemini service
backend/services/gemini.go
Switched from per-model SafetySettings to GenerateContentConfig; call changed to geminiClient.Models.GenerateContent(ctx, defaultGeminiModel, genai.Text(...), config) and use resp.Text.
Dependencies
backend/go.mod
Promoted casbin and mongodb-adapter to direct requires, bumped google.golang.org/genai and golang.org/x/net, adjusted indirect entries.
Frontend tooling
frontend/package.json
Downgraded devDependency vite from ^7.2.2^5.4.0.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server as WS Handler
    participant RoomStore as TeamRoomStore
    participant Recipients as snapshotTeamRecipients

    Client->>Server: connect / send event
    Server->>RoomStore: resolve room & sender info
    RoomStore->>Recipients: snapshotTeamRecipients(room, exclude=sender)
    Recipients-->>Server: recipient client list
    Server->>Recipients: send broadcast payload (exclude sender)
    Recipients-->>Client: recipients receive update
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Attention recommended on:
    • All uses of the renamed AdminComment (DB decoding, controllers, tests).
    • WebSocket broadcast changes and assumptions about Client.IsSpectator.
    • Gemini client API changes and SafetySettings mapping.
    • Config schema changes and removed config.prod.yml (consumers/deployments).

Possibly related PRs

Poem

🐇
I hopped through structs and YAML rows,
I nudged the sockets where the tea-light glows.
Recipients skip the sender’s cheer,
Gemini whispers a bit more clear.
Config snug — the burrow’s near. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Most changes align with compilation fixes, but some modifications extend beyond the stated scope: vite downgrade, SMTP config restructuring, Redis config changes, WebSocket broadcast refactoring, and spectator field removal appear unrelated to core compilation errors. Review and potentially separate out-of-scope changes into follow-up PRs. The core PR should focus on: config.go Redis removal, admin.go Comment renaming, db.go log import, team_websocket.go merge conflict resolution, and gemini.go SDK fixes.
Docstring Coverage ⚠️ Warning Docstring coverage is 73.91% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main objective of the PR: resolving backend compilation errors and structural conflicts, which is the central focus of all changes.
Linked Issues check ✅ Passed All five core requirements from issue #128 are addressed: Redis duplication removed, Comment renamed to AdminComment, log import added, merge conflicts resolved, and Gemini SDK fixed.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between abd4477 and c0477e1.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • frontend/package.json (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/package.json

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@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: 0

Caution

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

⚠️ Outside diff range comments (2)
backend/config/config.go (2)

45-52: SMTP struct fields missing YAML tags.

The SMTP struct fields lack yaml tags, unlike other configuration structs. This will prevent YAML configuration values from being parsed correctly into this struct.

-	SMTP struct {
-		Host        string
-		Port        int
-		Username    string // Gmail address
-		Password    string // App Password
-		SenderEmail string // Same as Username for Gmail
-		SenderName  string
-	}
+	SMTP struct {
+		Host        string `yaml:"host"`
+		Port        int    `yaml:"port"`
+		Username    string `yaml:"username"`    // Gmail address
+		Password    string `yaml:"password"`    // App Password
+		SenderEmail string `yaml:"senderEmail"` // Same as Username for Gmail
+		SenderName  string `yaml:"senderName"`
+	} `yaml:"smtp"`

40-43: JWT struct missing yaml tag on parent.

The JWT struct itself is missing the yaml tag for the parent struct, which may cause parsing issues.

 	JWT struct {
 		Secret string `yaml:"secret"`
 		Expiry int    `yaml:"expiry"`
-	}
+	} `yaml:"jwt"`
🧹 Nitpick comments (6)
backend/controllers/auth.go (2)

104-107: Silent error handling may hide persistence failures.

The error from persistUserStats is silently discarded. If the stats normalization persistence fails, it could lead to repeated unnecessary updates on subsequent requests and mask underlying database issues.

Consider at minimum logging the error:

 	if normalizeUserStats(&existingUser) {
 		if err := persistUserStats(dbCtx, &existingUser); err != nil {
+			log.Printf("Failed to persist normalized user stats for %s: %v", existingUser.Email, err)
 		}
 	}

274-278: Duplicate silent error handling pattern.

Same issue as in GoogleLogin - the error from persistUserStats is silently ignored in the Login function.

 	if normalizeUserStats(&user) {
 		if err := persistUserStats(dbCtx, &user); err != nil {
+			log.Printf("Failed to persist normalized user stats for %s: %v", user.Email, err)
 		}
 	}
backend/config/config.go (1)

5-5: Deprecated ioutil.ReadFile usage.

ioutil.ReadFile is deprecated since Go 1.16. Use os.ReadFile instead.

-	"io/ioutil"
+	"os"

And in LoadConfig:

-	data, err := ioutil.ReadFile(path)
+	data, err := os.ReadFile(path)
backend/services/gemini.go (1)

27-32: Safety settings disable all content filtering.

All harm categories are set to HarmBlockThresholdBlockNone, which disables safety filtering entirely. While this may be intentional for a debate platform, it should be documented and reviewed for compliance with content policies.

backend/websocket/team_websocket.go (2)

880-913: Potential race between room deletion check and room usage.

The goroutine checks if the room exists at lines 884-885, but there's a window between releasing teamRoomsMutex and acquiring room.Mutex where another goroutine could delete the room or modify its state.

Consider holding teamRoomsMutex until after acquiring room.Mutex, or using a different synchronization strategy:

 		go func() {
 			time.Sleep(3 * time.Second)

 			teamRoomsMutex.Lock()
 			room, stillExists := teamRooms[roomKey]
-			teamRoomsMutex.Unlock()
-
 			if !stillExists {
+				teamRoomsMutex.Unlock()
 				log.Printf("[handleTeamReadyStatus] Room %s no longer exists, aborting phase change", roomKey)
 				return
 			}

 			room.Mutex.Lock()
+			teamRoomsMutex.Unlock()

1072-1103: Duplicate countdown logic in handleCheckStart.

This countdown logic is nearly identical to the one in handleTeamReadyStatus (lines 880-913). Consider extracting to a shared helper function to reduce duplication and ensure consistent behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d22372 and 70cd342.

⛔ Files ignored due to path filters (1)
  • backend/go.sum is excluded by !**/*.sum
📒 Files selected for processing (10)
  • backend/config/config.go (2 hunks)
  • backend/config/config.prod.yml (0 hunks)
  • backend/controllers/auth.go (5 hunks)
  • backend/controllers/team_controller.go (0 hunks)
  • backend/db/db.go (2 hunks)
  • backend/go.mod (3 hunks)
  • backend/models/admin.go (2 hunks)
  • backend/services/gemini.go (1 hunks)
  • backend/websocket/team_websocket.go (2 hunks)
  • backend/websocket/websocket.go (0 hunks)
💤 Files with no reviewable changes (3)
  • backend/config/config.prod.yml
  • backend/websocket/websocket.go
  • backend/controllers/team_controller.go
🔇 Additional comments (14)
backend/controllers/auth.go (2)

6-6: Log import added and used for JWT debugging - LGTM.

The log import is correctly added and used for debugging JWT generation. The logging provides useful diagnostic information for token generation.

Also applies to: 545-561


582-586: Default config path references potentially deleted file.

The default config path points to ./config/config.prod.yml, but if this file was deleted in this PR, it could cause runtime failures when the CONFIG_PATH environment variable is not set. Verify that the configuration file still exists in the repository or provide an alternative fallback mechanism.

backend/db/db.go (2)

7-7: Missing log import added - fixes compilation error.

The log import was correctly added to resolve the compilation error when log.Println is called at line 116.


99-118: ConnectRedis implementation looks correct.

The Redis connection function properly initializes the client, tests connectivity with a ping, and logs success. Error handling is appropriate.

backend/go.mod (2)

8-9: Dependency additions look appropriate.

The casbin dependencies for RBAC, Redis client, and genai version bump align with the project's requirements.

Also applies to: 15-15, 19-19


3-5: Go 1.24 is a released stable version.

Go 1.24 was released on February 11, 2025, and go1.24.4 is a valid patch version. No build failures will occur due to version unavailability. However, Go 1.25 is now the latest stable version (as of December 2025), so consider upgrading to a more recent version if compatibility allows.

Likely an incorrect or invalid review comment.

backend/websocket/team_websocket.go (5)

62-73: SafeWrite methods with mutex protection - good pattern.

The SafeWriteJSON and SafeWriteMessage methods properly use a mutex to prevent concurrent writes to the WebSocket connection, which is required by the gorilla/websocket library.


439-450: Recipient snapshot helper properly handles concurrent access.

snapshotTeamRecipients correctly acquires the mutex and creates a copy of clients before releasing the lock, allowing safe iteration outside the critical section.


836-842: Mutex unlock placement after goroutine spawn is correct but fragile.

The mutex is unlocked at line 918, which is after the goroutine is spawned at line 880. This is correct because the goroutine doesn't execute immediately and re-acquires locks as needed. However, the code path is complex - consider restructuring for clarity.

Note: The goroutine correctly re-acquires teamRoomsMutex and room.Mutex before accessing shared state, which is proper.

Also applies to: 918-918


948-949: Minor formatting cleanup - LGTM.

The added blank line improves readability between variable assignment and the loop.


1-1179: Merge conflict markers successfully removed.

The PR objective of removing git merge conflict markers from this file has been achieved. No <<<<<<< HEAD, =======, or >>>>>>> main markers remain in the code.

backend/services/gemini.go (2)

13-19: initGemini return value not used to initialize geminiClient.

The initGemini function returns a *genai.Client, but there's no visible code assigning it to the geminiClient variable that's checked on line 22. This could leave geminiClient as nil.


26-39: API usage is compatible with google.golang.org/genai v1.37.0.

The GenerateContent method signature, SafetySettings configuration, and resp.Text() method are all valid and correct for this package version. No changes needed.

backend/models/admin.go (1)

20-35: Unable to verify - repository access failed.

The review comment requests verification of the Comment-to-AdminComment rename using shell commands, but no verification results are provided in the original review. Additionally, the codebase cannot be accessed to independently confirm that:

  • The old Comment type references have been fully updated across backend code
  • models/comment.go exists and contains a Comment struct that would cause the collision
  • The rename is complete and no broken references remain

The code snippet itself appears correctly documented, but the claimed namespace collision fix requires verification across the entire codebase to confirm completeness.

@ARCoder181105
Copy link
Contributor Author

@rixitgithub
please review the PR

Copy link

@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: 0

🧹 Nitpick comments (3)
backend/config/config.go (3)

45-52: SMTP configuration structure looks correct, but consider secrets management.

The SMTP struct is properly defined with appropriate fields and YAML tags. However, storing SMTP passwords in plain text YAML configuration files poses a security risk.

Consider using environment variable overrides or a secrets management solution for sensitive credentials like Password.


54-56: Consider adding YAML tag for consistency.

The GoogleOAuth struct is missing a YAML tag, unlike all other configuration structs. Consider adding yaml:"googleOAuth" (or your preferred tag name) to maintain consistency and ensure proper YAML unmarshaling if this configuration is used.


61-61: Prefer os.ReadFile over deprecated ioutil.ReadFile.

The ioutil.ReadFile function has been deprecated since Go 1.16. Consider using os.ReadFile instead.

Apply this diff to modernize the code:

 import (
 	"fmt"
-	"io/ioutil"
+	"os"
 
 	"gopkg.in/yaml.v3"
 )
-	data, err := ioutil.ReadFile(path)
+	data, err := os.ReadFile(path)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 70cd342 and 1d95d35.

📒 Files selected for processing (1)
  • backend/config/config.go (1 hunks)
🔇 Additional comments (1)
backend/config/config.go (1)

43-43: LGTM! YAML tag added for consistency.

The addition of the yaml:"jwt" tag is correct and ensures consistent YAML unmarshaling with all other configuration structs.

Copy link

@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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d95d35 and 7ed5128.

📒 Files selected for processing (1)
  • backend/config/config.go (2 hunks)
🔇 Additional comments (2)
backend/config/config.go (2)

5-5: LGTM: Modernized file reading API.

The change from ioutil.ReadFile to os.ReadFile is correct. ioutil.ReadFile was deprecated in Go 1.16, and os.ReadFile is the recommended replacement.

Also applies to: 62-62


43-43: LGTM: Added missing YAML tag.

The yaml:"jwt" tag makes the JWT struct consistent with other configuration blocks.

Comment on lines +45 to +52
SMTP struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
Username string `yaml:"username"` // Gmail address
Password string `yaml:"password"` // App Password
SenderEmail string `yaml:"senderEmail"` // Same as Username for Gmail
SenderName string `yaml:"senderName"`
} `yaml:"smtp"`
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential scope creep and security concern.

The SMTP configuration block appears to add new functionality rather than fix the compilation errors described in PR #128. Consider whether this belongs in a separate feature PR.

Additionally, storing the SMTP password in plain text in the YAML file poses a security risk. Consider using environment variables or a secrets manager for sensitive credentials.

Example using environment variables:

SMTP struct {
    Host        string `yaml:"host"`
    Port        int    `yaml:"port"`
    Username    string `yaml:"username"`
    Password    string // Load from environment variable instead
    SenderEmail string `yaml:"senderEmail"`
    SenderName  string `yaml:"senderName"`
} `yaml:"smtp"`

Then in your initialization code, load the password from an environment variable:

cfg.SMTP.Password = os.Getenv("SMTP_PASSWORD")
🤖 Prompt for AI Agents
In backend/config/config.go around lines 45–52, the new SMTP struct addition
introduces potential scope creep for PR #128 and stores the SMTP password in
plain text via YAML; remove or revert this SMTP block from this PR (move it to a
dedicated feature/security PR) and, if keeping it, remove the yaml tag from the
Password field and load the password from an environment variable or secrets
manager during config initialization (do not persist secrets in the YAML file).

Copy link

@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: 0

♻️ Duplicate comments (1)
backend/config/config.go (1)

45-52: Scope creep and security concern remain unaddressed.

The SMTP configuration block continues to:

  1. Add new functionality unrelated to the compilation errors described in PR #128
  2. Store the SMTP password in plain text via YAML, which poses a security risk

This block should be moved to a separate feature PR. For the password field, remove the yaml:"password" tag and load the password from an environment variable during initialization instead.

🧹 Nitpick comments (2)
backend/controllers/admin_controller.go (1)

363-375: Field mapping from team message structs to AdminComment looks correct

The mappings from TeamDebateMessage and TeamChatMessage into models.AdminComment (ID, content/message, user, team/debate IDs, timestamp → CreatedAt, IsDeleted=false) are coherent and match the AdminComment definition. DebateID being set only for debate messages is also consistent.

If this mapping logic grows further, consider extracting small helper functions (e.g., NewAdminCommentFromTeamDebateMessage / NewAdminCommentFromTeamChatMessage) to centralize the field wiring and reduce duplication.

Also applies to: 388-399

backend/controllers/transcript_controller.go (1)

408-415: Revert to the underscore pattern for unused return values.

The email is captured but never used in this function. The _ = email line is a workaround to silence the compiler warning, but the idiomatic Go approach is to use _ directly in the assignment to signal that the value is intentionally discarded.

Apply this diff to clarify intent:

-	// FIX: Assign email to variable
-	valid, email, err := utils.ValidateTokenAndFetchEmail("./config/config.prod.yml", token, c)
+	valid, _, err := utils.ValidateTokenAndFetchEmail("./config/config.prod.yml", token, c)
 	if err != nil || !valid {
 		c.JSON(401, gin.H{"error": "Invalid or expired token"})
 		return
 	}
 
-	_ = email // Keep compiler happy if email is indeed not used below
-
 	err = services.UpdatePendingTranscripts()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ed5128 and 7f00c93.

📒 Files selected for processing (3)
  • backend/config/config.go (2 hunks)
  • backend/controllers/admin_controller.go (4 hunks)
  • backend/controllers/transcript_controller.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
backend/controllers/transcript_controller.go (1)
backend/utils/auth.go (1)
  • ValidateTokenAndFetchEmail (133-146)
backend/controllers/admin_controller.go (1)
backend/models/admin.go (1)
  • AdminComment (22-35)
🔇 Additional comments (6)
backend/config/config.go (3)

5-5: LGTM: Correct modernization from deprecated ioutil.

The change from ioutil.ReadFile to os.ReadFile follows Go best practices since ioutil.ReadFile has been deprecated since Go 1.16.

Also applies to: 61-62


40-43: LGTM: YAML tag added for consistency.

The yaml:"jwt" tag ensures proper YAML unmarshaling and aligns with the tagging pattern used by other configuration blocks.


54-56: LGTM: Missing YAML tag now added.

The yaml:"googleOAuth" tag has been properly added, addressing the previous review feedback. This ensures consistent YAML unmarshaling across all configuration blocks.

backend/controllers/admin_controller.go (2)

352-353: Type change to []models.AdminComment correctly matches renamed model

Using []models.AdminComment here is consistent with the model rename and should resolve the name collision without changing the JSON shape, since the struct fields and tags remain the same.


515-515: No behavioral change

This line appears to be an end-of-file formatting/newline adjustment only; no functional impact.

backend/controllers/transcript_controller.go (1)

399-424: Add authorization check for sensitive operation.

This handler updates ALL pending transcripts without filtering by user or checking for admin privileges. Any authenticated user can currently trigger this operation. If this endpoint should be restricted, add an authorization check before calling services.UpdatePendingTranscripts() to verify admin role.

Consider checking whether your codebase has existing authorization patterns (admin middleware, role-checking utilities) and apply them consistently with other endpoints that perform privileged operations.

Copy link

@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

Caution

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

⚠️ Outside diff range comments (1)
backend/websocket/debate_spectator.go (1)

101-125: Connection lifecycle leak: DebateWebsocketHandler never returns due to select {}, so Unregister is never called

DebateWebsocketHandler defers hub.Unregister(debateID, conn) and conn.Close(), then starts readPump in a new goroutine and blocks forever on select {}. Since select {} never returns, the deferred functions never execute.

Effects:

  • Disconnected clients remain in room.clients, inflating presence counts
  • Handler goroutines leak (one per connection, forever)
  • Broadcast loops write to closed connections repeatedly

Fix: Run readPump on the handler goroutine instead of spawning it, so the handler blocks until the client disconnects and defers execute:

-	// Read pump
-	go readPump(client, hub)
-
-	// Keep connection alive
-	select {}
+	// Read pump; block until client disconnects so defers run
+	readPump(client, hub)

When readPump exits on read error or close, DebateWebsocketHandler returns and Unregister runs.

Also applies to: 227-264

🧹 Nitpick comments (1)
backend/websocket/debate_spectator.go (1)

18-22: Permissive CheckOrigin disables CSRF protection for WebSocket connections

debateUpgrader currently allows any origin:

CheckOrigin: func(r *http.Request) bool {
    return true
},

This is convenient during development but effectively disables origin checks, allowing arbitrary websites to establish WS connections to your backend if they can reach it over the network.

Consider tightening this to validate against a configured list of allowed origins or at least environment‑dependent behavior (e.g., strict in prod, permissive in local dev).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f00c93 and abd4477.

📒 Files selected for processing (3)
  • backend/cmd/server/main.go (3 hunks)
  • backend/config/config.prod.sample.yml (1 hunks)
  • backend/websocket/debate_spectator.go (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • backend/config/config.prod.sample.yml
🧰 Additional context used
🧬 Code graph analysis (1)
backend/cmd/server/main.go (1)
backend/websocket/debate_spectator.go (1)
  • DebateWebsocketHandler (196-264)
🔇 Additional comments (4)
backend/cmd/server/main.go (1)

166-167: LGTM! Correct namespacing for the debate WebSocket handler.

The handler is now properly referenced from the websocket package, resolving the previous compilation error.

backend/websocket/debate_spectator.go (3)

1-1: Package rename correctly aligns this file with the websocket package

Switching from package main to package websocket here is consistent with the other websocket files and avoids mixed-package compilation issues in the same directory.


188-193: Avoid concurrent writes on the same WebSocket: use SpectatorClient.WriteJSON instead of conn.WriteJSON in the handler

Gorilla WebSocket requires all writes to a connection to be serialized. In DebateWebsocketHandler, direct calls to conn.WriteJSON for the initial snapshot and presence event can race with concurrent broadcasts that call client.WriteJSON, which serializes writes via writeMu. Since client *SpectatorClient is already available, route these writes through its mutex-protected helper to ensure all writes on the connection are properly serialized:

-	conn.WriteJSON(snapshot)
+	_ = client.WriteJSON(snapshot)
-	conn.WriteJSON(presenceEvent)
+	_ = client.WriteJSON(presenceEvent)

55-99: Verify mutex locking pattern in Register and BroadcastPresence

The review identifies a potential self-deadlock where Register holds h.mu.Lock() and then calls h.BroadcastPresence, which attempts to acquire h.mu.RLock(). This pattern is theoretically problematic because Go's sync.RWMutex is not re-entrant—a writer lock (Lock) held cannot wait on a reader lock (RLock) without causing deadlock.

However, verification requires inspecting the actual BroadcastPresence implementation to confirm it indeed calls h.mu.RLock(), and checking lines 164-186 to confirm the same pattern exists there. The repository is currently unavailable for direct inspection.

The proposed fix (releasing h.mu before the broadcast call) is sound in principle, but cannot be validated against the actual codebase implementation.

Comment on lines +46 to 50
if cfg.Redis.Addr != "" {
redisURL := cfg.Redis.Addr
if redisURL == "" {
redisURL = "localhost:6379"
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Dead code: unreachable default assignment.

The inner check if redisURL == "" on line 48 is unreachable because line 46 already ensures cfg.Redis.Addr != "", and line 47 assigns that non-empty value to redisURL. The default "localhost:6379" will never be applied.

Apply this diff to remove the dead code:

 	if cfg.Redis.Addr != "" {
 		redisURL := cfg.Redis.Addr
-		if redisURL == "" {
-			redisURL = "localhost:6379"
-		}
 		if err := debate.InitRedis(redisURL, cfg.Redis.Password, cfg.Redis.DB); err != nil {

Alternatively, if a default Redis address is desired, restructure the logic:

-	if cfg.Redis.Addr != "" {
-		redisURL := cfg.Redis.Addr
-		if redisURL == "" {
-			redisURL = "localhost:6379"
-		}
+	redisURL := cfg.Redis.Addr
+	if redisURL == "" {
+		redisURL = "localhost:6379"
+	}
+	if redisURL != "" {
 		if err := debate.InitRedis(redisURL, cfg.Redis.Password, cfg.Redis.DB); err != nil {
 			log.Printf("⚠️ Warning: Failed to initialize Redis: %v", err)
 			log.Printf("⚠️ Some realtime features will be unavailable until Redis is reachable")
 		} else {
 			log.Println("Connected to Redis")
 		}
 	} else {
 		log.Println("Redis Addr not configured; continuing without Redis-backed features")
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if cfg.Redis.Addr != "" {
redisURL := cfg.Redis.Addr
if redisURL == "" {
redisURL = "localhost:6379"
}
if cfg.Redis.Addr != "" {
redisURL := cfg.Redis.Addr
if err := debate.InitRedis(redisURL, cfg.Redis.Password, cfg.Redis.DB); err != nil {
🤖 Prompt for AI Agents
In backend/cmd/server/main.go around lines 46-50, the inner check `if redisURL
== ""` is unreachable because you already gated with `if cfg.Redis.Addr != ""`
and then assigned that value to `redisURL`; remove the redundant inner check and
simply use cfg.Redis.Addr or, if you want a fallback default, restructure by
removing the outer `if` and assign redisURL from cfg.Redis.Addr with a
subsequent check to set `"localhost:6379"` when cfg.Redis.Addr is empty.

@ARCoder181105
Copy link
Contributor Author

@bhavik-mangla
Pls review my PR

@ARCoder181105
Copy link
Contributor Author

@rixitgithub please review my PR

@bhavik-mangla
Copy link
Contributor

please include testing evidences
PR looks good to me
@rixitgithub review pls

@ARCoder181105
Copy link
Contributor Author

image

@bhavik-mangla

I fixed all the build error now the backend is running fine

@bhavik-mangla
Copy link
Contributor

Good work fixing fields mismatch @ARCoder181105 🙌

@bhavik-mangla bhavik-mangla merged commit 251aa47 into AOSSIE-Org:main Dec 21, 2025
1 check passed
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.

fix: Backend compilation errors, struct collisions, and merge conflicts

2 participants