Table of Contents
- Crewing — Final Implementation Spec
- 1. Reconciliation method
- 2. Corrections to apply to the existing design pages
- 3. How Crewing slots into PPMS
- 4. Changes required to the current PPMS codebase
- 4.1 Schema (App/prisma/schema.prisma)
- 4.2 Permissions (App/lib/permissions.ts)
- 4.3 Navigation (App/components/layout/sidebar.tsx)
- 4.4 State machines (App/lib/…)
- 4.5 Audit, notifier, storage, flag
- 5. Domain model & state machines (reconciled)
- 5.1 Application pipeline (7 stages — R4)
- 5.2 Requisition lifecycle
- 5.3 Assignment + leave clash (R1, R6)
- 5.4 Appraisal & wage
- 6. Roles & permissions (final matrix)
- 7. Navigation & role visibility (final)
- 8. Screen spec (role-aware)
- 8.1 Dashboard (role-aware)
- 8.2 Requisitions (list) — MPO/Manager
- 8.3 Requisition detail — MPO/Manager
- 8.4 Recruitment pipeline (per requisition) — MPO/Manager
- 8.5 Candidate detail (recruitment workhorse) — MPO/Manager
- 8.6 Candidates (master list) — MPO/Manager
- 8.7 Crew (directory) — Manager/MPO/Site staff(own site)
- 8.8 Crew profile (tabbed)
- 8.9 Leave — Manager & Site staff (R1)
- 8.10 Attendance (month calendar) — Manager & Site staff (R5)
- 8.11 Verification (MPO) — and Accounts for bank/EPF
- 8.12 Ranks & document rules (Manager/Admin)
- 8.13 Approvals (Manager — unified queue, R8)
- 8.14 Appraisal (entry/verify) — under-specified in the prototype
- 8.15 Purchase orders (continuity)
- 9. Modals
- 10. User stories
- 11. Cross-cutting
- 12. Build order
- 13. Open questions (remaining)
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), theCrewing-*wiki design pages, and the Crewing CHANGELOG (the tiebreaker). Status: design-complete proposal, not yet built; behindNEXT_PUBLIC_CREWING_ENABLED.
1. Reconciliation method
Where the wiki design pages and the handoff prototype disagree, the rule is:
- Check the Crewing CHANGELOG (
design_handoff_crewingchange log). - If the point was an intentional design change recorded in the CHANGELOG → defer to the design (prototype).
- If it was not an intentional change (an oversight or omission in the prototype) → defer to the docs (wiki).
- Explicit director answers in Design Doc § Open Questions (Q1–Q7) 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 Q1–Q7)
- A1 — single new
SITE_STAFFrole, held only by PM/APM/Site In-charge; MPO isMANNING. - 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₂. →SalaryStructureis effective-dated (many per assignment), not single. - A5 — victualing is a separate accrual line, shown distinctly from base pay.
- A6 — no 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_leave→ Manager only (drop MAN);apply_leave→ SITE + MGR (drop MAN); drop leave fromverify_site_records; remove SITE fromraise_requisition; addrequest_relief_cover(SITE) andrequest/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→SELECTEDwaiver paths — ex-hands pass throughINTERVIEW, 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_REQUESTdecided by Manager;SalaryStructureeffective-dated witheffectiveFrom(R10/A4); addRELIEF_REQUESTmodel (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_STAFFtoRole. Current enum:TECHNICAL MANNING ACCOUNTS MANAGER SUPERUSER AUDITOR ADMIN→ appendSITE_STAFF. (MPO =MANNING.) - Add all crewing models + enums from Data Model, with the §1 reconciliations: 7-stage
ApplicationStage(§5.1), effective-datedSalaryStructure,RELIEF_REQUEST,Rank.grantsLogin(true only for PM/APM/Site In-charge),CrewAction+CrewActionType. - A
CrewMemberis promoted to aUser(with aSITE_STAFFlogin) only when its rankgrantsLogin; 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
CrewActionmodel (mirrorPOAction) +CrewActionTypeenum.- Add crewing events to
notifier.ts’NotificationEventunion (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", likeSUBMITTER_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 (
interviewWaivedset 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;JOININGis folded into it. - Each transition writes an
APPLICATION_GATE(gate,result,note,decidedById) + aCrewAction.
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 rank’s 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 toREJECTED/DRAFTwith 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 Today’s 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 candidate’s 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, 420–500px, 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 A–M) 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
LEAVErequisition (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 / I1 — MPO 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 anEXPERIENCE_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).
SalaryStructureis attached to theApplicationduring the pipeline and bound to theCrewAssignmentat onboarding (3c). Onboarding promotes the candidate toEMPLOYEEwith aCRW-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 internalEXPERIENCE_RECORD, flips the sameCrewMemberEMPLOYEE → EX_HAND(returns to Candidates), and auto-raises aSIGN_OFFbackfill — 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 belowminStrength(default 1 when unconfigured) auto-raises aLEAVErequisition (reuses the Phase-2autoRaiseRequisition). 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 newmanage_crewpermission.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; noverificationStatuson those models). 5b is the appraisal lifecycleraise → 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).
- Foundations —
SITE_STAFFrole; crewing schema + enums; permissions;CREWING_ENABLEDflag; nav scaffold; reference data (Ranks, RankDocRequirements). - Requisitions + relief (Epic A) — requisition lifecycle, relief requests, and the shared
autoRaiseRequisitionbackfill 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.) - 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.)
- 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 anEXPERIENCE_RECORD, and auto-raises a backfill requisition (reusing the Phase-2autoRaiseRequisitionhelper); the person returns to Candidates as an ex-hand. - Verification + appraisal (I, H).
- 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.comform → portal API contract and CV-parse service boundary. - Salary versioning (A4): confirm the proration rule for mid-month contract changes feeds
WageLinecorrectly (days×rate₁ + days×rate₂).
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.