# Pelagia Portal — Build Progress

Last updated: 2026-05-05

Legend: ✅ Complete · ⚠️ Partial (works but incomplete) · ❌ Not started

---

## Infrastructure & Config

| Item | Status | Notes |
|---|---|---|
| Next.js 15 App Router project | ✅ | Turbopack dev, strict TS |
| Tailwind CSS v4 + design tokens | ✅ | Colour palette matches spec |
| Prisma schema — all models | ✅ | Product, gstRate, piQuotationNo/Date, requisitionNo/Date, placeOfDelivery, tcDelivery/tcDispatch/tcInspection/tcTransitInsurance/tcPaymentTerms/tcOthers, address/gstin/contactMobile on Vendor — all migrated (latest: `structured_tc_fields`) |
| Database seed script | ✅ | 5 users, 3 vessels, 3 accounts, 3 vendors, 3 sample POs, 4 products |
| Dev / production environment split | ✅ | `NODE_ENV` gates R2 vs local storage, Resend vs console log |
| `.env.example` + `.env` / `.env.local` docs | ✅ | README covers full setup |
| README with dev + prod setup guide | ✅ | |
| CI/CD (GitHub Actions) | ❌ | No workflow files yet |

---

## Authentication & Authorisation

| Item | Status | Notes |
|---|---|---|
| Login page (credentials) | ✅ | Email + password, bcrypt hash |
| NextAuth.js v5 session | ✅ | Database sessions, role in JWT |
| Auth middleware (route protection) | ✅ | Redirects unauthenticated to `/login` |
| Role permissions matrix (`lib/permissions.ts`) | ✅ | All 7 roles; `manage_products` added for Admin |
| SSO / Azure AD login | ❌ | Open question — credentials only for v1 |

---

## PO State Machine (`lib/po-state-machine.ts`)

| Item | Status | Notes |
|---|---|---|
| All 10 statuses defined | ✅ | |
| All transitions with role guards | ✅ | |
| `canPerformAction`, `getAvailableActions` helpers | ✅ | |
| `requiresNote` helper | ✅ | |
| Unit tests | ✅ | `tests/unit/po-state-machine.test.ts` |

---

## Email Notifications (`lib/notifier.ts`)

| Item | Status | Notes |
|---|---|---|
| Notifier module (Resend in prod, console in dev) | ✅ | |
| Email templates (all 7 events) | ✅ | React Email components in `/emails/` |
| Notify on PO submitted | ✅ | Notifies managers + submitter (confirmation) |
| Notify on PO approved / rejected / edits requested | ✅ | Per notification matrix |
| Notify on vendor ID requested / provided | ✅ | |
| Notify on payment processed | ✅ | Notifies managers + accounts on processing; submitter + managers on confirmed |
| Notify on receipt confirmed | ✅ | Notifies managers + accounts |

---

## File Storage (`lib/storage.ts`)

| Item | Status | Notes |
|---|---|---|
| Dev local storage (`/api/files/dev/[...key]`) | ✅ | Auth-gated, path-traversal protected |
| Prod Cloudflare R2 presigned URLs | ✅ | Upload + download URL generation |
| Sign API (`/api/files/sign`) | ✅ | Returns `{ uploadUrl, key }` |
| File upload UI on New PO form | ✅ | `FileUploader` component + `uploadAndLinkFiles` utility; PO created first, then files signed+uploaded+linked |
| File upload UI on Receipt form | ✅ | Same pattern, type `"receipt"` |
| Document download links on PO detail | ✅ | `PoDetail` made async; `generateDownloadUrl` called server-side; filenames are clickable links |

---

## Pages & Server Actions

### Login
| Item | Status |
|---|---|
| Login page + credentials form | ✅ |

### Dashboard
| Item | Status | Notes |
|---|---|---|
| Submitter dashboard (stat cards + New PO CTA) | ✅ | Recent orders table; link to My Orders |
| Manager dashboard (stat cards) | ✅ | |
| Manager dashboard — approved POs listing | ✅ | Recent approved/in-progress POs table with vessel, status, amount |
| Manager dashboard — spend by vessel breakdown | ✅ | Recharts bar chart (top 5 vessels) |
| Manager spend-by-vessel bar chart | ✅ | `SpendCharts` component using Recharts |
| Manager spend-by-month bar chart | ✅ | Last 12 months, bar chart |
| Accounts dashboard (stat cards) | ✅ | |
| Auditor / Admin / generic dashboard | ✅ | Single total-count card |

### New PO
| Item | Status | Notes |
|---|---|---|
| Form (title, vessel, account, vendor, project code, date) | ✅ | |
| Line items — UoM dropdown (15 options) | ✅ | Replaces free-text unit field |
| Line items — Size field | ✅ | Optional free-text |
| Line items — GST rate per item (0 / 5 / 12 / 18 / 28%) | ✅ | Default 18%; taxable / GST / grand-total breakdown shown live in editor |
| PI / Quotation No. + Date | ✅ | Separate section on form |
| Vessel / Office Requisition No. + Date | ✅ | Separate section on form |
| Place of Delivery | ✅ | Pre-filled with company delivery address; editable |
| Terms & Conditions — structured fields | ✅ | Fixed line 1 (read-only); separate inputs for Delivery, Dispatch Instructions, Inspection, Transit Insurance, Payment Terms, Others (multiline); all pre-filled with defaults |
| Currency defaults to INR | ✅ | Changed from USD → INR throughout |
| Save as draft | ✅ | |
| Submit for approval (→ MGR_REVIEW) | ✅ | |
| Document file upload | ✅ | Drag-and-drop + click; signed upload after PO creation |

### PO Detail (`/po/[id]`)
| Item | Status | Notes |
|---|---|---|
| Full detail view (info, vendor, line items, activity trail) | ✅ | |
| New fields displayed (PI/Quotation, Requisition, Delivery, Approved By) | ✅ | |
| Line items with GST breakdown (taxable / GST / grand total) | ✅ | |
| Vendor detail (address, GSTIN, contact name + mobile + email) | ✅ | |
| Terms & Conditions block (structured display) | ✅ | Fixed line 1 always shown; each labeled field (Delivery, Dispatch, etc.) on its own line |
| Export PDF button | ✅ | `/api/po/[id]/export?format=pdf` — auto-triggers print dialog; matches Sample_PO layout |
| Export XLSX button | ✅ | `/api/po/[id]/export?format=xlsx` — SheetJS; matches Sample_PO column layout |
| Confirm Receipt CTA (PAID_DELIVERED state) | ✅ | |
| Document download links | ✅ | Clickable links with server-generated presigned/dev URLs |
| Edit PO link (DRAFT / EDITS_REQUESTED) | ✅ | |

### PO Edit (`/po/[id]/edit`)
| Item | Status | Notes |
|---|---|---|
| Edit page | ✅ | Pre-populated form including all new fields |
| Update draft action | ✅ | |
| Resubmit after edits | ✅ | Shows manager note banner + Resubmit button |

### Vendor ID Flow
| Item | Status | Notes |
|---|---|---|
| Request vendor ID action (manager) | ✅ | Sets status to `VENDOR_ID_PENDING` |
| Provide vendor ID UI (submitter / manager) | ✅ | Inline form on PO detail for VENDOR_ID_PENDING |
| Provide vendor ID server action | ✅ | Transitions back to `MGR_REVIEW`, notifies managers |

### Approvals
| Item | Status | Notes |
|---|---|---|
| Approval queue list | ✅ | |
| PO detail + decision view | ✅ | |
| Approve / Approve+Note actions | ✅ | |
| Reject action | ✅ | |
| Request edits action | ✅ | |
| Request vendor ID action | ✅ | |
| Manager edit line items (amber edit mode) | ✅ | Saves original snapshot to POAction; diff shown with strike-through |
| Search / filter (PO number, vessel, submitter, date) | ✅ | URL search params; `ApprovalsSearch` client component |

### Payments
| Item | Status | Notes |
|---|---|---|
| Payment queue list (MGR_APPROVED + SENT_FOR_PAYMENT) | ✅ | |
| Start payment processing (MGR_APPROVED → SENT_FOR_PAYMENT) | ✅ | Step 1 |
| Confirm payment sent with ref (SENT_FOR_PAYMENT → PAID_DELIVERED) | ✅ | Step 2 — auto-updates Product.lastPrice for linked line items |

### My Orders (`/my-orders`)
| Item | Status | Notes |
|---|---|---|
| My Orders page — all POs with open/past grouping | ✅ | Links to individual PO detail; shows manager note inline |

### Receipt Confirmation
| Item | Status | Notes |
|---|---|---|
| Notes + file receipt confirmation | ✅ | Closes PO to `CLOSED`; optional file attachment via `FileUploader` |

### History
| Item | Status | Notes |
|---|---|---|
| All-POs list (latest 200 by default) | ✅ | |
| CSV export | ✅ | Respects active filters |
| PDF export (bulk) | ✅ | Print-optimised HTML page (`/api/reports/export?format=pdf`); auto-triggers browser print dialog |
| Date range filter | ✅ | URL search params; `HistoryFilters` client component |
| Vessel / status filters | ✅ | Same component |

### Admin — User Management
| Item | Status | Notes |
|---|---|---|
| User list | ✅ | |
| Add user form + action | ✅ | `AdminDialog` modal; bcrypt password hash |
| Edit user form + action | ✅ | Optional password change |
| Deactivate / reactivate user | ✅ | Cannot deactivate own account |

### Admin — Vendor Management
| Item | Status | Notes |
|---|---|---|
| Vendor list | ✅ | |
| Add vendor form + action | ✅ | `AdminDialog` modal; sets `isVerified` if vendorId provided |
| Edit vendor form + action | ✅ | Includes address, GSTIN, contact mobile |
| Deactivate / reactivate vendor | ✅ | |

### Admin — Vessel Management
| Item | Status | Notes |
|---|---|---|
| Vessel list page | ✅ | `/admin/vessels` |
| Add vessel form + action | ✅ | Name-only cost centre creation |
| Edit vessel form + action | ✅ | |
| Deactivate / reactivate vessel | ✅ | |

### Admin — Account Management
| Item | Status | Notes |
|---|---|---|
| Account list page | ✅ | `/admin/accounts` |
| Add account form + action | ✅ | Code uniqueness check |
| Edit account form + action | ✅ | |
| Deactivate / reactivate account | ✅ | |

### Admin — Product Catalogue (`/admin/products`)
| Item | Status | Notes |
|---|---|---|
| Product list (code, name, last price, last vendor) | ✅ | Last price/vendor read-only — auto-populated on payment |
| Create product action | ✅ | Code must be unique |
| Toggle active/inactive action | ✅ | |
| Add product form (UI) | ✅ | `AdminDialog` modal wired to existing `createProduct` action |

---

## Type Safety

| Item | Status | Notes |
|---|---|---|
| Discriminated union narrowing in `approval-actions.tsx` | ✅ | Typed as `{ ok: true } \| { error: string } \| undefined`, checked with `"error" in result` |
| Union narrowing in `receipt-form.tsx` | ✅ | |
| Union narrowing in `new-po-form.tsx` | ✅ | |
| Buffer type in `api/files/dev/route.ts` | ✅ | Cast to `Uint8Array` |
| New PO fields in Prisma types | ⚠️ | Migration applied; Prisma client types stale — resolve by restarting dev server and running `pnpm db:generate` |

---

## Testing

| Item | Status | Notes |
|---|---|---|
| Unit: state machine | ✅ | `tests/unit/po-state-machine.test.ts` — 21 tests |
| Unit: permissions | ✅ | `tests/unit/permissions.test.ts` — 11 tests |
| Unit: utility functions | ✅ | `tests/unit/utils.test.ts` — 17 tests (formatCurrency INR, formatDate, generatePoNumber, status labels/variants) |
| Unit: Zod validation schemas | ✅ | `tests/unit/validations.test.ts` — 24 tests (createPoSchema, lineItemSchema, TC fields, defaults) |
| Component: PoStatusBadge | ✅ | `tests/unit/po-status-badge.test.tsx` — 17 tests (all 10 statuses) |
| Component: LineItemsEditor | ✅ | `tests/unit/po-line-items-editor.test.tsx` — 20 tests (add/remove rows, GST calc, totals, read-only, diff mode) |
| Integration: PO creation (S-01, S-02, S-03) | ✅ | `tests/integration/create-po.test.ts` — 9 tests; uses real DB + mocked auth/notifier |
| Integration: Approval actions (M-02, M-03, M-04, S-06, S-07) | ✅ | `tests/integration/approval-actions.test.ts` — 14 tests |
| Integration: Payment actions (A-01, A-02) | ✅ | `tests/integration/payment-actions.test.ts` — 8 tests |
| E2E: authentication flow | ✅ | `tests/e2e/auth.spec.ts` — 6 tests |
| E2E: submitter journey (S-01 to S-08) | ✅ | `tests/e2e/submitter-journey.spec.ts` — 8 tests |
| E2E: manager approvals (M-01 to M-04) | ✅ | `tests/e2e/manager-approvals.spec.ts` — 9 tests |
| E2E: accounts payment (A-01, A-02) | ✅ | `tests/e2e/accounts-payment.spec.ts` — 6 tests |
| E2E: PO export (PDF + XLSX) | ✅ | `tests/e2e/po-export.spec.ts` — 8 tests (buttons, endpoints, content, auth) |
| Accessibility (axe-core + Playwright) | ❌ | Not yet written |

---

## Summary

| Category | Total items tracked | ✅ Done | ⚠️ Partial | ❌ Pending |
|---|---|---|---|---|
| Infrastructure | 8 | 7 | 0 | 1 |
| Auth & Permissions | 5 | 4 | 0 | 1 |
| State Machine | 5 | 5 | 0 | 0 |
| Email Notifications | 7 | 7 | 0 | 0 |
| File Storage | 6 | 6 | 0 | 0 |
| Pages & Actions | 83 | 83 | 0 | 0 |
| Type Safety | 5 | 4 | 1 | 0 |
| Testing | 15 | 14 | 0 | 1 |
| **Total** | **134** | **130 (97%)** | **1 (1%)** | **3 (2%)** |

---

## Remaining Items

1. **Prisma client regeneration** — restart dev server, then `pnpm db:generate` (DLL was locked during the last generate; migration is fully applied, no data loss)
2. **CI/CD** — GitHub Actions workflow: lint, type-check, test, build on PR; deploy on merge
3. **Accessibility tests** — axe-core + Playwright
4. **SSO / Azure AD** — credentials-only for v1; open question for v2

---

## Not in Spec (deferred)

- SSO / Azure AD login
- Discount field on PO
- Account Group / Account Code hierarchy (codes currently flat)
- Cost centre vs vessel distinction (currently same entity)
- Vendor deactivation cascade — warn if vendor has open POs
- Approval queue — show VENDOR_ID_PENDING alongside MGR_REVIEW
- Vendor required before approval can be granted (currently advisory only)
