Skip to content

perf: optimize firestore reads and restore public routes#2601

Open
iamitprakash wants to merge 2 commits into
developfrom
fix-firstore-bill
Open

perf: optimize firestore reads and restore public routes#2601
iamitprakash wants to merge 2 commits into
developfrom
fix-firstore-bill

Conversation

@iamitprakash

Copy link
Copy Markdown
Member

No description provided.

@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: edd9c860-a043-4eab-b3ae-7394859cfe5a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Authentication is removed from GET /users/status and GET /users/search, making them public. Pagination (page/size or skip/limit) is added through validators, Firestore/in-memory model logic, the data access layer, and controllers. User enrichment in getAllUserStatus is optimized from per-item to bulk fetch.

Public Paginated User Status & Search

Layer / File(s) Summary
Remove authentication from routes
routes/userStatus.js, routes/users.js
GET /users/status and GET /users/search middleware chains drop authenticate and authorizeRoles([SUPERUSER]), leaving only query validation before the controller.
Pagination in models
models/userStatus.js, models/users.js
getAllUserStatus gains incremental Firestore query building with optional state filter and offset/limit; getUsersBasedOnFilter gains skip/limit parameters with in-memory slicing, archived-user exclusion, and totalCount on all return paths.
Service and controller wiring
services/dataAccessLayer.js, controllers/users.js, middlewares/validators/userStatus.js, controllers/userStatus.js
retreiveFilteredUsers passes skip/limit through; filterUsers uses pageNumber * limitNumber offset and reads totalCount from results; validator adds page/size fields; getAllUserStatus switches to bulk user retrieval and filters archived users.
Integration test updates
test/integration/userStatus.test.js, test/integration/usersFilter.test.js
Auth cookie setup and unauthorized-access assertions are removed from tests for the now-public endpoints.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • RealDevSquad/website-backend#2599: Directly modifies the same routes/userStatus.js and routes/users.js access control (authenticate/authorizeRoles([SUPERUSER])) for the same endpoints.

Suggested reviewers

  • AnujChhikara
  • MayankBansal12
  • prakashchoudhary07

Poem

🐇 Hop, hop, no lock on the gate!
The status and search now run free,
Pages slice through the data with glee,
Bulk fetches replace the old wait—
One query for all, not one per ID! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so there is no meaningful summary to evaluate. Add a brief description of the main code changes and intent, or provide the missing PR description.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main changes: Firestore read optimization and removal of auth from user routes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-firstore-bill

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (3)
models/users.js (1)

675-692: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Slice after the archived/onboarding filters.

finalItems.slice(skip, skip + limit) runs before !doc.roles?.archived and before getUsersWithOnboardingStateInRange(...). That lets archived or out-of-range users consume page slots, and totalCount = finalItems.length no longer matches the result set this endpoint actually returns. Compute the filtered result set (or at least its pre-pagination total) before slicing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@models/users.js` around lines 675 - 692, The pagination in the users query is
applied too early in the main flow around paginatedFinalItems, userDocs
filtering, and getUsersWithOnboardingStateInRange, so archived or out-of-range
users can still consume page slots. Move skip/limit handling to after the
archived filter and onboarding-state filtering, and make sure totalCount
reflects the full filtered result set rather than finalItems.length.
controllers/users.js (1)

975-990: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Apply page/size to both search branches.

This controller only forwards skip/limit when dev === "true". Requests like /users/search?role=member&page=1&size=20 still go through retreiveFilteredUsers(req.query) with no pagination, even though the lower layers now support it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controllers/users.js` around lines 975 - 990, Update the users search
controller so pagination is applied in both branches, not only when dev ===
"true". In the users search handler that calls dataAccess.retreiveFilteredUsers,
parse page and size once and pass the computed skip and limit into every
retreiveFilteredUsers call, including the non-dev path, so requests like
/users/search?role=member&page=1&size=20 are paginated consistently.
controllers/userStatus.js (1)

80-104: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Paginating raw statuses breaks visible-page semantics.

userStatusModel.getAllUserStatus(req.query) now slices status docs before this controller removes archived users. Archived rows can consume page slots, so a size=N response may return fewer than N visible users even when more valid rows exist later. totalUserStatus also becomes the current page length, not the total matching count.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controllers/userStatus.js` around lines 80 - 104, The pagination in
userStatusController.getAllUserStatus is applied before filtering archived
users, so page slots can be wasted and totalUserStatus only reflects the visible
page count. Move the archived-user filtering into the query or data-access
layer, or rework getAllUserStatus/userStatusModel.getAllUserStatus so pagination
is based on visible, non-archived statuses; also return an accurate total
matching count separate from the page length.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@middlewares/validators/userStatus.js`:
- Around line 88-89: The pagination schema in userStatus validation currently
allows page and size independently, but models/userStatus.js only applies
pagination when both are present. Update the Joi rules in the validator so page
and size are required together (or both omitted), using the existing schema area
around the page/size definitions to enforce the paired constraint and prevent
single-parameter requests from passing.

---

Outside diff comments:
In `@controllers/users.js`:
- Around line 975-990: Update the users search controller so pagination is
applied in both branches, not only when dev === "true". In the users search
handler that calls dataAccess.retreiveFilteredUsers, parse page and size once
and pass the computed skip and limit into every retreiveFilteredUsers call,
including the non-dev path, so requests like
/users/search?role=member&page=1&size=20 are paginated consistently.

In `@controllers/userStatus.js`:
- Around line 80-104: The pagination in userStatusController.getAllUserStatus is
applied before filtering archived users, so page slots can be wasted and
totalUserStatus only reflects the visible page count. Move the archived-user
filtering into the query or data-access layer, or rework
getAllUserStatus/userStatusModel.getAllUserStatus so pagination is based on
visible, non-archived statuses; also return an accurate total matching count
separate from the page length.

In `@models/users.js`:
- Around line 675-692: The pagination in the users query is applied too early in
the main flow around paginatedFinalItems, userDocs filtering, and
getUsersWithOnboardingStateInRange, so archived or out-of-range users can still
consume page slots. Move skip/limit handling to after the archived filter and
onboarding-state filtering, and make sure totalCount reflects the full filtered
result set rather than finalItems.length.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 36d18818-afae-467d-aee4-51970349d554

📥 Commits

Reviewing files that changed from the base of the PR and between fa0d483 and a6d21db.

📒 Files selected for processing (10)
  • controllers/userStatus.js
  • controllers/users.js
  • middlewares/validators/userStatus.js
  • models/userStatus.js
  • models/users.js
  • routes/userStatus.js
  • routes/users.js
  • services/dataAccessLayer.js
  • test/integration/userStatus.test.js
  • test/integration/usersFilter.test.js
💤 Files with no reviewable changes (1)
  • test/integration/usersFilter.test.js

Comment thread middlewares/validators/userStatus.js Outdated
Comment on lines +88 to +89
page: Joi.number().integer().min(0).error(new Error(`page must be a non-negative integer.`)),
size: Joi.number().integer().min(1).max(1000).error(new Error(`size must be a number between 1 and 1000.`)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Require page and size together.

models/userStatus.js only paginates when both values are present, but this schema accepts either one alone. Requests like ?page=1 or ?size=50 pass validation and then silently fall back to the unpaginated query.

💡 Suggested change
   const schema = Joi.object()
     .keys({
       aggregate: Joi.boolean().valid(true).error(new Error(`Invalid boolean value passed for aggregate.`)),
       state: Joi.string()
         .trim()
         .valid(userState.IDLE, userState.ACTIVE, userState.OOO, userState.ONBOARDING)
         .error(new Error(`Invalid State. State must be either IDLE, ACTIVE, OOO, or ONBOARDING`)),
       page: Joi.number().integer().min(0).error(new Error(`page must be a non-negative integer.`)),
       size: Joi.number().integer().min(1).max(1000).error(new Error(`size must be a number between 1 and 1000.`)),
     })
+    .and("page", "size")
     .messages({
📝 Committable suggestion

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

Suggested change
page: Joi.number().integer().min(0).error(new Error(`page must be a non-negative integer.`)),
size: Joi.number().integer().min(1).max(1000).error(new Error(`size must be a number between 1 and 1000.`)),
page: Joi.number().integer().min(0).error(new Error(`page must be a non-negative integer.`)),
size: Joi.number().integer().min(1).max(1000).error(new Error(`size must be a number between 1 and 1000.`)),
})
.and("page", "size")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@middlewares/validators/userStatus.js` around lines 88 - 89, The pagination
schema in userStatus validation currently allows page and size independently,
but models/userStatus.js only applies pagination when both are present. Update
the Joi rules in the validator so page and size are required together (or both
omitted), using the existing schema area around the page/size definitions to
enforce the paired constraint and prevent single-parameter requests from
passing.

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