Skip to content

Conversation

@harsha-nandan
Copy link

@harsha-nandan harsha-nandan commented Dec 6, 2025

Title: Fix backend build errors and restore server startup
Summary

This PR resolves multiple critical issues that prevented the backend from compiling and starting.
The project had several unresolved merge conflicts, missing structs, mismatched types, and incomplete API integrations that caused the build to fail.

Key Fixes

  1. Resolved merge conflicts across multiple files

Cleaned and merged conflict blocks in:

team_websocket.go

team_controller.go

websocket.go

others as necessary

Ensured consistent logic (e.g., team capacity, bson filters).

  1. Rebuilt the Comment model

Removed duplicate Comment struct definitions.

Unified Comment into a single model with fields required by controllers:

Type

UserEmail

DebateID

TeamID

IsDeleted

plus existing transcript/comment fields.

This restores compatibility with admin_controller.go, transcript_controller.go, and others.

  1. Fixed Redis config redeclaration

Removed duplicate nested Redis blocks in config.go.

Restored valid Config struct shape.

  1. Patched WebSocket build failures

Removed duplicate fields (IsSpectator).

Corrected missing/broken handler definitions.

Added stub for DebateWebsocketHandler.

  1. Repaired DB logging + imports

Restored missing "log" imports where needed.

  1. Stubbed Gemini integration safely

The project was using an outdated Gemini API that no longer exists.

To restore build:

Removed broken API calls.

Implemented stub functions:

initGemini

generateModelText

generateDefaultModelText

Ensured the correct type (*genai.Client) matches the rest of the codebase.

Restored consistent import paths.

This allows the backend to compile even without full Gemini support.

  1. Server builds and runs again

All compile-time issues are resolved; the project now proceeds to runtime, failing only on invalid MongoDB config (expected).

Why This PR Is Important

The backend was previously not buildable at all.

Merge conflicts and inconsistent models made it impossible for contributors to run or test.

This PR restores the project to a functional, maintainable state.

Enables future work such as improving Debate AI, fixing endpoints, or implementing real Gemini logic.

What Still Needs Work (Optional Future Tasks)

Implement real Gemini model integration.

Provide a valid MongoDB config or add a fallback local DB.

Improve websocket error handling and room management.

Add unit tests for Comment flows and team logic.

Summary by CodeRabbit

  • New Features

    • Added Google OAuth configuration support for authentication
    • Added debate WebSocket endpoint (implementation pending)
  • Bug Fixes

    • Fixed team join capacity validation to handle invalid team sizes gracefully
    • Corrected spectator role classification in WebSocket connections
  • Chores

    • Updated dependencies including access control and AI service libraries
    • Enhanced admin action logging with detailed metadata
    • Improved comment data model with additional metadata fields

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

…i service, restore config structure, and correct websocket handlers
@coderabbitai
Copy link

coderabbitai bot commented Dec 6, 2025

Walkthrough

This PR introduces multiple backend changes including Redis configuration renaming, Google OAuth configuration addition, model structure expansions (Comment struct with new fields), API handler stubs (Gemini and Debate WebSocket), dependency updates for Casbin integration, and WebSocket broadcast logic refinements following merge conflict resolution.

Changes

Cohort / File(s) Summary
Configuration & Dependency Management
backend/config/config.go, backend/go.mod, backend/db/db.go
Redis field renamed from Addr to URL, Google OAuth ClientID field added. Casbin and MongoDB adapter dependencies promoted to direct requirements; genai updated from v1.34.0 to v1.37.0 with related indirect dependency updates. Redis import handling adjusted in db initialization.
WebSocket Layer
backend/cmd/server/main.go, backend/websocket/team_websocket.go, backend/websocket/websocket.go
Debate WebSocket handler stub added returning HTTP 501. Team WebSocket broadcast logic expanded to include all connected clients in many scenarios rather than filtering per-recipient snapshots. IsSpectator field removed from Client creation, causing spectators to default to non-spectator role.
Data Models
backend/models/admin.go, backend/models/comment.go
Comment struct removed from admin.go and relocated to comment.go with new fields: Type, UserEmail, DebateID, TeamID, IsDeleted. AdminActionLog enriched with Details map field for metadata storage.
Controllers & Services
backend/controllers/auth.go, backend/controllers/team_controller.go, backend/controllers/transcript_controller.go, backend/services/gemini.go
Log import added to auth.go. Team join logic introduces capacity normalization fallback to 4. MongoDB BSON type handling updated to use bson.A. Unused email variable added to transcript handler. Gemini client initialization and API call logic stubbed out with placeholder returning nil/error.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • WebSocket broadcast logic changes across team_websocket.go may alter who receives real-time updates; merge conflict resolution requires careful verification of intended recipient behavior
  • IsSpectator field removal in websocket.go Client creation introduces a potential role misclassification bug with impact on participant lists and spectator-specific logic
  • Unused variables (email in transcript_controller.go) and stubbed implementations (Gemini, DebateWebsocketHandler) require clarification on development intent
  • Model structural changes (Comment struct relocation and field additions) may affect serialization/deserialization and database queries across services
  • Heterogeneous changes spanning configuration, models, controllers, and services require reasoning about consistency across multiple independent components

Possibly related PRs

Poem

🐰 Hops through code with whiskers twitching bright,
Redis URLs and OAuth in sight,
WebSocket broadcasts, far and wide,
Stubs await their logic inside,
Model shifts dance through the night,
Infrastructure preps for Debate's grand flight! 🚀

Pre-merge checks and finishing touches

✅ 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 'Fix backend build errors and restore server startup' accurately describes the primary purpose of this changeset—resolving compilation issues and enabling the backend to run.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 1

Caution

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

⚠️ Outside diff range comments (1)
backend/cmd/server/main.go (1)

44-58: Redis URL fallback is currently unreachable

The inner fallback to "localhost:6379" can never run because of the outer if cfg.Redis.URL != "":

if cfg.Redis.URL != "" {
    redisURL := cfg.Redis.URL
    if redisURL == "" { // unreachable
        redisURL = "localhost:6379"
    }
    ...
}

If you want a real default to localhost when cfg.Redis.URL is empty, consider:

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

Otherwise, you can safely drop the inner if redisURL == "" as dead code.

🧹 Nitpick comments (6)
backend/config/config.go (1)

3-8: Config structure and loader are fine; consider modernizing file I/O

The expanded Config shape and YAML unmarshalling look consistent and should work as intended. You might later replace ioutil.ReadFile with os.ReadFile since io/ioutil is deprecated in newer Go versions, but that’s purely a cleanup.

Also applies to: 10-57, 59-72

backend/controllers/transcript_controller.go (1)

407-415: Remove or replace the email stub in UpdatePendingTranscriptsHandler

The email := "" // or load actual email followed by _ = email is effectively a no-op and may confuse future maintainers. Either:

  • Capture the email from ValidateTokenAndFetchEmail and use it if/when the service needs it, or
  • Drop the local email variable entirely until it’s required.
backend/cmd/server/main.go (1)

164-175: Stub DebateWebsocketHandler is fine as a temporary placeholder

Wiring /ws/debate/:debateID to a 501 JSON stub unblocks routing and build. Just keep in mind this endpoint is effectively disabled until real WebSocket logic is hooked up, so any callers should expect the 501 for now.

If helpful, I can help adapt the existing debate WebSocket logic into a websocket.DebateWebsocketHandler and wire it here when you’re ready.

backend/controllers/team_controller.go (1)

354-377: Deduplicate capacity calculation in JoinTeam

Normalizing capacity with a fallback to 4 is a good safeguard, but you do it twice:

capacity := team.MaxSize
if capacity <= 0 {
    capacity = 4
}
if len(team.Members) >= capacity { ... }

...

capacity = team.MaxSize
if capacity <= 0 {
    capacity = 4
}
if len(team.Members) >= capacity { ... }

You can compute capacity once and reuse it:

capacity := team.MaxSize
if capacity <= 0 {
    capacity = 4
}

if len(team.Members) >= capacity {
    c.JSON(http.StatusBadRequest, gin.H{"error": "Team is already full"})
    return
}

totalElo := 0.0
for _, member := range team.Members {
    totalElo += member.Elo
}
totalElo += newMember.Elo
newAverageElo := totalElo / float64(len(team.Members)+1)

This keeps behavior the same and removes redundant logic.

backend/websocket/team_websocket.go (1)

488-507: snapshotAllTeamClients helper is a good concurrency-friendly addition

Capturing all TeamClient pointers under room.Mutex and then broadcasting outside the lock via snapshotAllTeamClients is a nice improvement over writing while holding the mutex. This pattern should scale better under load.

You might later migrate other broadcast paths that still iterate room.Clients under room.Mutex (e.g., in handleTeamReadyStatus / handleCheckStart) to reuse this helper for consistency and to keep I/O outside the critical section.

backend/models/comment.go (1)

12-29: Admin metadata fields look correct; consider clarifying dual email fields and deletion flag semantics

The added admin fields (Type, UserEmail, DebateID, TeamID, IsDeleted) have consistent BSON/JSON tags and should work fine with admin_controller.go. However, having both Email and UserEmail plus an IsDeleted bool with omitempty can be ambiguous for future readers/clients. Consider:

  • Adding brief doc comments (or renaming) to distinguish Email vs UserEmail.
  • Confirming that omitting isDeleted entirely (for false) is acceptable to all API consumers, vs always returning an explicit false.
📜 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 13a551d.

⛔ Files ignored due to path filters (1)
  • backend/go.sum is excluded by !**/*.sum
📒 Files selected for processing (12)
  • backend/cmd/server/main.go (1 hunks)
  • backend/config/config.go (1 hunks)
  • backend/controllers/auth.go (1 hunks)
  • backend/controllers/team_controller.go (2 hunks)
  • backend/controllers/transcript_controller.go (1 hunks)
  • backend/db/db.go (1 hunks)
  • backend/go.mod (4 hunks)
  • backend/models/admin.go (1 hunks)
  • backend/models/comment.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 (1)
  • backend/websocket/websocket.go
🧰 Additional context used
🧬 Code graph analysis (1)
backend/cmd/server/main.go (1)
backend/cmd/server/ws_debate_handler.go (1)
  • DebateWebsocketHandler (196-264)
🔇 Additional comments (9)
backend/db/db.go (1)

7-15: Redis client wiring and logging look correct

The switch to github.com/redis/go-redis/v9 plus the Ping check and success log in ConnectRedis are idiomatic and should be reliable as-is.

Also applies to: 99-118

backend/models/admin.go (1)

23-36: AdminActionLog.Details addition is a good, flexible extension

Adding the Details field with omitempty tags gives you room for richer audit data without breaking existing documents or responses. Looks good.

backend/controllers/team_controller.go (1)

625-635: Available-teams $expr query using bson.A looks correct

The $expr / $lt filter with bson.A{ bson.M{"$size": "$members"}, "$maxSize" } is valid and matches the intended “members count < maxSize” semantics.

backend/websocket/team_websocket.go (2)

510-529: Team join broadcast now correctly syncs all clients with team status

Using snapshotAllTeamClients in handleTeamJoin to send the "teamStatus" payload to everyone (including the joiner) is reasonable and avoids per-call map locking. No correctness issues spotted.


949-970: Turn-status broadcast changes in handleTeamTurnRequest look sound

Computing currentTurn once and then broadcasting "teamStatus" only to clients where r.TeamID == client.TeamID via snapshotAllTeamClients keeps the update scoped to the relevant team while reducing redundant locking. Behavior matches the per-team semantics of turns.

backend/services/gemini.go (1)

10-35: Verify error handling at all call sites of Gemini stub functions

initGemini returns (nil, nil) and generateModelText guards on geminiClient == nil, so any invocation of generateDefaultModelText or generateModelText will return an error unless a real client is initialized elsewhere. This changes behavior from silent no-op to explicit error.

Confirm that all call sites either:

  • Handle the "gemini client not initialized" error gracefully, or
  • Skip calling these helpers when Gemini is not available.
backend/models/comment.go (2)

40-51: MarshalJSON remains compatible; new fields are automatically included

The Alias-based MarshalJSON still correctly converts ID, TranscriptID, ParentID, and UserID to hex strings while delegating the rest of the fields (including the new admin metadata) to the embedded Alias. This keeps existing JSON shape for IDs and automatically serializes the new fields without extra code. No changes needed here.


56-70: DebatePost struct/tag setup is consistent and sane

DebatePost’s ObjectID fields, user info, and audit timestamps all have aligned BSON/JSON tags and mirror the patterns used on Comment. This should keep the public post API stable and predictable. Looks good as-is.

backend/go.mod (1)

8-9: Validate new Casbin/genai dependencies and clean up any legacy Gemini client usage

Promoting github.com/casbin/casbin/v2 and github.com/casbin/mongodb-adapter/v3 to direct deps and bumping google.golang.org/genai to v1.37.0 matches the new auth and Gemini stub work. Two follow-ups to keep the module graph tidy:

  • Verify all call sites are written against google.golang.org/genai v1.37.0's API surface (breaking changes exist across minor versions).
  • You have both google.golang.org/genai and github.com/google/generative-ai-go in the graph; if fully migrated to google.golang.org/genai, remove remaining generative-ai-go imports and run go mod tidy locally so the old client drops out.

"os"
"strings"
"time"
"log"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

PII logging creates compliance risk.

The log import enables logging statements in generateJWT (line 546) that log user email addresses. Logging PII such as emails may violate GDPR/CCPA requirements, especially if logs are retained, aggregated, or transmitted to third-party systems without proper safeguards.

Consider one of the following approaches:

  1. Remove email from log statements and use anonymized user IDs instead
  2. Implement structured logging with PII redaction/masking
  3. Ensure logs containing PII have appropriate retention policies and access controls

Apply this diff to remove email from the log statement:

-	log.Printf("JWT Generation - Email: %s, Now: %s, Expiry: %s (in %d minutes)", email, now.Format(time.RFC3339), expirationTime.Format(time.RFC3339), expiryMinutes)
+	log.Printf("JWT Generation - Now: %s, Expiry: %s (in %d minutes)", now.Format(time.RFC3339), expirationTime.Format(time.RFC3339), expiryMinutes)

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In backend/controllers/auth.go around lines 11 and 546, the file currently
imports the standard "log" (line 11) and later logs user email in generateJWT
(around line 546), which exposes PII; remove or change the log to avoid logging
the raw email — replace any email output with a non-PII identifier (e.g., user
ID or hashed/masked email) or remove the log entirely, and if the "log" import
becomes unused remove that import line; ensure any structured logging uses the
non-PII field and that the code still compiles after these changes.

@harsha-nandan harsha-nandan marked this pull request as draft December 6, 2025 20:13
@harsha-nandan harsha-nandan marked this pull request as ready for review December 6, 2025 20:15
@bhavik-mangla
Copy link
Contributor

Include testing evidences

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