- 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>
398 lines
23 KiB
Markdown
398 lines
23 KiB
Markdown
# 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.
|
||
|
||
```css
|
||
/* 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 **12–16px** 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 <Site>" 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 <name>? 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`.
|
||
- **Cart** — `localStorage` + 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.
|