9 Crewing Implementation Spec
Hardik edited this page 2026-06-22 22:12:28 +05:30
This file contains ambiguous Unicode characters

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.

Crewing — Final Implementation Spec

This page is the authoritative, reconciled build instruction set for the Crewing module. It supersedes the other Crewing-* design pages wherever they differ. Those pages remain as design background; a banner on each points here.

Inputs reconciled: the design handoff (design_handoff_crewing/ — the hi-fi clickable prototype is the source of truth for UI, behaviour and copy), the Crewing-* wiki design pages, and the Crewing CHANGELOG (the tiebreaker). Status: design-complete proposal, not yet built; behind NEXT_PUBLIC_CREWING_ENABLED.


1. Reconciliation method

Where the wiki design pages and the handoff prototype disagree, the rule is:

  1. Check the Crewing CHANGELOG (design_handoff_crewing change log).
  2. If the point was an intentional design change recorded in the CHANGELOG → defer to the design (prototype).
  3. If it was not an intentional change (an oversight or omission in the prototype) → defer to the docs (wiki).
  4. Explicit director answers in Design Doc § Open Questions (Q1Q7) are authoritative and folded in below.

1.1 Reconciliation decisions

# Point Wiki said Design said CHANGELOG Ruling
R1 Who approves leave MPO decides leave Manager approves; MPO has no Leave nav at all #8 Leave = manager-approved, #15 Leave is site + manager only Design — leave is Manager-approved; MPO is removed from leave entirely.
R2 Interview waiver (ex-hands) Interview auto-waived / "optional" for ex-hands Ex-hands go through Interview like everyone; waiver is an explicit "Request waiver → Manager" action #18 stopped auto-waiving; waiver is explicit Design — waiver is an explicit Manager-approved action, never automatic.
R3 Who raises requisitions Site staff or MPO raise requisitions Requisitions/Candidates not in site-staff nav; no Raise buttons for site staff #11 Requisitions/Recruitment = MPO/Manager only Design — only MPO/Manager raise requisitions. Site staff instead "Request relief cover" (a relief request the office converts).
R4 Pipeline shape 8-stage enum, order competency → docs → reference → salary 7-stage board: Shortlisted → Competency & references → Docs → Salary → Proposed → Interview → Selected #17 reworked the pipeline to these 7 stages Design — 7 visible stages; competency + reference merged; docs before salary. ONBOARDED stays a terminal system state, not a board column.
R5 MPO attendance access MPO has no attendance access; Manager reviews Handoff nav table shows Attendance ✓ for MPO (no entry granting MPO attendance) Docs — the ✓ for MPO is an oversight. MPO gets no Attendance; nav = Manager + Site staff only.
R6 Clash → requisition Automatic on leave approval Manual role-aware "Raise relief requisition" / "Request relief cover" + a relief-requests table #6/#11/#13 added the relief affordances (did not say "make it manual") Both — a detected hard clash (rank below required strength) auto-raises a LEAVE requisition (director-confirmed). The relief-request flow is a complementary, proactive site-staff channel for foreseen gaps.
R7 Wage reports surface Standalone wage flow No wage-reports nav; a Pay status tab on the Crew Profile (status-only for site staff, net pay for office) + Wage approval in the Approvals queue #12 replaced wage nav with Pay status tab Design — no standalone screen. Backend generation/approval/dispatch (wiki) is unchanged; surfaced via Pay-status tab, Approvals queue, and the Accounts export.
R8 Approvals Per-lifecycle approvals One unified Manager Approvals queue across PO + crewing (7 kinds) #20 expanded the central queue to all seven Design (additive) — one Manager Approvals queue.
R9 Candidates vs Crew CrewMember spine; ex-hands are a status Top-level Candidates page; ex-hands appear only in Candidates, not the Crew directory #16 added Candidates master; removed ex-hands from Crew Design — Crew directory lists active employees; ex-hands live in the Candidates pool.
R10 Salary basis basic + victualingPerDay per-month / per-day rate toggle, each derived from the other #3 salary per day/month toggle Design — capture both, derive. Aligns with A4 (mid-assignment changes; prorate).
R11 Verification scope MPO verifies docs/PPE/leave/NoK Leave is a Manager approval, not an MPO verification item follows from R1 Reconciled — MPO verifies docs/PPE/NoK (+ emergency); leave → Manager; bank/EPF → Accounts.

1.2 Director answers folded in (Design Doc Q1Q7)

  • A1 — single new SITE_STAFF role, held only by PM/APM/Site In-charge; MPO is MANNING.
  • A2 — the candidate self-apply form lives on the public marketing site (pelagiamarine.com) and posts to a portal API.
  • A3 — EPFO UAN/Aadhaar verification: assisted-manual in v1 (record the result); a future EPFO proxy microservice (GstService pattern) is preferred.
  • A4 — salary and the whole contract can change mid-assignment; wage must prorate: days×rate₁ + days×rate₂. → SalaryStructure is effective-dated (many per assignment), not single.
  • A5victualing is a separate accrual line, shown distinctly from base pay.
  • A6no crew self-service in v1; only PM/APM/Site In-charge log in and act for crew.
  • A7 — attendance with shift/hours + overtime is desired but tentative; v1 ships the daily model the prototype built (Present/Absent/Half-day/Leave). Hours/overtime is a deferred enhancement (§13).

2. Corrections to apply to the existing design pages

These follow from §1.1 and are listed so the design pages can be brought in line (each already carries a banner pointing here):

  • Roles & Permissions: decide_leaveManager only (drop MAN); apply_leave → SITE + MGR (drop MAN); drop leave from verify_site_records; remove SITE from raise_requisition; add request_relief_cover (SITE) and request/approve_interview_waiver. Use the final matrix in §6.
  • Workflows: leave decided by the Manager (not MPO) in §3.1 and §9; remove the automatic ex-hand PROPOSING→SELECTED / PROPOSED→SELECTED waiver paths — ex-hands pass through INTERVIEW, satisfied either by an interview result or a Manager-approved waiver; re-order the Application diagram to the 7-stage sequence (R4).
  • Data Model: ApplicationStage → the 7 board stages + system states (R4, see §5.1); LEAVE_REQUEST decided by Manager; SalaryStructure effective-dated with effectiveFrom (R10/A4); add RELIEF_REQUEST model (R6).
  • Module / Design Doc / Use Cases / User Stories: "interview optional/waived for ex-hands" → "ex-hands interview unless a Manager-approved waiver is granted"; "site staff raise requisitions" → "site staff request relief cover"; "MPO decides leave" → "Manager decides leave".

3. How Crewing slots into PPMS

One portal, one role-aware sidebar. Crewing is a feature area inside the existing Next.js app, not a new app — exactly like Purchasing. It reuses the PPMS stack (Next.js 15 App Router, Prisma + PostgreSQL, NextAuth v5, Tailwind v4, shadcn/ui) and the proven PO primitives.

Crewing needs Reuse this existing PPMS primitive Path
Per-lifecycle state machines po-state-machine.ts pattern (TRANSITIONS map → {to, allowedRoles, requiresNote, sideEffects}, canPerformAction, getAvailableActions) App/lib/po-state-machine.ts
Permission gating requirePermission(role, permission) + ROLE_PERMISSIONS: Record<Role, Permission[]> App/lib/permissions.ts
Audit trail POAction model + ActionType enum, written via nested actions: { create: … } App/prisma/schema.prisma
Server-action shape auth → fetch → permission/state guard → transaction → audit → notify → revalidatePath App/app/(portal)/approvals/[id]/actions.ts
Email + in-app notify notify({ event, … }) (console in dev, Resend + Notification rows in prod) App/lib/notifier.ts
File storage buildStorageKey, generateUploadUrl, uploadBuffer, signed download URLs (R2 in prod, .dev-uploads/ in dev) App/lib/storage.ts
Nav NavItem {href,label,icon,roles?} arrays + SectionHeader, filtered by role App/components/layout/sidebar.tsx
Feature flag NEXT_PUBLIC_* boolean exports App/lib/feature-flags.ts
Cost centre Vessel (and Site) reused as the crew cost axis App/prisma/schema.prisma

New modules to add (mirroring the above): lib/requisition-state-machine.ts, lib/application-pipeline.ts, lib/assignment-state-machine.ts, lib/appraisal-state-machine.ts, lib/wage-report.ts, and routes under app/(portal)/crewing/….


4. Changes required to the current PPMS codebase

4.1 Schema (App/prisma/schema.prisma)

  • Add SITE_STAFF to Role. Current enum: TECHNICAL MANNING ACCOUNTS MANAGER SUPERUSER AUDITOR ADMIN → append SITE_STAFF. (MPO = MANNING.)
  • Add all crewing models + enums from Data Model, with the §1 reconciliations: 7-stage ApplicationStage (§5.1), effective-dated SalaryStructure, RELIEF_REQUEST, Rank.grantsLogin (true only for PM/APM/Site In-charge), CrewAction + CrewActionType.
  • A CrewMember is promoted to a User (with a SITE_STAFF login) only when its rank grantsLogin; all other ranks are data subjects with no account.

4.2 Permissions (App/lib/permissions.ts)

Extend the Permission string union with the crewing permissions and add a ROLE_PERMISSIONS row for SITE_STAFF; update MANNING/MANAGER/ACCOUNTS rows. The final grant matrix is §6.

4.3 Navigation (App/components/layout/sidebar.tsx)

Add a CREWING_ITEMS: NavItem[] array and a SectionHeader label="Crewing" block (after Purchasing), gated by CREWING_ENABLED and per-item roles. Add Ranks & documents under the existing Administration section. Final visibility matrix in §7.

4.4 State machines (App/lib/…)

Five machines, each the po-state-machine.ts shape (status-keyed TRANSITIONS, allowedRoles, sideEffects, audit on transition): Requisition, Application (the 7-stage pipeline), Assignment (+ leave/clash), Appraisal, Wage report. Cancellation is orthogonal (CANCEL_ROLES pattern). See reconciled diagrams in §5.

4.5 Audit, notifier, storage, flag

  • CrewAction model (mirror POAction) + CrewActionType enum.
  • Add crewing events to notifier.ts NotificationEvent union (REQUISITION_RAISED, CANDIDATE_PROPOSED, SALARY_FOR_APPROVAL, SELECTION_FOR_APPROVAL, WAIVER_REQUESTED, LEAVE_FOR_APPROVAL, APPRAISAL_VERIFIED, WAGE_REPORT_READY, RELIEF_REQUESTED, …) with subject/body/link builders.
  • Document/CV/contract uploads use buildStorageKey("crew-document"|"cv"|"contract", crewId, fileName).
  • feature-flags.ts: export const CREWING_ENABLED = process.env.NEXT_PUBLIC_CREWING_ENABLED === "true"; (off unless "true", like SUBMITTER_VIEW_ALL_ENABLED).

5. Domain model & state machines (reconciled)

Full ER + enums in Data Model. Deltas vs that page:

5.1 Application pipeline (7 stages — R4)

SHORTLISTED → COMPETENCY_AND_REFERENCES → DOC_VERIFICATION → SALARY_AGREEMENT
            → PROPOSED → INTERVIEW → SELECTED            (→ system: ONBOARDED)
any stage   → REJECTED (remarks)
  • Competency & references is one stage (was two). Docs before Salary.
  • Interview applies to everyone. For returning crew it may be satisfied by a Manager-approved waiver (interviewWaived set only after approval) — never auto-waived (R2).
  • Selected requires all prior gates cleared and Manager approval of both the salary structure and the selection. Onboard is the side-effecting action off SELECTED (joining formalities) → ONBOARDED; JOINING is folded into it.
  • Each transition writes an APPLICATION_GATE (gate, result, note, decidedById) + a CrewAction.

5.2 Requisition lifecycle

OPEN → SHORTLISTING → PROPOSING → INTERVIEWING → SELECTED → FILLED; → CANCELLED from OPEN/SHORTLISTING (Manager). Raised by MPO/Manager (manual), or by the system on sign-off / EOC and on a leave clash (R6). No direct ex-hand shortcut around INTERVIEWING (R2).

5.3 Assignment + leave clash (R1, R6)

ACTIVE ⇄ ON_LEAVE, → SIGNED_OFF. Leave: applied by Site In-charge on a crew member (LeaveRequest APPLIED) → approved by the Manager (APPROVED → assignment ON_LEAVE). On approval the assignment machine checks rank cover over the window; if it would drop below the ranks required strength, it auto-raises Requisition(OPEN, reason=LEAVE, autoRaised) and notifies the office. Sign-off appends an EXPERIENCE_RECORD and auto-raises a backfill requisition; the person returns to Candidates as an ex-hand. (Phasing: the auto-raised backfill requisition ships in Phase 2 via the shared autoRaiseRequisition helper; sign-off itself + the EXPERIENCE_RECORD ship in Phase 4 with the assignment lifecycle — see §12.)

5.4 Appraisal & wage

  • Appraisal: DRAFT → SUBMITTED →(MPO) MPO_VERIFIED →(Manager) MANAGER_APPROVED; returns to REJECTED/DRAFT with remarks.
  • Wage report: DRAFT → GENERATED →(Manager) MANAGER_APPROVED → SENT_TO_ACCOUNTS. WageLine = daysAttended × dailyRate (+ victualing as a separate line, A5), prorated across effective-dated salary structures (A4). Generated by Manager / month-end job — never the MPO (no attendance access).

6. Roles & permissions (final matrix)

SITE = SITE_STAFF · MAN = MANNING (MPO) · ACC = ACCOUNTS · MGR = MANAGER · SU = SUPERUSER · AUD = AUDITOR · ADM = ADMIN.

Permission SITE MAN ACC MGR SU AUD ADM
raise_requisition
request_relief_cover (new)
convert_relief_to_requisition (new)
cancel_requisition
view_requisitions
manage_candidates
record_reference_check
record_interview_result (new)
request_interview_waiver (new)
approve_interview_waiver (new)
approve_salary_structure
select_candidate (final approval)
onboard_crew
sign_off_crew
view_crew_records ✓¹ ✓²
upload_crew_records
issue_ppe
apply_leave
decide_leave (Manager — R1)
record_attendance
view_attendance (no MPO — R5)
verify_site_records (docs/PPE/NoK — R11)
verify_bank_epf
raise_appraisal
verify_appraisal
approve_appraisal
generate_wage_report
approve_wage_report
view_wage_report
manage_ranks

¹ Site staff: own site only; contract view-only-except-salary, bank view-only masked. ² Accounts: bank/EPF + wage only, not the full HR record.

Field-level (PII): salary, full bank account number, Aadhaar/PAN, and candidate rejection remarks are masked/gated per Roles & Permissions §3.


7. Navigation & role visibility (final)

Item Group Manager MPO Site staff Accounts
Dashboard
Purchase orders Purchasing (PO roles)
Approvals Purchasing (badge)
Requisitions Crewing
Candidates Crewing
Crew Crewing (own site) (bank/EPF/wage)
Leave Crewing
Attendance Crewing
Verification Crewing (bank/EPF)
Ranks & documents Administration

Bold = corrected from the handoff nav table (R1/R5): MPO has neither Leave nor Attendance. Recruitment (Requisitions/Candidates) is office-only (R3). There is no Wage-reports nav item (R7) — wages live on the Crew Profile Pay status tab and in the Approvals queue. The role switcher in the prototype is a demo affordance; in production the role comes from auth.


8. Screen spec (role-aware)

Layout: fixed 248px sidebar + 56px top bar + scrollable main on #fafafa, content max-width 1080px. Tokens (Inter / JetBrains Mono, the primary/success/warning/danger/neutral ramps, radii, badges, buttons, inputs, tables) are specified in the the design handoff README (design_handoff_crewing/README.md) and match the PPMS Design System — build with shadcn/ui, do not copy the prototype HTML.

8.1 Dashboard (role-aware)

KPI cards grouped by section + two action-queue list cards. Deep-links into each screen. Per role:

  • Manager: Purchasing KPIs (Open POs, Approvals pending, Payments due, Spend MTD) + Crewing KPIs (Open requisitions, In pipeline, Docs expiring, Crew on leave); lists Approvals waiting + Recruitment at a glance; header Raise requisition.
  • MPO: my orders PO KPIs + Crewing KPIs (Requisitions to source, In my pipeline, Verifications pending, Docs expiring); lists My verification queue + Requisitions needing action.
  • Site staff: one My site KPI group (Crew on site, Days to mark, Leave to submit, Docs/PPE pending); lists Todays tasks + Expiring documents · my site. No Raise button.

8.2 Requisitions (list) — MPO/Manager

Search + status + vessel filters; Raise requisition (modal). Columns: Requisition (mono id + age), Vessel/site, Rank, Reason, Candidates (count), Status badge → row opens detail. Status→variant: Open→outline, Shortlisting/Proposing→default, Interviewing→warning, Filled→success, Cancelled→danger. Below the table — "Relief requests from sites" (R3/R6): gaps flagged by site staff; columns Vessel/site, Rank, Reason, Requested by, and an "Open" action (people icon) that converts the request into a requisition (prefilled Raise modal). Empty-state row when none.

8.3 Requisition detail — MPO/Manager

Back link; header "{Rank} — {Vessel}" + status badge; sub line (mono id · reason · age). Actions Open pipeline (primary) + Withdraw (Manager). Cards: Vacancy details (key/value + an auto-raised-vs-manual info callout) and Candidates (attached list, ex-hands tagged → candidate detail).

8.4 Recruitment pipeline (per requisition) — MPO/Manager

Reached from a requisition (not top-level nav). Header names rank/vessel/req id; Add candidate (secondary). A horizontal board of 7 columns (§5.1). Each card: avatar, name, rank · N yrs, ex-hand tag → candidate detail. Cards grouped by the candidates effective stage (advancing moves cards live).

8.5 Candidate detail (recruitment workhorse) — MPO/Manager

Back link; header avatar, name, ex-hand badge, meta. 7-step stepper (§5.1; done=green check, current=blue, todo=grey). Adaptive action card by stage:

  • Shortlisted / Competency & references: description + advance + Reject.
  • Docs: MPO collects & verifies — a document checklist (verify icon, name, sub, Verified/Upload badge) + a Bank & EPF form (Account no., IFSC, UAN, Aadhaar/PAN). Primary Verify & continue to salary + Reject.
  • Salary: Basic + Allowances with a per-month / per-day basis toggle (R10), each derived; note "office-only; Manager approves". Primary Agree salary & propose (sends salary for Manager approval).
  • Proposed: "awaiting candidate" callout. Primary Candidate accepted — schedule interview.
  • Interview (R2): Interview result row (Accept/Reject, recorded by MPO) → Manager approval row (Approve/Return, after MPO accepts) → optional Waive interview row ("Request waiver → Manager", returning crew only). Primary Approved — select (after Manager approval).
  • Selected: success callout; primary Onboard to crew (Onboard modal → assigns employee no., candidate becomes crew). No Reject. Right column: Profile (Rank applied, Last rank held, Experience, Source) + an ex-hand "Returning crew" callout (prior docs/bank/tour on file; interview may be waived with Manager approval). Reject → back to pipeline with remarks.

8.6 Candidates (master list) — MPO/Manager

The whole talent pool (careers applicants, ex-hands, walk-ins, referrals). Header Add (+) → Add-candidate modal. Filters: search, Source, Rank-applied, Min-experience → active filters render as removable chips + match count + Clear all. Columns: Name, Source (ex-hand=purple), Rank held, Rank applied, Experience, Status ("In {REQ-id}" / "Available") → candidate detail.

8.7 Crew (directory) — Manager/MPO/Site staff(own site)

Search + vessel filter. Columns: Name, Employee (mono CRW-xxxx), Rank, Vessel/site, Status (Active→success, On leave→warning) → Crew profile. Ex-hands are not here (R9) — they live in Candidates. Site staff see their site only.

8.8 Crew profile (tabbed)

Back link; header avatar, name, status badge, mono employee no · rank · vessel; Sign off button. Underline tabs: Documents · Bank & EPF · Next of kin · PPE · Experience · Pay status.

  • Documents: Upload header; rows = thumbnail, name, issue/expiry, state badge (Verified / Expires in Nd / Pending / Missing).
  • Bank & EPF: masked for non-Accounts (•••• 4471 + warning callout); full for Accounts. Two-column mono key/value.
  • Next of kin / Emergency: two-column key/value.
  • PPE: summary (boiler-suit & shoe size); rows = item, size, issued date, state badge, per-row Issue (pending) / Reissue (issued) → PPE modal.
  • Experience: timeline rows (role, vessel, period).
  • Pay status (R7): per-month rows, Month + Status badge (Paid→success, Processing→secondary); Net pay column shown only to office roles, hidden from site staff.

8.9 Leave — Manager & Site staff (R1)

Header Apply for leave (modal; site staff apply on behalf of a crew member). Leave planner card: 6-month timeline, one row per crew member, contract bars + approved-leave bars + same-rank clash bars. A red coverage-clash callout names the two overlapping same-rank crew + dates; action button is role-aware — site staff → "Request relief cover" (relief modal, notifies office); Manager → "Raise relief requisition". (A detected hard clash also auto-raises a LEAVE requisition, R6.) Leave requests card: Approve/Decline only in the Manager view; site staff see "Awaiting manager". Subtitle: "Site staff apply on behalf of crew · the Manager approves." MPO has no Leave screen.

8.10 Attendance (month calendar) — Manager & Site staff (R5)

Header Save (icon + "Save", grey until an edit, blue when dirty). A site-wide "N days still need marking" warning (feeds the dashboard KPI). Three summary cards (Present / Absent / On leave) for the selected crew member. Calendar: month label + prev/next + crew-member dropdown; legend; 7-column weekday grid; tap a day cell cycles Unmarked → Present → Absent → Leave → Half day (dashed border = unmarked). MPO has no Attendance screen. No verification gate.

8.11 Verification (MPO) — and Accounts for bank/EPF

Queue of site-entered records awaiting office verification (everything except attendance; bank/EPF route to Accounts). Columns: Item, Crew, Site, Submitted, Review → → Verification detail (submitted fields + document preview

  • expiry alert + Verify / Reject-with-remarks). Leave is not here (R11) — it is a Manager approval.

8.12 Ranks & document rules (Manager/Admin)

Two cards: Rank hierarchy (indented self-hierarchy; the org chart, with the grantsLogin flag visible on PM/APM/Site In-charge) and Required documents — {rank} (checklist with mandatory/conditional tags). Drives candidate vetting and crew uploads.

8.13 Approvals (Manager — unified queue, R8)

One queue for everything needing Manager sign-off; each row: kind badge, title, sub, amount (mono), Approve / Return. Kinds: PO, Salary (structure), Selection (candidate), Waiver (interview), Leave, Appraisal, Wage (report). Nav badge = count. This is where Leave and Waiver approvals live (R1/R2).

8.14 Appraisal (entry/verify) — under-specified in the prototype

The prototype only shows Appraisal in the Approvals queue. Build the entry/verify screens to the wiki lifecycle (§5.4): a PM raises (DRAFT→SUBMITTED) from the Crew profile; an MPO verifies (MPO_VERIFIED) from the Verification area; the Manager approves from the Approvals queue. Reuse the same card/badge/stepper vocabulary.

8.15 Purchase orders (continuity)

Existing purchasing workspace, unchanged — shown so the unified portal reads as one product.


9. Modals

Centered, 420500px, 12px radius, heavy shadow, dim overlay; header (title + sub) · padded form body · footer (Cancel + primary, right-aligned):

  • Raise requisition — Vessel/site, Rank, Reason, Needed-by.
  • Apply for leave — Crew-member dropdown (apply on behalf), From/To, computed-duration callout, Reason.
  • Onboard — Joining date, Contract-letter upload, "Starts automatically" chips (Salary, Victualing, Attendance, Experience, EPF/PF, PPE). Confirm assigns employee no.
  • Add candidate — CV dropzone, parsed/autofill callout, editable fields (name, source, rank applied, experience, vessel type).
  • Issue / Reissue PPE — "{Issue|Reissue} — {item}", Size dropdown, optional Comment.
  • Request relief cover (site staff, R3/R6) — clash warning, Rank needed, note to office → creates a relief request.

10. User stories

The backlog in Crewing User Stories (Epics AM) stands, with these reconciliations:

  • A2 — site staff request relief cover; only MPO/Manager raise requisitions (R3).
  • A5 / G3 — the Manager decides leave; an approved clash auto-raises a LEAVE requisition (R1/R6).
  • C7 / C8 / UC-08 — ex-hands are interviewed; waiver is an explicit Manager-approved action (R2).
  • C9 — the pipeline board has the 7 stages of §5.1 (R4).
  • G3 / G4 / I1MPO has no attendance; Manager reviews it (R5).
  • J1 — wage prorates across effective-dated salary structures; victualing is a separate line (A4/A5).

11. Cross-cutting

  • Audit: every transition + verification writes a CrewAction (actor, type, note, metadata) — "one transition, one row, declared side-effects", like PO approval. Onboarding is the side-effecting event (salary/victualing/attendance/experience/PF/PPE + employeeId + requisition→FILLED) in one transaction.
  • Notifications: declarative per-transition email/in-app via notifier.ts (requisition raised → MPO; salary/selection/waiver/leave/appraisal/wage → Manager; wage ready → Accounts; relief requested → office).
  • PII: bank/EPF/identity stored masked/encrypted via the signed-URL File Storage; access gated by §6.
  • Document expiry: docs with expiryDate (medical, passport, CDC, STCW) raise upcoming-expiry warnings on the profile and a queue.
  • Consistency: all mutations are Server Actions (requirePermission → state-machine guard → transactional write → audit → notify); no mutation REST endpoints (except the public careers-apply intake, A2).

12. Build order

Implementation status (reconciled 2026-06-22): Phase 1 shipped. Phase 2 ships Epic A (Requisitions + relief) plus the shared auto-backfill helper (autoRaiseRequisition). The sign-off/experience portion of Epic K has been moved to Phase 4 — sign-off transitions an assignment (→ SIGNED_OFF) and writes an EXPERIENCE_RECORD, neither of which exists until onboarding (D, Phase 3) and the assignment lifecycle (Phase 4) land. The auto-raised backfill requisition it relies on is already built in Phase 2, so Epic K is purely additive when it arrives.

Phase 3 complete — delivered as three stacked sub-PRs: 3a Candidates (Epic B) , 3b Recruitment pipeline (Epic C) , 3c Onboarding (Epic D) . 3b's central-Approvals integration follows §8.13 R8 (Salary/Selection/Waiver gates surface in the unified Manager queue). SalaryStructure is attached to the Application during the pipeline and bound to the CrewAssignment at onboarding (3c). Onboarding promotes the candidate to EMPLOYEE with a CRW- number; SITE_STAFF login creation for management ranks (grantsLogin) is a deferred follow-up.

Phase 4 complete — stacked sub-PRs: 4a Crew records & profile + PPE (Epics E, F) , 4b Leave & attendance (Epic G) , 4c Sign-off & experience (Epic K) . Sign-off ends a tour (SIGNED_OFF), appends an internal EXPERIENCE_RECORD, flips the same CrewMember EMPLOYEE → EX_HAND (returns to Candidates), and auto-raises a SIGN_OFF backfill — the reverse of onboarding/placement on one row. 4a applies role-based PII masking server-side (bank/Aadhaar full only for Accounts; salary hidden from site staff, §6/§8.8). Deferrals carried in 4a: site-staff own-site scoping (needs a User↔Site link), the records verify queue (§8.11 → Phase 5), and the Pay-status tab beyond the salary structure (→ payroll, Phase 6).

R6 clash detection — reconciled to Option A (director decision): a VesselRankRequirement{vesselId, rankId, minStrength} configures required crew strength per rank per vessel; approving a leave that drops active same-rank cover over the window below minStrength (default 1 when unconfigured) auto-raises a LEAVE requisition (reuses the Phase-2 autoRaiseRequisition). A follow-up crewing-admin PR adds the office UI to manage requirements, Manager direct crew placement (assign crew to a vessel/site without a requisition), and Admin crew CRUD, behind a new manage_crew permission.

Phase 5 complete — stacked sub-PRs: 5a Verification (Epic I) , 5b Appraisal (Epic H) . 5a is the office verify queue (/crewing/verification): the MPO verifies/rejects documents (verify_site_records) and Accounts verifies/rejects bank/EPF (verify_bank_epf) — leave is not here (it's a Manager approval, R11). PPE/next-of-kin verify gates were deferred (low-risk; no verificationStatus on those models). 5b is the appraisal lifecycle raise → verify → approve (Appraisal/AppraisalStatus) across three role-gated surfaces (§8.14): PM raises on the crew-profile Appraisals tab, MPO verifies in the Verification queue, Manager approves in the central /approvals queue (Appraisal kind).

  1. FoundationsSITE_STAFF role; crewing schema + enums; permissions; CREWING_ENABLED flag; nav scaffold; reference data (Ranks, RankDocRequirements).
  2. Requisitions + relief (Epic A) — requisition lifecycle, relief requests, and the shared autoRaiseRequisition backfill helper. (Epic K sign-off/experience originally sat here; moved to Phase 4 — see status note above, as it depends on the onboarding/assignment schema.)
  3. Candidate intake + 7-stage pipeline + onboarding (B, C, D) — incl. salary→Manager approval, explicit waiver. (Delivered as stacked sub-PRs 3a candidates → 3b pipeline → 3c onboarding — see status note above.)
  4. Crew records, PPE, leave/attendance + sign-off/experience (E, F, G, K) — leave→Manager, MPO no attendance, clash auto-req + relief requests; sign-off transitions the assignment to SIGNED_OFF, appends an EXPERIENCE_RECORD, and auto-raises a backfill requisition (reusing the Phase-2 autoRaiseRequisition helper); the person returns to Candidates as an ex-hand.
  5. Verification + appraisal (I, H).
  6. Payroll (Pay-status tab + Approvals "Wage"), dashboards, notifications (J, M).

13. Open questions (remaining)

  • Attendance granularity (A7): v1 ships daily Present/Absent/Half/Leave; shift/hours + overtime is a deferred enhancement — confirm before payroll work if hours must feed wages.
  • EPFO verification (A3): assisted-manual in v1; schedule the EPFO proxy microservice (GstService pattern) for a later phase.
  • Careers intake (A2): confirm the public pelagiamarine.com form → portal API contract and CV-parse service boundary.
  • Salary versioning (A4): confirm the proration rule for mid-month contract changes feeds WageLine correctly (days×rate₁ + days×rate₂).