pelagia-portal/design_handoff_pelagia_portal/README.md
Hardik d769cae71e chore(inventory): remove item detail page; move SiteSelect to shared components
- Delete /inventory/items/[id] — items expand inline in the list
- Move SiteSelect from deleted [id] folder to components/inventory/site-select
- Fix admin product detail page import to use new shared path
- Fix items-table: Fragment key prop, restore Link import, plain text item names
- Fix vendor-items-table: remove broken link to deleted item detail page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 00:07:04 +05:30

23 KiB
Raw Blame History

Handoff: Pelagia Portal — Internal Purchase-Order Management

Overview

Pelagia Portal is an internal web application for a maritime company that digitises the full purchase-order lifecycle: requisition aboard a vessel → manager approval → finance payment → receipt confirmation on delivery. It is a role-gated, traceable workflow replacing paper and email-based processes.

This handoff covers the design system and 16 primary screens spanning the seven user roles defined in the spec (TECHNICAL, MANNING, ACCOUNTS, MANAGER, SUPERUSER, AUDITOR, ADMIN).

The full functional specification lives in DESIGN.md (included). The HTML prototype demonstrates layout, look, and key interactions; this README documents what to build.


About the Design Files

The files in this bundle are design references created in HTML/JSX — prototypes showing intended look and behaviour, not production code to ship. They use React via Babel-in-browser for fast iteration, with no build step, no API layer, and mock data hard-coded in data.jsx.

The task is to recreate these designs in the target codebase's existing environment (likely Next.js / React + a real backend) using its established patterns, component library, and conventions. If no environment exists yet, pick the most appropriate stack — Next.js App Router with TypeScript + Tailwind/shadcn or Radix is a natural fit for this product.

A role-switcher dropdown appears in the prototype header. It is a prototype-only affordance to preview how the sidebar adapts per role. In production, role is determined by the authenticated user's record.


Fidelity

High-fidelity. Final typography, colour, spacing, status-badge palette, table density, and form layout are intended to ship as-is. The chrome (header, sidebar, page-head, card, table, badge) is a complete design system — recreate it pixel-faithfully with the codebase's chosen primitives.

Charts are illustrative — the line and bar charts in the prototype are hand-rolled CSS/SVG. In production use a charting library (Recharts, Visx, Chart.js) but keep the visual style: low chroma fills, monospaced numerals, minimal axes, no gradients.


Design Tokens

Colour

All colours are defined in oklch and pinned to a consistent chroma/lightness band per role (foreground vs background, status hue, etc). Convert to hex/RGB for the target environment if needed.

/* Surface */
--paper:        oklch(98%  0.005 240);   /* page background — warm-cool off-white */
--paper-2:      oklch(96.5% 0.006 240);  /* recessed surfaces, table headers */
--surface:      #ffffff;                  /* cards, inputs */

/* Ink */
--ink:          oklch(22% 0.02 245);     /* primary text */
--ink-2:        oklch(35% 0.02 245);     /* secondary text */
--muted:        oklch(55% 0.015 245);    /* labels, meta */
--faint:        oklch(72% 0.012 245);    /* placeholder, separator copy */

/* Lines */
--line:         oklch(91% 0.006 245);    /* default borders */
--line-2:       oklch(87% 0.008 245);    /* hover/active borders */

/* Primary maritime */
--primary:      oklch(38% 0.06 230);     /* brand mark, primary CTA */
--primary-ink:  oklch(28% 0.06 230);     /* primary CTA hover, active nav text */
--primary-soft: oklch(95% 0.02 230);     /* active nav background, soft fills */

Status Badge Palette

Nine PO statuses, each with a paired bg/fg keeping chroma and lightness consistent across the set:

Status Background hue Foreground hue
DRAFT oklch(94% 0.005 245) oklch(40% 0.015 245)
SUBMITTED / MGR_REVIEW oklch(94% 0.03 245) oklch(38% 0.09 245)
VENDOR_ID_PENDING oklch(94% 0.04 60) oklch(42% 0.12 60)
EDITS_REQUESTED oklch(95% 0.05 95) oklch(42% 0.1 80)
MGR_APPROVED oklch(94% 0.04 190) oklch(38% 0.08 195)
SENT_FOR_PAYMENT oklch(94% 0.04 300) oklch(40% 0.1 300)
PAID_DELIVERED oklch(94% 0.04 215) oklch(38% 0.08 220)
CLOSED oklch(94% 0.04 150) oklch(38% 0.08 150)
REJECTED oklch(94% 0.04 25) oklch(45% 0.13 28)

Badge style: pill (100px radius), 2×8 padding, 10.5px uppercase, 5px round dot prefix using currentColor.

Typography

  • UI sans: Geist, 400 / 500 / 600 / 700 (Google Fonts).
  • Mono: Geist Mono, 400 / 500 / 600 — used for PO numbers, amounts, codes, timestamps, GSTINs, geocoded coordinates. Always with font-variant-numeric: tabular-nums.
  • Base body size 13px with line-height 1.5.
  • Page titles 22px / 600 / -0.01em tracking.
  • Section titles 11px uppercase / 500 / 0.08em tracking, colour --muted.
  • Field labels 11px uppercase / 500 / 0.05em.
  • Stat values 26px monospaced / 500 / -0.02em.

Spacing & Radii

  • Sidebar width 232px, header height 52px, main padding 22px 32px 60px, max content width 1280px.
  • Border radii: 4px (chips), 6px (buttons, inputs), 10px (cards, large surfaces).
  • Form input height 32px, secondary/button height 30px, small-button 26px.
  • Card head padding 13px 16px, body 16px. Tables: header 10px 16px, cell 12px 16px.
  • Grid gap 1216px for stat grids / dashboard layouts; 22px between page sections.

Iconography

Custom 16×16 monoline SVG icons with stroke-width: 1.4, linecap: round, linejoin: round. Recreate in your icon library of choice (Lucide is a near-perfect match — Home, FileText, List, Check, ShoppingCart, Package, Truck, Users, Ship, Map, BarChart3, User, Settings, Plus, Download, Upload, Search, ChevronRight, Star, Pencil, Trash, Bell, Eye, RotateCw, Paperclip, ArrowRight).

Shadow / Elevation

No drop shadows anywhere in the chrome. Depth comes from hairline borders (--line) and the recessed --paper-2 background. The brand mark sits on solid --primary.


Navigation Structure

The left sidebar is role-aware (groups and items hide/show per role). Group titles are 10.5px uppercase, --faint.

Role Groups visible
TECHNICAL / MANNING Dashboard · Purchase Orders (New PO, My Orders) · Inventory (Items, Cart)
MANAGER Dashboard · Purchase Orders (New PO, My Orders, Approvals, Import PO, History) · Inventory (Vendors, Items, Vessels, Sites, Cart)
ACCOUNTS Dashboard · Purchase Orders (Payments, History) · Inventory (Vendors)
SUPERUSER Full submitter + manager + accounts surface
AUDITOR Dashboard · Purchase Orders (History)
ADMIN Dashboard · Purchase Orders (Import PO, History) · Inventory (Vendors, Items, Vessels, Sites) · Administration (Users, Accounts)

Nav item: 6×10 padding, 6px radius, 12.5px label, leading 14px icon. Active state: --primary-soft background, --primary-ink text, weight 500. Optional count pill on the right (10.5px monospace).


Screen Catalogue

1. Login (/login)

  • Centred 360px-wide card on --paper background.
  • Brand mark + "Pelagia Portal" wordmark + 11.5px subtitle "Internal · Purchase Order Management".
  • Email + password inputs, then a full-width maritime-primary "Sign in" button (height 36).
  • Footnote: "Contact an administrator to request access." No self-registration.

2. Dashboard (/dashboard)

Content adapts per role. Page-head left: crumb "Dashboard", title "Good afternoon, <name>", sub-line with date/time and a "3 vessels active at sea" indicator. Page-head right: Export + New PO buttons.

Manager view:

  • 4 stat tiles in auto-fit minmax(190px, 1fr) grid: Awaiting approval (clickable → approvals queue, shows trend "↑ 2 vs last week"), Approved this month, Approved spend, Avg cycle (submit → approve).
  • Two side-by-side cards (1fr 1fr): "Monthly spend — last 8 months" (vertical bar chart, ₹ in thousands, current month highlighted in --primary); "Spend by vessel — YTD" (horizontal bar rows with --primary fills).
  • "Recently approved" card-flush table with "View history →" link.

Submitter (TECH/MANNING) view:

  • 4 stat tiles: Open orders, Pending approval, Completed, Total spend YTD.
  • "Open orders" mini-table.

Accounts view:

  • 4 stat tiles: Ready for payment, Awaiting confirmation, Value awaiting payment, Paid this month.
  • "Payments queue" link.

Auditor/Admin view:

  • 4 stat tiles + quick-access button row (Order history, Vendor registry, Export PDF, Export CSV).

3. My Purchase Orders (/my-orders)

  • Page-head with status counts: <n> open · <n> past.
  • Two stacked sections: "Open orders" and "Past orders", each a flush card with table.
  • Columns: PO Number (monospace, --primary-ink), Title, Vessel (muted), Status badge, Updated, Amount (right-aligned monospace).
  • For EDITS_REQUESTED rows, a tinted sub-row below the data row shows Manager note · <name>: <text> with the inline badge.
  • Whole row clickable → /po/[id]. Hover row: --paper-2.

4. Approval Queue (/approvals)

  • Title "Approval queue" + appended count "· N pending" in muted regular weight.
  • Filter bar (recessed --paper-2, 1px border, 6px radius): search field with icon, vessel dropdown, submitter dropdown, date-from picker, right-aligned "Sorted by submitted date" note.
  • Table columns: PO Number, Title, Submitter, Vessel, Submitted, Amount, "Review →" link on right.

5. PO Detail (/po/[id])

Two-column layout: main content (1fr) + sidebar (280px).

  • Detail band (full width, above the two-col): card with PO id (18px monospace), status badge, project code chip (mono pill), and right-aligned "GRAND TOTAL · ₹X,XX,XXX" (22px monospace).
  • Manager-note alert if EDITS_REQUESTED (yellow-warning alert above main content).
  • Main column sections (each preceded by an 11px uppercase section title):
    • Summary — key/value dl (130px 1fr columns).
    • Line items — flush card with table; footer row inside card has Taxable / GST / Grand Total summary (right-aligned, monospace).
    • Terms & conditions — key/value dl of the 6 T&C fields.
    • Documents — list of attached files with paperclip icon + size + Download button.
    • Confirm receipt — visible only when PAID_DELIVERED: dashed-border upload zone + notes textarea + maritime CTA.
  • Sidebar:
    • Timestamps card — Created / Submitted / Approved / Paid / Closed (monospace dates).
    • Audit trail card — list of actor · action · monospaced timestamp rows with green dot per row (1px dashed separator between).

Action buttons in page-head are contextual per status & role (see DESIGN.md §5.4 table).

6. Approval Detail (/approvals/[id])

Same as PO Detail, plus a Manager actions card at the top of the main column:

  • Default state: row of buttons — Approve (maritime primary), Approve with Note, Request Edits, Request Vendor ID, with Reject (danger) pushed right via a flex spacer.
  • Clicking any action other than plain Approve swaps the row for an inline form with title, subtitle, textarea, Cancel + tinted-CTA buttons. CTA colour matches the action's intent (edits = --st-edits-fg, reject = --st-rejected-fg, etc).
  • Manager line-item editing happens inline on the line-items card (not in a modal) — per spec §9.

7. New PO (/po/new)

Four numbered sections, each prefixed by a section title:

  1. Header — Title (full row) + 3-col (Vessel, Account, Vendor) + 3-col (Date Required, Project Code, Currency) + Description textarea.
  2. Line items — flush card with table of editable rows. Per-row inputs: Name, Description, Qty, Unit, Unit price, GST%, Total (computed, monospace), trash icon. Footer "Add line item" button + tip text. Card footer with live Taxable / GST / Grand Total summary identical to the PO Detail footer.
    • As-you-type product autocomplete: when a name input is focused with text, a tinted sub-row appears showing "Last seen at: Vendor A ₹X · Vendor B ₹X · Vendor C ₹X" hints (per spec §9).
  3. Terms & conditions — 6 textareas in a 2-col grid (Delivery, Dispatch, Inspection, Transit Insurance, Payment Terms, Other).
  4. Documents — dashed drop zone with paperclip-list of attached files.

Footer: Cancel · Save as Draft · Submit for Approval (maritime primary).

8. Payment Queue (/payments)

ACCOUNTS only. Two sections:

  • "Ready for payment" — card grid auto-fill minmax(320px, 1fr).
  • "Processing — awaiting confirmation" — same grid layout, different action button.

Each card: PO number (mono header) + title, status badge, kv table (Vessel, Vendor, Submitter, Approved/Sent on), prominent amount (22px monospace), then a row of two buttons — View (neutral) and the action button (maritime primary, larger flex weight 1.6).

9. History / Export (/history)

  • Page-head right: Export PDF · Export CSV buttons.
  • Filter bar: From + To date pickers (with prefix labels), vessel dropdown, status dropdown. Right side: "N matching · export uses current filters".
  • Full PO table, columns: PO Number, Title, Vessel, Submitter, Status, Created, Amount.

10. Vendor Registry (/admin/vendors)

  • Page-head right: "Add vendor" maritime button.
  • Add-vendor opens an inline panel (not a modal) above the table — a .action-panel Card with the GSTIN lookup wizard:
    • Step 1: GSTIN input + "Look up" button.
    • Step 2: a hand-drawn captcha image placeholder (45° striped background, line-through wavy effect on the 6-char code) + input + Refresh icon button + "Verify" button.
    • Step 3: green confirmation alert + auto-filled form fields (Legal name, Trade name, Address textarea, Pincode, Geocoded location read-only, Contact name, Email, Mobile) + Cancel / Save.
  • Vendor table columns: Vendor ID (mono or "Pending" badge), Name + city + GSTIN (two-line cell), Contact (name + email two-line), Items count, Verified (check + "Verified" or em-dash), Status badge, edit icon.

11. Vendor Detail (/admin/vendors/[id])

Two-column layout (1fr + 280px).

  • Page-head sub: vendor ID (mono) · "GSTIN verified" check · Active badge.
  • Main: Items supplied table (Code, Product, Last quoted, Last updated) + Recent POs table.
  • Sidebar: Vendor info kv (GSTIN, Pincode, City, Contact, Mobile, Email); Address card with a striped placeholder "map" graphic + geocoded coordinates label.

12. Item Catalogue (/admin/products)

  • Info alert at top (per spec §5.15 footer note): "Items are added automatically when a PO is marked as paid. Manual entry is reserved for ADMIN."
  • Table columns: Code (mono), Name (medium weight), Description (muted), Vendors, Last price, Last vendor, Updated, Status badge.

13. Item Detail (/admin/products/[id])

  • Stat row: Vendors supplying, Lowest price, Highest price, Sites with stock.
  • 2-col card row: "Price comparison" vertical bar chart (lowest-priced vendor bar in --primary) + "Stock by site" chip list.
  • Vendor pricing table with site-proximity filter (top-right "Sort by distance from " dropdown). When a site is chosen: a Distance column appears, rows sort by distance ascending, and the closest vendor row gets a star ★ marker. Per-row "Add to Cart" small button.

14. Sites (/admin/sites) & Site Detail (/admin/sites/[id])

  • List: Name, Code (mono), Address (muted), Vessels, Items, Location (mono coords), Status, edit icon.
  • Detail: 4 stat tiles (Vessels at site, Items tracked, Inventory value, 30-day consumption). 2-col card row: Current stock horizontal bars + Consumption SVG line chart (5 colored series for 5 products) with a flat legend below. Then a 2/3 + 1/3 split: Inventory table & Recent POs on the left, Log-consumption form & assigned vessels chips on the right.

15. Cart (/inventory/cart)

  • 2/3 + 1/3 split.
  • Left card: header row + per-item rows (5-col grid: name+vendor / price / qty input / subtotal / delete). Inline qty editing.
  • Right column: "Order summary" card (Taxable / GST / Grand Total) + "Delivery site" dropdown card.
  • Page-head right: Clear cart · Create PO from cart (maritime primary).

16. Import PO (/po/import)

  • Step 1 card (1.6fr): drop zone + parsed-file confirmation row (check icon + "5 line items detected").
  • Step 2 card (1fr): vessel & account selectors.
  • Step 3: extracted line-items table (read-only-style) for review.
  • Footer: Cancel · Save as Draft.

17. Vessels / Accounts / Users (admin tables)

Straightforward dense tables matching the design system's table primitive. Per-row edit icon, status badge. Add buttons in page-head.


Interactions & Behaviour

Routing

  • Hash-based in the prototype (#dashboard, #po-detail/PO-2026-00481). In production, use real URL routing.
  • Browser back/forward should restore exact screen state.

Click handlers

  • Every table row with a PO is row-clickable → opens PO Detail. Action buttons within rows must stopPropagation.
  • Status badges are non-clickable (decorative only).
  • Stat tiles with an underline cursor are clickable to drill into the relevant list.

Hover / focus

  • Buttons: --paper-2 background and --line-2 border on hover. Inputs/selects: --primary border + 3px --primary-soft focus ring.
  • Nav items: --paper-2 hover (when not active).
  • Table rows with .clickable: --paper-2 background.

Forms

  • All required fields marked with a red * after the label (.req).
  • Live totals on the New PO line-items table — recompute Taxable / GST / Grand Total on every change.
  • Save as Draft is always available; Submit requires required fields.

Confirmation

  • Per spec §9: destructive actions use inline two-step confirm (Delete → "Delete ? Confirm / Cancel"), not a modal.

Notifications / emails

  • Every PO status transition fires an email (spec §9). Outside scope of UI but worth wiring on the backend.

Approval action flow

  • Clicking Approve immediately moves the PO to MGR_APPROVED (toast confirm in production).
  • Clicking Approve-with-Note / Edits / Reject / Vendor-ID swaps the action panel for an inline form with mandatory note (Edits/Reject) or optional note (Vendor ID, Approve w/ note).

Cart persistence

  • LocalStorage under a fixed key. Fire a cart-updated custom event on mutation so header counters can react.

GSTIN lookup

  • Three-step inline wizard inside the Add Vendor form. Captcha image and verify response should be proxied via the company's microservice to the GST portal.

Charts

  • Use Recharts/Visx. Bar charts: rounded top corners, no axis lines, monospaced tick labels in --muted, the highlighted bar in --primary, the rest in --primary-soft. Line charts: 1.5px stroke, rounded caps, 5 distinct hues at moderate chroma (sampled from the consumption chart series).

Responsive

  • Desktop-first per spec §10. Minimum supported width 1280px. The header has fixed-width sidebar (232px); cards collapse to single column under 1024px if you want to graceful-degrade.

State Management

State boundaries that matter:

  • Auth / current user / role — global (Context or Zustand). Drives sidebar nav and action visibility.
  • PO list / detail — server state via TanStack Query / RTK Query. Cache invalidation on status transition.
  • Approval inline form — local component state (mode enum: null | edits | reject | note | vendor).
  • New PO form — react-hook-form with useFieldArray for line items; live totals are derived from watch.
  • CartlocalStorage + an in-memory store synced via a cart-updated event.
  • Vendor add wizard — local component state (step 1 → 3); GSTIN captcha and verify are async mutations.

PO lifecycle state machine (per spec §6)

DRAFT → SUBMITTED → MGR_REVIEW
  ↓ (approve)
MGR_APPROVED → SENT_FOR_PAYMENT → PAID_DELIVERED → CLOSED

Re-entry branches from MGR_REVIEW:
  → REJECTED (terminal)
  → EDITS_REQUESTED → submitter edits → MGR_REVIEW
  → VENDOR_ID_PENDING → submitter picks vendor → MGR_REVIEW

Terminal states: REJECTED, CLOSED.


Data Entities

See DESIGN.md §8 for the full field list. Tables you'll need:

  • purchase_order — id, title, status, total_amount, currency, date_required, project_code, manager_note, payment_ref, quotation_no/date, requisition_no/date, place_of_delivery, terms.{delivery,dispatch,inspection,insurance,payment,others}, all timestamps.
  • po_line_item — fk po_id, name, description, qty, unit, size, unit_price, gst_rate (default 18), total (computed), sort_order, optional product_id.
  • vendor — name, vendor_id (nullable unique), address, pincode, gstin, contact, latitude, longitude, verified, active.
  • product — code, name, description, last_price, last_vendor_id, active.
  • product_vendor_price — composite (product_id, vendor_id) → price, updated_at.
  • vessel — name, imo, active, assigned_site_id.
  • site — name, code, address, pincode, lat, lng, active.
  • account — code, name, description, active.
  • user — emp_id, email, name, role, active, password_hash.
  • item_inventory — (product_id, site_id) → qty.
  • item_consumption — (product_id, site_id, date) → qty.
  • po_audit_log — fk po_id, actor_id, action, note, timestamp.

Auto-sync of product / product_vendor_price on PO mark_paid per spec §7.9.


Files in this Bundle

File Role
Pelagia Portal.html Entry point — references all scripts and styles
styles.css Complete design system: tokens, components, layout, charts
components.jsx Shared primitives — Icon, Badge, Card, Stat, Crumbs, format helpers
data.jsx Mock data — vessels, accounts, vendors, products, sites, users, orders
pages-1.jsx LoginPage, Dashboard, MyOrders
pages-2.jsx ApprovalsPage, PODetailBase (shared by detail + approval), NewPOPage, ApprovalActions
pages-3.jsx PaymentsPage, HistoryPage, VendorsPage + AddVendorPanel, VendorDetailPage, ItemsPage, ItemDetailPage
pages-4.jsx SitesPage, SiteDetailPage, VesselsPage, AccountsPage, UsersPage, CartPage, ImportPOPage
app.jsx Router, role-aware Sidebar, Header (with prototype role-switcher), App entrypoint
DESIGN.md Original product specification — authoritative for behaviour, copy, and role matrix

The fastest way to absorb the design: open Pelagia Portal.html in a browser, switch roles via the header dropdown, and click through the sidebar. Then port screen-by-screen using DESIGN.md as the source of truth for any behavioural ambiguity.


Assets

  • Fonts: Geist + Geist Mono via Google Fonts. Both free and OFL-licensed.
  • Icons: custom 16×16 monoline set; reproduce with Lucide React.
  • Logo / brand mark: generated in CSS (a navy square with a clipped semicircle representing a wave/anchor abstract). Replace with the real Pelagia mark when available.
  • Map/photographic imagery: none used. Vendor-detail "map" is an intentionally schematic placeholder.

Out of Scope (per spec §10)

  • Mobile app — web-only, desktop-first.
  • Public-facing pages — entirely internal.
  • Self-registration / OAuth — admin-created accounts only.
  • Vendor portal — vendors do not log in.
  • Automated bank/payment-gateway integration — payment is marked manually.