Skip to content

fix(admin): mount the /api/admin catalogue and order endpoints the dashboard calls - #1702

Open
MOHITKOURAV01 wants to merge 1 commit into
AnthropicBots:mainfrom
MOHITKOURAV01:fix/1697-admin-api-endpoints
Open

fix(admin): mount the /api/admin catalogue and order endpoints the dashboard calls#1702
MOHITKOURAV01 wants to merge 1 commit into
AnthropicBots:mainfrom
MOHITKOURAV01:fix/1697-admin-api-endpoints

Conversation

@MOHITKOURAV01

@MOHITKOURAV01 MOHITKOURAV01 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Closes #1697

What was wrong

frontend/scripts/admin.js was repointed at a /api/admin/* surface in the Admin Dashboard change (#1666). None of it was mounted:

admin.js calls adminRoutes.js had
GET /api/admin/verify
GET /api/admin/products
POST / PUT / DELETE /api/admin/products[/:id]
GET /api/admin/orders
PATCH /api/admin/orders/:id/status

verifyAdminAccess() is the first thing that runs on admin.html. Its 404 made response.success falsy, which the client reads as "not an admin", so every admin was redirected to signin.html before the page rendered anything.

What this adds

backend/controllers/adminCatalogController.js with the four handlers, mounted on the existing admin router — which already applies adminLimiter, authMiddleware and adminMiddleware, so they inherit the guard rather than restating it.

GET /verify — echoes req.user. Reaching the handler is itself the answer: the middleware above has already resolved the session and rejected anyone outside ADMIN_ROLES. Kept as its own endpoint so the client has one cheap call before drawing a page it may not be allowed to see. adminMiddleware accepts superadmin, matching the client-side check.

GET /products — deliberately not a proxy for /api/products. That route restricts itself to PUBLIC_PRODUCT_STATUSES (constants/productVisibility.js), and an operator managing the catalogue has to see drafts, inactive and archived rows — those are the ones that need attention. Supports ?search=, ?status= and ?includeDeleted=; soft-deleted rows are hidden by default because the dashboard's delete button archives rather than drops, and a list that keeps showing what you just deleted reads as a failed delete.

GET /orders — the whole queue rather than /api/orders, which is scoped to req.user.id. Carries item_count off a LEFT JOIN so the dashboard does not make a round trip per row.

PATCH /orders/:id/status — whitelisted statuses, and the same transitions order.service.js#updateOrderStatusService refuses: a cancelled order cannot be moved at all, and a delivered order can only be moved to cancelled (that is a return, and a real thing an operator does). Re-selecting the current status answers 200 without a write, because the <select> fires change on re-selection and a 4xx there makes the dropdown bounce back.

Product writes are not reimplemented — the router delegates POST/PUT/DELETE to productController, which already owns validation, slug generation and archive-on-delete. The only difference from the public route is the guard: /api/products writes are gated on ROLES.ADMIN alone, so a superadmin cannot use them; this router accepts both.

Both list responses carry the payload twice — at the top level under products / orders, which is what admin.js reads, and under data, which is the shape every other admin route answers with. Cheap, and it avoids a client change landing in the same PR as the server one.

Guard

backend/tests/adminCatalogRoutes.test.js, 36 cases. The first block is the one that matters most: it reads the paths out of admin.js and asserts the router answers them, so the endpoints cannot be renamed out from under the dashboard again with every test still green. The rest cover the role gate on each route (admin / superadmin / shopper / anonymous), the response keys admin.js actually reads, that the product list carries no public-status filter and the order list no user_id scope, LIKE-wildcard escaping in the search term, the page-size cap, every allowed status transition and each refused one, and that the status list has not drifted from the copy in order.service.js.

Verification

$ backend/node_modules/.bin/jest --config backend/jest.config.js tests/adminCatalogRoutes.test.js
Tests:       36 passed, 36 total

$ npm run check:syntax   # 652 files parsed cleanly
$ npm run check:boot     # backend/server.js loaded with 96 mounted layers
$ npm run check:modules  # 435 backend modules imported cleanly

CI note — merge #1701 first

The Syntax check job fails on this branch, and it is not this change:

❌ 1 of 654 JavaScript file(s) failed to parse:
  frontend/scripts/shop.js:2499
      Unexpected end of input

frontend/scripts/shop.js is unparsable on main — the responsive refactor duplicated and interleaved its initialization block. Every open PR against this repository inherits it, and because check:syntax is the first CI job and the other two are gated on it, Backend tests and Server boots are skipped rather than run. That is why this PR shows no test result.

#1701 fixes it. Once that merges, this branch picks the fix up from main with no rebase needed — the two touch no file in common. All gates pass locally on this branch's changes:

$ npm run check:boot     ✅
$ npm run check:modules  ✅
$ npm run check:assets   ✅
$ npm run check:a11y     ✅
$ npm run check:sitemap  ✅

and I verified the whole set merges cleanly by merging all five of these branches together locally: no conflicts, check:syntax green at 659 files, and the full Jest suite at 2976 passing.

The Vercel check fails on every PR in this repository with "Authorization required to deploy" against the bhuvanshs-projects team, unrelated to any change.

…shboard calls

frontend/scripts/admin.js was repointed at /api/admin/verify,
/api/admin/products and /api/admin/orders in the Admin Dashboard change. None
of those paths were mounted. verifyAdminAccess() is the first thing that runs
on admin.html, so its 404 read as 'not an admin' and every admin was redirected
to signin.html before the page rendered anything.

Add adminCatalogController with the four handlers that were missing -- verify,
the admin product list, the order queue and the order status transition -- and
mount them on adminRoutes, which already applies the auth, admin and rate-limit
middleware.

These are separate from the public routes on purpose. /api/products restricts
itself to PUBLIC_PRODUCT_STATUSES, and an operator managing the catalogue needs
to see drafts, inactive and archived rows; /api/orders is scoped to the calling
user, and an admin needs the whole queue. Product writes are not reimplemented
-- the router delegates create, update and delete to productController, which
already owns validation, slugging and archive-on-delete, and differs only in
accepting superadmin as well as admin.

Status transitions refuse the same moves order.service.js refuses, and the
audit row is best-effort: order_status_logs is not in every environment's
schema, and losing a log line is worth less than refusing a change the operator
has already made.
@hydra-maintainer

Copy link
Copy Markdown

🔍 Quality Gate Report

✅ All quality gates passed!

Status Check Details
Linked Issue PR description references a closing issue ✅

@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the Bhuvansh's projects Team on Vercel.

A member of the Team first needs to authorize it.

@hydra-maintainer

Copy link
Copy Markdown

🤖 AI Code Review

🔴 Score: 50/100 | comment

AI review unavailable at this time.


Automated AI review — a human maintainer will also review.

@hydra-maintainer

Copy link
Copy Markdown

💡 Suggested reviewers based on relevant file history: @Aditya8369, @Pcmhacker-hero

@hydra-maintainer

Copy link
Copy Markdown

🟡 PR Health Score: 55/100

This PR's health score is below the 75/100 threshold for a healthy label.

Status Signal
Test coverage
Linked issue
PR description (≥50 chars)
DCO sign-off
⬜ 0 approval(s) Approvals
Diff size < 400 lines

Improving these signals will help reviewers engage faster and raise your score. 💪

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.

[Bug] Admin dashboard is unusable — admin.js calls /api/admin/verify, /admin/products and /admin/orders, none of which are mounted

1 participant