Skip to content

feat: add Queue Management APIs#8

Open
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1780594831-add-queue-apis
Open

feat: add Queue Management APIs#8
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1780594831-add-queue-apis

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds three queue management endpoints under /api/queues/:departmentId/:

Method Path Auth Description
GET /current any authenticated user Returns the ticket currently being served
POST /next admin only Moves the oldest waiting ticket to serving
GET /waiting any authenticated user Returns all waiting tickets (FIFO order)

Key additions:

  • queue.controller.js — three handlers with department existence validation
  • adminOnly middleware — checks req.user.role === 'admin', returns 403 otherwise
  • queue.routes.js — wires authenticate globally + adminOnly on the next endpoint
  • 24 new tests (controller unit + route integration + middleware), 123 total, 100% coverage

Link to Devin session: https://app.devin.ai/sessions/b08d56b5cecf4545a99acb077c5d872d
Requested by: @0xpritam


Open in Devin Review

Summary by CodeRabbit

  • New Features

    • Queue management endpoints to get current serving, advance to the next ticket (admin-only), and list waiting tickets; routes are now available under the API.
  • Access Control

    • Admin-only middleware added to restrict advancing the queue to admin users.
  • Tests

    • New comprehensive tests covering queue controllers, API routes, and the admin-only access middleware.

- GET /api/queues/:departmentId/current (current serving ticket)
- POST /api/queues/:departmentId/next (admin only, move next to serving)
- GET /api/queues/:departmentId/waiting (waiting tickets list)
- Admin-only middleware for role-based access control
- 24 new tests with 100% coverage

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9231856b-420d-4a34-ae7c-f32a3b60ba93

📥 Commits

Reviewing files that changed from the base of the PR and between 21134c2 and 9ad7376.

📒 Files selected for processing (2)
  • backend/src/__tests__/queue.controller.test.js
  • backend/src/controllers/queue.controller.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/src/controllers/queue.controller.js
  • backend/src/tests/queue.controller.test.js

📝 Walkthrough

Walkthrough

Adds admin-only middleware, three queue controller endpoints for department-scoped ticket management, a router mounted at /api/queues, and Jest/Supertest tests for middleware, controllers, and routes.

Changes

Queue Management System

Layer / File(s) Summary
Admin-only authorization middleware
backend/src/middleware/adminOnly.js, backend/src/__tests__/adminOnly.middleware.test.js
New middleware enforces admin role by returning 403 for non-admin or missing users; tests cover admin pass-through, non-admin rejection, and missing user/role cases.
Queue controller implementation
backend/src/controllers/queue.controller.js
Adds getCurrentServing, callNext, and getWaiting. callNext runs inside a sequelize.transaction, completes any current serving ticket, and promotes the oldest waiting ticket using row locks; handlers validate department presence and return 200/404/500 responses.
Queue controller tests
backend/src/__tests__/queue.controller.test.js
Jest tests mock Ticket, Department, and sequelize.transaction to cover missing departments, empty results, successful promotions (including completing current serving), and error cases for all three handlers.
Queue routes and app integration
backend/src/routes/queue.routes.js, backend/src/app.js, backend/src/__tests__/queue.routes.test.js
Adds router with global auth and admin-only gating on POST /:departmentId/next, mounts it at /api/queues, and adds Supertest/JWT tests verifying 401 unauthenticated, 403 for non-admin on protected endpoint, and 200 for authorized requests.

Sequence Diagram

sequenceDiagram
  participant Client
  participant AuthMiddleware
  participant AdminMiddleware
  participant QueueController
  participant TicketModel
  participant Response

  Client->>AuthMiddleware: Request to /api/queues/:departmentId/next (JWT)
  AuthMiddleware->>AdminMiddleware: Forward authenticated request
  AdminMiddleware->>AdminMiddleware: Check req.user.role === 'admin'
  alt Non-admin or missing user
    AdminMiddleware->>Response: 403 { success: false, message: 'Access denied. Admin only.' }
    Response->>Client: 403
  else Admin user
    AdminMiddleware->>QueueController: callNext(req)
    QueueController->>TicketModel: Find oldest waiting (LOCK.UPDATE, skipLocked)
    TicketModel-->>QueueController: waiting ticket (or null)
    alt No waiting
      QueueController->>Response: 404 { success: false, message: 'No waiting tickets' }
      Response->>Client: 404
    else Promote ticket
      QueueController->>TicketModel: Find current serving (FOR UPDATE)
      TicketModel-->>QueueController: current serving (or null)
      QueueController->>TicketModel: Mark current completed & save (if exists)
      QueueController->>TicketModel: Update waiting -> serving & save
      QueueController->>Response: 200 { success: true, ticket: {...} }
      Response->>Client: 200
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • 0xpritam/SmartQueue#5: Adds the Department Sequelize model that the new queue controllers query via Department.findByPk.

Poem

🐰 I hopped through code to queue the line,
Admin gates set, the tickets align,
Waiting turned serving with a tiny cheer,
Tests assert order — the path is clear,
A rabbit claps for each well-run queue!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add Queue Management APIs' directly and concisely describes the main change: adding new queue management API endpoints.
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.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch devin/1780594831-add-queue-apis

Comment @coderabbitai help to get the list of available commands and usage tips.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

- Wrap findOne/save in sequelize.transaction with LOCK.UPDATE
- Complete currently serving ticket before promoting next
- Use skipLocked to prevent duplicate selection under concurrency
- Add test for completing current ticket before next promotion

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +58 to +71
if (currentServing) {
currentServing.status = 'completed';
await currentServing.save({ transaction: t });
}

// Promote next waiting ticket with row lock
const ticket = await Ticket.findOne({
where: { departmentId, status: 'waiting' },
order: [['createdAt', 'ASC']],
transaction: t,
lock: t.LOCK.UPDATE,
skipLocked: true,
});
if (!ticket) return null;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🔴 callNext silently completes the currently serving ticket even when no waiting tickets exist

In callNext, the transaction first marks the currently serving ticket as 'completed' (lines 58-61), then looks for the next waiting ticket (lines 64-70). If no waiting ticket is found, the transaction callback returns null without throwing, so the transaction commits. The currently serving ticket is now permanently marked 'completed' in the database, but the API responds with a 404 "No waiting tickets" error. The admin has no indication that the current customer's ticket was just completed as a side effect of a failed operation. This leaves the department in a state where no ticket is being served, which is likely unintended.

Scenario walkthrough
  1. Department has one 'serving' ticket and zero 'waiting' tickets.
  2. Admin calls POST /api/queues/:departmentId/next.
  3. Transaction: currentServing found → status set to 'completed' → saved.
  4. Transaction: ticket (next waiting) → null → return null.
  5. Transaction commits (no error thrown).
  6. Response: 404 { message: 'No waiting tickets' }.
  7. The serving ticket is now completed. No ticket is serving.
Prompt for agents
In callNext (backend/src/controllers/queue.controller.js), the transaction unconditionally marks the current serving ticket as completed before checking if a next waiting ticket exists. If no waiting ticket is found, the transaction still commits, leaving the department with no serving ticket.

Two possible fixes:

1. Only complete the current ticket if a next ticket exists: move the currentServing completion after the next-waiting lookup, so both updates happen atomically only when there is a next ticket.

2. Throw an error inside the transaction when no waiting ticket is found (after checking) to trigger a rollback, preserving the current serving ticket's state. For example, throw a custom error that the outer catch can detect and return the 404 response.

Option 1 is cleaner:
- First, find the next waiting ticket with the lock.
- If no waiting ticket, return null immediately (without touching currentServing).
- If found, then complete the current serving ticket and promote the waiting ticket.

This ensures the current ticket is only completed when there is someone to replace it.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed — reordered the transaction logic to find the next waiting ticket first. The current serving ticket is now only completed when a replacement exists, preventing the department from ending up with no active ticket on an empty queue.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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