Skip to content

Conversation

Baalmart
Copy link
Contributor

@Baalmart Baalmart commented Sep 16, 2025

🚀 Pull Request

📋 Description

What does this PR do?
This PR refactors the list static method in User.model.js and the update function in user.util.js. The list method's complex aggregation pipeline is replaced with a more robust manual population pattern. The update function is streamlined to remove environment-specific logic for sending emails, delegating this responsibility to the mailer utility.

Why is this change needed?
The previous aggregation in the list method was complex and could be brittle across different deployment environments, leading to potential performance issues or unexpected failures. The update function's logic for sending emails was inconsistent across environments. These changes improve performance, reliability, and maintainability, ensuring the API behavior remains consistent while making the code more explicit and stable.


🔗 Related Issues

  • Closes #
  • Fixes #
  • Related to #

🔄 Type of Change

  • 🔧 Enhancement/improvement
  • ♻️ Refactor

🏗️ Affected Services

Microservices changed: auth-service


🧪 Testing

  • Manual testing completed
  • All existing tests pass

Test summary:
Manual testing was performed on the /users (list) and user profile update endpoints to ensure the API responses remain identical to the previous implementation, guaranteeing backward compatibility with any consuming frontend applications. Verified that user data is correctly populated and profile updates trigger the expected side effects.


💥 Breaking Changes

  • No breaking changes

📝 Additional Notes

The refactoring of the list method away from a large aggregation pipeline to a "manual population" pattern is a deliberate choice to increase code stability and avoid environment-specific issues with complex Mongoose/MongoDB features. This makes the data retrieval process more explicit and resilient.


✅ Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Documentation updated (if needed)
  • Ready for review

Summary by CodeRabbit

  • Performance

    • Faster, more scalable user list retrieval with reduced latency.
  • Refactor

    • Streamlined user list response with a consistent envelope; legacy/internal fields removed.
    • Group and network roles presented in a clearer, structured format.
  • New Features

    • Non-blocking password reset initiation and new initiatePasswordReset API.
    • Transition-based token expiry behavior for logins.
  • Bug Fixes

    • Profile updates handle interests more robustly; email notifications no longer block updates and have improved logging.
  • Style

    • Consistent timestamp formatting in user list responses.

Copy link
Contributor

coderabbitai bot commented Sep 16, 2025

📝 Walkthrough

Walkthrough

Rewrote User.list from aggregation to find().lean() plus parallel lookups and manual in-memory population; changed error propagation to thrown HttpError. Updated user utilities to always invoke mailer.update (awaited or fire-and-forget), sanitize interests, make password-reset emails async, add initiatePasswordReset and generateResetToken, and add transition-based token expiry in login.

Changes

Cohort / File(s) Summary
User listing refactor
src/auth-service/models/User.js
Replaced aggregation pipeline with find().lean() + collection of related IDs, parallel queries, maps for permissions/roles/groups/networks, manual population of nested relations, removal of legacy group_roles/network_roles, omission of password, derived timestamps, and changed error handling to thrown HttpError. Returns standardized envelope { success, message, data, totalCount, status }.
User utilities: mailer, password, tokens, interests
src/auth-service/utils/user.util.js
Always call mailer.update (awaited in one path, fire-and-forget in another with logging); sanitize interests (string/array → trimmed array or removed); make forgotten-password and password-reset email sends asynchronous (fire-and-forget) while returning success immediately; add transition-based token expiry logic in loginWithEnhancedTokens; add public methods initiatePasswordReset({ email, token, tenant }) and generateResetToken(next); enhanced mailer error logging and updated payloads.
Tenant-aware client model retrieval
src/auth-service/models/Client.js
Use getModelByTenant(dbTenant, "client", ClientSchema) directly instead of mongoose.model("clients") fallback; remove fallback in catch and rethrow original error.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor C as Caller
  participant S as UserService.list
  participant DBU as Users DB
  participant DBP as Permissions DB
  participant DBR as Roles DB
  participant DBG as Groups DB
  participant DBN as Networks DB
  participant DBC as Clients DB

  C->>S: list(request)
  rect rgba(230,240,255,0.5)
    S->>DBU: find().lean() base users
    S->>S: collect related IDs (perm/role/group/network/client)
    par Parallel lookups
      S->>DBP: find by permission IDs
      S->>DBR: find by role IDs
      S->>DBG: find by group IDs
      S->>DBN: find by network IDs
      S->>DBC: find by client IDs
    end
    S->>S: build maps, populate users, remove legacy fields, omit password
  end
  S-->>C: { success, message, data, totalCount, status }
  note over S: Errors thrown as HttpError
Loading
sequenceDiagram
  autonumber
  actor U as Updater
  participant M as Mailer
  participant DB as User DB

  U->>DB: apply user modifications
  alt Awaited mailer path
    U->>M: mailer.update(updatedUserDetails, ids)
    M-->>U: success / failure / no response
    alt success
      U-->>Caller: return modification result
    else failure or no response
      U-->>Caller: throw 500 HttpError
    end
  else Fire-and-forget path
    U-)M: mailer.update(...).catch(log)
    U-->>Caller: return modification result
  end
Loading
sequenceDiagram
  autonumber
  actor C as Caller
  participant U as UserUtil
  participant Auth as AuthService
  participant M as Mailer

  C->>U: initiatePasswordReset({email})
  U->>Auth: generateResetToken(next)
  Auth-->>U: token
  U-)M: send reset email (async).catch(log)
  U-->>C: success (immediate)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

Aggregates shed weight, lean queries stride,
Maps stitch relations that once lived inside.
Mailers whisper later, or answer now,
Tokens soften transitions — rules avow.
Small tidy edits, a steadier prow.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Refactor: Optimize user list and update functions for performance" is a concise and accurate summary of the main change, focusing on refactoring the user list and update flows for performance; it directly reflects the changes in the diff and is clear for reviewers scanning history. It avoids extraneous details and correctly emphasizes the primary intent of the changeset.
Description Check ✅ Passed The PR description follows the repository template: it includes a clear "What" and "Why", marks change types, lists the affected service (auth-service), summarizes testing performed, states breaking-change status, and provides checklist and additional notes, so it is largely complete and actionable for reviewers. Non-critical omissions are that Related Issues contains no linked issue numbers and unit tests were not added, but these do not make the description insufficient given the claimed manual testing and passing existing tests.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch perf-user-apis

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

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

codecov bot commented Sep 16, 2025

Codecov Report

❌ Patch coverage is 1.14943% with 86 lines in your changes missing coverage. Please review.
✅ Project coverage is 11.99%. Comparing base (c534fe3) to head (8e34a73).
⚠️ Report is 16 commits behind head on staging.

Files with missing lines Patch % Lines
src/auth-service/models/User.js 1.17% 84 Missing ⚠️
src/auth-service/models/Client.js 0.00% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           staging    #5268      +/-   ##
===========================================
- Coverage    11.99%   11.99%   -0.01%     
===========================================
  Files          198      199       +1     
  Lines        25634    25813     +179     
  Branches       721      756      +35     
===========================================
+ Hits          3076     3095      +19     
- Misses       22535    22695     +160     
  Partials        23       23              
Files with missing lines Coverage Δ
src/auth-service/models/Client.js 17.47% <0.00%> (ø)
src/auth-service/models/User.js 11.33% <1.17%> (-2.31%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

Auth-service changes in this PR available for preview here

Copy link
Contributor

@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 (2)
src/auth-service/utils/user.util.js (2)

762-897: Duplicate ‘update’ definitions — later one overrides the earlier (logic lost).

Only the second update (Lines 4029–4135) is exported; the first (Lines 762–897) is dead code. That silently drops the “interests” sanitization and the awaited mailer path.

  • Keep a single update and merge the missing pieces:
    • Port the “interests” sanitization into the surviving function.
    • Gate “await vs fire-and-forget” on a config flag instead of duplicating functions.

Suggested consolidation:

@@ 4034,4051 @@
-      const sanitizedUpdate = { ...body };
+      const sanitizedUpdate = { ...body };
+
+      // Interests sanitization (ported from the earlier update)
+      if ("interests" in sanitizedUpdate) {
+        const v = sanitizedUpdate.interests;
+        if (typeof v === "string") {
+          sanitizedUpdate.interests = v.trim() ? [v.trim()] : [];
+        } else if (Array.isArray(v)) {
+          sanitizedUpdate.interests = v.map((i) => (i ? String(i).trim() : "")).filter(Boolean);
+        } else {
+          delete sanitizedUpdate.interests;
+        }
+      }
@@ 4096,4115 @@
-        // Asynchronously send email without blocking the response.
-        // The mailer utility should handle environment-specific logic (e.g., using a mock mailer in dev).
-        mailer
-          .update(
-            {
-              email,
-              firstName,
-              lastName,
-              updatedUserDetails: emailUpdatePayload,
-            },
-            next
-          )
-          .catch((error) => {
-            logger.error(
-              `Failed to send profile update email to ${email}: ${error.message}`
-            );
-          });
+        // Configurable: await in non-prod, fire-and-forget in prod
+        const shouldAwaitMailer =
+          (constants && constants.ENVIRONMENT !== "production") ||
+          process.env.NODE_ENV !== "production";
+        const send = () =>
+          mailer.update(
+            { email, firstName, lastName, updatedUserDetails: emailUpdatePayload },
+            next
+          );
+        if (shouldAwaitMailer) {
+          try {
+            const mailerRes = await send();
+            if (mailerRes && mailerRes.success === false) {
+              logger.error(`Profile update email failed for ${email}: ${mailerRes.message}`);
+            }
+          } catch (e) {
+            logger.error(`Profile update email threw for ${email}: ${e.message}`);
+          }
+        } else {
+          send().catch((e) =>
+            logger.error(`Profile update email failed for ${email}: ${e.message}`)
+          );
+        }

Also remove the earlier duplicate update to avoid future drift.

Also applies to: 4029-4135


710-721: Action required: refactor removed legacy fields — update callers or restore backward compatibility

UserModel.list now returns populated "groups/networks/permissions" and deletes "group_roles"/"network_roles" (see src/auth-service/models/User.js:1007-1008). Multiple consumers still read the legacy fields and will break:

  • src/auth-service/services/rbac.service.js (uses group_roles/network_roles in many places — e.g. ~68-76, 136-159, 245-309, 512-531).
  • src/device-registry/utils/organization.util.js (user.group_roles at 161,192,289-297).
  • src/auth-service/routes/v2/users.routes.js and v3/users.routes.js (manual populate/mapping of network_roles — see ~236-266, 291-304).
  • src/auth-service/utils/group.util.js (aggregation formatting of group_roles.createdAt via $dateToString "%Y-%m-%d" — ~3459-3462).
  • src/auth-service/utils/role-permissions.util.js (summaries and lookups expect group_roles/network_roles).
  • Unit tests and migrations under src/auth-service/utils/test/** and src/auth-service/migrations/** reference legacy fields.

Either (A) reintroduce group_roles/network_roles in User.list as a backward-compatible shim, or (B) update all listed consumers (and tests/migrations) to use the new populated fields ("groups", "networks", "permissions").

🧹 Nitpick comments (6)
src/auth-service/models/User.js (5)

804-810: Don’t fetch secrets; project out password/reset fields up front.

Instead of deleting later, exclude sensitive fields in the base query to reduce payload and risk.

-      const users = await this.find(filter)
+      const users = await this.find(filter)
+        .select("-password -resetPasswordToken -resetPasswordExpires")
         .sort({ createdAt: -1 })
         .skip(skip ? parseInt(skip) : 0)
         .limit(limit ? parseInt(limit) : parseInt(constants.DEFAULT_LIMIT))
         .lean(); // Use lean for performance

858-869: Redundant re-import of getModelByTenant.

It’s already imported at the top (Line 13). Drop this inner require to avoid shadowing and confusion.

-      const { getModelByTenant } = require("@config/database");
       const GroupModel = require("@models/Group");
       const NetworkModel = require("@models/Network");
       const RoleModel = require("@models/Role");
       const ClientSchema = new mongoose.Schema({}, { strict: false });
       const ClientModel = getModelByTenant(
         this.db.name,
         "client",
         ClientSchema
       );

869-901: Large related queries lack projections; trim fields to control response size.

Consider adding .select() to clients, my_networks, and my_groups (and possibly roles) to avoid returning heavy/unused fields.


953-1030: Membership entries are dropped if role is missing.

The current mapping returns null when either group/network or role is missing, potentially hiding memberships with a null role. Prefer keeping the membership and setting role to null for visibility.

-            if (!group || !role) return null;
+            if (!group) return null; // require group
             return {
               _id: group._id,
               ...
-              role: {
-                _id: role._id,
-                role_name: role.role_name,
-                role_permissions: role.role_permissions,
-              },
+              role: role
+                ? {
+                    _id: role._id,
+                    role_name: role.role_name,
+                    role_permissions: role.role_permissions,
+                  }
+                : null,
               userType: gr.userType || "user",
             };

Apply the same pattern for networks.


1011-1026: createdAt formatting: prefer ISO/UTC for consistency (or verify compatibility).

Manual local-time formatting may diverge from prior API expectations/timezone. If backward compatibility doesn’t require this exact format, return ISO (UTC) for both createdAt and updatedAt.

Would switching to createdAt = ts.toISOString() break any known consumers?

src/auth-service/utils/user.util.js (1)

4096-4115: Non-blocking mailer path: solid pattern, but add minimal backoff.

Add a tiny retry/backoff (e.g., 1 retry with jitter) to improve resilience on transient SMTP/API hiccups.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d18e700 and 36f3ac4.

📒 Files selected for processing (2)
  • src/auth-service/models/User.js (2 hunks)
  • src/auth-service/utils/user.util.js (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/auth-service/utils/user.util.js (2)
src/auth-service/utils/request.util.js (9)
  • user (22-25)
  • responseFromSendEmail (81-90)
  • responseFromSendEmail (295-309)
  • responseFromSendEmail (647-656)
  • responseFromSendEmail (759-768)
  • responseFromSendEmail (859-867)
  • responseFromSendEmail (894-897)
  • logger (12-14)
  • httpStatus (7-7)
src/auth-service/utils/common/mailer.util.js (8)
  • mailer (573-1519)
  • logger (20-20)
  • httpStatus (7-7)
  • error (895-898)
  • error (920-923)
  • error (941-944)
  • error (1291-1298)
  • error (1318-1325)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-push-deploy-auth-service
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (2)
src/auth-service/utils/user.util.js (1)

221-221: Good fix: add cache TTL.

Setting 10‑minute expiration prevents stale/infinite cache entries.

src/auth-service/models/User.js (1)

1051-1057: Behavior change — list now throws; verified callers handle it

All occurrences of UserModel(...).list are awaited inside try/catch blocks that call next(...) on error (checked: src/auth-service/utils/user.util.js — lines ~624, 711, 739, 1148, 4282; src/auth-service/utils/network.util.js — lines ~1267, 1314). Thrown errors will be routed to the existing catch → next(...) paths — no change required.

Copy link
Contributor

Auth-service changes in this PR available for preview here

Copy link
Contributor

@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 (4)
src/auth-service/utils/user.util.js (4)

849-881: Duplicate update() + awaited mailer can turn a successful DB update into a 500

  • This file defines createUserModule.update twice; the later definition (Line 4017+) overrides this one. Keep a single implementation to avoid dead code and confusion.
  • Awaiting mailer.update here couples DB success to email delivery and can regress UX into a 500 path.

Action:

  • Remove the earlier duplicate update (Lines 762–897) and keep the later fire‑and‑forget version.
  • If you must keep an awaited path, never fail the request on email failure; surface as a non‑blocking warning.

4104-4122: Background email in update(): remove next to avoid late middleware execution

Fire‑and‑forget is good. However, passing next into a background promise can trigger middleware after the HTTP response has been sent.

Apply:

-        mailer
-          .update(
-            {
-              email,
-              firstName,
-              lastName,
-              updatedUserDetails: emailUpdatePayload,
-            },
-            next
-          )
+        void mailer
+          .update({
+            email,
+            firstName,
+            lastName,
+            updatedUserDetails: emailUpdatePayload,
+          })
           .catch((error) => {
             logger.error(
               `Failed to send profile update email to ${email}: ${error.message}`
             );
           });

4208-4231: Same here: don’t pass next into async mailer in resetPassword()

Avoid invoking route middleware from a detached promise.

-        mailer
-          .updateForgottenPassword(
-            {
-              email,
-              firstName,
-              lastName,
-            },
-            next
-          )
+        void mailer
+          .updateForgottenPassword({
+            email,
+            firstName,
+            lastName,
+          })
           .catch((error) => {
             logger.error(
               `Failed to send password reset confirmation email to ${email}: ${error.message}`
             );
           });

3890-3911: Don’t pass next into fire‑and‑forget mailer calls

Passing next to an async/background task risks “headers already sent” or double error-handling after the response returns. Drop next and just log.

Apply:

-        mailer
-          .updateForgottenPassword(
-            {
-              email,
-              firstName,
-              lastName,
-            },
-            next
-          )
+        void mailer
+          .updateForgottenPassword({
+            email,
+            firstName,
+            lastName,
+          })
           .catch((error) => {
             logger.error(
               `Failed to send password reset confirmation email to ${email}: ${error.message}`
             );
           });
🧹 Nitpick comments (1)
src/auth-service/utils/user.util.js (1)

4026-4043: Interests sanitization: dedupe entries

Nice normalization. Consider de‑duplicating to avoid repeated values.

-          sanitizedUpdate.interests = interestsValue
-            .map((item) => (item ? String(item).trim() : ""))
-            .filter(Boolean);
+          sanitizedUpdate.interests = Array.from(
+            new Set(
+              interestsValue
+                .map((item) => (item ? String(item).trim() : ""))
+                .filter(Boolean)
+            )
+          );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 36f3ac4 and 2d882b5.

📒 Files selected for processing (1)
  • src/auth-service/utils/user.util.js (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/auth-service/utils/user.util.js (2)
src/auth-service/utils/request.util.js (9)
  • user (22-25)
  • responseFromSendEmail (81-90)
  • responseFromSendEmail (295-309)
  • responseFromSendEmail (647-656)
  • responseFromSendEmail (759-768)
  • responseFromSendEmail (859-867)
  • responseFromSendEmail (894-897)
  • logger (12-14)
  • httpStatus (7-7)
src/auth-service/utils/common/mailer.util.js (8)
  • mailer (573-1519)
  • logger (20-20)
  • httpStatus (7-7)
  • error (895-898)
  • error (920-923)
  • error (941-944)
  • error (1291-1298)
  • error (1318-1325)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-push-deploy-auth-service
🔇 Additional comments (1)
src/auth-service/utils/user.util.js (1)

4256-4274: LGTM: generateResetToken helper

Small, focused, and returns a consistent shape; good reuse across flows.

Copy link
Contributor

Auth-service changes in this PR available for preview here

Copy link
Contributor

@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 (3)
src/auth-service/models/Client.js (3)

4-4: Use Schema.Types.ObjectId; mongoose.ObjectId is non-standard.

This can cause type resolution issues across Mongoose versions.

Apply:

-const ObjectId = mongoose.ObjectId;
+const ObjectId = Schema.Types.ObjectId;

243-252: Do not expose client_secret in API serialization — make it non-selectable and remove it from toJSON

toJSON currently returns client_secret (src/auth-service/models/Client.js) and must be removed; make the schema field non-selectable and opt-in where required.

Apply:

@@
-    client_secret: { type: String, trim: true },
+    client_secret: { type: String, trim: true, select: false },
@@
   toJSON() {
     return {
       _id: this._id,
-      client_secret: this.client_secret,
       redirect_uri: this.redirect_uri,
       name: this.name,
       isActive: this.isActive,
       description: this.description,
       rateLimit: this.rateLimit,
       ip_address: this.ip_address,
       ip_addresses: this.ip_addresses,
     };
   },

Action items (brief):

  • Update call sites that intentionally return the secret to explicitly opt-in with .select('+client_secret') and gate access with proper authorization: notably src/auth-service/utils/client.util.js (create/regenerate/update flows).
  • Review and adjust DB projection configs that reference client_secret (src/auth-service/config/global/db-projections.js and blog-content-manager equivalents) so they don’t re-introduce accidental exposure.
  • Update tests and any code that currently assumes the secret is in default serialization (src/auth-service/models/test/ut_client.model.js, src/auth-service/routes/v2/test/ut_clients.routes.js, and parallel blog-content-manager tests).
  • Re-run a repository-wide search for "client_secret" and fix remaining callers and projections to opt in or stop expecting the secret.

256-264: Fix tenant-model registration to avoid OverwriteModelError; add tenant-context logging.

getModelByTenant currently registers models unconditionally on tenant connections — calling db.model(modelName, schema) in getQueryTenantDB/getCommandTenantDB will throw Mongoose's OverwriteModelError on repeated calls. Fix model registration and add contextual logging.

  • Critical (must fix): src/auth-service/config/database.js — change getQueryTenantDB/getCommandTenantDB to avoid re-defining a compiled model. Example options (pick one):
    • Check and return existing model: if (db.models && db.models[modelName]) return db.model(modelName); db.model(modelName, schema); return db.model(modelName);
    • Or wrap registration in try/catch and return the existing model when OverwriteModelError is thrown.
  • Minor (apply): src/auth-service/models/Client.js (lines ~256-264) — add tenant-context logging in the catch before rethrowing; the original diff below is still relevant.

Apply this diff to Client.js:

 const ClientModel = (tenant) => {
   const defaultTenant = constants.DEFAULT_TENANT || "airqo";
   const dbTenant = isEmpty(tenant) ? defaultTenant : tenant;
   try {
-    return getModelByTenant(dbTenant, "client", ClientSchema);
+    return getModelByTenant(dbTenant, "client", ClientSchema);
   } catch (error) {
-    throw error;
+    logger.error(`getModelByTenant failed for tenant=${dbTenant}`, error);
+    throw error;
   }
 };

Files to update: src/auth-service/config/database.js (getQueryTenantDB, getCommandTenantDB), src/auth-service/models/Client.js (lines 256-264).

🧹 Nitpick comments (3)
src/auth-service/models/Client.js (3)

219-224: Prefer findOneAndDelete and explicit select over projection with findOneAndRemove.

findOneAndRemove is legacy and projection semantics can be surprising, especially with select: false fields. Use findOneAndDelete() and an explicit .select().

Apply:

-      const options = {
-        projection: { _id: 1, client_secret: 1 }, // Preserve client_secret projection
-      };
-
-      const removedClient = await this.findOneAndRemove(filter, options).exec();
+      const removedClient = await this.findOneAndDelete(filter)
+        .select('+client_secret _id')
+        .exec();

174-176: Avoid relying on Mongoose’s internal _doc; use toObject().

This is more stable across versions.

Apply:

-        return createSuccessResponse("update", updatedClient._doc, "client");
+        return createSuccessResponse("update", updatedClient.toObject(), "client");

48-50: Remove no-op pre("update") hook.

Dead hook adds noise and can confuse maintainers.

Apply:

-ClientSchema.pre("update", function (next) {
-  return next();
-});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2d882b5 and 8e34a73.

📒 Files selected for processing (2)
  • src/auth-service/models/Client.js (1 hunks)
  • src/auth-service/models/User.js (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/auth-service/models/User.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-push-deploy-auth-service

@Baalmart Baalmart marked this pull request as draft September 16, 2025 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant