5 Crewing Roles and Permissions
Hardik edited this page 2026-06-22 11:59:08 +05:30

Crewing Roles and Permissions

Authoritative build spec: the same matrix appears in Crewing Implementation Spec § 6, alongside the codebase wiring. This page is the detailed rationale, aligned with that spec.

Crewing extends the existing lib/permissions.ts map (see Roles and Permissions) with crewing permissions. Every crewing Server Action calls requirePermission(role, permission) first; the relevant state machine adds the status+role gate on top.

1. Role mapping

Crewing actor PPMS role Notes
PM / APM / Site In-charge (the only on-site logins) SITE_STAFF (new, proposed) apply-only leave (on behalf of crew), attendance, PPE issue, doc upload, view-only contract (except salary) & bank; requests relief cover (does not raise requisitions)
MPO MANNING (existing — "crew-management staff") recruitment + verifies site data (docs/PPE/NoK), except bank/EPF (Accounts) and leave (Manager); no leave and no attendance access
Accounts ACCOUNTS verifies bank + EPF; consumes wage report
Manager MANAGER approves salary structures, candidate selection, interview waivers, leave, appraisals, wage reports; reviews attendance
Superuser SUPERUSER combined authority across crewing actions
Auditor AUDITOR read-only across crewing
Admin ADMIN manages ranks & doc requirements
Candidate none public careers form only

Proposed enum change: add SITE_STAFF to Role. If review prefers reuse, TECHNICAL could host site staff, but its PO semantics ("deck/engine crew") differ from PM/APM managerial duties — hence the new role.

Only PM, Assistant PM and Site In-charge get a login (a single SITE_STAFF role). No other on-vessel rank — Dredger in-charge, dredge/engine operators, deck hands, support staff, down to Mess Boy — has a portal account; they are crew members / data subjects whose leave, attendance, PPE and documents are entered for them by site staff. The on-vessel rank tree in Data Model § Rank is an org chart, not a list of users.

2. Permission → role matrix

✓ = granted. (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
convert_relief_to_requisition
cancel_requisition
view_requisitions
manage_candidates (shortlist/vetting)
record_reference_check
record_interview_result
request_interview_waiver
approve_interview_waiver
approve_salary_structure
select_candidate (final approval)
onboard_crew
sign_off_crew
view_crew_records ✓¹ ✓²
upload_crew_records (docs/NoK/emergency/EPF)
issue_ppe
apply_leave
decide_leave
record_attendance
view_attendance ³
verify_site_records (docs/PPE/NoK)
verify_bank_epf
raise_appraisal
verify_appraisal
approve_appraisal
generate_wage_report
approve_wage_report
view_wage_report
manage_ranks

¹ Site staff get crew records for their own site only, with contract view-only-except-salary and bank view-only. ² Accounts see bank/EPF and the wage report, not the full HR record. ³ Attendance is deliberately not visible to the MPO (or Accounts). Site staff record it; the Manager reviews it (it feeds the wage report). ⁴ The wage report reads attendance, so it is generated by the Manager (or the month-end job) — not the MPO, who has no attendance access. ⁵ Site staff do not raise requisitions. They flag a gap with request_relief_cover; the office (MPO/Manager) reviews it and converts it into a requisition. ⁶ Everyone is interviewed. For a returning ex-hand the MPO may request_interview_waiver; only a Manager can approve_interview_waiver (never automatic). ⁷ Leave is decided by the Manager, not the MPO. Site staff apply on behalf of crew; the MPO has no role in leave.

3. Field-level restrictions (PII)

Enforced in Server Components/Actions on top of the permission map:

Field Visible to Hidden from
Salary (contract letter, salary structure) MPO, Manager, Accounts, Superuser, Auditor Site staff
Full bank account number Accounts (verify), Manager, Superuser Site staff (view-only masked), MPO
Aadhaar / PAN number MPO (verify), Accounts (EPF), Superuser Site staff (masked)
Candidate rejection remarks MPO, Manager, Superuser, Auditor Candidate

4. Business rules layered on top

  • A candidate cannot be onboarded until the salary structure is Manager-approved and a contract letter is attached.
  • Bank and EPF records can only be set VERIFIED by Accounts (UAN/Aadhaar EPFO check); everything else site staff enter is verified by MPO.
  • Attendance has no verification gate (operational record). It is recorded by site staff and visible only to site staff and the Manager — the MPO cannot see attendance; the Manager reviews it (it feeds the wage report).
  • Leave is applied by the Site in-charge on behalf of crew (crew are not portal users); the Manager decides (approves/rejects) leave — the MPO has no leave role. An approved leave that clashes — overlaps another for the same rank below its required strength — auto-raises a LEAVE-reason requisition (system-raised, same backfill path as sign-off).
  • Site staff do not raise requisitions. A foreseen gap is flagged with request_relief_cover; the office converts the relief request into a requisition.
  • Everyone is interviewed; an ex-hand interview is waived only with Manager approval (request_interview_waiver by MPO → approve_interview_waiver by Manager).
  • An appraisal must be MPO_VERIFIED before a Manager can approve it.
  • A wage report must be MANAGER_APPROVED before it is SENT_TO_ACCOUNTS.
  • Only one ACTIVE assignment per crew member; sign-off is required before a new one.
  • Site staff actions are scoped to the site/vessel they are assigned to.

5. Implementation pattern

// app/(portal)/crewing/candidates/actions.ts
'use server'
export async function onboardCandidate(input: OnboardInput) {
  const session = await auth()
  requirePermission(session.user.role, 'onboard_crew')   // role gate
  const app = await db.application.findUniqueOrThrow(...)
  assertCanTransition(app.stage, 'onboard')              // pipeline gate
  // ...create assignment + side-effects in a transaction,
  //    write a CrewAction, dispatch notifications
}

Same shape as every PO Server Action: permission → state-machine guard → transactional write → audit row → notify.