docs: submitter view-all feature flag (read+export every PO, History)

Hardik 2026-06-22 04:58:22 +05:30
parent 9bcc43f460
commit 8eaf2ed0a0
4 changed files with 46 additions and 4 deletions

@ -31,6 +31,7 @@ Server-side env on pms1 lives in `~/pms/App/.env`; locally in `App/.env.local`
| `FORGEJO_TOKEN` | optional | optional | Token scope `write:issue` |
| `GST_SERVICE_URL` | optional | optional | GstService base (default `http://localhost:3003`) |
| `NEXT_PUBLIC_INVENTORY_ENABLED` | optional | optional | Inventory flag — **off only when `"false"`** |
| `NEXT_PUBLIC_SUBMITTER_VIEW_ALL_ENABLED` | optional | optional | Submitter view-all flag — **on only when `"true"`**. Lets TECHNICAL/MANNING read & export every PO and open History |
| `NEXT_PUBLIC_ENV_LABEL` | optional | **unset** | When set, shows the non-prod banner (`EnvBanner`). Leave unset in production |
| `PORT` | optional | optional | App port (default 3000; staging 3200; autofix 3100) |
@ -44,6 +45,12 @@ Server-side env on pms1 lives in `~/pms/App/.env`; locally in `App/.env.local`
[File Storage](File-Storage) and [Notifications](Notifications).
- **Inventory flag** — `INVENTORY_ENABLED = NEXT_PUBLIC_INVENTORY_ENABLED !==
"false"`, i.e. enabled unless explicitly `"false"`.
- **Submitter view-all flag** — `SUBMITTER_VIEW_ALL_ENABLED =
NEXT_PUBLIC_SUBMITTER_VIEW_ALL_ENABLED === "true"`, i.e. **off unless
explicitly `"true"`** (opt-in, since it widens read access). When on, submitter
roles (TECHNICAL/MANNING) can read & export **every** PO and reach the History
page; it grants no approval/payment/edit rights. See
[Roles and Permissions](Roles-and-Permissions#feature-flagged-access).
- **Env banner**`EnvBanner` renders nothing when `NEXT_PUBLIC_ENV_LABEL` is
unset, so production is unaffected; staging sets it to the
"INTERNAL DEV / STAGING - NOT PRODUCTION" string.

@ -50,7 +50,9 @@ with the detail, or names the code that implements it.
centre and by month (Recharts).
- **In-app notification bell** with unread badge, plus email at every transition.
- **History & export** — filter by date range, cost centre, and **multiple
statuses**; CSV/PDF export (up to ~200 rows).
statuses**; CSV/PDF export (up to ~200 rows). Open to `export_reports` holders;
**submitters get read+export access under the `NEXT_PUBLIC_SUBMITTER_VIEW_ALL_ENABLED`
flag** (read-only). See [Roles and Permissions](Roles-and-Permissions#feature-flagged-access).
- **Mobile experience** — manager/accounts get mobile cards + bottom nav; other
roles see a "Desktop Required" overlay.
- **PPMS rebrand** — login, sidebar, and title show "PPMS".

@ -15,7 +15,8 @@ My Orders /my-orders ← TECH, MANNING, MANAGER, SUPERUSER
Approvals /approvals ← MANAGER, SUPERUSER
Import PO /po/import ← MANAGER, SUPERUSER, ADMIN
Payments /payments ← ACCOUNTS (+ MANAGER, SUPERUSER)
History / Export /history ← MANAGER, SUPERUSER, ACCOUNTS, AUDITOR, ADMIN
History / Export /history ← MANAGER, SUPERUSER, AUDITOR, ADMIN
(+ TECHNICAL, MANNING when SUBMITTER_VIEW_ALL flag on)
Vendors /inventory/vendors ← MANAGER, ACCOUNTS, ADMIN
Items /inventory/items ← all (read-only catalogue)
Cart /inventory/cart ← TECH, MANNING, MANAGER, SUPERUSER
@ -39,7 +40,7 @@ SuperUser Requests /admin/superuser-requests ← ADMIN
| `/dashboard` | Dashboard | Role-specific stat cards + charts |
| `/my-orders` | My Purchase Orders | Submitter's open & past POs (Closed list scoped by role) |
| `/po/new` | New PO | Multi-section form (header, line items, T&C, documents) |
| `/po/[id]` | PO Detail | Read view; contextual action buttons by status/role; export |
| `/po/[id]` | PO Detail | Read view; contextual action buttons by status/role; export. Own PO always; any PO for `view_all_pos` holders (and submitters when the `SUBMITTER_VIEW_ALL` flag is on) |
| `/po/[id]/edit` | Edit PO | DRAFT or EDITS_REQUESTED, owner/SUPERUSER; "Update & Resubmit" |
| `/po/[id]/receipt` | Confirm Receipt | PAID_DELIVERED; upload receipt; full or partial |
| `/po/import` | Import PO | Upload Pelagia-format Excel → CLOSED |
@ -47,7 +48,7 @@ SuperUser Requests /admin/superuser-requests ← ADMIN
| `/approvals/[id]` | Approval Detail | Approve / Approve+Note / Reject / Request Edits / Request Vendor ID; inline line-item edit |
| `/payments` | Payment Queue | MGR_APPROVED & SENT_FOR_PAYMENT cards; send/mark paid; partial |
| `/payments/history` | Payment History | Completed payments (ACCOUNTS, MANAGER) |
| `/history` | History & Export | All POs; filter by date/cost centre/multiple statuses; CSV/PDF |
| `/history` | History & Export | All POs; filter by date/cost centre/multiple statuses; CSV/PDF. `export_reports` holders, plus submitters when the `SUBMITTER_VIEW_ALL` flag is on |
| `/inventory/items` | Items (read-only) | Catalogue; expand for per-vendor prices; Cheapest/★Closest tags |
| `/inventory/items/[id]` | Item Detail | Price comparison, site-distance sort, stock by site |
| `/inventory/vendors` | Vendors | List with verified/active badges |

@ -62,6 +62,38 @@ The exact `ROLE_PERMISSIONS` map in `lib/permissions.ts`. ✓ = granted.
(`manage_users` plus the catalogue/`manage_*` permissions) and can view/export.
- **AUDITOR is strictly read-only** (`view_*`, `export_reports`).
## Feature-flagged access
### Submitter view-all (`NEXT_PUBLIC_SUBMITTER_VIEW_ALL_ENABLED`)
By default submitters (**TECHNICAL**, **MANNING**) only see the POs they raised.
When `NEXT_PUBLIC_SUBMITTER_VIEW_ALL_ENABLED="true"` they gain **read-only**
access to every PO:
- the **History** page (`/history`) and its CSV/PDF report export;
- any other user's **PO detail** page (`/po/[id]`);
- the **Export PDF / XLSX** buttons on those POs (approved & cancelled POs only,
same status gate as everyone else).
It is a pure read widening — it grants **no** approval, payment, edit, cancel, or
admin rights, and does not change what non-submitter roles can do. The flag is
**opt-in** (off unless the value is exactly `"true"`).
Implementation lives in `lib/permissions.ts`:
| Helper | Meaning |
|---|---|
| `isSubmitterRole(role)` | `role ∈ {TECHNICAL, MANNING}` |
| `submitterCanViewAll(role)` | flag is on **and** `isSubmitterRole(role)` |
| `canViewAllPos(role)` | `hasPermission(role, "view_all_pos") \|\| submitterCanViewAll(role)` |
`canViewAllPos` gates the PO detail page and the per-PO export route;
`submitterCanViewAll` is OR'd into the `export_reports` gate on the History page,
the report-export route, and the sidebar's History link. When the flag is off,
all of these collapse to the prior behaviour (view_all_pos holders only). The
`my-orders` "Closed Purchase Orders" list stays personal for submitters
regardless — History is the all-POs surface.
## Business rules layered on top
Beyond the permission map, server actions and the state machine enforce: