From 864141c105cae357b0145c39163099439a7da7cc Mon Sep 17 00:00:00 2001 From: Hardik Date: Fri, 19 Jun 2026 13:48:03 +0530 Subject: [PATCH] @ docs(wiki): organise into folders + migrate retired Docs/ - Group pages into Overview/, Build-and-Run/, System/, Product/, Quality/, Ops/ so the on-disk layout mirrors the sidebar hierarchy. - Migrate retired design/test docs from the app repo Docs/ into the wiki: Product/Workflows, Product/Design-System, and the Quality/ test references (Test-Plan, E2E-Test-Framework, E2E-Test-Plan, Playwright-Test-Design). - Rewrite internal links to folder-qualified, root-relative targets. Co-Authored-By: Claude Opus 4.8 @ --- .../Environment-Variables.md | 6 +- .../Getting-Started.md | 8 +- Home.md | 15 +- .../Deployment-and-Operations.md | 6 +- .../Issue-to-Deploy-Pipeline.md | 2 +- Changelog.md => Overview/Changelog.md | 16 +- Glossary.md => Overview/Glossary.md | 6 +- .../Open-Questions.md | 4 +- Product/Design-System.md | 74 ++++ .../Feature-Catalogue.md | 16 +- File-Storage.md => Product/File-Storage.md | 2 +- .../Inventory-and-Catalogue.md | 2 +- Notifications.md => Product/Notifications.md | 4 +- .../Pages-and-Navigation.md | 0 .../Purchase-Orders.md | 10 +- .../Vendors-and-GST-Lookup.md | 4 +- Product/Workflows.md | 157 ++++++++ Quality/E2E-Test-Framework.md | 311 ++++++++++++++++ Quality/E2E-Test-Plan.md | 242 ++++++++++++ Quality/Playwright-Test-Design.md | 343 ++++++++++++++++++ Quality/Test-Plan.md | 266 ++++++++++++++ Testing.md => Quality/Testing.md | 18 +- Architecture.md => System/Architecture.md | 8 +- Data-Model.md => System/Data-Model.md | 14 +- PO-Lifecycle.md => System/PO-Lifecycle.md | 6 +- .../Roles-and-Permissions.md | 4 +- _Sidebar.md | 58 +-- 27 files changed, 1506 insertions(+), 96 deletions(-) rename Environment-Variables.md => Build-and-Run/Environment-Variables.md (91%) rename Getting-Started.md => Build-and-Run/Getting-Started.md (91%) rename Deployment-and-Operations.md => Ops/Deployment-and-Operations.md (96%) rename Issue-to-Deploy-Pipeline.md => Ops/Issue-to-Deploy-Pipeline.md (98%) rename Changelog.md => Overview/Changelog.md (87%) rename Glossary.md => Overview/Glossary.md (92%) rename Open-Questions.md => Overview/Open-Questions.md (92%) create mode 100644 Product/Design-System.md rename Feature-Catalogue.md => Product/Feature-Catalogue.md (86%) rename File-Storage.md => Product/File-Storage.md (97%) rename Inventory-and-Catalogue.md => Product/Inventory-and-Catalogue.md (98%) rename Notifications.md => Product/Notifications.md (95%) rename Pages-and-Navigation.md => Product/Pages-and-Navigation.md (100%) rename Purchase-Orders.md => Product/Purchase-Orders.md (95%) rename Vendors-and-GST-Lookup.md => Product/Vendors-and-GST-Lookup.md (95%) create mode 100644 Product/Workflows.md create mode 100644 Quality/E2E-Test-Framework.md create mode 100644 Quality/E2E-Test-Plan.md create mode 100644 Quality/Playwright-Test-Design.md create mode 100644 Quality/Test-Plan.md rename Testing.md => Quality/Testing.md (86%) rename Architecture.md => System/Architecture.md (96%) rename Data-Model.md => System/Data-Model.md (94%) rename PO-Lifecycle.md => System/PO-Lifecycle.md (95%) rename Roles-and-Permissions.md => System/Roles-and-Permissions.md (96%) diff --git a/Environment-Variables.md b/Build-and-Run/Environment-Variables.md similarity index 91% rename from Environment-Variables.md rename to Build-and-Run/Environment-Variables.md index 31c66f8..1976e15 100644 --- a/Environment-Variables.md +++ b/Build-and-Run/Environment-Variables.md @@ -38,14 +38,14 @@ Server-side env on pms1 lives in `~/pms/App/.env`; locally in `App/.env.local` - **SSO at module load** — `auth.ts` evaluates the `AZURE_AD_*` vars when the module loads, so they must be *present* (even as placeholders) for the app to - start in non-SSO environments. See [Architecture](Architecture#auth--authorisation). + start in non-SSO environments. See [Architecture](System/Architecture#auth--authorisation). - **Storage / email auto-toggle** — with R2/Resend unset in dev, uploads go to `.dev-uploads/` and emails print to the terminal. See - [File Storage](File-Storage) and [Notifications](Notifications). + [File Storage](Product/File-Storage) and [Notifications](Product/Notifications). - **Inventory flag** — `INVENTORY_ENABLED = NEXT_PUBLIC_INVENTORY_ENABLED !== "false"`, i.e. enabled unless explicitly `"false"`. - **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. - **GstService** has its own `PORT` (default 3003); the portal reaches it via - `GST_SERVICE_URL`. See [Vendors and GST Lookup](Vendors-and-GST-Lookup). + `GST_SERVICE_URL`. See [Vendors and GST Lookup](Product/Vendors-and-GST-Lookup). diff --git a/Getting-Started.md b/Build-and-Run/Getting-Started.md similarity index 91% rename from Getting-Started.md rename to Build-and-Run/Getting-Started.md index 1ebf1af..a432253 100644 --- a/Getting-Started.md +++ b/Build-and-Run/Getting-Started.md @@ -21,7 +21,7 @@ In development the app needs **only a database and an auth secret**. Cloudflare R2 and Resend are **not** required — file uploads land in `.dev-uploads/` and emails are printed to the terminal (lines prefixed `📧 [DEV EMAIL]`). The switch is automatic, driven by `NODE_ENV` (`next dev` → development, `next build/start` -→ production). See [File Storage](File-Storage) and [Notifications](Notifications). +→ production). See [File Storage](Product/File-Storage) and [Notifications](Product/Notifications). ## Setup @@ -46,7 +46,7 @@ pnpm dev # Next.js + Turbopack at http://localhost:3000 > `auth.ts` reads the Azure/Entra SSO variables at **module load**. In a non-SSO > dev environment, set placeholder values for `AZURE_AD_*` so the app boots. See -> [Environment Variables](Environment-Variables). +> [Environment Variables](Build-and-Run/Environment-Variables). ## Seed credentials @@ -95,7 +95,7 @@ pnpm email:preview # live-preview email templates at http://localhost:3001 - **GstService** (`GstService/`) — a small Express + Playwright microservice that proxies the GST portal CAPTCHA/lookup. Optional in dev; defaults to - `http://localhost:3003`. See [Vendors and GST Lookup](Vendors-and-GST-Lookup). + `http://localhost:3003`. See [Vendors and GST Lookup](Product/Vendors-and-GST-Lookup). ## Project layout @@ -112,4 +112,4 @@ App/ └── tests/ # unit (Vitest), integration (Vitest+DB), e2e (Playwright) ``` -See [Architecture](Architecture) for the full layer breakdown and [Data Model](Data-Model) for the schema. +See [Architecture](System/Architecture) for the full layer breakdown and [Data Model](System/Data-Model) for the schema. diff --git a/Home.md b/Home.md index cd29bf0..71d0797 100644 --- a/Home.md +++ b/Home.md @@ -29,11 +29,12 @@ This wiki is the project's living reference. It is synthesised from the in-repo ## Start here -- **New to the codebase?** → [Getting Started](Getting-Started) -- **Understanding the system?** → [Architecture](Architecture) · [Data Model](Data-Model) · [PO Lifecycle](PO-Lifecycle) -- **Who can do what?** → [Roles and Permissions](Roles-and-Permissions) -- **What's been built?** → [Feature Catalogue](Feature-Catalogue) · [Pages and Navigation](Pages-and-Navigation) -- **Operating it?** → [Deployment and Operations](Deployment-and-Operations) · [Issue-to-Deploy Pipeline](Issue-to-Deploy-Pipeline) -- **Unsure of a term?** → [Glossary](Glossary) +- **New to the codebase?** → [Getting Started](Build-and-Run/Getting-Started) +- **Understanding the system?** → [Architecture](System/Architecture) · [Data Model](System/Data-Model) · [PO Lifecycle](System/PO-Lifecycle) +- **Who can do what?** → [Roles and Permissions](System/Roles-and-Permissions) +- **What's been built?** → [Feature Catalogue](Product/Feature-Catalogue) · [Pages and Navigation](Product/Pages-and-Navigation) · [Workflows](Product/Workflows) +- **Designing UI?** → [Design System](Product/Design-System) +- **Operating it?** → [Deployment and Operations](Ops/Deployment-and-Operations) · [Issue-to-Deploy Pipeline](Ops/Issue-to-Deploy-Pipeline) +- **Unsure of a term?** → [Glossary](Overview/Glossary) -> The full page list is in the sidebar. See [Changelog](Changelog) for what shipped recently and [Open Questions](Open-Questions) for decisions still pending sign-off. +> The full page list is in the sidebar. See [Changelog](Overview/Changelog) for what shipped recently and [Open Questions](Overview/Open-Questions) for decisions still pending sign-off. diff --git a/Deployment-and-Operations.md b/Ops/Deployment-and-Operations.md similarity index 96% rename from Deployment-and-Operations.md rename to Ops/Deployment-and-Operations.md index 43e3a7f..3f08bf3 100644 --- a/Deployment-and-Operations.md +++ b/Ops/Deployment-and-Operations.md @@ -37,7 +37,7 @@ same host. All production env vars must be set (auth, DB, R2, Resend, optionally Forgejo/GST). Server-side env lives in `~/pms/App/.env`. The full list and the -dev/prod split is on [Environment Variables](Environment-Variables). +dev/prod split is on [Environment Variables](Build-and-Run/Environment-Variables). ## Release & deploy flow @@ -66,7 +66,7 @@ Watch progress under **Actions** in Forgejo, or `pm2 logs forgejo-runner`. > not-yet-migrated column yields `P2022 … column does not exist` at runtime. The > deploy workflow runs `migrate deploy` for you; for manual deploys, run it (and > restart) before/with the swap. This was a real production incident — see -> [Changelog](Changelog). +> [Changelog](Overview/Changelog). ## Staging (smoke test before deploy) @@ -106,5 +106,5 @@ data.** to missing fork information" even when `mergeable: true`. Fix: close and reopen the PR (UI or API). Resolves on upgrade past v10. -See [Issue-to-Deploy Pipeline](Issue-to-Deploy-Pipeline) for the automation, and +See [Issue-to-Deploy Pipeline](Ops/Issue-to-Deploy-Pipeline) for the automation, and `automation/README.md` for the full runbook. diff --git a/Issue-to-Deploy-Pipeline.md b/Ops/Issue-to-Deploy-Pipeline.md similarity index 98% rename from Issue-to-Deploy-Pipeline.md rename to Ops/Issue-to-Deploy-Pipeline.md index 791c056..5179525 100644 --- a/Issue-to-Deploy-Pipeline.md +++ b/Ops/Issue-to-Deploy-Pipeline.md @@ -91,5 +91,5 @@ So the fix stage verifies against realistic data without touching production: - Schema-migration issues are routed to `interactive`, so the unattended fixer should not be altering the schema. -See [Deployment and Operations](Deployment-and-Operations) for the deploy +See [Deployment and Operations](Ops/Deployment-and-Operations) for the deploy workflow and staging, and `automation/README.md` for the authoritative runbook. diff --git a/Changelog.md b/Overview/Changelog.md similarity index 87% rename from Changelog.md rename to Overview/Changelog.md index 8e3f3df..1efd512 100644 --- a/Changelog.md +++ b/Overview/Changelog.md @@ -2,7 +2,7 @@ Mirrors `CHANGELOG.md` at the repo root (the authoritative copy). Releases are tagged `vX.Y.Z`; the deployed production version is whichever tag is currently -checked out in `~/pms`. See [Deployment and Operations](Deployment-and-Operations). +checked out in `~/pms`. See [Deployment and Operations](Ops/Deployment-and-Operations). ## [Unreleased] @@ -12,10 +12,10 @@ checked out in `~/pms`. See [Deployment and Operations](Deployment-and-Operation `/admin/companies` CRUD. A PO is billed under a selected company (name, short `code`, GST number, address, phone/mobile, contact + invoice email, invoice address); details populate the exported PO header / invoice block. See - [Purchase Orders](Purchase-Orders#companies-multi-company-invoicing). + [Purchase Orders](Product/Purchase-Orders#companies-multi-company-invoicing). - **Structured PO numbers** (`lib/po-number.ts`) — `COMPANY/VESSEL/ID/FY`; Indian financial year; system IDs start at 9000; imported POs keep their original - number. See [Purchase Orders](Purchase-Orders#po-numbering). + number. See [Purchase Orders](Product/Purchase-Orders#po-numbering). - **3-level accounting-code hierarchy** — `Account.parentId` self-relation (Top → Sub → Leaf), 6-digit codes seeded from `prisma/accounting-codes-data.ts`. Only leaf codes are PO-selectable, via a @@ -26,24 +26,24 @@ checked out in `~/pms`. See [Deployment and Operations](Deployment-and-Operation `poDate ?? approvedAt ?? createdAt`. - **Submitter vendor creation** — `create_vendor` lets Technical/Manning add vendors; created **unverified**, verified when a PO closes/pays with them, on - import, or via Manager/Accounts/Admin. See [Vendors](Vendors-and-GST-Lookup). + import, or via Manager/Accounts/Admin. See [Vendors](Product/Vendors-and-GST-Lookup). - **Import PO → Closed** — `/po/import` saves a parsed Excel PO directly as `CLOSED`, auto-detecting company, matching vessel, auto-creating vendor, products, and per-vendor prices. - **Inventory feature flag** (`NEXT_PUBLIC_INVENTORY_ENABLED`) — site stock/consumption gated; PO catalogue stays available. Inventory increments at - **PO approval**. See [Inventory and Catalogue](Inventory-and-Catalogue). + **PO approval**. See [Inventory and Catalogue](Product/Inventory-and-Catalogue). - **Dashboards** — Accounts gains a "Payments Completed This Month" card. - **Automated issue-to-deploy pipeline** — Report Issue button → Forgejo issue → Claude watcher triage/fix → PR → tag-triggered deploy. See - [Issue-to-Deploy Pipeline](Issue-to-Deploy-Pipeline). + [Issue-to-Deploy Pipeline](Ops/Issue-to-Deploy-Pipeline). ### Changed - **Cost centre is now a Vessel only.** The Vessel-or-Site cost-centre model was removed: `PurchaseOrder.vesselId` is required, `costCentreRef` is gone, and `Vessel` no longer links to a `Site`. Vessels are surfaced as **"Cost Centre"** - (`/admin/vessels` → "Cost Centre Management"). See [Glossary](Glossary). + (`/admin/vessels` → "Cost Centre Management"). See [Glossary](Overview/Glossary). - **Closed PO list** — submitters see only their own `CLOSED` POs; Managers/SuperUsers see all. - **Sidebar** reorganised into **Purchasing** and **Administration** (role-aware); @@ -60,7 +60,7 @@ checked out in `~/pms`. See [Deployment and Operations](Deployment-and-Operation - Production `P2022 … column does not exist` after deploy — caused by shipping code whose Prisma client expected a column before `migrate deploy` ran. Migrations must be applied before the new build serves traffic (now in the - README and the [deploy workflow](Deployment-and-Operations#release--deploy-flow)). + README and the [deploy workflow](Ops/Deployment-and-Operations#release--deploy-flow)). --- diff --git a/Glossary.md b/Overview/Glossary.md similarity index 92% rename from Glossary.md rename to Overview/Glossary.md index fd0ad25..767a8f8 100644 --- a/Glossary.md +++ b/Overview/Glossary.md @@ -6,7 +6,7 @@ original design — the definitions below are the **shipped** meanings. | Term | Meaning | |---|---| | **PPMS** | "Pelagia Payment Management System" — the in-UI brand for Pelagia Portal (login, sidebar, title). | -| **Purchase Order (PO)** | The central record: a request to buy goods/services, tracked through its [lifecycle](PO-Lifecycle) from DRAFT to CLOSED. | +| **Purchase Order (PO)** | The central record: a request to buy goods/services, tracked through its [lifecycle](System/PO-Lifecycle) from DRAFT to CLOSED. | | **Cost Centre** | **A Vessel.** Every PO is raised against a Vessel (`PurchaseOrder.vesselId`, required). Surfaced as "Cost Centre" everywhere in the UI (`/admin/vessels` → "Cost Centre Management"). The earlier Vessel-or-Site cost-centre model was removed. | | **Vessel** | A ship; the cost centre a PO is charged to. Has a unique `code` used in PO numbers. | | **Accounting Code** | A budget head: a leaf in the 3-level `Account` hierarchy (Top Category → Sub-Category → Leaf), 6-digit numeric. Only leaf codes are PO-selectable. Previously labelled "Account". | @@ -14,7 +14,7 @@ original design — the definitions below are the **shipped** meanings. | **PO Number** | Auto-formatted `COMPANY/VESSEL/ID/FY` (e.g. `PMS/HNR1/9000/2024-25`). System IDs start at 9000; imported POs keep their original number. | | **FY** | Indian financial year (Apr–Mar), rendered `YYYY-YY` in PO numbers. | | **Vendor** | A supplier. Submitter-created vendors are **unverified** until a PO closes/pays with them, on import, or a Manager/Accounts/Admin verifies. The formal `vendorId` is the verified code. | -| **GSTIN** | 15-char Indian GST identification number; looked up via the [GST microservice](Vendors-and-GST-Lookup) to auto-fill vendor details. | +| **GSTIN** | 15-char Indian GST identification number; looked up via the [GST microservice](Product/Vendors-and-GST-Lookup) to auto-fill vendor details. | | **Site** | A port/depot/office that holds inventory; used for delivery and vendor-distance sourcing. **Not** a cost centre. | | **Product / Item** | A catalogue entry (`code`, `name`). Tracks `lastPrice`/`lastVendor` and per-vendor prices, updated on payment. | | **Line Item** | A row on a PO: name, qty, unit, unit price, GST rate; optional product link and per-line accounting code. | @@ -27,5 +27,5 @@ original design — the definitions below are the **shipped** meanings. | **pms1** | The single Ubuntu server hosting the app, DB, Forgejo, and CI runner. | | **`ppms`** | The pm2 process running the production app on port 3000. | | **`pelagia` / `pelagia_test`** | Production DB / its daily mirror used for staging + autofix verification. | -| **Report Issue** | Header button that files a Forgejo issue, kicking off the [issue-to-deploy pipeline](Issue-to-Deploy-Pipeline). | +| **Report Issue** | Header button that files a Forgejo issue, kicking off the [issue-to-deploy pipeline](Ops/Issue-to-Deploy-Pipeline). | | **Staging** | A deployed instance of latest `master` (pm2 `ppms-staging`, port 3200, SSH-tunnel only) for pre-release smoke testing. | diff --git a/Open-Questions.md b/Overview/Open-Questions.md similarity index 92% rename from Open-Questions.md rename to Overview/Open-Questions.md index 8d3819d..3710e7d 100644 --- a/Open-Questions.md +++ b/Overview/Open-Questions.md @@ -12,10 +12,10 @@ product — annotated below. Update as they resolve. | 4 | Is SSO required, or is internal credential management enough? | **Resolved** — both: Microsoft Entra SSO **and** a credentials provider; SSO users have nullable passwords. | | 5 | What currency/currencies? Multi-currency with FX in scope? | **Partly** — `currency` defaults to `INR`; multi-currency/FX not implemented. | | 6 | Hard-delete vs permanent archive for rejected POs; retention window? | **Open**. | -| 7 | Public document URLs vs always-signed/authenticated downloads? | **Resolved** — downloads are auth-gated/presigned (dev route 404s in prod). See [File Storage](File-Storage). | +| 7 | Public document URLs vs always-signed/authenticated downloads? | **Resolved** — downloads are auth-gated/presigned (dev route 404s in prod). See [File Storage](Product/File-Storage). | | 8 | Row-level vessel/account restrictions per submitter? | **Open** — any submitter can raise a PO against any cost centre. | | 9 | Expected volume (POs/day, concurrent users) — for pool sizing / `pms1` resourcing? | **Open**. | -| 10 | Should manager analytics count only CLOSED POs, or all from MGR_APPROVED onwards? | **Resolved** — "Approved this month" counts by `approvedAt` (all POs approved in the period), not just those currently in `MGR_APPROVED`. See [Changelog](Changelog). | +| 10 | Should manager analytics count only CLOSED POs, or all from MGR_APPROVED onwards? | **Resolved** — "Approved this month" counts by `approvedAt` (all POs approved in the period), not just those currently in `MGR_APPROVED`. See [Changelog](Overview/Changelog). | For the design-era spec context, see `Docs/01-design-document.md` and `Docs/DESIGN.md`. diff --git a/Product/Design-System.md b/Product/Design-System.md new file mode 100644 index 0000000..e671538 --- /dev/null +++ b/Product/Design-System.md @@ -0,0 +1,74 @@ +# Design System + +Visual language and UI conventions, migrated from the original design spec +(`Docs/01-design-document.md` §7, §9 and `Docs/DESIGN.md` §9, now retired). These +are the design intentions; the implemented source of truth is Tailwind v4 + +shadcn/ui in `App/components/`. + +## Colour palette + +| Token | Hex | Usage | +|---|---|---| +| `primary` | `#2563EB` | Primary actions, active states, links | +| `primary-dark` | `#1D4ED8` | Hover on primary | +| `success` | `#16A34A` | Approved, paid, closed states | +| `warning` | `#D97706` | Pending review, edits requested | +| `danger` | `#DC2626` | Rejected, destructive actions | +| `neutral-50` | `#F9FAFB` | Page background | +| `neutral-100` | `#F3F4F6` | Card / panel background | +| `neutral-700` | `#374151` | Body text | +| `neutral-900` | `#111827` | Headings | + +## Typography + +| Element | Font | Weight | Size | +|---|---|---|---| +| Headings (H1–H3) | Inter | 600–700 | 24 / 20 / 16 px | +| Body | Inter | 400 | 14 px | +| Labels / captions | Inter | 500 | 12 px | +| Data / mono values | JetBrains Mono | 400 | 13 px | + +## Component conventions + +- Cards: `rounded-lg`, `shadow-sm`, 16 px padding. +- Status badges: pill shape, colour-coded to match the + [PO lifecycle](System/PO-Lifecycle#status-badges) state colours. +- Tables: alternating row shading, sticky header on scroll. +- Forms: floating labels; validation errors below the field in `danger` colour. +- Buttons: primary = blue fill, secondary = white with border, danger = red fill. +- Admin action buttons (Edit / Delete) are **bordered** (asserted in E2E). + +## Key UI patterns + +- **Status badges** — every PO status has a distinct colour (see the lifecycle + page); colour is never the sole signal (icon + label accompany it). +- **Confirm-before-destruction** — Delete uses a two-step *inline* confirm + ("Delete X? Confirm / Cancel") that replaces the button in place — no modal. +- **Inline table editing** — manager line-item editing happens inline on the + approval page (not a modal) so the rest of the PO stays visible. +- **Live GST summary** — below the line-items table: Taxable, GST, Grand Total + update as you type. See [Purchase Orders](Product/Purchase-Orders#gst-calculation). +- **Product autocomplete** — typing in a line-item name field fuzzy-searches the + catalogue; the dropdown shows product name/code and per-vendor price hints + (e.g. "Vendor A: ₹1,200 · Vendor B: ₹1,050"). +- **Cheapest / ★ Closest tags** — computed independently so both can show at + once. See [Inventory and Catalogue](Product/Inventory-and-Catalogue#cheapest--closest-tags). +- **Cart persistence** — `localStorage` under a fixed key; survives navigation, + local to the device/user; a `cart-updated` event lets components react live. +- **Mobile** — Manager/Accounts get mobile cards + a bottom nav; other roles get + a "Desktop Required" overlay. See + [Pages and Navigation](Product/Pages-and-Navigation#mobile). +- **Environment banner** — a fixed non-prod banner via `NEXT_PUBLIC_ENV_LABEL` + (`EnvBanner`); renders nothing in production. + +## Accessibility & i18n + +- Target **WCAG 2.1 AA**. +- All interactive elements keyboard-navigable with a visible focus ring. +- Colour is never the sole conveyor of meaning (icons + labels accompany status + colours). +- English-only for v1; an i18n architecture (react-i18next) was envisioned to be + wired but not populated. + +> A non-functional **Reports** UX mockup also exists in the wiki +> (`Reports-Mockup`) — proposed layouts and chart treatments for spend reporting. diff --git a/Feature-Catalogue.md b/Product/Feature-Catalogue.md similarity index 86% rename from Feature-Catalogue.md rename to Product/Feature-Catalogue.md index 56a9d46..9b3e6f4 100644 --- a/Feature-Catalogue.md +++ b/Product/Feature-Catalogue.md @@ -7,12 +7,12 @@ with the detail, or names the code that implements it. - **Full PO lifecycle** — DRAFT → … → CLOSED with manager approval, vendor validation, payment, and receipt confirmation. Enforced by - [the state machine](PO-Lifecycle); every change is an audit row. + [the state machine](System/PO-Lifecycle); every change is an audit row. - **Partial payments & partial receipts** — `PARTIALLY_PAID` / `PARTIALLY_CLOSED` loop until fully settled (`deliveredQuantity` per line). - **Structured PO numbers** — `COMPANY/VESSEL/ID/FY` (e.g. `PMS/HNR1/9000/2024-25`); system IDs start at 9000; imported POs keep their original number. - See [Purchase Orders](Purchase-Orders#po-numbering). + See [Purchase Orders](Product/Purchase-Orders#po-numbering). - **GST-inclusive totals** — per-line `gstRate` (default 18%); live taxable/GST/ grand-total summary in the form. - **Manager line-item editing** — managers adjust quantities, prices, GST, @@ -28,18 +28,18 @@ with the detail, or names the code that implements it. ## Catalogue, vendors, inventory - **Multi-company invoicing** — bill a PO under a sister company (PMS/HNR/DEI); - details flow to the exported PO. See [Data Model](Data-Model#company--multi-company-invoicing). + details flow to the exported PO. See [Data Model](System/Data-Model#company--multi-company-invoicing). - **3-level accounting codes** — Top → Sub → Leaf (6-digit); only leaf codes selectable, via a searchable combobox. - **Vendor management** — submitter-created (unverified) vendors; auto-verify-on-payment; **GSTIN lookup** via the GST microservice; geocoded - vendor-distance sourcing. See [Vendors and GST Lookup](Vendors-and-GST-Lookup). + vendor-distance sourcing. See [Vendors and GST Lookup](Product/Vendors-and-GST-Lookup). - **Product catalogue** — editable at `/admin/products`, read-only at `/inventory/items`; per-vendor price history; "Cheapest" / "★ Closest" tags. - **Cart** — collect items (localStorage) → create a PO pre-filled. - **Site inventory (feature-flagged)** — stock per site, daily consumption log; inventory incremented at PO **approval**. Gated by - `NEXT_PUBLIC_INVENTORY_ENABLED`. See [Inventory and Catalogue](Inventory-and-Catalogue). + `NEXT_PUBLIC_INVENTORY_ENABLED`. See [Inventory and Catalogue](Product/Inventory-and-Catalogue). ## Platform @@ -64,8 +64,8 @@ with the detail, or names the code that implements it. - **Report Issue button** — any signed-in user files a Forgejo issue from the header (`lib/forgejo.ts`). - **Automated issue→fix→PR pipeline** + **tag-triggered deploy**. See - [Issue-to-Deploy Pipeline](Issue-to-Deploy-Pipeline). + [Issue-to-Deploy Pipeline](Ops/Issue-to-Deploy-Pipeline). - **Staging instance** against a daily **prod-mirror test DB** for smoke testing. -For the screen-by-screen breakdown, see [Pages and Navigation](Pages-and-Navigation). -For what shipped recently, see [Changelog](Changelog). +For the screen-by-screen breakdown, see [Pages and Navigation](Product/Pages-and-Navigation). +For what shipped recently, see [Changelog](Overview/Changelog). diff --git a/File-Storage.md b/Product/File-Storage.md similarity index 97% rename from File-Storage.md rename to Product/File-Storage.md index 05d2ec4..9ccb0ef 100644 --- a/File-Storage.md +++ b/Product/File-Storage.md @@ -58,4 +58,4 @@ R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, R2_PUBLIC ``` In development these can be left as placeholders. See -[Environment Variables](Environment-Variables). +[Environment Variables](Build-and-Run/Environment-Variables). diff --git a/Inventory-and-Catalogue.md b/Product/Inventory-and-Catalogue.md similarity index 98% rename from Inventory-and-Catalogue.md rename to Product/Inventory-and-Catalogue.md index 3cb36c7..04a7268 100644 --- a/Inventory-and-Catalogue.md +++ b/Product/Inventory-and-Catalogue.md @@ -50,7 +50,7 @@ regardless of whether the list is sorted by Price or Distance. Selecting a site also auto-switches the active sort to **Distance** (a `useEffect` keyed on the site id resets it on every site change — important because Next.js soft navigation preserves React state). With no site selected, neither distance tag -shows. See [Testing](Testing) for the specs pinning this down. +shows. See [Testing](Quality/Testing) for the specs pinning this down. ## Cart diff --git a/Notifications.md b/Product/Notifications.md similarity index 95% rename from Notifications.md rename to Product/Notifications.md index 5982b46..93bfd82 100644 --- a/Notifications.md +++ b/Product/Notifications.md @@ -32,7 +32,7 @@ The switch is automatic on `NODE_ENV`. Preview templates live with ## Event → recipient matrix Driven by the side-effects declared per transition in the -[state machine](PO-Lifecycle#transition-table): +[state machine](System/PO-Lifecycle#transition-table): | Event | Side-effect | Notified | |---|---|---| @@ -64,5 +64,5 @@ Separate from PO notifications: any signed-in user can file a bug from the heade via the **Report Issue** button (`components/layout/report-issue-button.tsx` → `report-issue-actions.ts` → `lib/forgejo.ts`), which creates a Forgejo issue labelled `portal`. That kicks off the -[Issue-to-Deploy Pipeline](Issue-to-Deploy-Pipeline). Requires `FORGEJO_URL`, +[Issue-to-Deploy Pipeline](Ops/Issue-to-Deploy-Pipeline). Requires `FORGEJO_URL`, `FORGEJO_REPO`, `FORGEJO_TOKEN` (token scope `write:issue`). diff --git a/Pages-and-Navigation.md b/Product/Pages-and-Navigation.md similarity index 100% rename from Pages-and-Navigation.md rename to Product/Pages-and-Navigation.md diff --git a/Purchase-Orders.md b/Product/Purchase-Orders.md similarity index 95% rename from Purchase-Orders.md rename to Product/Purchase-Orders.md index aff4d81..5841a24 100644 --- a/Purchase-Orders.md +++ b/Product/Purchase-Orders.md @@ -2,8 +2,8 @@ This page covers the mechanics specific to purchase orders: numbering, GST, the create/edit forms, company invoicing, accounting codes, and Excel import. -For the status graph see [PO Lifecycle](PO-Lifecycle); for the schema see -[Data Model](Data-Model). +For the status graph see [PO Lifecycle](System/PO-Lifecycle); for the schema see +[Data Model](System/Data-Model). ## PO numbering @@ -57,7 +57,7 @@ PO `totalAmount`. (`/api/products/search`). 3. **Terms & Conditions** — Delivery, Dispatch, Inspection, Transit Insurance, Payment Terms, Others (all optional text → `tc*` fields). -4. **Documents** — drag-and-drop / browse uploader (see [File Storage](File-Storage)). +4. **Documents** — drag-and-drop / browse uploader (see [File Storage](Product/File-Storage)). Footer: **Save as Draft** / **Submit for Approval** (and **Update & Resubmit** when editing an `EDITS_REQUESTED` PO, which returns it to `MGR_REVIEW`). @@ -68,7 +68,7 @@ Validation lives in `lib/validations/po.ts` (Zod), which also exports > **Form selector gotcha** (for tests): the PO form labels are visual-only — no > `htmlFor`/`id` binding. Use `name`-attribute selectors -> (`input[name="title"]`, `select[name="vesselId"]`). See [Testing](Testing). +> (`input[name="title"]`, `select[name="vesselId"]`). See [Testing](Quality/Testing). ## Companies (multi-company invoicing) @@ -87,7 +87,7 @@ groups leaf codes by sub-category in a searchable, portal-rendered combobox `accountId`. Seed data: `prisma/accounting-codes-data.ts`. > "Accounting Code" replaces the older "Account" label. The **Cost Centre** is a -> separate concept — it is the Vessel. See [Glossary](Glossary). +> separate concept — it is the Vessel. See [Glossary](Overview/Glossary). ## Payments diff --git a/Vendors-and-GST-Lookup.md b/Product/Vendors-and-GST-Lookup.md similarity index 95% rename from Vendors-and-GST-Lookup.md rename to Product/Vendors-and-GST-Lookup.md index d9417af..dc27aee 100644 --- a/Vendors-and-GST-Lookup.md +++ b/Product/Vendors-and-GST-Lookup.md @@ -1,7 +1,7 @@ # Vendors and GST Lookup Vendors are suppliers a PO can be raised against. The model and its evolution -are on [Data Model](Data-Model#vendor--vendorcontact); this page covers the +are on [Data Model](System/Data-Model#vendor--vendorcontact); this page covers the verification lifecycle, distance-based sourcing, and the GST microservice that backs GSTIN lookup. @@ -33,7 +33,7 @@ and a `VendorContact[]` list (name, role, mobile, email, isPrimary). Managed at detail / items pages, selecting a **Site** re-sorts vendors by proximity to that site; the nearest vendor gets a **★ Closest** tag and the lowest price gets a **Cheapest** tag — computed independently so both can show at once, regardless -of the active sort. See [Inventory and Catalogue](Inventory-and-Catalogue). +of the active sort. See [Inventory and Catalogue](Product/Inventory-and-Catalogue). ## GSTIN lookup (GstService) diff --git a/Product/Workflows.md b/Product/Workflows.md new file mode 100644 index 0000000..b2ad70b --- /dev/null +++ b/Product/Workflows.md @@ -0,0 +1,157 @@ +# Workflows + +Step-by-step user workflows, migrated from the original UI/UX spec +(`Docs/DESIGN.md`, now retired). For the screen list see +[Pages and Navigation](Product/Pages-and-Navigation); for the status graph see +[PO Lifecycle](System/PO-Lifecycle). + +## Submit a purchase order (Technical / Manning) + +1. Click **New PO** in the sidebar. +2. Select **Cost Centre** (Vessel) and **Accounting Code**. +3. Add line items — type a name to search the catalogue; previous vendor prices + appear as hints. +4. Optionally attach documents and fill in Terms & Conditions. +5. Click **Submit for Approval** → Manager is emailed; status shows "Under + Review" on My Orders. +6. If the manager **requests edits**: the PO shows `EDITS_REQUESTED` with the + note; edit and resubmit. +7. If the manager **requests a vendor ID**: select a vendor and submit; the PO + returns to the manager queue. +8. On **approval**: you're emailed and the PO appears in the Accounts payment + queue. + +## Approve a purchase order (Manager) + +1. Open **Approvals**; see the pending count. +2. Click **Review** on a PO; read line items, vendor, documents, notes. +3. Optionally **Edit** to adjust quantities/prices/GST or change + vendor/vessel/account inline (logged as `MANAGER_LINE_EDIT`). +4. Choose an action: + - **Approve** → moves to the Accounts payment queue. + - **Approve with Note** → same, with a note visible to the submitter. + - **Request Edits** → write a note; PO returns to the submitter. + - **Request Vendor ID** → PO returns to the submitter to select a vendor. + - **Reject** → write a reason; PO is closed permanently. + +> A vendor must be assigned before approval, and only **verified** vendors may be +> assigned. See [Roles and Permissions](System/Roles-and-Permissions). + +## Process a payment (Accounts) + +1. Open **Payments**; see cards for `MGR_APPROVED` POs. +2. **Send for Payment** → notifies submitter and manager. +3. When the bank/finance confirms, **Mark as Paid** (capturing the **compulsory + payment date** — no future dates) → notifies all parties. Partial payments + loop via `PARTIALLY_PAID` until fully settled. +4. The submitter can now upload a delivery receipt. + +## Confirm receipt (Technical / Manning) + +1. Goods are delivered to the vessel/site. +2. Open the PO detail (status `PAID_DELIVERED`). +3. **Confirm Receipt** → upload the delivery receipt and optionally add notes. +4. Submit → PO is `CLOSED` (or `PARTIALLY_CLOSED` for a partial receipt); + accounts and manager are notified. + +## Look up a vendor by GSTIN (Manager / Admin) + +1. Open the Add/Edit Vendor form. +2. Type the 15-digit GSTIN and click **Look up** → a CAPTCHA image loads from the + GST microservice. +3. Type the 6-digit CAPTCHA and click **Verify** → the form auto-fills legal + name, address, and pincode. +4. Save; location is geocoded silently from the pincode for distance sorting. + +Detail: [Vendors and GST Lookup](Product/Vendors-and-GST-Lookup). + +## Source items by proximity (Manager) + +1. Open **Items** → click an item name. +2. See all vendors that supply it with their last quoted price. +3. Select a **site** from the "Sort by distance from" dropdown. +4. The table re-sorts by proximity; distance shows per row; the closest vendor is + marked **★** and the cheapest is tagged **Cheapest**. +5. **Add to Cart** on the desired vendor row. + +## Create a PO from the cart (Manager / Technical) + +1. Add items to the cart from item detail pages. +2. Open **Cart**; adjust quantities, remove items, select a delivery site. +3. **Create PO** → opens New PO pre-filled with the cart line items and vendor. +4. Fill in title, cost centre, accounting code; submit normally. + +## Track inventory at a site (Manager / Admin) + +1. Open **Sites** → click a site. +2. View the current-stock bar chart and the 30-day consumption line chart. +3. Use **Log Consumption** to record a daily drawdown (product, date, quantity, + note). See [Inventory and Catalogue](Product/Inventory-and-Catalogue). + +## Import a PO from Excel (Manager / SuperUser / Admin) + +1. Open **Import PO** and upload a Pelagia-format `.xlsx`. +2. The parser extracts line items, vendor, and quotation details; the company is + auto-detected and the vessel auto-matched by code. +3. The PO is saved **directly as `CLOSED`** (a historical record), auto-creating + the vendor and any unknown products. See + [Purchase Orders](Product/Purchase-Orders#import-po--closed). + +## Export PO history (Auditor / Manager) + +1. Open **History**; apply filters (date range, cost centre, one or more + statuses). +2. **Export PDF** or **Export CSV** → downloads the matching POs (up to ~200). + +--- + +## User stories (priority reference) + +From the original spec (`Docs/01-design-document.md` §8); IDs are referenced by +the [Test Plan](Quality/Test-Plan). P0 = must-have, P1 = should-have. + +**Submitter (Technical / Manning)** + +| ID | Story | Pri | +|---|---|---| +| S-01 | Create a PO with line items and attach documents | P0 | +| S-02 | Save a PO as draft before submitting | P0 | +| S-03 | Submit a draft PO for approval | P0 | +| S-04 | Receive email when my PO is approved/rejected | P0 | +| S-05 | View status and history of all my POs | P0 | +| S-06 | Provide a vendor ID when requested | P0 | +| S-07 | Edit and resubmit when edits are requested | P0 | +| S-08 | Confirm receipt and upload a receipt to close a PO | P0 | + +**Manager** + +| ID | Story | Pri | +|---|---|---| +| M-01 | See all POs awaiting my approval | P0 | +| M-02 | Approve / reject / request edits | P0 | +| M-03 | Add a note when approving or rejecting | P0 | +| M-04 | Flag a PO for vendor-ID verification | P0 | +| M-05 | View spend analytics by cost centre and month | P1 | +| M-06 | Export a full PO history report (CSV/PDF) | P1 | + +**Accounts** + +| ID | Story | Pri | +|---|---|---| +| A-01 | See all manager-approved POs ready for payment | P0 | +| A-02 | Mark a PO as paid with a reference | P0 | +| A-03 | Receive email when a PO enters my payment queue | P0 | + +**Admin** + +| ID | Story | Pri | +|---|---|---| +| AD-01 | Create, edit, deactivate user accounts | P0 | +| AD-02 | Manage cost centres, accounting codes, vendors | P0 | +| AD-03 | Manage the product catalogue | P1 | + +## Non-goals (out of scope) + +Mobile-native app (web is desktop-first), public-facing pages, self-registration +/ generic OAuth, a vendor self-service portal, and automated +bank/payment-gateway integration (payment is marked manually). diff --git a/Quality/E2E-Test-Framework.md b/Quality/E2E-Test-Framework.md new file mode 100644 index 0000000..4c86c67 --- /dev/null +++ b/Quality/E2E-Test-Framework.md @@ -0,0 +1,311 @@ +# PPMS — E2E Test Framework Reference + +> _Migrated from the retired `Docs/e2e-test-framework.md`. Index: [Testing](Quality/Testing)._ + +This document describes the Playwright-based end-to-end test framework for the +PPMS portal: its stack, directory layout, configuration, shared utilities, and +the conventions every spec must follow. + +--- + +## Stack + +| Layer | Tool | Version | +|---|---|---| +| Test runner | `@playwright/test` | 1.60 | +| Browser | Chromium (headless) | bundled with Playwright | +| Language | TypeScript | inherits from app `tsconfig.json` | +| Package manager | pnpm | same as portal app | +| App server | Next.js 15 dev server (`pnpm dev`) | auto-started by Playwright config | + +--- + +## Directory Layout + +``` +App/pelagia-portal/ +├── playwright.config.ts # Root config — workers, retries, baseURL, webServer +└── tests/ + ├── e2e/ + │ ├── helpers/ + │ │ ├── login.ts # Shared login(), createDraftPo(), submitPo(), USERS + │ │ └── auth.js # Legacy plain-JS login helper (pre-existing) + │ ├── dashboard/ + │ │ └── po-status-badges.js + │ ├── inventory/ + │ │ ├── items-tags.spec.ts + │ │ └── cart-icon.spec.ts + │ ├── mobile/ + │ │ ├── desktop-required.spec.ts + │ │ ├── manager-approvals.spec.ts + │ │ ├── accounts-payments.spec.ts + │ │ └── bottom-nav.spec.ts + │ ├── admin-bordered-buttons.spec.ts + │ ├── approvals-edit-highlight.spec.ts + │ ├── export-gate.spec.ts + │ ├── notification-bell.spec.ts + │ ├── partial-receipt.spec.ts + │ ├── payment-history.spec.ts + │ ├── po-submit-button.spec.ts + │ ├── profile.spec.ts + │ ├── rebrand.spec.ts + │ └── vendor-auto-verify.spec.ts + ├── integration/ # Vitest integration tests (separate suite) + └── unit/ # Vitest unit tests (separate suite) +``` + +--- + +## Configuration (`playwright.config.ts`) + +```ts +export default defineConfig({ + testDir: "./tests/e2e", + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 1, // 1 local retry reduces flakiness from auth concurrency + workers: process.env.CI ? 1 : 2, // 2 local workers — more causes NextAuth bcrypt flooding + reporter: "html", + use: { + baseURL: "http://localhost:3000", + trace: "on-first-retry", + }, + webServer: { + command: "pnpm dev", + url: "http://localhost:3000", + reuseExistingServer: !process.env.CI, // reuse running dev server locally + }, +}); +``` + +### Why workers: 2 + +The app uses NextAuth v5 with bcrypt password hashing for every login. Under high +parallelism (the default of ~50% CPU cores) all workers attempt to authenticate +simultaneously, overwhelming the dev server and causing login redirects to time out. +Two workers provide enough parallelism to keep the suite fast without triggering +the concurrency limit. + +--- + +## Shared Helpers (`tests/e2e/helpers/login.ts`) + +### `USERS` — seed credentials + +```ts +export const USERS = { + TECH: { email: "tech@pelagia.local", password: "tech1234" }, + MANNING: { email: "manning@pelagia.local", password: "manning1234" }, + ACCOUNTS: { email: "accounts@pelagia.local", password: "accounts1234" }, + MANAGER: { email: "manager@pelagia.local", password: "manager1234" }, + SUPERUSER: { email: "superuser@pelagia.local", password: "super1234" }, + AUDITOR: { email: "auditor@pelagia.local", password: "audit1234" }, + ADMIN: { email: "admin@pelagia.local", password: "admin1234" }, +}; +``` + +### `login(page, creds)` + +Navigates to `/login`, fills credentials, and waits up to **20 s** for the +redirect away from `/login`. The 20 s timeout is intentional — the bcrypt hash +check plus DB round-trip can exceed the Playwright default 5 s under any load. + +```ts +await login(page, USERS.MANAGER); +``` + +### `createDraftPo(page, title)` + +Creates a minimal PO as DRAFT and returns the absolute PO URL. Uses +**`name`-attribute selectors** because the PO form labels have no `htmlFor`/`id` +binding — `getByLabel()` will not resolve. + +```ts +const poUrl = await createDraftPo(page, "Test PO - boiler parts"); +``` + +### `submitPo(page, title)` + +Same as `createDraftPo` but clicks the **Submit for Approval** button instead of +Save as Draft. Returns the PO URL after redirect. + +--- + +## Selector Conventions + +### Critical: PO form has no accessible label bindings + +The new-PO form (`/po/new`) and the edit form use `