Commit graph

20 commits

Author SHA1 Message Date
8982118eee feat(crewing): Phase 5a — verification queue (flagged)
First slice of Phase 5 (verification + appraisal). The office queue for verifying
site-entered records, per Crewing-Implementation-Spec §8.11/R11. Stacks on 4c.
Behind NEXT_PUBLIC_CREWING_ENABLED.

What's in
- Schema: CrewActionType += RECORD_VERIFIED/RECORD_REJECTED (migration
  crewing_verification_actions). No model changes — SeafarerDocument/BankDetail/
  EpfDetail already carry verificationStatus + verifiedById (3b/4a).
- Actions (crewing/verification/actions.ts): verifyDocument (verify_site_records —
  MPO/Manager) and verifyBankEpf (verify_bank_epf — Accounts) set
  verificationStatus VERIFIED/REJECTED + verifiedById; rejection requires remarks;
  each writes a CrewAction. Already-decided records are guarded.
- Screen: /crewing/verification — role-aware (MPO: pending documents with expiry
  flags; Accounts: pending bank/EPF), Verify / Reject-with-remarks. Leave is not
  here (Manager approval, R11). Verification added to nav (MPO + Accounts + SU, §7).

Tests & docs
- Integration: verification.test.ts (6) — doc verify/reject + already-decided
  guard, bank/EPF verify, permission gating (Accounts can't verify docs, MPO can't
  verify bank/EPF). type-check clean; full unit (241) + integration (201) green
  (verified with RESEND_API_KEY unset, mimicking CI).
- CLAUDE.md updated.

Deferred (per decision): PPE / next-of-kin verification gates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:59:31 +05:30
bb5f4126b0 feat(crewing): admin crew management — direct placement, CRUD, strength config
Office/admin crewing-management surface behind a new manage_crew permission
(Manager + SuperUser + Admin). Stacks on 4b. Behind NEXT_PUBLIC_CREWING_ENABLED.

What's in
- Permission: manage_crew added to the §6 matrix (MGR/SU/ADMIN).
- Direct placement (placeCrew): a Manager assigns a crew member to a vessel/site
  WITHOUT a requisition — creates an ACTIVE CrewAssignment, promotes a candidate to
  EMPLOYEE with a CRW- number (generateEmployeeId), blocked if already actively
  assigned.
- Admin crew CRUD: createCrewMember / updateCrewMember / deleteCrewMember (delete
  blocked when assignments/applications exist).
- Crew strength config: upsert/delete VesselRankRequirement (the minStrength that
  drives R6 leave-clash detection).
- Screens under Administration (flag-gated, MGR/SU/ADMIN): /admin/crew (list + add/
  edit/delete + Place modal) and /admin/crew-strength (requirement table + form).

Tests & docs
- Unit: permissions-crewing.test.ts gains a manage_crew check. Integration:
  crewing-admin.test.ts (9) — CRUD, delete guard, direct placement (+promotion,
  +active-assignment guard), strength upsert/delete, manage_crew gating.
  type-check clean; full unit (241) + integration (192) green.
- CLAUDE.md updated with the crewing-admin surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:23:31 +05:30
aac31c6755 feat(crewing): Phase 4b — leave & attendance (flagged)
Second slice of Phase 4 (stacked on 4a crew records). Leave (site-applied,
Manager-decided) with clash auto-backfill, and the daily attendance calendar,
per Crewing-Implementation-Spec §5.3/§8.9–8.10. Behind NEXT_PUBLIC_CREWING_ENABLED.

What's in
- Schema (crewing_leave_attendance migration): LeaveRequest (LeaveType,
  LeaveStatus) + Attendance (AttendanceStatus, unique per assignment+date) on
  CrewAssignment; CrewActionType += LEAVE_APPLIED/LEAVE_DECIDED/ATTENDANCE_RECORDED.
- Leave (R1): site staff apply on behalf (apply_leave); Manager decides
  (decide_leave) → assignment ON_LEAVE; MPO has no leave role. Leave approvals also
  surface in the central /approvals queue (§8.13 Leave kind). Notification
  LEAVE_FOR_APPROVAL.
- Clash auto-backfill (R6): lib/leave-clash.ts, required strength = 1 — approving a
  leave that leaves the vessel with zero active same-rank cover auto-raises a LEAVE
  requisition via the Phase-2 autoRaiseRequisition.
- Attendance (R5): daily month calendar; site staff record (record_attendance),
  Manager views (view_attendance) but cannot edit, MPO neither. saveAttendance
  bulk-upserts dirty cells.
- Screens: /crewing/leave (apply-on-behalf + Manager Approve/Decline) and
  /crewing/attendance (tap-to-cycle calendar + Save). Leave + Attendance added to
  the flag-gated nav (Manager + Site staff).

Tests & docs
- Integration: leave-attendance.test.ts (7) — apply/decide, clash auto-raise (and
  no-raise when cover remains), MPO/Manager attendance lockout, permission gating.
  type-check clean; full unit (240) + integration (182) green.
- CLAUDE.md updated with the Phase 4b surface.

Deferred: the 6-month leave-planner timeline (lightweight list for now); hours/
overtime attendance (A7).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:07:15 +05:30
37b1debc9d feat(crewing): Phase 4a — crew records & profile + PPE (flagged)
First slice of Phase 4 (stacked on 3c onboarding). The Crew directory and tabbed
crew profile with documents, bank/EPF (role-masked), next of kin, PPE and
experience, per Crewing-Implementation-Spec §8.7–8.8. Behind
NEXT_PUBLIC_CREWING_ENABLED; production unchanged.

What's in
- Schema (crewing_crew_records migration): SeafarerDocument, NextOfKin
  (isEmergency), ExperienceRecord, PpeIssue (PpeItem enum) — all on CrewMember;
  CrewActionType += DOCUMENT_UPLOADED/RECORD_UPDATED/PPE_ISSUED/PPE_RETURNED/
  EXPERIENCE_ADDED.
- PII masking (lib/crew-pii.ts, §6/§8.8): bank account + Aadhaar full only for
  Accounts/SuperUser, masked otherwise; salary hidden from site staff. Applied
  server-side before crossing to the client.
- Actions (crewing/crew/actions.ts): uploadDocument/deleteDocument, saveBankEpf,
  addNextOfKin/deleteNextOfKin, issuePpe/returnPpe, addExperience — guarded by
  upload_crew_records / issue_ppe, each writes a CrewAction.
- Screens: /crewing/crew (directory, search + vessel filter, ex-hands excluded)
  and /crewing/crew/[id] (tabbed profile: Documents · Bank & EPF · Next of kin ·
  PPE · Experience · Pay status). Crew added to the flag-gated nav (MGR/MPO/Site/
  Accounts).

Tests & docs
- Unit: crew-pii.test.ts (6). Integration: crew-records.test.ts (7) — documents,
  bank/EPF upsert, NoK, PPE issue/return, experience + permission gating.
  type-check clean; full unit (240) + integration (175) green.
- CLAUDE.md updated with the Phase 4a surface.

Deferred: site-staff own-site scoping (needs a User↔Site link); the records verify
queue (§8.11, Phase 5); Pay-status shows the salary structure only until payroll
(Phase 6).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:27:21 +05:30
be6db075dc feat(crewing): Phase 3a — candidates / talent pool (flagged)
First slice of Phase 3 (Epics B/C/D shipped as stacked sub-PRs). Adds the
CrewMember talent-pool spine and the Candidates screens. Behind
NEXT_PUBLIC_CREWING_ENABLED; production unchanged. Stacks on the requisitions
branch (Phase 2).

What's in
- Schema (crewing_candidates migration): CrewMember (spine) + CrewStatus,
  CandidateType, CandidateSource enums; CrewAction gains a nullable crewMemberId;
  CrewActionType += CANDIDATE_ADDED/UPDATED. employeeId is assigned at onboarding
  (3c), so it's nullable here.
- Actions (crewing/candidates/actions.ts): addCandidate / updateCandidate —
  guard flag + manage_candidates, write a CrewAction, optional CV upload via
  buildStorageKey("cv", …) + uploadBuffer (no parsing — A2 deferred). EX_HAND
  source ⇒ type/status EX_HAND; edits never downgrade an EMPLOYEE.
- Screens: /crewing/candidates (master list with search/source/rank-applied/
  min-experience filters as removable chips + match count + Clear all; Add-candidate
  modal) and /crewing/candidates/[id] (profile; pipeline stepper is 3b). Candidates
  added to the flag-gated Crewing nav (Manager + MPO).

Tests & docs
- Integration: candidates.test.ts (7) — add/update, ex-hand derivation, employee
  no-downgrade, permission gating. type-check clean; full unit (225) + integration
  (153) suites green.
- CLAUDE.md "Crewing" section updated with the Phase 3a surface.

Deferred: public careers intake API (A2, §13 open question); CV parsing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:23:01 +05:30
0b2ed9ac07 feat(crewing): Phase 2 — requisitions + relief requests (flagged)
Second slice of the Crewing module per wiki Crewing-Implementation-Spec §12
(build order item 2). Everything stays behind NEXT_PUBLIC_CREWING_ENABLED;
production is unchanged. Schema is added incrementally — this lands the
requisition lifecycle layer.

What's in
- Schema: Requisition (OPEN→SHORTLISTING→PROPOSING→INTERVIEWING→SELECTED→FILLED,
  →CANCELLED), ReliefRequest, CrewAction (the POAction mirror) + their enums.
  Migration crewing_requisitions.
- State machine: lib/requisition-state-machine.ts mirrors po-state-machine
  (selection Manager-only; orthogonal cancel from OPEN/SHORTLISTING by
  cancel_requisition holders, §6). Codes REQ-9000… via lib/requisition-number.ts.
- Actions: raise/cancel/transition + requestReliefCover/convertReliefToRequisition,
  each guarding flag+permission+state, writing a CrewAction and notifying. Shared
  autoRaiseRequisition() (lib/requisition-service.ts) is the backfill entry point
  for sign-off / leave-clash (later phases).
- Notifier: notifyCrew() PO-independent path + CrewNotificationEvent.
- Screens: /crewing/requisitions (list + Raise modal + relief convert) and
  /crewing/requisitions/[id] (detail). Requisitions added to the flag-gated
  Crewing sidebar (Manager + MPO, §7).

Tests & docs
- Unit: requisition-state-machine.test.ts (11).
- Integration: requisitions.test.ts (15) — raise/cancel/transition, relief
  request + convert, auto-raise, permission gating.
- CLAUDE.md "Crewing" section updated with the Phase 2 surface.

Deferred: sign-off/experience (Epic K, §12 item 2) depends on the crew/assignment
models from Phase 3/4; autoRaiseRequisition() is ready for it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:22:59 +05:30
d0006a8fc7 feat(crewing): foundations — SITE_STAFF role, ranks reference data + admin (flagged)
Phase 1 of the Crewing module per wiki Crewing-Implementation-Spec §12, all dark
behind NEXT_PUBLIC_CREWING_ENABLED (off by default — production unchanged).

- schema: add SITE_STAFF to Role; add Rank (self-referential org hierarchy, like
  Account) + RankDocRequirement, RankCategory & SeafarerDocType enums.
- permissions: full §6 crewing grant matrix (PO_ROLE_PERMISSIONS +
  CREWING_ROLE_PERMISSIONS merged); SITE_STAFF row; MPO has no attendance/leave,
  approvals are Manager-only, manage_ranks is Manager+Admin.
- feature flag: CREWING_ENABLED (opt-in "true").
- nav: flag-gated Crewing section scaffold + "Ranks & documents" under Admin.
- reference data: rank-data.ts + rank-doc-data.ts seeded via shared seed-ranks.ts
  in both dev and prod seeds (19 ranks, 118 doc requirements).
- screen: /admin/ranks — rank hierarchy card + per-rank required-documents card.
- role-label/prefix maps updated for the new role.

Tests: unit (permission matrix + flag), integration (ranks admin CRUD, parent
linking, cycle/children guards, doc-requirement upsert/remove, permission gating).
Docs: CLAUDE.md "Crewing (feature-flagged)" section + env var.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 13:26:04 +05:30
b5a5097ab5 feat(sidebar): add Sites to Administration section for admin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 08:49:58 +05:30
025b932f70 feat(sidebar): no Purchasing section for admin; Cost Centres in Administration
PURCHASING_MGMT roles narrowed to MANAGER only, so the entire Purchasing
section disappears for ADMIN (they never needed the /inventory/ browse links).
Cost Centres (/admin/vessels) added to the top of ADMIN_ITEMS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 08:46:19 +05:30
982a114eb5 feat(products): edit support on /admin/products; Purchasing Items -> /inventory/items
- updateProduct server action (name + description, code locked)
- EditProductButton dialog in product-form.tsx
- Edit entry wired into ProductActionsMenu
- Sidebar Purchasing Items for Manager/Admin now points to /inventory/items (cart view)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:14:15 +05:30
9bbc97b9bd feat(sidebar): add Items (/admin/products) to Administration for Manager
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 06:10:42 +05:30
0d6df57a88 fix(sidebar): purchasing Vendors links to /inventory, admin to /admin
No mirroring: the two vendor links serve different purposes.
Purchasing -> /inventory/vendors (site selector, distance sort)
Administration -> /admin/vendors (CRUD registry)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 03:08:25 +05:30
cc9c7b7e1f feat(sidebar): add Vendors to Purchasing section for Manager/Admin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 03:01:48 +05:30
e3851a1799 feat(sidebar+vessels): Purchasing section, split Administration, Cost Centre rename
Sidebar:
- Inventory section renamed to Purchasing
- Manager gets separate Administration section for Vendors only
- Admin gets full Administration (Vendors + Users + Accounting Codes + Companies)
- Sites hidden from Manager when NEXT_PUBLIC_INVENTORY_ENABLED=false
- Cost Centres replaces Vessels in the Purchasing nav link

Admin vessel pages:
- All headings, titles, dialogs, breadcrumbs: Vessels -> Cost Centre
- Error messages updated accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 02:53:33 +05:30
56b0490229 feat: structured PO numbers, import closed, auto-vendor/product, company code, inventory flag
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:56:33 +05:30
e308d86e93 feat: Companies — multi-company PO support with admin CRUD and export integration
Schema:
- New Company model (name, gstNumber, address, telephone, mobile, email, invoiceAddress, isActive)
- PurchaseOrder.companyId FK (optional, SET NULL on company delete)
- Migration: 20260530000003_add_company

Admin:
- /admin/companies page with full CRUD (create, edit, deactivate, delete)
- Companies table shows name, GST, contact details, status
- Companies link added to Admin section of sidebar (Briefcase icon)

PO forms (new / edit / import / manager-edit):
- Company dropdown appears at the top of Order Information when companies exist
- Pre-populated with first active company; selection persisted to DB via companyId

Import form:
- parseSheet() now extracts companyName from Excel row 1 (col A)
- Import preview auto-matches detected company name against known companies
- Shows detected name as a hint; user can override before saving

Export (PDF + XLSX):
- Company constants (CO_NAME, CO_ADDR, CO_TEL, INV_ADDR, INV_GST) are now
  derived from the linked Company record when present, falling back to the
  original Pelagia Marine hardcoded defaults when no company is set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 19:31:34 +05:30
cc7251e6b7 feat: Cost Centre covers vessels and sites, vessel codes, Accounting Code rename, vessel-site assignment
- Undo Vessel→Cost Centre rename in admin (admin shows "Vessel Management" again)
- Sidebar: "Cost Centres"→"Vessels", "Accounts"→"Accounting Codes"
- PO forms (new/edit/import/manager-edit) now show both Vessels (with code) and Sites in the
  Cost Centre dropdown, encoded as v:<id> / s:<id> via a costCentreRef field
- vesselId on PurchaseOrder is now nullable; siteId is set when a site is the cost centre
- History, approvals, dashboard, my-orders, payments display vessel.name ?? site.name as Cost Centre
- History and approvals cost centre filters use costCentreRef URL param supporting both types
- Admin vessel form: adds Site assignment dropdown
- Admin accounts: renamed to "Accounting Code" throughout (pages, forms, sidebar)
- PO detail and exports: "Account" label renamed to "Accounting Code"
- Site detail: "Assigned Vessels (Cost Centres)" heading; vessel detail breadcrumb fixed
- Create PO links from vessel/site detail use ?costCentreRef= param
- Export routes handle costCentreRef filter param (with legacy vesselId fallback)
- DB migration: ALTER TABLE PurchaseOrder ALTER COLUMN vesselId DROP NOT NULL
- CLAUDE.md updated with Cost Centre Model documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 03:04:29 +05:30
d4007ee222 feat(my-orders): rename to Closed Purchase Orders, show only closed POs
Open POs are already visible on the dashboard. The /my-orders page now
fetches and displays only completed/closed statuses (MGR_APPROVED through
REJECTED) and is labelled 'Closed Purchase Orders' throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 04:21:53 +05:30
32ea27331c fix(po): tighten filters and export data 2026-05-22 17:15:03 +05:30
19029a5a77 chore: restructure repo — flatten App/pelagia-portal to App, rename Prototype→Wireframe and Spec→Design
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 23:18:58 +05:30
Renamed from App/pelagia-portal/components/layout/sidebar.tsx (Browse further)