This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Inventory and Catalogue
This covers the product catalogue, per-vendor pricing, the cart, and the feature-flagged site-inventory surfaces.
Products
Two views over the same Product records:
/admin/products— the editable catalogue (MANAGER, ADMIN). Add a product (code, name, description), toggle Active/Inactive, delete./inventory/items— read-only catalogue, available to all roles for PO creation. Expand a row to see per-vendor prices.
Both link to a shared item detail page. A product carries lastPrice and
lastVendor (read-only — auto-populated on payment) and per-vendor history via
ProductVendorPrice (one row per product–vendor pair).
Auto-sync on payment confirmation
When a PO is marked paid, for each line item:
- if it has a
productId, setProduct.lastPrice = line.unitPriceandProduct.lastVendorId = po.vendorId; - upsert the
(product, vendor)price intoProductVendorPrice; - log a
PRODUCT_PRICE_UPDATEDaction.
Future POs using that product show the vendor's latest price as a hint in the line-item editor. (The original spec also described fuzzy-matching unlinked items into new products; price/vendor tracking is the shipped behaviour.)
Product search
/api/products/search powers the line-item name autocomplete: min 2 chars,
case-insensitive match on name / code / description, max 10 results, inactive
products excluded, lastPrice serialised as a plain number (not a Prisma
Decimal).
Cheapest / ★ Closest tags
On the item detail and items pages, when a Site is selected each item's vendor list is annotated:
- Cheapest — vendor with the minimum
ProductVendorPrice. - ★ Closest — vendor nearest the selected site by geocoded distance
(
distanceKm).
These are computed independently, so both tags can appear simultaneously
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 for the specs pinning this down.
Cart
A persistent cart (lib/cart.ts) stored in browser localStorage under a fixed
key, surviving navigation but local to the device/user. A cart-updated custom
event lets components (e.g. the header cart icon with its count badge) react in
real time.
Flow: add items from product/item detail → open /inventory/cart → adjust
quantities, remove items, pick a delivery site → Create PO opens /po/new
pre-filled with the cart line items and vendor/site.
Site inventory (feature-flagged)
Gated by NEXT_PUBLIC_INVENTORY_ENABLED (lib/feature-flags.ts):
INVENTORY_ENABLED = process.env.NEXT_PUBLIC_INVENTORY_ENABLED !== "false"
(i.e. on unless explicitly "false"). When off, site stock/consumption
surfaces are hidden; the vendor/product catalogue and cart remain available.
- Sites (
/admin/sites) — ports/depots/offices that hold stock; geocoded from pincode; vessels can be associated. ItemInventory— quantity per(product, site). Designed to be incremented at PO approval (not on close) for the ordered quantities, when the PO has asiteId. ⚠️ In production this rarely fires — POs are raised against a Vessel and carry nositeId, and the write isn't gated by the flag. See Inventory on Approval and Tech Debt.ItemConsumption— daily draw-down per(product, site, date), recorded via the "Log Consumption" form on the site detail page (withrecordedBy).
Site detail (/admin/sites/[id]) shows a stock bar chart, a 30-day consumption
line chart, the inventory table, assigned vessels, and recent POs for the site.
Pelagia Portal (PPMS)
Overview
Build & Run
System
Product
- Feature Catalogue
- Pages and Navigation
- Workflows
- Purchase Orders
- Vendors and GST Lookup
- Inventory and Catalogue
- Inventory on Approval
- Notifications
- File Storage
- Design System
Planned
Quality
Ops
Engineering
Pelagia Portal (PPMS) — internal purchase-order management. Self-hosted on pms1, live at pms.pelagiamarine.com. This wiki tracks the shipped product; authoritative sources are the repo code, App/CLAUDE.md, Docs/, and CHANGELOG.md.