Skip to content

Conversation

@Basharkhan7776
Copy link
Contributor

@Basharkhan7776 Basharkhan7776 commented Jan 20, 2026

Issue #230

This PR executes a major architectural refactor of the backend to enable strict dependency injection, resolving circular dependencies and allowing for robust automated testing. It isolates business logic from the controller layer into dedicated Services (AuthService, VotingService) and implements a multi-layered testing strategy covering unit, integration, and concurrency vectors.

Technical Changes

Architecture & Refactoring

  • Service Layer Extraction: Decoupled AuthService and VotingService from controllers, moving core business logic into services/ package.
  • Dependency Injection: Introduced repositories interfaces (UserRepository, DebateRepository) and EmailSender interface to abstract external dependencies (MongoDB, SMTP) for mocking.
  • Controller Wiring: Refactored controllers/auth.go to consume a global AuthService singleton (initialized in services/init.go), removing direct DB dependencies from the controller.
  • Circular Dependency Fix: Extracted test data seeding logic from utils/ to a standalone cmd/seeder binary, resolving the utils <-> services import cycle.
  • Route Setup: Moved router initialization to routes.SetupRouter to facilitate httptest integration.

Testing Infrastructure

  • Unit Testing: Implemented table-driven tests for AuthService (SignUp, Login, VerifyEmail) and VotingService (JudgeDebate, result parsing) using testify/mock.
  • Concurrency Testing: Added specific tests for WebSocket Room locking mechanisms ensuring thread safety during concurrent client broadcasts.
  • Integration Testing: Created tests/integration_test.go utilizing httptest to verify HTTP route registration, middleware binding, and status codes (403 vs 404).
  • Test Utils: Added utils/test_utils.go for test-specific configuration loading and mock generation.

Bug Fixes

  • Fixed fmt.Sprintf argument mismatch in debatevsbot.go.
  • Resolved config vs testConfig struct mismatches in test files.

Testing Strategy

All tests pass with race detection enabled:

go test -v ./... -race

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * AI-powered debate outcome evaluation (automated judging)
  * Centralized authentication service for signup, login, and email verification

* **Improvements**
  * Consolidated router for more consistent HTTP and WebSocket endpoints
  * Sensitive fields hidden from API responses (improved user data privacy)
  * Stronger startup logging and clearer seeding outcomes

* **Bug Fixes**
  * Safer seeding to prevent duplicate test users and surface failures

* **Tests**
  * Added unit and integration tests plus test utilities for auth, voting, and websockets

<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@coderabbitai
Copy link

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Walkthrough

Centralizes HTTP routing into routes.SetupRouter, introduces Mongo-backed repositories (User, Debate), extracts auth logic into a new AuthService with JWT/email flows, adds a VotingService for AI judging, converts the seeder to a standalone main command, and adds test scaffolding and utilities for integration and concurrency.

Changes

Cohort / File(s) Summary
Router & Server
backend/routes/setup.go, backend/cmd/server/main.go
Move in-file router and route registrations into routes.SetupRouter; server main now calls routes.SetupRouter. Startup retains service inits (DB, Casbin, Redis, rating, seeding) but removes inline route wiring.
Authentication Service & Controllers
backend/services/auth_service.go, backend/services/init.go, backend/services/email_service.go, backend/controllers/auth.go
New AuthService interface and implementation (SignUp, Login, VerifyEmail, GenerateJWT), email sender abstraction, service init/getter, and controllers refactored to delegate auth operations to the service.
Repositories
backend/repositories/user_repository.go, backend/repositories/debate_repository.go
New Mongo-backed MongoUserRepository and MongoDebateRepository with constructors and CRUD/update methods; methods guard against uninitialized DB collection.
Voting / Judging
backend/services/voting_service.go, backend/services/voting_service_test.go
New VotingService and GeminiClientInterface to generate/judge debate content; ParseJudgeResult for verdict parsing and unit tests with mocks.
Seeder CLI
backend/cmd/seeder/main.go
Seeder converted to package main with main() entry: explicit config load, Mongo connect, rating init, skip when users exist, and fatal-logged failures.
Tests & Test Utilities
backend/tests/integration_test.go, backend/utils/test_utils.go, backend/services/auth_service_test.go, backend/websocket/concurrency_test.go
Integration test scaffolding using SetupTestRouter, test DB setup/teardown, mock Gemini client, auth service unit tests using testify mocks, and concurrency tests for websocket Room.
Module deps
backend/go.mod
Added github.com/stretchr/testify v1.11.1 and related indirect deps for tests.
Misc / Cleanup
backend/services/debatevsbot.go, backend/test_server.go
Minor fmt argument change in debatevsbot.go (cosmetic). Removed backend/test_server.go test driver.
Models
backend/models/user.go
Hide Password and VerificationCode from JSON, add VerificationCodeSentAt time.Time, and reorder/format struct fields.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AuthController
    participant AuthService
    participant UserRepository
    participant Database
    participant EmailService

    rect rgba(100, 150, 255, 0.5)
    Note over Client,EmailService: SignUp Flow
    Client->>AuthController: POST /signup (email, password)
    AuthController->>AuthService: SignUp(ctx, email, password)
    AuthService->>UserRepository: FindByEmail(ctx, email)
    UserRepository->>Database: Query user by email
    Database-->>UserRepository: User or not found
    UserRepository-->>AuthService: result
    AuthService->>AuthService: Hash password & build user
    AuthService->>UserRepository: Create(ctx, newUser)
    UserRepository->>Database: Insert user
    Database-->>UserRepository: Insert result
    UserRepository-->>AuthService: created user
    AuthService->>EmailService: SendVerificationEmail(email, code)
    EmailService-->>AuthService: success/error
    AuthService-->>AuthController: success/error
    AuthController-->>Client: 200 / 4xx/5xx
    end
Loading
sequenceDiagram
    participant Client
    participant AuthController
    participant AuthService
    participant UserRepository
    participant Database

    rect rgba(150, 200, 150, 0.5)
    Note over Client,Database: Verify Email & Login Flow
    Client->>AuthController: POST /verify-email (email, code)
    AuthController->>AuthService: VerifyEmail(ctx, email, code)
    AuthService->>UserRepository: FindByEmail(ctx, email)
    UserRepository->>Database: Query user
    Database-->>UserRepository: User
    UserRepository-->>AuthService: User
    AuthService->>AuthService: Validate code & expiry
    AuthService->>UserRepository: UpdateByEmail(ctx, email, verified)
    UserRepository->>Database: Update user
    Database-->>UserRepository: Success
    UserRepository-->>AuthService: Success
    AuthService->>AuthService: Generate JWT
    AuthService-->>AuthController: User + Token
    AuthController-->>Client: 200 (user, accessToken)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through routes and repos bright,

Auth now hums with JWT light,
Tests lined up in tidy rows,
Seeder sows where seeders go,
Votes judged fair beneath moonlight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Refactor Backend Architecture for Service Layer Isolation & Comprehensive Test Coverage' accurately captures the primary objectives of this comprehensive PR: service layer extraction, dependency injection via repositories and interfaces, and expanded test coverage.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

Caution

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

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

40-59: Seeded users are missing required fields.

The test users lack several required fields from the User model: Password, Nickname, IsVerified, LastRatingUpdate, UpdatedAt, Score, and CurrentStreak. These fields have no omitempty BSON tags, meaning they must be populated. Either set default values for these fields in the seeded data or handle their initialization in the seeding logic.

🤖 Fix all issues with AI agents
In `@backend/cmd/seeder/main.go`:
- Around line 28-34: The call to collection.CountDocuments in main.go ignores
its returned error which can make the seeder proceed on failures; update the
seeding logic around the CountDocuments call (the variable named collection and
the CountDocuments(context.Background(), bson.M{}) invocation) to capture the
returned error, check if err != nil, and on error log the detailed error (via
log.Printf or similar) and abort/return instead of continuing; only proceed to
check count and seed when err is nil.

In `@backend/repositories/debate_repository.go`:
- Around line 40-50: The Create method on MongoDebateRepository currently
performs an unguarded type assertion on result.InsertedID to primitive.ObjectID
which can panic; update MongoDebateRepository.Create to use the comma-ok form
when converting result.InsertedID to primitive.ObjectID (same approach as
UserRepository.Create), and if the assertion fails return a clear typed error
(e.g., errors.New("failed to convert inserted ID to ObjectID")) instead of
panicking; ensure you reference result.InsertedID and primitive.ObjectID in the
check and return the hex string only after successful assertion.
- Around line 66-75: The UpdateOutcome implementation in MongoDebateRepository
is using a userId parameter and filtering on "userId", but the interface and
DebateVsBot model use email; update the function signature and internal
references so the parameter is named email (UpdateOutcome(ctx context.Context,
email, outcome string) error) and change the filter to bson.M{"email": email}
before calling UpdateOne (ensure any callers are updated to pass email if
needed).

In `@backend/repositories/user_repository.go`:
- Around line 64-74: In MongoUserRepository.Create, guard the untyped assertion
on result.InsertedID before assigning to user.ID: check whether
result.InsertedID is a primitive.ObjectID (e.g. via a type switch or ok :=
result.InsertedID.(primitive.ObjectID)), only set user.ID when the assertion
succeeds, and return a clear error if the InsertedID is of an unexpected type;
update the Create function to mirror the safe pattern used in
services/debatevsbot.go so it never panics on non-ObjectID _id values.

In `@backend/routes/setup.go`:
- Around line 52-54: SetupRouter currently hardcodes "./config/config.prod.yml"
when wiring middlewares.AuthMiddleware which ignores the cfg passed in and can
mismatch JWT secrets; change SetupRouter to accept and use the effective config
path or pass the loaded cfg object into the middleware instead of the hard-coded
string: update the SetupRouter signature (and its call sites such as
backend/cmd/server/main.go and tests) to forward the config path or cfg to
middlewares.AuthMiddleware and replace the hard-coded "./config/config.prod.yml"
usage in the auth and admin middleware wiring so the middleware reads the same
config used by LoadConfig.
- Around line 22-23: router.SetTrustedProxies is being called with an invalid
"localhost" entry and its returned error is ignored; replace invalid names with
valid IPs/CIDR (e.g., "127.0.0.1/32", "::1/128" or your proxy network ranges)
and check the returned error from SetTrustedProxies, handling it (log and exit
or return the error) so the router does not silently default to trusting all
proxies; update the call site where SetTrustedProxies is used to validate the
input slice and handle the error accordingly.

In `@backend/services/auth_service.go`:
- Around line 112-114: The expiry check currently uses user.CreatedAt (the code:
if time.Since(user.CreatedAt) > 24*time.Hour), which ties verification validity
to account creation; change the logic to use a dedicated timestamp for when the
verification code was issued (e.g., user.VerificationCodeSentAt or
user.CodeIssuedAt) and check time.Since(user.VerificationCodeSentAt) >
24*time.Hour instead; add/update the corresponding field on the User model,
ensure it is set when issuing/resending codes (where verification codes are
generated/sent), and update persistence/DB migrations and any tests that assume
CreatedAt-based expiry.
- Around line 40-45: The SignUp method currently treats any error from
userRepo.FindByEmail as "user not found", which masks DB errors; update SignUp
in authServiceImpl to distinguish a not-found sentinel error from other errors:
call s.userRepo.FindByEmail(ctx, email) and if err == nil return
errors.New("user already exists"); if err != nil then if errors.Is(err,
repo.ErrNotFound) or errors.Is(err, mongo.ErrNoDocuments) proceed to create the
user, otherwise return the error (propagate DB/connection errors). If the
repository lacks a sentinel ErrNotFound, add one (or translate
mongo.ErrNoDocuments) in the repository implementation so SignUp can reliably
use errors.Is.

In `@backend/services/voting_service_test.go`:
- Around line 36-39: The mock method MockDebateRepository.FindByID currently
does an unchecked type assertion which will panic if the mock returns nil;
change it to first retrieve args.Get(0) into a variable, check if that value is
nil and if so return nil and args.Error(1), otherwise perform the type assertion
and return the typed *models.DebateVsBot and args.Error(1) so it matches the
pattern used in the other mock methods.
- Around line 102-110: The "Invalid JSON" subtest currently returns early and
performs no assertions; update the subtest handling for the case where tt.name
== "Invalid JSON" (within the loop that calls ParseJudgeResult) to assert that
ParseJudgeResult returned an error (e.g., require/Error or assert.Error on the
returned error) and optionally assert that the result is the zero/default value
if desired; for all other cases keep the existing assert.Equal(t, tt.expected,
result). Reference: ParseJudgeResult and the test loop variable tt in
voting_service_test.go.

In `@backend/services/voting_service.go`:
- Around line 37-57: JudgeDebate currently discards GetBotPersonality(botName),
ignores botLevel and topic, and uses a placeholder prompt; fix by capturing the
personality (p := GetBotPersonality(botName)) and incorporating p, botLevel and
topic into the prompt built before calling FormatHistory and
s.gemini.GenerateContent (e.g., include personality description, judging
criteria based on botLevel, and the debate topic), and if you intend to keep a
placeholder instead of full logic add a clear TODO comment in JudgeDebate to
indicate incomplete implementation.

In `@backend/websocket/concurrency_test.go`:
- Line 36: The UserID construction uses string(rune(id)) which converts the
integer to a Unicode code point (producing control characters for small ids)
instead of a numeric string; update the UserID generation (where UserID:
"user"+string(rune(id)) is set) to use a proper integer-to-string conversion
such as strconv.Itoa(id) or fmt.Sprintf("user%d", id), and add the corresponding
import (strconv or fmt) to the test file.
🧹 Nitpick comments (14)
backend/websocket/concurrency_test.go (1)

62-107: Concurrency pattern is valid for race detection.

The test correctly exercises concurrent read/write patterns with proper mutex usage. Running with -race will verify thread safety.

Optional improvement: The snapshot simulation (lines 97-100) could actually build the slice to more closely mirror production broadcast logic:

♻️ Optional enhancement
 			room.Mutex.Lock()
 			// Simulate snapshot
-			_ = make([]*Client, 0, len(room.Clients))
+			snapshot := make([]*Client, 0, len(room.Clients))
 			for _, cl := range room.Clients {
-				_ = cl
+				snapshot = append(snapshot, cl)
 			}
 			room.Mutex.Unlock()
+			_ = snapshot // Use snapshot
backend/cmd/seeder/main.go (2)

17-17: Hardcoded relative config path is fragile.

The path ../../config/config.prod.yml depends on the working directory when the binary is executed. Consider using an environment variable or command-line flag for flexibility.

💡 Suggested improvement using environment variable
+import (
+	"os"
+	...
+)
+
 func main() {
-	cfg, err := config.LoadConfig("../../config/config.prod.yml")
+	configPath := os.Getenv("CONFIG_PATH")
+	if configPath == "" {
+		configPath = "../../config/config.prod.yml"
+	}
+	cfg, err := config.LoadConfig(configPath)

61-64: Consider simplifying slice conversion.

The conversion loop is correct but can be slightly more concise.

💡 Alternative approach
-	var documents []interface{}
-	for _, user := range testUsers {
-		documents = append(documents, user)
-	}
+	documents := make([]interface{}, len(testUsers))
+	for i, user := range testUsers {
+		documents[i] = user
+	}

This pre-allocates the slice to avoid repeated allocations during append.

backend/repositories/user_repository.go (1)

29-37: Consider failing fast when the DB isn’t initialized.

Returning an empty repo defers failure to later calls; consider returning an error (or at least logging) to avoid a “successful” startup with a nil collection.

backend/services/debatevsbot.go (1)

204-206: Remove trailing empty fmt.Sprintf argument (optional cleanup).

The empty string only fills the final %s and adds trailing whitespace; if no value is intended, drop the extra placeholder + argument.

♻️ Suggested cleanup
-[Your opening argument]
-%s %s`,
+[Your opening argument]
+%s`,
@@
-			limitInstruction,
-			baseInstruction,
-			"",
+			limitInstruction,
+			baseInstruction,
backend/routes/setup.go (1)

26-32: Make allowed origins configurable (avoid localhost-only in prod).

Hard-coding http://localhost:5173 can break CORS in non-dev environments. Consider pulling origins from config/env with a safe default.

backend/services/voting_service_test.go (2)

46-54: Avoid duplicate MockGeminiClient definitions.

You already have MockGeminiClient in backend/utils/test_utils.go. Consider reusing it to reduce drift between test helpers.


56-71: Assert mock expectations to ensure the Gemini call happens.

Without AssertExpectations, the test can pass even if GenerateContent is never called.

🔧 Proposed fix
 		resp, err := service.JudgeDebate(ctx, history, "Bot", "Medium", "Topic")
 		assert.NoError(t, err)
 		assert.Equal(t, expectedResponse, resp)
+		mockGemini.AssertExpectations(t)
 	})
 }
backend/tests/integration_test.go (1)

3-29: Reuse utils.LoadTestConfig to avoid config drift.

This duplicates test config initialization already provided in backend/utils/test_utils.go. Reusing it centralizes defaults.

🔧 Proposed fix
 import (
 	"net/http"
 	"net/http/httptest"
 	"testing"
 
 	"arguehub/config"
 	"arguehub/routes"
+	"arguehub/utils"
 
 	"github.com/gin-gonic/gin"
 	"github.com/stretchr/testify/assert"
 )
@@
 func SetupTestRouter() *gin.Engine {
 	gin.SetMode(gin.TestMode)
-	// Create minimal test config
-	cfg := &config.Config{}
-	cfg.Database.URI = "mongodb://localhost:27017/test_db"
-	cfg.JWT.Secret = "testsecret"
-	cfg.JWT.Expiry = 60
+	cfg := utils.LoadTestConfig()
+	cfg.Database.URI = "mongodb://localhost:27017/test_db" // override if needed
 	// Redis defautls to zero value (empty Addr), which is fine for tests that don't need it or handle it gracefully
backend/utils/test_utils.go (1)

29-33: Add a timeout to the initial DB drop to avoid hanging tests.

Using context.Background() can stall the test suite if Mongo stalls. Match the teardown’s timeout pattern.

🔧 Proposed fix
-	// Ensure we are starting with a clean slate
-	err = db.MongoDatabase.Drop(context.Background())
+	// Ensure we are starting with a clean slate
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancel()
+	err = db.MongoDatabase.Drop(ctx)
 	if err != nil {
 		log.Printf("Warning: Failed to drop test database: %v", err)
 	}
backend/services/voting_service.go (2)

23-35: Unused debateRepo dependency.

The debateRepo field is injected but never used in the current implementation. If it's intended for future use, consider adding a TODO comment or removing it until needed to keep the code clean.

♻️ If not needed, consider removing
 type votingServiceImpl struct {
-	debateRepo repositories.DebateRepository
-	gemini     GeminiClientInterface
+	gemini GeminiClientInterface
 }

-func NewVotingService(debateRepo repositories.DebateRepository, gemini GeminiClientInterface) VotingService {
+func NewVotingService(gemini GeminiClientInterface) VotingService {
 	return &votingServiceImpl{
-		debateRepo: debateRepo,
-		gemini:     gemini,
+		gemini: gemini,
 	}
 }

61-86: Silent fallback to "loss" may mask parsing issues.

The function defaults to "loss" when:

  • verdict key is missing or not a map (line 69)
  • winner key is missing or not a string (line 74)
  • winner value is unrecognized (line 85)

This makes it difficult to distinguish between a legitimate bot win and a malformed response. Consider returning an error for unexpected structures, or at least logging when defaults are applied.

♻️ Alternative: Return error for malformed verdict
 func ParseJudgeResult(jsonResult string) (string, error) {
 	var result map[string]interface{}
 	if err := json.Unmarshal([]byte(jsonResult), &result); err != nil {
 		return "", err
 	}
 	
 	verdict, ok := result["verdict"].(map[string]interface{})
 	if !ok {
-		return "loss", nil // Default failure
+		return "", errors.New("missing or invalid verdict field")
 	}
 	
 	winner, ok := verdict["winner"].(string)
 	if !ok {
-		return "loss", nil
+		return "", errors.New("missing or invalid winner field")
 	}

 	if strings.EqualFold(winner, "User") {
 		return "win", nil
 	} else if strings.EqualFold(winner, "Bot") {
 		return "loss", nil
 	} else if strings.EqualFold(winner, "Draw") {
 		return "draw", nil
 	}
 	
-	return "loss", nil
+	return "", fmt.Errorf("unrecognized winner value: %s", winner)
 }
backend/controllers/auth.go (2)

426-447: Duplicate JWT generation logic.

The private generateJWT function duplicates services.GenerateJWT. The only difference is logging statements. Consider using the service function and adding logging there if needed, or removing this function once GoogleLogin is refactored to use the service.

♻️ Consider consolidating
 // In GoogleLogin and other methods still using generateJWT:
-token, err := generateJWT(existingUser.Email, cfg.JWT.Secret, cfg.JWT.Expiry)
+token, err := services.GenerateJWT(existingUser.Email, cfg.JWT.Secret, cfg.JWT.Expiry)

Then remove the local generateJWT function once all callers are migrated.


33-122: Inconsistent service layer usage across auth endpoints.

GoogleLogin, ForgotPassword, VerifyForgotPassword, and VerifyToken still access db.MongoDatabase directly, while SignUp, Login, and VerifyEmail now use the service layer. Consider tracking this as follow-up work to complete the refactor and achieve consistent architecture.

Would you like me to open an issue to track migrating the remaining auth endpoints to the service layer?

Comment on lines 28 to 34
collection := db.MongoDatabase.Collection("users")
count, _ := collection.CountDocuments(context.Background(), bson.M{})

if count > 0 {
log.Println("Users already exist, skipping seed.")
return
}
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

Ignored error from CountDocuments can cause unexpected behavior.

If CountDocuments fails (e.g., network issue, permissions), count defaults to 0 and the seeder proceeds to insert, potentially causing duplicate key errors or masking the real failure.

🐛 Proposed fix
 	collection := db.MongoDatabase.Collection("users")
-	count, _ := collection.CountDocuments(context.Background(), bson.M{})
+	count, err := collection.CountDocuments(context.Background(), bson.M{})
+	if err != nil {
+		log.Fatal("Failed to count users: " + err.Error())
+	}
 
 	if count > 0 {
 		log.Println("Users already exist, skipping seed.")
 		return
 	}
🤖 Prompt for AI Agents
In `@backend/cmd/seeder/main.go` around lines 28 - 34, The call to
collection.CountDocuments in main.go ignores its returned error which can make
the seeder proceed on failures; update the seeding logic around the
CountDocuments call (the variable named collection and the
CountDocuments(context.Background(), bson.M{}) invocation) to capture the
returned error, check if err != nil, and on error log the detailed error (via
log.Printf or similar) and abort/return instead of continuing; only proceed to
check count and seed when err is nil.

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

🤖 Fix all issues with AI agents
In `@backend/models/user.go`:
- Around line 23-28: Add JSON omit tags to the sensitive fields on the User
struct: update the struct fields Password, VerificationCode,
VerificationCodeSentAt, and ResetPasswordCode to include json:"-" in addition to
their existing bson tags (e.g., Password string `bson:"password" json:"-"`),
leaving other tags and omitempty behavior intact so these fields cannot be
accidentally marshaled to JSON.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant