Commit graph

137 commits

Author SHA1 Message Date
2e6678f829 fix(gst): correct microservice default port and captcha field name
Default port changed 3002 → 3003 in the GstService and both proxy
routes.  The vendor-form was reading `captchaB64` from the API
response but the GstService returns `captchaBase64`, so the CAPTCHA
image was never displayed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 17:07:31 +05:30
f372fae953 feat(gst): replace API-key lookup with Playwright microservice
Problem: GST portal's public taxpayer search (services.gst.gov.in/
searchtp) now requires human CAPTCHA verification but no login.
The BIG-IP WAF blocks direct Node.js HTTP clients via TLS
fingerprinting; Playwright (real Chromium) bypasses it successfully.
Confirmed working: GSTIN 27AAHCP5787B1Z6 → full PELAGIA MARINE
SERVICES data including address, jurisdiction, filing status.

GstService/ (new standalone microservice):
- src/index.ts: Express + Playwright singleton browser
  GET  /health  → { ok: true }
  GET  /captcha → launches browser, loads GST portal, fetches
                  CAPTCHA image from same origin (sets CaptchaCookie),
                  stores BrowserContext in session map (3 min TTL)
                  → { sessionId, captchaBase64 }
  POST /search  → { sessionId, gstin, captcha } → submits form
                  via page.evaluate fetch() using live browser session,
                  closes context, returns parsed taxpayer data
- package.json, tsconfig.json, npm install
- src/test-lookup.ts: interactive CLI test (prompted user for captcha)

App changes:
- Remove playwright dep from Next.js app (was incorrectly added)
- Remove lib/gst-lookup.ts (sandbox.co.in placeholder — unused)
- Remove lib/gst-browser.ts (Playwright singleton — moved to service)
- app/api/gst/captcha/route.ts: thin proxy → GST_SERVICE_URL/captcha
- app/api/gst/route.ts: thin proxy POST → GST_SERVICE_URL/search
- vendor-form.tsx: two-step captcha UI
    Step 1: "Look up" → calls /api/gst/captcha → shows PNG inline
    Step 2: user types 6 digits → "Verify" → calls /api/gst → fills
            form (name, address, lat/lng from Nominatim geocoding)
    Wrong captcha → SWEB_9034 error with retry option
- .env.example: GST_SERVICE_URL=http://localhost:3002

Start the microservice: cd GstService && npm run dev

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 13:27:15 +05:30
bea798324c feat(inventory): Sites, GST lookup, distance sorting, cart, inventory tracking
Schema:
- Site model (name, code, address, lat/lng, isActive)
- ItemInventory model (quantity per product per site, unique[productId,siteId])
- ItemConsumption model (daily usage per product per site)
- Vendor: add latitude, longitude
- Vessel: add siteId (home port)
- PurchaseOrder: add siteId (delivery site)

Permissions: add manage_sites to MANAGER and ADMIN

Sidebar: Inventory section (Vendors, Items, Vessels, Sites, Cart)
for MANAGER and ADMIN; old admin items reorganised

Lib:
- lib/geo.ts: Haversine distance + Nominatim pincode geocoding
- lib/gst-lookup.ts: AbhiAPI GSTIN lookup (ABHIAPI_KEY env var)
- lib/cart.ts: localStorage cart (add/remove/clear + cart-updated event)

API: GET /api/gst?gstin= — validates GSTIN, fetches via AbhiAPI,
  geocodes pincode via Nominatim, returns name/address/lat/lng

Vendor form: GSTIN "Look up" button auto-fills name, address,
  and lat/lng; lat/lng fields editable as override

Sites: full CRUD at /admin/sites; detail page with inventory
  table, consumption recording form, BarChart (stock) +
  LineChart (30-day consumption), linked vessels, recent POs

Vessels: detail page at /admin/vessels/[id] with "Create PO"
  button, PO history and spend summary; accessible to MANAGER

Items detail: price comparison BarChart; site distance filter
  (dropdown → re-render sorted by Haversine distance); "Add to
  Cart" per vendor row; stock-by-site section

Cart: /inventory/cart — localStorage CartView; qty edit, remove,
  clear; "Create PO →" encodes cart into /po/new?cart=...

Receipt/delivery: confirmReceipt now upserts ItemInventory
  (increment qty) for each linked line item, using PO siteId or
  vessel home site as the delivery location

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:50:11 +05:30
1c7d0b8901 feat(catalog): vendor & item detail pages; enable for MANAGER role
Permissions:
- Add manage_products to MANAGER (alongside existing manage_vendors)

Sidebar:
- Add Items link for MANAGER under main nav (alongside Vendors)

Vendor list (/admin/vendors):
- Name is now a link to /admin/vendors/[id]
- Show item count column

Vendor detail (/admin/vendors/[id]):
- Vendor info card (GSTIN, address, contact)
- Items Supplied table: name (links to item detail), code, last price, updated
- Recent Purchase Orders table

Item list (/admin/products):
- Name is now a link to /admin/products/[id]
- Show vendor count column; reorder columns (name first)
- Add/Toggle buttons shown only for ADMIN

Item detail (/admin/products/[id]):
- Price summary cards (vendor count, lowest price, highest price)
- Available From table: vendor (links to vendor detail), vendor ID,
  verified badge, price (lowest highlighted in green), last updated

Both detail pages cross-link to each other.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 04:25:30 +05:30
f4e0d8ae63 feat(catalog): track per-vendor prices; auto-sync catalog on payment
Schema:
- Add ProductVendorPrice table (productId, vendorId, price, updatedAt)
  with unique constraint on (productId, vendorId)

Payment action (markPaid):
- Auto-create Product for any unlinked line item (matched by name
  case-insensitively, or created fresh with auto-generated code)
- Link POLineItem.productId for newly matched/created products
- Upsert ProductVendorPrice for the PO vendor + unit price
- Always update Product.lastPrice / lastVendorId as denormalized cache

Search API:
- Include vendorPrices[] in results (vendorId, vendorName, price)

Editor dropdown:
- Show per-vendor prices below item name when available

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 03:47:39 +05:30
f95b3279c8 feat(line-items): separate name (mandatory, searchable) from description (optional)
- Add POLineItem.name column; migrate existing description→name; description is now optional
- NameCell component: name input with fuzzy product search, description input stacked below
- Read-only view shows name prominently, description in subdued text below
- All server actions (create, edit, manager edit, import) updated to read/write name
- ParsedImportLine.description renamed to .name throughout import parser and form
- Seed data updated; CLAUDE.md added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 03:37:53 +05:30
2b5e125260 feat(export): match Sample_PO.xlsx formatting in XLSX and PDF exports
XLSX (ExcelJS replaces bare SheetJS):
- Full cell-level styling: bold fonts, gray fills, thin/medium borders,
  cell alignment, wrap-text — all matching the sample PO layout
- Correct merge map across all sections:
  header block (A1:I4), PO meta row (A5:B5, C5:G5), PI/Quotation row
  (A6:B6, C6:F6, G6:H6), Vessel/Budget/Requested row (A7:B7, D7:E7,
  H7:I7), Requisition row (A8:B8, D8:E8, H8:I8), Place of Delivery
  spanning 2 rows (A9:B10, C9:I10), Invoice Details spanning 2 rows
  (A11:B12, C11:I11, C12:I12), Vendor block (A13:B13, D13:I13, A14:B14,
  C14:I14), line item Description column (B:C per row), totals labels
  and values (F:G and H:I), instructions header (A:I), T&C text (B:I
  per row), dual signature blocks
- Description column spans B:C in header and every item row
- Minimum 7 body rows reserved; alternating row fills
- Totals section: gray fill, right-aligned, grand total darker gray
- Instructions header with distinct fill; numbered T&C with B:I merge
- Paired signature blocks (submitter left, vendor right) with borders
- Column widths and row heights tuned to the sample dimensions
- Page setup: A4 portrait, fit-to-width

PDF (HTML print page):
- Typography matches sample: Arial 8.5pt body, 13pt bold company name,
  11pt underlined PURCHASE ORDER heading
- All meta tables use gray (f2f2f2) label cells with borders
- Place of Delivery and Invoice Details use rowspan for correct layout
- Line items table: dark gray (d8d8d8) header, 1px borders, alternating
  row fills, minimum 7 blank rows reserved
- Totals table (55% width, right-aligned) with gray rows and darker
  grand total
- Instructions: distinct header fill, clean numbered layout
- Signature blocks: flex-spaced bordered boxes with submitter/vendor
- Print CSS: A4 page size, no-print class for the print button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 00:28:34 +05:30
48e1f19e58 test: add comprehensive tests for all new features + test plan
Parser extraction:
- Move parseSheet/parseWorkbook/cellStr/cellNum to lib/po-import-parser.ts
  so they can be unit-tested without HTTP overhead
- Route now re-exports types and delegates to the lib

Unit tests (165 total, all passing):
- permissions.test.ts: +15 cases covering MANAGER create_po/submit_po/
  manage_vendors, ACCOUNTS manage_vendors, AUDITOR all-denied, ADMIN
  operational denial, SUPERUSER no manage_vendors
- po-state-machine.test.ts: +12 cases covering MANAGER submit from DRAFT
  and EDITS_REQUESTED, ACCOUNTS provide_vendor_id, AUDITOR/ADMIN denied
  on all transitions
- po-import-parser.test.ts (new, 32 cases): cellStr/cellNum edge cases;
  parseSheet against real Sample_PO.xlsx (1 line item, correct values,
  T&C not included, vendor/quotation/T&C extraction); synthetic sheet
  edge cases (GST normalisation, INSTRUCTIONS stop, zero-price skip,
  empty rows); parseWorkbook happy path and empty-workbook

Integration tests (new files):
- discard-po.test.ts: owner/MANAGER/SUPERUSER can discard; ACCOUNTS and
  non-owners denied; status guard blocks non-DRAFT; cascade cleanup of
  POActions and POLineItems verified in DB
- vendor-approval.test.ts: approval blocked without vendor; approval
  succeeds with vendor; ACCOUNTS can provideVendorId; unverified vendor
  rejected; AUDITOR denied; wrong-status denied
- manager-po-creation.test.ts: MANAGER creates DRAFT and submits; stores
  correct submitterId; can discard own draft; ACCOUNTS denied; unauth
  returns Unauthorized
- products-search.test.ts: 401 unauth; min-length validation; search by
  name/code/description; case-insensitive; max 10 results; lastPrice as
  number; inactive products excluded
- import-api.test.ts: 401 unauth; 403 for TECHNICAL and ACCOUNTS; 400
  no file; 400 invalid binary; 200 for MANAGER with Sample_PO.xlsx;
  correct line item values; T&C absent from results; vendor/PI extracted

Spec/TEST_PLAN.md (new):
- Testing strategy, stack, and environment setup
- Coverage matrix across unit/integration/E2E layers
- Permission test matrix for all 7 roles × 15 operations
- Feature-level scenario index (F-01 through F-06) with IDs mapping to test files
- Known gaps and out-of-scope items
- Authoring conventions (PREFIX isolation, negative-first, no any)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 19:15:58 +05:30
4a848f50cf fix(import): stop parsing line items at T&C section
Row 26 ("INSTRUCTIONS TO VENDORS") had an empty col-1 so the loop
continued into the numbered T&C rows (27-33), which all have text in
col-1 and were mistakenly added as line items.

Two guards added:
1. Break immediately when col-0 contains "INSTRUCTION" (catches the
   section header even though col-1 is empty).
2. Skip any row where both qty and unitPrice are 0 (belt-and-suspenders
   for T&C rows that might slip through in other PO layouts).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 19:00:20 +05:30
96314d89f8 feat: discard draft POs
Adds a "Discard" button to the PO detail header for any DRAFT PO.
Submitters, managers, and superusers can discard. The action deletes
the PO and its related actions/notifications, then redirects to
/my-orders. Non-cascade child records (POAction, Notification) are
explicitly deleted in a transaction before the PO row is removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 18:57:01 +05:30
43f0861591 feat: manager PO creation, vendor management, import from Excel, item fuzzy search
Permissions & access:
- MANAGER gains create_po, submit_po, edit_own_draft_po, view_own_pos, manage_vendors
- ACCOUNTS gains manage_vendors
- ACCOUNTS added to provide_vendor_id state transition
- MANAGER added to DRAFT/EDITS_REQUESTED submit allowed roles
- canProvideVendorId now includes ACCOUNTS and any MANAGER/SUPERUSER

Vendor required for approval:
- approvepo() now returns error if po.vendorId is null
- Approval page shows danger banner when vendor is missing

Navigation:
- MANAGER gets "New PO", "My Purchase Orders", "Import PO", "Vendors" nav items
- ACCOUNTS gets "Vendors" nav item

Seed data:
- Vendors: 12 total (up from 3), with GST, address, contact details
- Products: 25 total (up from 4), with lastPrice pre-populated

Product fuzzy search in line items editor:
- Typing ≥2 chars in description fetches /api/products/search?q=
- Dropdown shows code, name, description, last price
- Selecting a product auto-fills description and unit price
- Linked items show a "✓ linked" indicator
- productId passed through FormData to createPo action and stored on POLineItem

Excel PO import (/po/import):
- MANAGER, SUPERUSER, ADMIN can access
- Uploads .xlsx file to /api/po/import which parses the Pelagia PO format
- Extracts vendor, line items, quotation ref, T&C, delivery address
- Preview step: user selects vessel + account, auto-matches vendor by name
- Confirmed import creates PO in DRAFT status

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 18:52:51 +05:30
17586e6ea1 fix: serialize Prisma Decimal fields before server→client boundary
Convert quantity, unitPrice, totalPrice, gstRate, and totalAmount to
plain numbers in server pages before passing to client components,
preventing Next.js serialization errors on Decimal objects.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 17:51:54 +05:30
dd7a40e523 fix(ui): remove font-mono from line items numeric cells; revert formatCurrency
font-mono (monospace) renders optically larger than the surrounding
sans-serif at the same em size. Removing it from quantity, unit price,
taxable, GST% and total cells in both read-only and edit mode makes
all numbers visually consistent with the rest of the page.

formatCurrency reverted to Intl.NumberFormat with style:currency (the
original implementation); the spacing issue the user saw was font-related,
not symbol-related.
2026-05-06 00:50:32 +05:30
6f536734bd fix(ui): cohesive currency symbol and vendor field styling
formatCurrency: manually prepend Rs symbol instead of using Intl currency
style, which could inject a non-breaking space between the symbol and number.

po-detail vendor section: replace font-mono on Vendor ID with font-medium
text-neutral-900 so it matches all other detail fields. Not assigned
indicator changed from italic warning text to a small pill badge.
GSTIN keeps mono (it is a standardised code) but now has correct text colour
and tracking for legibility.
2026-05-06 00:45:39 +05:30
2ca1861226 feat(approvals): manager can edit all PO fields during review
Replaces the line-items-only editor with a full ManagerEditPoForm that
covers every field: title, vessel, account, vendor, project code, delivery
date, PI/Quotation No+Date, Requisition No+Date, place of delivery, all
structured T&C fields, and line items (with GST rate).

Edit toggle is amber-styled to distinguish manager changes from submitter
input. On save, a complete snapshot of original values is written to the
audit trail (MANAGER_LINE_EDIT action with metadata.original).

managerEditPo server action: validates manager permission, checks
status == MGR_REVIEW, recalculates totalAmount as grand total including
GST, and persists all updated fields.

Approval detail page now fetches vessels/accounts/vendors to populate the
edit form dropdowns.
2026-05-06 00:38:14 +05:30
ac584bce2f fix: totalAmount always stores grand total including GST
manager-line-edit-actions: add gstRate to lineItemSchema; recalculate
newTotal as sum(qty * unitPrice * (1 + gstRate)) and persist gstRate
on recreated line items.

seed: patch existing POs totalAmount to grand total (taxable * 1.18):
  PO-2026-00001: 8450 -> 9971
  PO-2026-00002: 3200 -> 3776
  PO-2026-00003:  950 -> 1121
2026-05-06 00:30:49 +05:30
bde7fc9842 fix(seed): patch existing PO currency from USD to INR on re-seed 2026-05-06 00:26:59 +05:30
67beccc16d fix(seed): upsert POs so re-running seed does not fail on duplicate poNumber; currency USD -> INR 2026-05-06 00:21:37 +05:30
7c31b0e838 feat(storage): shared link-document action and Python package requirements
link-document server action attaches an uploaded file to a PO after creation.
requirements.txt lists Python packages used for standalone PO generation scripts.
2026-05-06 00:17:56 +05:30
e07ce9bd02 test: unit, integration and E2E test suite (110 unit tests passing)
Unit (Vitest + jsdom):
  po-state-machine.test.ts   21 tests — all transitions and helpers
  permissions.test.ts        11 tests — all 7 roles
  utils.test.ts              17 tests — formatCurrency INR, formatDate, status labels
  validations.test.ts        24 tests — createPoSchema, lineItemSchema, TC defaults
  po-status-badge.test.tsx   17 tests — all 10 statuses
  po-line-items-editor.test.tsx 20 tests — add/remove, GST calc, read-only, diff mode

Integration (Vitest + real DB, mocked auth/notifier):
  create-po.test.ts          — S-01 create, S-02 draft, S-03 submit
  approval-actions.test.ts   — M-02 approve, M-03 reject, M-04 edits/vendor-id, S-06/S-07
  payment-actions.test.ts    — A-01 queue, A-02 mark paid with reference

E2E (Playwright):
  auth.spec.ts               — login, role nav, sign out
  submitter-journey.spec.ts  — S-01 to S-08
  manager-approvals.spec.ts  — M-01 to M-04
  accounts-payment.spec.ts   — A-01, A-02
  po-export.spec.ts          — export buttons, endpoint responses, PDF content
2026-05-06 00:16:10 +05:30
5cb8b228b1 feat(export): individual PO export as PDF and XLSX matching Sample_PO format
GET /api/po/[id]/export?format=pdf — HTML print page; company header, PO meta grid,
vendor block with GSTIN, line items table with taxable/GST%/total columns,
totals (taxable subtotal, GST, grand total), numbered T&C list, dual signature block.
GET /api/po/[id]/export?format=xlsx — SheetJS workbook matching Sample_PO.xlsx column layout.
Export PDF / Export XLSX buttons added to PO detail header.
2026-05-06 00:15:57 +05:30
0d053d9bd4 feat(products): admin product catalogue with auto price update on payment
Products: code, name, description; lastPrice and lastVendor are read-only.
On markPaid: for each line item linked to a product, Product.lastPrice and
lastVendorId are updated automatically and logged as PRODUCT_PRICE_UPDATED.
2026-05-06 00:15:47 +05:30
446c226c77 feat(admin): user, vendor, vessel and account management
Users: CRUD with role assignment, bcrypt password, cannot deactivate own account.
Vendors: CRUD with address, GSTIN, contact mobile; isVerified set when vendorId provided.
Vessels: CRUD with IMO number uniqueness check.
Accounts: CRUD with unique account code.
2026-05-06 00:15:41 +05:30
31906ec8bb feat(history): PO history list with date/vessel/status filters and bulk CSV and PDF export
Full audit list of all POs (latest 200). Filters: date range, vessel, status.
CSV export respects active filters. PDF export renders print-optimised HTML table.
2026-05-06 00:15:33 +05:30
c0ec7716d7 feat(orders): my orders list and receipt confirmation to close PO
My Orders: all submitter POs grouped as open/past with live status, manager note inline.
Receipt: upload receipt file, optional notes; confirms delivery and closes PO to CLOSED.
2026-05-06 00:15:22 +05:30
207c16e0e5 feat(payments): accounts payment queue with two-step payment and product price auto-update
Step 1 (process): MGR_APPROVED → SENT_FOR_PAYMENT, notifies submitter and managers.
Step 2 (mark paid): SENT_FOR_PAYMENT → PAID_DELIVERED, stores paymentRef.
On mark paid: auto-updates Product.lastPrice and lastVendorId for any line items
linked to a product code; logs PRODUCT_PRICE_UPDATED action.
2026-05-06 00:15:14 +05:30
a685e093ac feat(approvals): manager approval queue with decisions and line item editing
Approval queue: paginated list with search (PO number, vessel, submitter, date range).
Decision actions: approve, approve with note, reject (with reason), request edits,
request vendor ID.
Manager line edit: amend line items during review; original snapshot saved to audit
trail; diff shown with amber strikethrough on PO detail.
2026-05-06 00:15:05 +05:30
7e12e24af0 feat(po): PO detail view, vendor ID form and edit/resubmit flow
Detail: order info, vendor (address/GSTIN/contact), line items with GST breakdown,
structured T&C, attachments, activity trail, Export PDF/XLSX buttons.
Vendor ID form: inline on PO detail when status is VENDOR_ID_PENDING.
Edit: pre-populated form for DRAFT and EDITS_REQUESTED; resubmit transitions to MGR_REVIEW.
2026-05-06 00:14:55 +05:30
5a1db32cee feat(po): new PO form with line items, GST rate, structured T&C and file uploads
Form sections: order info, quotation reference (PI No/Date), requisition (No/Date),
place of delivery, line items (UoM dropdown, size, GST% per item), vendor, T&C, attachments.
Line items editor: add/remove rows, GST dropdown (0/5/12/18/28%, default 18%),
live taxable/GST/grand-total breakdown.
T&C: fixed line 1, individual inputs for Delivery, Dispatch, Inspection,
Transit Insurance, Payment Terms, Others.
Save as draft or submit directly for approval (→ MGR_REVIEW).
2026-05-05 23:25:06 +05:30
94774ca96b feat(dashboard): role-specific dashboards for submitter, manager, accounts and admin
Submitter: open PO count, recent orders table, New PO CTA.
Manager: approvals count, approved PO listing, spend by vessel and month bar charts (Recharts).
Accounts: payment queue total value, ready-for-payment count.
Admin/Auditor: total PO count card.
2026-05-05 23:24:55 +05:30
77aafcce99 feat(ui): shared component library — buttons, badges, cards, inputs, header, stat cards 2026-05-05 23:24:46 +05:30
62c5a52fc0 feat(storage): file storage with local dev server and Cloudflare R2 for production
Sign API returns presigned upload URL + storage key.
Dev: files served through auth-gated /api/files/dev route with path-traversal protection.
Prod: R2 presigned URLs for upload and time-limited download.
2026-05-05 23:24:41 +05:30
92b80dd278 feat(notifications): email notifications via Resend with React Email templates
7 event templates: po-submitted, po-approved, po-rejected, edits-requested,
vendor-id-needed, payment-processed, receipt-confirmed.
Notifier uses Resend in production and console.log in development.
2026-05-05 23:24:34 +05:30
c67afb2fff feat(state-machine): PO lifecycle state machine with role-gated transitions
10 statuses, 11 transitions. Each transition declares allowedRoles,
requiresNote flag and sideEffects (which email groups to notify).
Helpers: getTransition, canPerformAction, getAvailableActions, requiresNote.
2026-05-05 23:24:24 +05:30
043b26921a feat(auth): NextAuth v5 credentials login, database sessions and role permissions
7 roles: TECHNICAL, MANNING, ACCOUNTS, MANAGER, SUPERUSER, AUDITOR, ADMIN.
hasPermission / requirePermission helpers used across all server actions.
Login page with email + bcrypt password auth.
Middleware protects all portal routes.
2026-05-05 23:24:15 +05:30
535200aca2 feat(db): Prisma schema with all 11 models, migrations and seed data
Models: User, Vessel, Account, Vendor, Product, PurchaseOrder, POLineItem,
PODocument, POAction, Receipt, Notification.
PO fields include piQuotationNo/Date, requisitionNo/Date, placeOfDelivery,
structured T&C (tcDelivery/tcDispatch/tcInspection/tcTransitInsurance/
tcPaymentTerms/tcOthers), currency default INR.
POLineItem includes gstRate (default 0.18).
Vendor includes address, gstin, contactMobile.
Seed: 5 users across all roles, 3 vessels, 3 accounts, 3 vendors, 3 POs, 4 products.
2026-05-05 23:24:04 +05:30
36f3826684 chore: initialize Next.js 15 project with Tailwind, TypeScript and tooling config 2026-05-05 23:23:43 +05:30