Feature #3244
open[oms-menu-permissions] web: Permission-based menu & action access control (FE+BE)
0%
Description
Overview¶
Feature for the web side. 13 test case(s) generated.
Requirement¶
Hi Claude,
We need to implement permission-based menu and functionality access across the OMS application.
Currently, all menus and functionalities are visible to all users regardless of their assigned permissions. We need to change this so that the UI dynamically shows or hides menus and actions based on the user's permissions.
1. Menu-Level Permissions¶
All OMS menus should be displayed based on the logged-in user's permissions.
For example:
User Permissions
↓
Permission Check
↓
Show only permitted menus
If the user does not have permission to access a particular module/menu:
- The menu should not be displayed.
- The user should not be able to access the corresponding screen directly through the URL.
- The backend/API should also enforce the permission.
Do not rely only on hiding the menu in the frontend.
2. Functionality-Level Permissions¶
Within each module, individual actions must also be controlled by permissions.
For example:
Supplier
├── View
├── Create
├── Edit
└── Delete
Based on the user's permissions:
- View permission → Show/access the supplier list/details.
- Create permission → Show the Add/Create action.
- Edit permission → Show the Edit action.
- Delete permission → Show the Delete action.
The same permission-based behaviour should be applied consistently to all OMS modules and their available actions.
For example:
Item
├── View
├── Create
├── Edit
└── Delete
Project
├── View
├── Create
├── Edit
└── Delete
UOM
├── View
├── Create
├── Edit
└── Delete
Please do not hardcode permission checks separately in every component. Use a reusable and maintainable permission-checking mechanism.
3. Frontend + Backend Authorization¶
Permission enforcement should happen at both levels:
Frontend:
- Hide menus when the user doesn't have access.
- Hide buttons/actions when the user doesn't have the corresponding permission.
- Prevent direct navigation to unauthorized screens.
Backend/API:
- Validate the user's permissions for every protected operation.
- Reject unauthorized API requests even if someone manually calls the API.
The frontend should never be considered the security layer by itself.
4. Dynamic & Future-Proof¶
The implementation should be driven by the existing role/permission structure.
Do not implement logic like:
if user is admin → show everything
Instead, use the actual permission assigned to the user.
The solution should also support adding new modules, menus, roles, and permissions in the future without requiring major changes to the authorization architecture.
5. Before Implementation¶
First inspect the existing OMS implementation and provide:
- Current menu structure.
- Current permission/role implementation.
- Existing permission definitions.
- Which menus currently ignore permissions.
- Which actions currently ignore permissions.
- Existing frontend authorization/guard logic.
- Existing backend/API authorization logic.
- Recommended reusable permission-checking architecture.
- List of files/components/API endpoints that need to be updated.
Provide a table like:
| Module | Menu Permission | View | Create | Edit | Delete | Current Status |
|---|---|---|---|---|---|---|
| Supplier | ... | ... | ... | ... | ... | ... |
| Item | ... | ... | ... | ... | ... | ... |
| Project | ... | ... | ... | ... | ... | ... |
| UOM | ... | ... | ... | ... | ... | ... |
After the analysis, implement the changes and verify all permission combinations.
Acceptance Criteria¶
- Menus are shown/hidden based on permissions.
- Unauthorized screens cannot be accessed directly.
- View permission controls screen/data access.
- Create permission controls Add/Create actions.
- Edit permission controls Edit actions.
- Delete permission controls Delete actions.
- All OMS modules follow the same permission mechanism.
- Backend APIs enforce the same permissions.
- No permission checks are unnecessarily hardcoded.
- Existing authorized functionality continues to work.
- The implementation is reusable for future modules and permissions.
Please first analyze the current implementation and do the implementation. can you give it to me properly
Explicit Constraints¶
- Do not rely only on hiding the menu in the frontend. frontend/backend authorization
- Please do not hardcode permission checks separately in every component. implementation architecture
- Do not implement logic like: if user is admin → show everything permission logic/role checks
- The frontend should never be considered the security layer by itself. frontend/backend authorization
Acceptance Criteria¶
(none extracted — spec-extract has not run for this session)
Test Cases¶
☐ A logged-in user only sees navigation menu entries for OMS modules they hold at least one permission for; modules they have no permission on are absent from the rendered menu, not merely disabled.
☐ Typing or following a direct URL to a module screen the user lacks permission for is blocked by the route guard, independent of whether a menu link to it exists.
☐ Backend API endpoints re-validate the authenticated caller's permission on every protected operation, so a request sent directly (bypassing the UI) without the required permission is rejected.
☐ View permission is required to access a module's list/detail screen and its underlying data, enforced both in the UI and by the API.
☐ Create permission gates both the visibility of the Add/Create action in the UI and whether the backend accepts create requests for that module.
☐ Edit permission gates both the visibility of the Edit action in the UI and whether the backend accepts update requests for that module.
☐ Delete permission gates both the visibility of the Delete action in the UI and whether the backend accepts delete requests for that module.
☐ The view/create/edit/delete permission-gating behavior verified for Supplier is applied identically to Item, Project, and UOM, with no module exempted.
☐ Every permission check in the codebase — frontend and backend, across all modules — resolves through one shared, reusable permission-checking mechanism rather than separate hardcoded checks per component or controller.
☐ No access decision anywhere in the codebase is made by branching on role identity (e.g. checking for an 'admin' role name); all decisions resolve against the user's actual assigned permission set.
☐ Registering a new module/menu/permission through the mechanism's configuration is sufficient to get it enforced — no changes to the core permission-checking logic are required.
☐ For a user who is authorized on all four existing modules, previously-working view/create/edit/list/navigation flows continue to succeed unchanged after permission enforcement is added.
☐ A pre-implementation analysis deliverable exists and covers every required topic: current menu structure, current permission/role implementation, existing permission definitions, which menus/actions currently ignore permissions, existing frontend/backend authorization logic, the recommended reusable architecture, and the per-module View/Create/Edit/Delete status table of files/components/endpoints needing updates.
Implementation Details¶
(populated once implementation completes — see the run's completion note on this ticket for the real commit list and MR link)
Verification¶
(populated once verification completes — see the run's completion note on this ticket for UI/live-verification evidence)
Orchestration slug: oms-menu-permissions (side: web)
Updated by Bot AI 3 days ago · Edited
Phase Timeline¶
| # | Process | Start (IST) | End (IST) | Duration | Tokens | Cost | Model |
|---|---|---|---|---|---|---|---|
| 1 | Requirement scope detection | 28-08-2026 12:10:40 | 28-08-2026 12:11:01 | 21s | 52,242 | $0.1849 | claude-sonnet-5 |
| 2 | Extract explicit constraints | 28-08-2026 12:11:01 | 28-08-2026 12:11:08 | 7s | 36,912 | $0.1344 | claude-sonnet-5 |
| 3 | Probe environment | 28-08-2026 12:11:09 | 28-08-2026 12:11:16 | 7s | not available | not available | not recorded |
| 4 | Execution environment — discover runners | 28-08-2026 12:11:16 | 28-08-2026 12:14:22 | 3m | 2,109,257 | $1.5815 | claude-sonnet-5 |
| 5 | Execution environment — confirm | 28-08-2026 12:14:22 | 28-08-2026 12:16:15 | 2m | n/a | n/a | n/a |
| 6 | Task Granularity | 28-08-2026 12:16:20 | 28-08-2026 12:17:10 | 50s | 81,579 | $0.2398 | claude-opus-5 |
| 7 | Task Granularity — human gate | 28-08-2026 12:17:10 | 28-08-2026 12:17:26 | 15s | n/a | n/a | n/a |
| 8 | Do screen inventory + field checklist? — human gate | 28-08-2026 12:17:30 | 28-08-2026 12:17:47 | 16s | n/a | n/a | n/a |
| 9 | Start Confirmation | 28-08-2026 12:17:51 | 28-08-2026 12:19:13 | 1m | 47,565 | $0.2345 | claude-opus-5 |
| 10 | Start Confirmation — human gate | 28-08-2026 12:19:14 | 28-08-2026 12:19:36 | 22s | n/a | n/a | n/a |
| 11 | Determine web connection | 28-08-2026 12:19:40 | 28-08-2026 12:23:33 | 4m | 2,340,934 | $1.1629 | claude-sonnet-5 |
| 12 | Extract ticket-spec / acceptance criteria | 28-08-2026 12:23:34 | 28-08-2026 12:24:03 | 29s | 52,904 | $0.1643 | claude-sonnet-5 |
| 13 | Generate test-spec scenarios and assertions | 28-08-2026 12:24:04 | 28-08-2026 12:25:52 | 2m | 161,489 | $0.3625 | claude-sonnet-5 |
| 14 | Create/Reuse Web Redmine Ticket | 28-08-2026 12:25:52 | 28-08-2026 12:25:53 | 1s | not available | not available | not recorded |
| 15 | Cross-link tickets | 28-08-2026 12:25:54 | 28-08-2026 12:25:54 | 0s | not available | not available | not recorded |
| 16 | Initialise timing note | 28-08-2026 12:25:54 | 28-08-2026 12:25:55 | 0s | not available | not available | not recorded |
| 17 | Analyze → Implementation Plan | 28-08-2026 12:25:55 | 28-08-2026 12:34:20 | 8m | 1,349,162 | $1.2054 | claude-opus-5 |
| 18 | Design | 28-08-2026 12:34:20 | 28-08-2026 12:36:18 | 2m | 1,094,957 | $0.8309 | claude-sonnet-5 |
| 19 | Schema Review | 28-08-2026 12:36:18 | 28-08-2026 12:40:43 | 4m | 688,193 | $0.8600 | claude-opus-5 |
| 20 | Create Branch | 28-08-2026 12:40:43 | 28-08-2026 12:40:46 | 2s | not available | not available | not recorded |
| 21 | Data Layer | 28-08-2026 12:40:47 | 28-08-2026 12:45:05 | 4m | 1,783,412 | $1.2257 | claude-sonnet-5 |
| 22 | UI Implementation | 28-08-2026 12:45:05 | 28-08-2026 12:55:07 | 10m | 4,717,068 | $2.4916 | claude-sonnet-5 |
| 23 | 1. Unit Tests | 28-08-2026 12:55:08 | 28-08-2026 13:16:32 | 21m | 3,489,231 | $2.2171 | claude-sonnet-5 |
| 24 | 2. TypeScript FAILED | 28-08-2026 13:16:32 | 28-08-2026 13:16:41 | 9s | not available | not available | not recorded |
| 25 | GAP — unattributed | 28-08-2026 13:16:41 | 28-08-2026 13:32:35 | 16m | n/a — wait time, not compute | n/a — wait time, not compute | n/a |
| 26 | 3. Lint FAILED | 28-08-2026 13:32:35 | 28-08-2026 13:32:40 | 5s | not available | not available | not recorded |
| 27 | 4. Dead Code | 28-08-2026 13:41:18 | 28-08-2026 13:47:37 | 6m | 1,220,760 | $1.0103 | claude-opus-5 |
| 28 | 5. Code & Style Quality Audit | 28-08-2026 13:47:38 | 28-08-2026 13:58:13 | 11m | 3,668,212 | $2.6442 | claude-opus-5 |
| 29 | 6. Design Consistency Audit | 28-08-2026 13:58:14 | 28-08-2026 14:05:52 | 8m | 1,844,039 | $1.5249 | claude-opus-5 |
| 30 | 7. Responsive Audit | 28-08-2026 14:05:53 | 28-08-2026 14:16:15 | 10m | 1,578,834 | $1.5257 | claude-opus-5 |
| 31 | Code Review | 28-08-2026 14:16:16 | 28-08-2026 14:22:44 | 6m | 2,452,347 | $1.4762 | claude-sonnet-5 |
| 32 | UI Verify | 28-08-2026 14:22:45 | 28-08-2026 14:26:19 | 4m | 1,102,025 | $0.9001 | claude-opus-5 |
| 33 | GAP — unattributed | 28-08-2026 14:26:19 | 28-08-2026 14:41:20 | 15m | n/a — wait time, not compute | n/a — wait time, not compute | n/a |
| 34 | Web: Live verification (re-dispatched ×2; first attempt 28-08-2026 14:26:19) | 28-08-2026 14:41:20 | 28-08-2026 15:13:03 | 32m | 18,210,476 | $7.9792 | claude-sonnet-5 |
| 35 | Contract | 28-08-2026 15:13:04 | 28-08-2026 15:14:03 | 58s | 376,221 | $0.3445 | claude-sonnet-5 |
| 36 | Git & MR (retried ×2) (re-dispatched ×4; first attempt 28-08-2026 15:14:03) | 28-08-2026 15:22:16 | 28-08-2026 15:22:19 | 2s | not available | not available | not recorded |
| 37 | Trigger GitLab Local Verification (retried ×2) (re-dispatched ×4; first attempt 28-08-2026 15:22:20) | 28-08-2026 15:31:33 | 28-08-2026 15:31:34 | 1s | not available | not available | not recorded |
| 38 | Poll verification jobs | 28-08-2026 15:31:35 | 28-08-2026 15:38:49 | 7m | 3,532,692 | $1.7982 | claude-sonnet-5 |
| 39 | Validate verification evidence | 28-08-2026 15:38:49 | 28-08-2026 15:38:49 | 0s | not available | not available | not recorded |
| 40 | Verification approval | 28-08-2026 15:38:50 | 28-08-2026 15:39:25 | 34s | n/a | n/a | n/a |
| 41 | Completion Summary | 28-08-2026 15:39:30 | 28-08-2026 15:39:30 | 0s | not available | not available | not recorded |
| 42 | Write handoff doc | 28-08-2026 15:39:30 | 28-08-2026 15:39:30 | 0s | not available | not available | not recorded |
| 43 | Resolve tickets + post usage summary | 28-08-2026 15:39:31 | 28-08-2026 15:39:33 | 2s | not available | not available | not recorded |
| 44 | Gate failure decision | -- | 28-08-2026 13:41:14 | -- | not available | not available | not recorded |
| 45 | Human intervention (escape hatch) | -- | 28-08-2026 15:31:28 | -- | not available | not available | not recorded |
| 46 | Join — all active sides implemented | -- | 28-08-2026 15:22:19 | -- | not available | not available | not recorded |
ORCHESTRATOR TOTAL: 3m, 0 tokens, $0.0000, 3 row(s) with no token data (rows 5–46)
SHARED TOTAL: 2h 28m, 51,990,511 tokens, $32.0986, 13 row(s) with no token data (rows 1–43)
Total Run Time: 3h 29m (wall clock, 28-08-2026 12:10:40 → 28-08-2026 15:39:33 IST — not a sum of the per-side totals above, since sides overlap)
Active time: 2h 58m | Waiting (session limits, approvals, dead sessions): 31m — 2 gap(s) still unattributed; label them with driver.py gap <slug> --from <ISO> --to <ISO> --reason '<why>'
Total Tokens Consumed: 51,990,511 (plus 16 row(s) whose usage was never captured — run execution_tracker.py enrich-audit to backfill. This is a floor, not the total.)
Total Cost: $32.0986 (plus 16 row(s) whose usage was never captured — run execution_tracker.py enrich-audit to backfill. This is a floor, not the total.)
Updated by Bot AI 3 days ago
- Status changed from In Progress to Resolved
Run oms-menu-permissions — web side complete¶
Diagnosis & Fix¶
Ticket #3244 asks for permission-driven menus and per-action gating across OMS. A codebase scan shows ticket #3242 already delivered most of the architecture the ticket asks for: a central registry (lib/permissions/registry.ts), a pure evaluator (lib/permissions/evaluate.ts), a DB-backed Node guard (lib/permissions/guard.ts), Edge route gating (middleware.ts), permission-filtered navigation (lib/nav.ts), and requirePermission() on all 14 mutating Server Actions plus checkPermission() on the upload Route Handler. The genuinely outstanding work is therefore narrow and specific: (1) the /403 destination that both middleware.ts:48 and guard.ts:53 redirect to DOES NOT EXIST — confirmed absent from the real npm run build route table — so every denial currently lands on the 404 page; (2) functionality-level UI gating (ticket section 2) is entirely absent — every 'New X' button, every RowActions view/edit/delete icon, the expenses Edit link and the Cancel Order button render unconditionally for any user who can reach the page; (3) there is no RSC page-level guard, so read access to list/detail data is enforced only by the Edge middleware's stale cookie snapshot, and lib/queries/* is completely unguarded; (4) app/page.tsx and app/not-found.tsx hardcode /orders as home, bouncing any user without order:read into the broken /403. A required pre-implementation analysis deliverable (test case 13) must also be written as a real file.
Merge Request¶
- Repository: oms/oms-web
- Branch: feat/3244-permission-based-menu-ac
- MR: https://gitlab.techbumbles.co.in/oms/oms-web/-/merge_requests/6
Commits¶
- d70af1a ci: stop uploading .next/ as a build artifact — 413 Request Entity Too Large failed the whole pipeline
- 8373681 ci: allow api/web/trigger pipeline sources — V01 triggers pipelines via the GitLab API, not push/MR
- 25b1251 Contract (oms-menu-permissions)
- 07b73c4 4. Dead Code (oms-menu-permissions)
- 2d7f77e 1. Unit Tests (oms-menu-permissions)
- 9b3e4bf UI Implementation (oms-menu-permissions)
- 2c9ef45 Data Layer (oms-menu-permissions)
UI Verification¶
N/A
- (Verified UI evidence at docs/gate-evidence/ui-verify-3244.txt could not be attached — see log above)
Live verification: PASSED - (Live verification evidence at No in-repo write access this run (read-only checkout) — raw evidence lives outside the repo at /tmp/w30_full_result2.json (17-row live permission matrix, all endpoints, both arms) and /tmp/w30_result.json (nav/row-action/fulfillment DOM gating + login flows), produced by ad hoc Playwright scripts /tmp/w30_full.js and /tmp/w30_run.js run against a real
next build && next startinstance (ports 3450/3451) and the project's own seeded Postgres (oms_test@localhost:5432). Recommend committing an equivalent script under a future ticket so this evidence can live in verification/ instead of /tmp. could not be attached — see log above)
Updated by Bot AI 3 days ago
Token usage summary (grouped by model):
Total known tokens: 0
Processes with no token data: 0
processesWithNoTokenData are orchestrator-internal steps with no sub-agent spawn — their token cost is real but not measurable in this environment, not zero. Do not treat totalKnownTokens as full spend.