Conversation
657db35 to
33712a2
Compare
📝 WalkthroughWalkthroughMove user-listing behind an admin-only route, add RequireAdmin middleware that checks DB for is_admin, extend User model with IsAdmin and time-based timestamps, include FCMToken in migrations, add API.md documentation, parameterize Postgres creds in docker-compose, and remove the entire services/listings feature (controllers, models, service layer). Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client
participant Server as API Server
participant DB as Database
Client->>Server: GET /api/admin/users (Authorization: Bearer <access_token>)
Server->>Server: RequireAuth validates token, extracts uid
Server->>Server: RequireAdmin reads uid from context
Server->>DB: SELECT * FROM users WHERE firebase_uid = uid
DB-->>Server: user row (IsAdmin = true/false)
alt IsAdmin true
Server->>Server: controllers.FindUsers queries users
Server->>DB: SELECT * FROM users
DB-->>Server: users list
Server-->>Client: 200 OK + users list
else IsAdmin false
Server-->>Client: 403 Forbidden
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
Comment Tip CodeRabbit can enforce grammar and style rules using `languagetool`.Configure the |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
main.go (3)
31-32:⚠️ Potential issue | 🟡 MinorDuplicate AutoMigrate call.
FCMTokenis already auto-migrated inmodels.ConnectDatabase()(line 41 ofmodels/setup.go). This duplicate call is unnecessary.🗑️ Proposed fix: Remove duplicate migration
- // Migrate fcm token table - models.DB.AutoMigrate(&models.FCMToken{})🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@main.go` around lines 31 - 32, Remove the redundant migration by deleting the duplicate call to models.DB.AutoMigrate(&models.FCMToken{}) in main.go; the FCMToken model is already migrated inside models.ConnectDatabase(), so keep ConnectDatabase()'s migration and remove the models.DB.AutoMigrate(&models.FCMToken{}) invocation to avoid duplicate work.
37-43:⚠️ Potential issue | 🟠 MajorServer continues after fatal Firebase initialization failure.
Similar to the database error, the server logs
[FATAL]but continues. If Firebase auth fails, all authenticated endpoints will be broken.🐛 Proposed fix: Exit on fatal errors
if _, err := os.Stat(serviceAccountPath); err != nil { - log.Printf("[FATAL] Missing service account file: %s (cwd: %s): %v", serviceAccountPath, getwdSafe(), err) + log.Fatalf("[FATAL] Missing service account file: %s (cwd: %s): %v", serviceAccountPath, getwdSafe(), err) } ac, err := auth.NewAuthClient(context.Background(), serviceAccountPath) if err != nil { - log.Printf("[FATAL] Firebase init failed: %v", err) + log.Fatalf("[FATAL] Firebase init failed: %v", err) } // Initialize Firebase Messaging if err := auth.InitFirebase(serviceAccountPath); err != nil { - log.Printf("[FATAL] Firebase Messaging init failed: %v", err) + log.Fatalf("[FATAL] Firebase Messaging init failed: %v", err) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@main.go` around lines 37 - 43, The code logs fatal messages but continues running when Firebase auth fails; update the checks around serviceAccountPath and auth.NewAuthClient to terminate the process on error: after the os.Stat failure (serviceAccountPath/getwdSafe()) and after auth.NewAuthClient returning an error, call a process exit (e.g., os.Exit(1)) or use log.Fatalf to log and exit so the server does not start with a nil/invalid auth client (referencing serviceAccountPath, getwdSafe(), and auth.NewAuthClient).
27-29:⚠️ Potential issue | 🟠 MajorServer continues after fatal database connection failure.
Logging
[FATAL]suggests the error is unrecoverable, but the server continues to start. This will cause panics or undefined behavior when handlers try to use the nil/invalidDB.🐛 Proposed fix: Exit on fatal errors
if err := models.ConnectDatabase(); err != nil { - log.Printf("[FATAL] Database connection failed: %v", err) + log.Fatalf("[FATAL] Database connection failed: %v", err) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@main.go` around lines 27 - 29, The code logs a fatal DB error but continues running; change the main startup path that calls models.ConnectDatabase() so the process exits on error — e.g., replace the current log.Printf in the if err := models.ConnectDatabase(); err != nil block with a terminating call (log.Fatalf("[FATAL] Database connection failed: %v", err) or log.Printf(...) followed by os.Exit(1)) so the server does not start with an invalid DB; update the error handling in main around models.ConnectDatabase() accordingly.controllers/users.go (1)
17-20:⚠️ Potential issue | 🟡 MinorMissing error handling on database query.
DB.Find(&users)can fail, but errors are not checked. Consider handling the error to avoid returning an empty response when the database is unavailable.🛡️ Proposed fix
func FindUsers(c *gin.Context) { var users []models.User - models.DB.Find(&users) - - c.JSON(http.StatusOK, gin.H{"data": users}) + if err := models.DB.Find(&users).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch users"}) + return + } + c.JSON(http.StatusOK, gin.H{"data": users}) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@controllers/users.go` around lines 17 - 20, The DB.Find call can fail but its error is ignored; update the users listing handler to capture the GORM result (e.g., res := models.DB.Find(&users)) and check res.Error; on error, log or return an HTTP 500/appropriate status using the gin.Context (c.JSON) with an error message instead of continuing to return an empty users array; otherwise proceed to return the users as before. Ensure you reference the existing users slice and models.DB.Find call and do not change the response shape on success.
🧹 Nitpick comments (4)
controllers/healthcheck.go (1)
12-22: Good addition of database health verification.The enhanced health check properly returns 503 when the database is unreachable. Consider logging the error for debugging purposes before returning the unhealthy response.
💡 Optional: Add error logging for debugging
func HealthCheck(c *gin.Context) { sqlDB, err := models.DB.DB() if err != nil { + log.Printf("[WARN] Health check failed to get DB handle: %v", err) c.JSON(http.StatusServiceUnavailable, gin.H{"status": "unhealthy", "database": "disconnected"}) return } if err := sqlDB.Ping(); err != nil { + log.Printf("[WARN] Health check DB ping failed: %v", err) c.JSON(http.StatusServiceUnavailable, gin.H{"status": "unhealthy", "database": "disconnected"}) return } c.JSON(http.StatusOK, gin.H{"status": "healthy", "database": "connected"}) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@controllers/healthcheck.go` around lines 12 - 22, In HealthCheck, log the actual error before returning the 503 so failures are debuggable: when models.DB.DB() returns err and when sqlDB.Ping() returns err, emit a log entry (e.g., using the application's logger or log.Printf / c.Error) containing the error and a short context message, then continue to return the existing c.JSON unhealthy response; update the error handling around models.DB.DB() and sqlDB.Ping() accordingly.models/setup.go (1)
40-44: Consider migration strategy for production.
AutoMigrateon every startup is convenient for development but may cause issues in production (e.g., long-running migrations blocking startup, lack of rollback capability). Consider using a dedicated migration tool (likegolang-migrate) for production deployments.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@models/setup.go` around lines 40 - 44, The code currently calls database.AutoMigrate(&User{}, &FCMToken{}) on startup; for production replace this approach with a dedicated migration workflow: remove or guard the database.AutoMigrate call in the setup code and instead generate explicit up/down SQL migrations (e.g., using golang-migrate) for the User and FCMToken schema changes, add a startup option or CI/CD step that runs the migration tool (not AutoMigrate) before app processes traffic, and keep a short runtime fallback only for local/dev (guarded by an env flag like ENABLE_AUTO_MIGRATE) so production runs use the migration tool with rollback capability and controlled execution.models/users.go (1)
33-34: Consider adjusting log level for expected flow."User not found by Firebase UID" is an expected condition during first-time user creation, not an error. Consider using
log.Printf("[DEBUG]...")orlog.Printf("[INFO]...")to avoid noisy error logs.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@models/users.go` around lines 33 - 34, The lookup that logs "User not found by Firebase UID" treats an expected first-time-miss as an error; change the log level in the branch that checks result.Error (the code referencing result.Error and firebaseUID in models/users.go) from "[ERROR]" to a non-error level such as "[DEBUG]" or "[INFO]" (e.g., log.Printf("[DEBUG] User not found by Firebase UID (%s): %v", firebaseUID, result.Error)) so misses during initial user creation don't produce noisy error logs; keep other error-handling behavior unchanged.API.md (1)
134-159: Document how theis_adminfield is initialized and managed.The admin routes documentation shows that users must have
is_admin = trueto access these endpoints, but there's no documentation on:
- How the
is_adminfield is set when users are created (alwaysfalseby default?)- How to promote a user to admin status
- Whether there's an admin creation/promotion endpoint
The PR objectives mention "Add an admin-creation route protected by admin authorization" as a next step, but it would be helpful to document the current state and planned approach for managing admin users.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@API.md` around lines 134 - 159, Document that the is_admin boolean field defaults to false on user creation (mention the is_admin field), state how admin status can be granted (e.g., via an admin-only promotion endpoint or a one-time seeded admin user), and explicitly describe the current options: (1) no public admin creation endpoint today so promotion must be done by DB seed/CLI or an existing admin calling the admin promotion API, (2) planned admin-creation route protected by admin authorization (refer to the "admin-creation route" and GET /api/admin/users), and include guidance on required Authorization: Bearer <access_token> and that only users with is_admin = true can call promotion/admin-creation endpoints; additionally note migration/DB default behavior and any recommended audit/logging for admin promotions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@API.md`:
- Around line 8-14: Update the API docs to match the implemented route: change
the documented endpoint from "GET /healthcheck" to "GET /health" in API.md so it
aligns with the registered handler (the actual route registered as GET /health
in main). Ensure the heading and any example request paths reflect "/health" and
keep the existing response body unchanged.
- Around line 75-101: The POST /api/users endpoint conflicts with the
verify-token flow and will cause DB constraint violations because it calls
DB.Create() without checking for existing users; either remove POST /api/users
entirely (relying on POST /api/verify-token and FindOrCreateUser) or convert it
to an admin-only endpoint by adding an admin privilege check and replacing the
DB.Create() call with the shared FindOrCreateUser logic so it safely handles
existing users; update any route handler named for POST /api/users and ensure
auth/authorization checks (admin flag) are enforced if you keep the endpoint.
In `@controllers/users.go`:
- Around line 46-48: The DB.Create(&user) call in controllers/users.go ignores
errors and can return invalid data to clients; update the CreateUser flow to
check the result := models.DB.Create(&user) (or use tx :=
models.DB.Create(&user)) and if result.Error != nil return an appropriate HTTP
error via c.JSON (e.g., http.StatusBadRequest or http.StatusInternalServerError)
with the error message/context, and avoid returning the user on failure; also
handle result.RowsAffected if needed for additional validation.
---
Outside diff comments:
In `@controllers/users.go`:
- Around line 17-20: The DB.Find call can fail but its error is ignored; update
the users listing handler to capture the GORM result (e.g., res :=
models.DB.Find(&users)) and check res.Error; on error, log or return an HTTP
500/appropriate status using the gin.Context (c.JSON) with an error message
instead of continuing to return an empty users array; otherwise proceed to
return the users as before. Ensure you reference the existing users slice and
models.DB.Find call and do not change the response shape on success.
In `@main.go`:
- Around line 31-32: Remove the redundant migration by deleting the duplicate
call to models.DB.AutoMigrate(&models.FCMToken{}) in main.go; the FCMToken model
is already migrated inside models.ConnectDatabase(), so keep ConnectDatabase()'s
migration and remove the models.DB.AutoMigrate(&models.FCMToken{}) invocation to
avoid duplicate work.
- Around line 37-43: The code logs fatal messages but continues running when
Firebase auth fails; update the checks around serviceAccountPath and
auth.NewAuthClient to terminate the process on error: after the os.Stat failure
(serviceAccountPath/getwdSafe()) and after auth.NewAuthClient returning an
error, call a process exit (e.g., os.Exit(1)) or use log.Fatalf to log and exit
so the server does not start with a nil/invalid auth client (referencing
serviceAccountPath, getwdSafe(), and auth.NewAuthClient).
- Around line 27-29: The code logs a fatal DB error but continues running;
change the main startup path that calls models.ConnectDatabase() so the process
exits on error — e.g., replace the current log.Printf in the if err :=
models.ConnectDatabase(); err != nil block with a terminating call
(log.Fatalf("[FATAL] Database connection failed: %v", err) or log.Printf(...)
followed by os.Exit(1)) so the server does not start with an invalid DB; update
the error handling in main around models.ConnectDatabase() accordingly.
---
Nitpick comments:
In `@API.md`:
- Around line 134-159: Document that the is_admin boolean field defaults to
false on user creation (mention the is_admin field), state how admin status can
be granted (e.g., via an admin-only promotion endpoint or a one-time seeded
admin user), and explicitly describe the current options: (1) no public admin
creation endpoint today so promotion must be done by DB seed/CLI or an existing
admin calling the admin promotion API, (2) planned admin-creation route
protected by admin authorization (refer to the "admin-creation route" and GET
/api/admin/users), and include guidance on required Authorization: Bearer
<access_token> and that only users with is_admin = true can call
promotion/admin-creation endpoints; additionally note migration/DB default
behavior and any recommended audit/logging for admin promotions.
In `@controllers/healthcheck.go`:
- Around line 12-22: In HealthCheck, log the actual error before returning the
503 so failures are debuggable: when models.DB.DB() returns err and when
sqlDB.Ping() returns err, emit a log entry (e.g., using the application's logger
or log.Printf / c.Error) containing the error and a short context message, then
continue to return the existing c.JSON unhealthy response; update the error
handling around models.DB.DB() and sqlDB.Ping() accordingly.
In `@models/setup.go`:
- Around line 40-44: The code currently calls database.AutoMigrate(&User{},
&FCMToken{}) on startup; for production replace this approach with a dedicated
migration workflow: remove or guard the database.AutoMigrate call in the setup
code and instead generate explicit up/down SQL migrations (e.g., using
golang-migrate) for the User and FCMToken schema changes, add a startup option
or CI/CD step that runs the migration tool (not AutoMigrate) before app
processes traffic, and keep a short runtime fallback only for local/dev (guarded
by an env flag like ENABLE_AUTO_MIGRATE) so production runs use the migration
tool with rollback capability and controlled execution.
In `@models/users.go`:
- Around line 33-34: The lookup that logs "User not found by Firebase UID"
treats an expected first-time-miss as an error; change the log level in the
branch that checks result.Error (the code referencing result.Error and
firebaseUID in models/users.go) from "[ERROR]" to a non-error level such as
"[DEBUG]" or "[INFO]" (e.g., log.Printf("[DEBUG] User not found by Firebase UID
(%s): %v", firebaseUID, result.Error)) so misses during initial user creation
don't produce noisy error logs; keep other error-handling behavior unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d3ac18f5-d016-47c2-8ff8-ddbdb50d1f17
📒 Files selected for processing (11)
API.mdcontrollers/healthcheck.gocontrollers/users.godocker-compose.ymlhustle-backendmain.gomiddleware/auth.gomodels/errors.gomodels/setup.gomodels/users.gotest_auth_flow.md
💤 Files with no reviewable changes (1)
- test_auth_flow.md
API.md
Outdated
| ### GET /healthcheck | ||
| Check if the server is running. | ||
|
|
||
| **Response** | ||
| ```json | ||
| { "message": "Chimes is healthy!" } | ||
| ``` |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Find the actual health check endpoint registration in the codebase.
# Search for health check route definitions
rg -nP --type=go '\bGET\b.*health' -A2 -B2Repository: cuappdev/chimes-backend
Length of output: 468
Update health check endpoint path in documentation from /healthcheck to /health.
The actual implementation registers the endpoint as GET /health (main.go line 52), but the API documentation incorrectly shows /healthcheck. Update line 8 of API.md to match the actual endpoint.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@API.md` around lines 8 - 14, Update the API docs to match the implemented
route: change the documented endpoint from "GET /healthcheck" to "GET /health"
in API.md so it aligns with the registered handler (the actual route registered
as GET /health in main). Ensure the heading and any example request paths
reflect "/health" and keep the existing response body unchanged.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
main.go (1)
79-79: Add pagination before exposing full user lists.Line 79 points to
controllers.FindUsers, andcontrollers/users.goLine 16 currently does an unboundedmodels.DB.Find(&users). This can degrade latency/memory as the table grows. Please addlimit/offset(or cursor pagination) on this path.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@main.go` at line 79, The FindUsers endpoint currently returns an unbounded user list by calling models.DB.Find(&users) in controllers.FindUsers, which can cause latency/memory issues; modify controllers.FindUsers to accept pagination parameters (e.g., query params "limit" and "offset" or a cursor), validate/default them, and replace the unbounded call with a paginated DB query (e.g., models.DB.Limit(limit).Offset(offset).Find(&users) or equivalent cursor logic), and return pagination metadata (total/count/next cursor) alongside the users; ensure you update any request parsing in controllers.FindUsers and use safe defaults and upper bounds for limit to prevent abuse.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@models/users.go`:
- Line 11: The User model currently exposes the Refresh_Token field via JSON;
change the struct field tag Refresh_Token in models.User to `json:"-"` (or
remove any json tag) so it is never serialized, and update controllers/users.go
(where full models.User objects are returned) to return a safe DTO or explicit
response object that omits sensitive fields (or copy only allowed fields from
models.User) to ensure refresh tokens are not sent in API responses.
---
Nitpick comments:
In `@main.go`:
- Line 79: The FindUsers endpoint currently returns an unbounded user list by
calling models.DB.Find(&users) in controllers.FindUsers, which can cause
latency/memory issues; modify controllers.FindUsers to accept pagination
parameters (e.g., query params "limit" and "offset" or a cursor),
validate/default them, and replace the unbounded call with a paginated DB query
(e.g., models.DB.Limit(limit).Offset(offset).Find(&users) or equivalent cursor
logic), and return pagination metadata (total/count/next cursor) alongside the
users; ensure you update any request parsing in controllers.FindUsers and use
safe defaults and upper bounds for limit to prevent abuse.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
controllers/users.go (1)
16-21:⚠️ Potential issue | 🟠 MajorMissing error handling on database query.
models.DB.Find(&users)can fail (e.g., connection issues), but errors are silently ignored. The endpoint will return an empty array with200 OKeven on failure.🐛 Proposed fix to add error handling
func FindUsers(c *gin.Context) { var users []models.User - models.DB.Find(&users) - - c.JSON(http.StatusOK, gin.H{"data": users}) + if err := models.DB.Find(&users).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch users"}) + return + } + + c.JSON(http.StatusOK, gin.H{"data": users}) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@controllers/users.go` around lines 16 - 21, In FindUsers, check the result of models.DB.Find(&users) for an error (use the returned result's Error field) instead of ignoring it; if there is an error, log or return a non-200 response (e.g., c.JSON with http.StatusInternalServerError and an error message) and only return the users with http.StatusOK when no error occurred; update references to models.DB.Find, the users slice, and the c.JSON response accordingly to ensure failures (DB connection/query errors) are surfaced instead of returning an empty 200 response.
🧹 Nitpick comments (1)
controllers/users.go (1)
47-53: Consider using appropriate HTTP status codes.Two suggestions:
- Return
http.StatusCreated(201) for successful resource creation instead ofhttp.StatusOK(200).- The comment mentions rejecting duplicates, but returning 500 for duplicate key violations is misleading. Consider returning 409 Conflict for duplicate
firebase_uid.♻️ Proposed improvement
// Reject duplicate users — firebase_uid has a unique constraint in the DB if err := models.DB.Create(&user).Error; err != nil { + if strings.Contains(err.Error(), "duplicate") || strings.Contains(err.Error(), "UNIQUE constraint") { + c.JSON(http.StatusConflict, gin.H{"error": "user already exists"}) + return + } c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user"}) return } - c.JSON(http.StatusOK, gin.H{"data": user}) + c.JSON(http.StatusCreated, gin.H{"data": user}) }Note: For more robust duplicate detection, consider using GORM's error types or database-specific error codes rather than string matching.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@controllers/users.go` around lines 47 - 53, The handler currently returns 200 on create and 500 for any DB error; change the success response to use http.StatusCreated (201) when models.DB.Create(&user) succeeds, and detect duplicate-key/unique-constraint errors from the Create call (inspect the returned err from models.DB.Create(&user).Error using DB-specific error codes or a string/check helper) to return http.StatusConflict (409) for duplicate firebase_uid, otherwise return the existing 500 for other errors; update the c.JSON calls accordingly (references: models.DB.Create(&user).Error and the subsequent c.JSON(...) lines).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@controllers/users.go`:
- Around line 16-21: In FindUsers, check the result of models.DB.Find(&users)
for an error (use the returned result's Error field) instead of ignoring it; if
there is an error, log or return a non-200 response (e.g., c.JSON with
http.StatusInternalServerError and an error message) and only return the users
with http.StatusOK when no error occurred; update references to models.DB.Find,
the users slice, and the c.JSON response accordingly to ensure failures (DB
connection/query errors) are surfaced instead of returning an empty 200
response.
---
Nitpick comments:
In `@controllers/users.go`:
- Around line 47-53: The handler currently returns 200 on create and 500 for any
DB error; change the success response to use http.StatusCreated (201) when
models.DB.Create(&user) succeeds, and detect duplicate-key/unique-constraint
errors from the Create call (inspect the returned err from
models.DB.Create(&user).Error using DB-specific error codes or a string/check
helper) to return http.StatusConflict (409) for duplicate firebase_uid,
otherwise return the existing 500 for other errors; update the c.JSON calls
accordingly (references: models.DB.Create(&user).Error and the subsequent
c.JSON(...) lines).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b89c3b44-e9da-4f9e-820e-cf84ac74bd11
📒 Files selected for processing (4)
controllers/services.gocontrollers/users.gomodels/services.goservices/listingservice.go
💤 Files with no reviewable changes (3)
- services/listingservice.go
- models/services.go
- controllers/services.go
There was a problem hiding this comment.
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)
models/users.go (1)
34-47:⚠️ Potential issue | 🟠 Major
FindOrCreateUsertreats all query errors as "not found".On Lines 34-47, any DB error enters the create path. Only
ErrRecordNotFoundshould do that; other errors should return immediately. This causes connection failures, query errors, and other DB issues to incorrectly trigger user creation instead of returning an error.🛠️ Proposed fix
import ( + "errors" "log" "time" + + "gorm.io/gorm" ) @@ - if result.Error != nil { - log.Printf("[ERROR] User not found by Firebase UID (%s): %v", firebaseUID, result.Error) - // User doesn't exist, create new one - user = User{ - Firebase_UID: firebaseUID, - Email: email, - FirstName: firstName, - LastName: lastName, - } - - if err := DB.Create(&user).Error; err != nil { - log.Printf("[ERROR] Failed to create user (Firebase UID: %s): %v", firebaseUID, err) - return nil, err - } - } + if result.Error != nil { + if !errors.Is(result.Error, gorm.ErrRecordNotFound) { + log.Printf("[ERROR] Failed to query user (Firebase UID: %s): %v", firebaseUID, result.Error) + return nil, result.Error + } + + user = User{ + Firebase_UID: firebaseUID, + Email: email, + FirstName: firstName, + LastName: lastName, + } + + if err := DB.Create(&user).Error; err != nil { + log.Printf("[ERROR] Failed to create user (Firebase UID: %s): %v", firebaseUID, err) + return nil, err + } + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@models/users.go` around lines 34 - 47, FindOrCreateUser currently treats any DB error as "not found" and proceeds to create a user; change the logic to only enter the create path when the query error is gorm.ErrRecordNotFound (use errors.Is(result.Error, gorm.ErrRecordNotFound)). If result.Error is non-nil and not ErrRecordNotFound, immediately return nil and the error instead of creating a new User; keep the existing DB.Create(&user) and error logging for the actual create path. Make sure to reference result.Error, gorm.ErrRecordNotFound, FindOrCreateUser, and DB.Create when applying the fix.
♻️ Duplicate comments (1)
models/users.go (1)
11-11:⚠️ Potential issue | 🟠 MajorRefresh tokens are still JSON-exposed via
User.Line 11 keeps
json:"refresh_token", so serializingmodels.Usercan leak credential material.🔐 Proposed fix
- Refresh_Token string `json:"refresh_token"` + Refresh_Token string `json:"-"` // never serialize refresh tokens#!/bin/bash # Verify whether refresh token is still JSON-tagged and where User might be serialized. rg -n -C2 --type=go 'Refresh_Token\s+string\s+`json:"refresh_token"`|type User struct|c\.JSON\('Expected result: field remains tagged for JSON output and should be hardened to
json:"-".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@models/users.go` at line 11, The User struct's Refresh_Token field is still annotated as json:"refresh_token" causing models.User serialization to leak credentials; update the Refresh_Token field's struct tag to json:"-" to prevent JSON marshaling, and scan usages of models.User (look for the User struct, Refresh_Token, and call sites like c.JSON or any json.Marshal) to remove or replace any code that relies on that field being present in JSON (or explicitly map safe fields for responses).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@controllers/users.go`:
- Around line 16-17: In FindUsers, the GORM query currently calls
models.DB.Find(&users) with users typed as []models.UserResponse which causes
GORM to target the wrong table (user_responses) and hides failures; change the
query to use models.DB.Model(&models.User{}).Find(&users) to explicitly target
the users table, add proper error handling on the result (check result.Error and
handle non-nil by logging and returning an appropriate non-200 HTTP response),
and ensure the handler returns the expected payload only on success; keep types
as []models.UserResponse for response mapping but query from
Model(&models.User{}).
---
Outside diff comments:
In `@models/users.go`:
- Around line 34-47: FindOrCreateUser currently treats any DB error as "not
found" and proceeds to create a user; change the logic to only enter the create
path when the query error is gorm.ErrRecordNotFound (use errors.Is(result.Error,
gorm.ErrRecordNotFound)). If result.Error is non-nil and not ErrRecordNotFound,
immediately return nil and the error instead of creating a new User; keep the
existing DB.Create(&user) and error logging for the actual create path. Make
sure to reference result.Error, gorm.ErrRecordNotFound, FindOrCreateUser, and
DB.Create when applying the fix.
---
Duplicate comments:
In `@models/users.go`:
- Line 11: The User struct's Refresh_Token field is still annotated as
json:"refresh_token" causing models.User serialization to leak credentials;
update the Refresh_Token field's struct tag to json:"-" to prevent JSON
marshaling, and scan usages of models.User (look for the User struct,
Refresh_Token, and call sites like c.JSON or any json.Marshal) to remove or
replace any code that relies on that field being present in JSON (or explicitly
map safe fields for responses).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e6a5cbe4-42ea-4754-9b84-88e5a598822b
📒 Files selected for processing (4)
API.mdcontrollers/users.gomain.gomodels/users.go
✅ Files skipped from review due to trivial changes (1)
- API.md
🚧 Files skipped from review as they are similar to previous changes (1)
- main.go
| var users []models.UserResponse | ||
| models.DB.Find(&users) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify DTO-based query + absence of explicit model/table binding.
rg -n -C2 --type=go '\bfunc FindUsers\b|DB\.Find\(&users\)|Model\(&models\.User\{\}\)|Select\('
rg -n -C2 --type=go 'type UserResponse struct|TableName\('Repository: cuappdev/chimes-backend
Length of output: 612
🏁 Script executed:
cat -n models/users.goRepository: cuappdev/chimes-backend
Length of output: 2074
🏁 Script executed:
rg -n "type User struct|TableName\(" models/users.go -A 5Repository: cuappdev/chimes-backend
Length of output: 358
🏁 Script executed:
rg -n "\.Model\(|\.Table\(" controllers/users.goRepository: cuappdev/chimes-backend
Length of output: 49
🏁 Script executed:
rg -n "DB\s*=" --type=go | head -20Repository: cuappdev/chimes-backend
Length of output: 100
🏁 Script executed:
fd -e go -x rg -l "gorm\|database" {} + | head -10Repository: cuappdev/chimes-backend
Length of output: 570
🏁 Script executed:
cat -n main.go 2>/dev/null || cat -n cmd/main.go 2>/dev/null || find . -name "main.go" -type f -exec cat -n {} \;Repository: cuappdev/chimes-backend
Length of output: 2981
🏁 Script executed:
cat -n models/setup.goRepository: cuappdev/chimes-backend
Length of output: 1743
🏁 Script executed:
rg -n "naming\|TableName\|NamingStrategy" --type=goRepository: cuappdev/chimes-backend
Length of output: 49
FindUsers queries with the wrong table due to DTO type mismatch—fix by using .Model(&models.User{}) and add error handling.
On Line 17, models.DB.Find(&users) uses []models.UserResponse as the destination. GORM's default naming convention (SnakeCase) infers the table name from the struct type, so this targets user_responses instead of users. Additionally, UserResponse is never migrated (only User and FCMToken are in AutoMigrate), so the query will fail silently. The missing error handler also means failures return HTTP 200 with empty data.
Use .Model(&models.User{}) to explicitly target the correct table and add error handling:
Proposed fix
func FindUsers(c *gin.Context) {
var users []models.UserResponse
- models.DB.Find(&users)
+ result := models.DB.Model(&models.User{}).
+ Select("id, first_name, last_name, email").
+ Find(&users)
+ if result.Error != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch users"})
+ return
+ }
c.JSON(http.StatusOK, gin.H{"data": users})
}📝 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.
| var users []models.UserResponse | |
| models.DB.Find(&users) | |
| func FindUsers(c *gin.Context) { | |
| var users []models.UserResponse | |
| result := models.DB.Model(&models.User{}). | |
| Select("id, first_name, last_name, email"). | |
| Find(&users) | |
| if result.Error != nil { | |
| c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch users"}) | |
| return | |
| } | |
| c.JSON(http.StatusOK, gin.H{"data": users}) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@controllers/users.go` around lines 16 - 17, In FindUsers, the GORM query
currently calls models.DB.Find(&users) with users typed as []models.UserResponse
which causes GORM to target the wrong table (user_responses) and hides failures;
change the query to use models.DB.Model(&models.User{}).Find(&users) to
explicitly target the users table, add proper error handling on the result
(check result.Error and handle non-nil by logging and returning an appropriate
non-200 HTTP response), and ensure the handler returns the expected payload only
on success; keep types as []models.UserResponse for response mapping but query
from Model(&models.User{}).
Overview
Added admin authorization and an isAdmin field to the Users model. Also removed legacy GitHub-related routes and models, including services listing functionality.
Changes Made
Test Coverage
Tested locally.
Next Steps
Summary by CodeRabbit
New Features
Documentation
Removed Features
Chores
Bug Fixes