Update Crewing Design Document

shad0w 2026-06-21 20:19:21 +00:00
parent 24dc4c62c1
commit 9bcc43f460

@ -1,164 +1,171 @@
# Crewing Design Document
> Companion pages: [Architecture](Crewing-Architecture) ·
> [Data Model](Crewing-Data-Model) · [Workflows](Crewing-Workflows) ·
> [Use Cases](Crewing-Use-Cases) · [Roles & Permissions](Crewing-Roles-and-Permissions) ·
> [User Stories](Crewing-User-Stories)
## 1. Purpose & scope
The Crewing Module digitises Pelagia's **manning process**: keeping every
dredger and site crewed with competent, documented, paid people, and recording
the full lifecycle of each crew member.
**In scope**
1. Vacancy detection & **requisitions**.
2. **Recruitment pipeline** (shortlist → vetting → proposal → interview →
selection) for ex-hands and new candidates.
3. **Onboarding** and the automatic processes it kicks off.
4. **Crew records**: documents, bank, EPF, next-of-kin, emergency contact,
contract, PPE.
5. **Site HR**: leave planner, attendance.
6. **Appraisal** (PM → MPO → Manager).
7. **Sign-off** and experience accrual.
8. **Wage report** generation for Accounts.
**Out of scope (v1)** — actual salary disbursement / banking integration (we
produce the report; Accounts pays), payslip generation, statutory return filing,
training-course delivery, and seafarer-document issuance (we store and verify,
we don't issue).
## 2. Actors
| Actor | Real-world role | Maps to PPMS role |
|---|---|---|
| **Site staff** | PM / Assistant PM / Site In-charge on the dredger | new `SITE_STAFF` role (proposed) |
| **MPO** | Manning / Personnel Officer in the office | existing `MANNING` role |
| **Accounts** | Finance team | existing `ACCOUNTS` role |
| **Manager** | Department / crewing manager | existing `MANAGER` role |
| **Candidate** | External applicant (ex-hand or new) | unauthenticated public form / lightweight `CANDIDATE` identity |
| **Crew member** | Onboarded employee | data subject; not necessarily a portal login in v1 |
| Admin / Superuser / Auditor | as in PO module | existing roles |
See the on-vessel **rank hierarchy** (PM → … → Mess Boy) in
[Data Model § Rank](Crewing-Data-Model#rank-the-org-hierarchy).
## 3. Domain narrative
### 3.1 A vacancy opens
A crew member goes on leave, finishes a contract (EOC), is terminated, is
signed off on medical grounds, or leaves for another reason. Any of these
creates a **gap** for a specific **rank** on a specific **vessel/site**. On a
*scheduled sign-off* the gap (and its **Requisition**) is raised automatically;
otherwise site staff or the MPO raise it manually.
### 3.2 Sourcing candidates
The MPO shortlists candidates for the rank. **Ex-hands are preferred** (people
who have sailed with Pelagia before — their record is already in the system).
New candidates either **apply on the Pelagia site** (uploading a CV, which is
**parsed** for age, vessel type, current/past rank and experience — with manual
entry as fallback) or are **uploaded manually** by the MPO.
### 3.3 Vetting (gated)
Each shortlisted candidate is evaluated against the rank's **minimum criteria**:
- **Competency** — qualifications for the rank.
- **Document verification** — seafarer documents present and valid.
- **Experience***type of vessel*, *time in rank*, *total duration*.
- **Reference check** — previous-employer confirmation.
- **Salary agreement** — proposed structure accepted in principle.
The candidate is then **proposed** and (except for ex-hands, where it's
**optional**) **interviewed**. The outcome is **Selection** or **Rejection with
remarks**. Every gate is recorded.
### 3.4 Onboarding
On selection: **joining formalities** run — salary is confirmed and a
**contract letter** issued. Creating the **CrewAssignment** automatically starts:
- **salary** (the agreed structure becomes active),
- **victualing** (food/messing allowance accrual),
- **attendance** capture,
- **experience** accrual on this vessel/rank,
- **PF** tracking (UAN/EPF), and
- the **PPE issue** checklist.
The crew member receives an **Employee ID**.
### 3.5 Life on site
Site staff record **attendance** daily, **issue PPE** (with boiler-suit and shoe
sizes), maintain **documents/bank/EPF/next-of-kin/emergency contact**, and apply
for **leave** through the site **leave planner** (which shows every crew
member's contract span and leaves on one timeline). The PM raises **appraisals**;
the **MPO verifies**, the **Manager approves**.
### 3.6 Office verification
The office is the source of truth for verified data. **The MPO verifies
everything site staff enter, except attendance**; **bank details and EPF are
verified by Accounts** (UAN/Aadhaar checked against EPFO).
### 3.7 Sign-off & backfill
When a crew member signs off, the assignment closes, their **experience record
is updated** with the completed tour, and a **backfill Requisition** is raised
automatically — closing the loop back to §3.1.
### 3.8 Payroll feed
At month end a **Wage Report** is generated per site:
`crew × salary × days-attended (+ victualing)`. It is reviewed, **approved by the
Manager**, and **sent to Accounts** for disbursement.
## 4. Salient features & design decisions
| # | Decision | Rationale |
|---|---|---|
| D1 | **Two coupled state machines**`Requisition` (the vacancy) and `Application` (a candidate's progress against a requisition). | The requisition is "is this seat filled?"; the application is the per-candidate gated pipeline. Many applications per requisition; exactly one ends in onboarding. |
| D2 | **Unified `CrewMember`** record with a `status` (PROSPECT → CANDIDATE → EMPLOYEE → EX_HAND). | "Ex-hand preferred" only works if a candidate and an ex-employee are the same record; experience carries forward automatically. |
| D3 | **Onboarding is a side-effecting transition**, exactly like PO approval increments inventory. | Single source of truth: salary/victualing/attendance/experience/PF/PPE all start from one event, recorded as one `CrewAction`. |
| D4 | **Verification is a field-level state**, not a separate workflow. Each verifiable record carries `verificationStatus + verifiedBy`. Routing: site-entered → MPO; bank/EPF → Accounts. | Mirrors "view-only / upload / verify" split from the notebook; keeps the office as the trust boundary. |
| D5 | **Sensitive fields are masked & gated.** Salary on the contract letter, full bank account number, and Aadhaar/PAN are restricted; site staff get *view-only-except-salary* on contracts and *view-only* bank. | Matches the explicit notebook rules and basic PII hygiene. |
| D6 | **Rank is reference data with a self-hierarchy** (3+ levels), mirroring the `Account` accounting-code hierarchy. | Drives requisition criteria, document requirements (e.g. licence for drivers), and the org chart. |
| D7 | **Document requirements are rank-driven.** A `RankDocRequirement` defines which seafarer docs a rank must hold. | "Seafarer docs (based on role)"; driving licence only for drivers. |
| D8 | **Wage report is a generated artefact**, not live-computed on the Accounts screen. | Auditable monthly snapshot; mirrors PO export/report pattern. |
| D9 | **Reuse `Vessel`/`Site` as the cost centre** so crew cost is attributable on the same axis as PO spend. | Single cost-centre vocabulary across the portal. |
| D10 | **CV parsing is best-effort with manual fallback.** Extraction populates a draft; a human confirms. | Never block intake on a parser; keep the office in control. |
## 5. Non-functional requirements
- **Auditability** — every lifecycle transition and verification writes a
`CrewAction` row (actor, type, note, metadata), like `POAction`.
- **Privacy** — bank/EPF/identity documents are PII: stored via the same
signed-URL [file storage](File-Storage); account numbers and identity numbers
stored masked/encrypted; access gated by permission.
- **Consistency** — all mutations are Server Actions calling `requirePermission`
then the relevant state-machine guard; **no mutation REST endpoints**.
- **Notifications** — declarative per-transition email/in-app side-effects via
`lib/notifier.ts` (e.g. requisition raised → MPO; proposal → Manager;
appraisal verified → Manager; wage report ready → Accounts).
- **Document expiry** — documents with `expiryDate` surface upcoming-expiry
warnings (medical fitness, passport, CDC, STCW).
## 6. Assumptions
1. PM/APM/Site In-charge get a dedicated `SITE_STAFF` role rather than reusing
`TECHNICAL`. (Confirm in review — see Open Questions.)
2. Crew members are **data subjects**, not portal logins, in v1. A future phase
may give crew a self-service login.
3. **EPFO** UAN/Aadhaar verification is a manual/assisted step in v1 (record the
result); a programmatic check can follow the GstService precedent.
4. "Victualing" is a per-day messing allowance, configurable per rank/vessel.
5. One **active** assignment per crew member at a time.
## 7. Open questions
| # | Question |
|---|---|
| Q1 | New role `SITE_STAFF`, or extend `TECHNICAL`/`MANNING`? |
| Q2 | Does the candidate self-apply form live inside the portal (public route) or on the marketing site posting to an API? |
| Q3 | EPFO verification — assisted-manual now, or build an EPFO proxy microservice like GstService? |
| Q4 | Should salary structures be versioned per assignment (raises mid-contract) in v1, or single-structure-per-assignment? |
| Q5 | Is victualing part of the wage report total, or a separate accrual line? |
| Q6 | Do we need crew self-service (view own docs/payslip) in v1 or v2? |
| Q7 | Attendance granularity — daily present/absent only, or shift/hours? |
See the requirement backlog in [Crewing User Stories](Crewing-User-Stories).
# Crewing Design Document
> Companion pages: [Architecture](Crewing-Architecture) ·
> [Data Model](Crewing-Data-Model) · [Workflows](Crewing-Workflows) ·
> [Use Cases](Crewing-Use-Cases) · [Roles & Permissions](Crewing-Roles-and-Permissions) ·
> [User Stories](Crewing-User-Stories)
## 1. Purpose & scope
The Crewing Module digitises Pelagia's **manning process**: keeping every
dredger and site crewed with competent, documented, paid people, and recording
the full lifecycle of each crew member.
**In scope**
1. Vacancy detection & **requisitions**.
2. **Recruitment pipeline** (shortlist → vetting → proposal → interview →
selection) for ex-hands and new candidates.
3. **Onboarding** and the automatic processes it kicks off.
4. **Crew records**: documents, bank, EPF, next-of-kin, emergency contact,
contract, PPE.
5. **Site HR**: leave planner, attendance.
6. **Appraisal** (PM → MPO → Manager).
7. **Sign-off** and experience accrual.
8. **Wage report** generation for Accounts.
**Out of scope (v1)** — actual salary disbursement / banking integration (we
produce the report; Accounts pays), payslip generation, statutory return filing,
training-course delivery, and seafarer-document issuance (we store and verify,
we don't issue).
## 2. Actors
| Actor | Real-world role | Maps to PPMS role |
|---|---|---|
| **Site staff** | PM / Assistant PM / Site In-charge on the dredger | new `SITE_STAFF` role (proposed) |
| **MPO** | Manning / Personnel Officer in the office | existing `MANNING` role |
| **Accounts** | Finance team | existing `ACCOUNTS` role |
| **Manager** | Department / crewing manager | existing `MANAGER` role |
| **Candidate** | External applicant (ex-hand or new) | unauthenticated public form |
| **Crew member** | Onboarded employee | data subject; not necessarily a portal login in v1 |
| Admin / Superuser / Auditor | as in PO module | existing roles |
See the on-vessel **rank hierarchy** (PM → … → Mess Boy) in
[Data Model § Rank](Crewing-Data-Model#rank-the-org-hierarchy).
## 3. Domain narrative
### 3.1 A vacancy opens
A crew member goes on leave, finishes a contract (EOC), is terminated, is
signed off on medical grounds, or leaves for another reason. Any of these
creates a **gap** for a specific **rank** on a specific **vessel/site**. On a
*scheduled sign-off* the gap (and its **Requisition**) is raised automatically;
otherwise site staff or the MPO raise it manually.
### 3.2 Sourcing candidates
The MPO shortlists candidates for the rank. **Ex-hands are preferred** (people
who have sailed with Pelagia before — their record is already in the system).
New candidates either **apply on the Pelagia site** (uploading a CV, which is
**parsed** for age, vessel type, current/past rank and experience — with manual
entry as fallback) or are **uploaded manually** by the MPO.
### 3.3 Vetting (gated)
Each shortlisted candidate is evaluated against the rank's **minimum criteria**:
- **Competency** — qualifications for the rank.
- **Document verification** — seafarer documents present and valid.
- **Experience***type of vessel*, *time in rank*, *total duration*.
- **Reference check** — previous-employer confirmation.
- **Salary agreement** — proposed structure accepted in principle.
The candidate is then **proposed** and (except for ex-hands, where it's
**optional**) **interviewed**. The outcome is **Selection** or **Rejection with
remarks**. Every gate is recorded.
### 3.4 Onboarding
On selection: **joining formalities** run — salary is confirmed and a
**contract letter** issued. Creating the **CrewAssignment** automatically starts:
- **salary** (the agreed structure becomes active),
- **victualing** (food/messing allowance accrual),
- **attendance** capture,
- **experience** accrual on this vessel/rank,
- **PF** tracking (UAN/EPF), and
- the **PPE issue** checklist.
The crew member receives an **Employee ID**.
### 3.5 Life on site
Site staff record **attendance** daily, **issue PPE** (with boiler-suit and shoe
sizes), maintain **documents/bank/EPF/next-of-kin/emergency contact**, and apply
for **leave** through the site **leave planner** (which shows every crew
member's contract span and leaves on one timeline). The PM raises **appraisals**;
the **MPO verifies**, the **Manager approves**.
### 3.6 Office verification
The office is the source of truth for verified data. **The MPO verifies
everything site staff enter, except attendance**; **bank details and EPF are
verified by Accounts** (UAN/Aadhaar checked against EPFO).
### 3.7 Sign-off & backfill
When a crew member signs off, the assignment closes, their **experience record
is updated** with the completed tour, and a **backfill Requisition** is raised
automatically — closing the loop back to §3.1.
### 3.8 Payroll feed
At month end a **Wage Report** is generated per site:
`crew × salary × days-attended (+ victualing)`. It is reviewed, **approved by the
Manager**, and **sent to Accounts** for disbursement.
## 4. Salient features & design decisions
| # | Decision | Rationale |
|---|---|---|
| D1 | **Two coupled state machines**`Requisition` (the vacancy) and `Application` (a candidate's progress against a requisition). | The requisition is "is this seat filled?"; the application is the per-candidate gated pipeline. Many applications per requisition; exactly one ends in onboarding. |
| D2 | **Unified `CrewMember`** record with a `status` (PROSPECT → CANDIDATE → EMPLOYEE → EX_HAND). | "Ex-hand preferred" only works if a candidate and an ex-employee are the same record; experience carries forward automatically. |
| D3 | **Onboarding is a side-effecting transition**, exactly like PO approval increments inventory. | Single source of truth: salary/victualing/attendance/experience/PF/PPE all start from one event, recorded as one `CrewAction`. |
| D4 | **Verification is a field-level state**, not a separate workflow. Each verifiable record carries `verificationStatus + verifiedBy`. Routing: site-entered → MPO; bank/EPF → Accounts. | Mirrors "view-only / upload / verify" split from the notebook; keeps the office as the trust boundary. |
| D5 | **Sensitive fields are masked & gated.** Salary on the contract letter, full bank account number, and Aadhaar/PAN are restricted; site staff get *view-only-except-salary* on contracts and *view-only* bank. | Matches the explicit notebook rules and basic PII hygiene. |
| D6 | **Rank is reference data with a self-hierarchy** (3+ levels), mirroring the `Account` accounting-code hierarchy. | Drives requisition criteria, document requirements (e.g. licence for drivers), and the org chart. |
| D7 | **Document requirements are rank-driven.** A `RankDocRequirement` defines which seafarer docs a rank must hold. | "Seafarer docs (based on role)"; driving licence only for drivers. |
| D8 | **Wage report is a generated artefact**, not live-computed on the Accounts screen. | Auditable monthly snapshot; mirrors PO export/report pattern. |
| D9 | **Reuse `Vessel`/`Site` as the cost centre** so crew cost is attributable on the same axis as PO spend. | Single cost-centre vocabulary across the portal. |
| D10 | **CV parsing is best-effort with manual fallback.** Extraction populates a draft; a human confirms. | Never block intake on a parser; keep the office in control. |
## 5. Non-functional requirements
- **Auditability** — every lifecycle transition and verification writes a
`CrewAction` row (actor, type, note, metadata), like `POAction`.
- **Privacy** — bank/EPF/identity documents are PII: stored via the same
signed-URL [file storage](File-Storage); account numbers and identity numbers
stored masked/encrypted; access gated by permission.
- **Consistency** — all mutations are Server Actions calling `requirePermission`
then the relevant state-machine guard; **no mutation REST endpoints**.
- **Notifications** — declarative per-transition email/in-app side-effects via
`lib/notifier.ts` (e.g. requisition raised → MPO; proposal → Manager;
appraisal verified → Manager; wage report ready → Accounts).
- **Document expiry** — documents with `expiryDate` surface upcoming-expiry
warnings (medical fitness, passport, CDC, STCW).
## 6. Assumptions
1. PM/APM/Site In-charge get a dedicated `SITE_STAFF` role rather than reusing
`TECHNICAL`. (Confirm in review — see Open Questions.)
2. Crew members are **data subjects**, not portal logins, in v1. A future phase
may give crew a self-service login.
3. **EPFO** UAN/Aadhaar verification is a manual/assisted step in v1 (record the
result); a programmatic check can follow the GstService precedent.
4. "Victualing" is a per-day messing allowance, configurable per rank/vessel.
5. One **active** assignment per crew member at a time.
## 7. Open questions
| # | Question |
|---|---|
| Q1 | New role `SITE_STAFF`, or extend `TECHNICAL`/`MANNING`? |
| A1 | New role `SITE_STAFF_*` for the site heirarchy, MPO is "MANNING" |
| Q2 | Does the candidate self-apply form live inside the portal (public route) or on the marketing site posting to an API? |
| A2 | Lives at the static site pelagiamarine.com |
| Q3 | EPFO verification — assisted-manual now, or build an EPFO proxy microservice like GstService? |
| A3 | EPFO proxy microservice like GstService would be better |
| Q4 | Should salary structures be versioned per assignment (raises mid-contract) in v1, or single-structure-per-assignment? |
| A4 | It is possible for the salary and entire contract to be changed mid assignment and salary must be calculated accordingly (days x amt 1 + days x amt 2) |
| Q5 | Is victualing part of the wage report total, or a separate accrual line? |
| A5 | separate accrual line? |
| Q6 | Do we need crew self-service (view own docs/payslip) in v1 or v2? |
| A6 | No, only PM APM Site-incharge users needed from site, they will generate slips for other site crew members |
| Q7 | Attendance granularity — daily present/absent only, or shift/hours? |
| A7 | Shift/hours + overtime? |
See the requirement backlog in [Crewing User Stories](Crewing-User-Stories).