docs(crewing): add reconciled Implementation Spec; link under Planned

Reconcile the Crewing wiki design pages with the design handoff prototype,
using the Crewing CHANGELOG as tiebreaker, into one authoritative
Crewing-Implementation-Spec page: reconciliation decisions (R1-R11),
director Q&A folded in, how it slots into PPMS, codebase changes, the
final roles/permission + nav matrices, domain/state-machine deltas, a
detailed role-aware screen spec, modals, user-story reconciliations,
cross-cutting concerns, build order and open questions.

Key reconciled rulings: leave is Manager-approved (not MPO); interview
waiver is an explicit Manager-approved action (never auto for ex-hands);
only MPO/Manager raise requisitions (site staff request relief cover);
7-stage pipeline; MPO has no attendance access; effective-dated salary.

Add an authoritative-spec banner to each Crewing design page and link the
spec from the Module hub, Planned Features and the sidebar.
Hardik 2026-06-22 11:48:26 +05:30
parent 06276857ea
commit b9e5118693
10 changed files with 463 additions and 0 deletions

@ -1,5 +1,11 @@
# Crewing Data Model
> **Reconciled:** [Crewing Implementation Spec](Crewing-Implementation-Spec) is the
> authoritative build instruction set. Where this page differs, follow the spec —
> notably the **7-stage `ApplicationStage`**, **effective-dated `SalaryStructure`**
> (mid-assignment changes), the new **`RELIEF_REQUEST`** model, and **leave decided
> by the Manager**.
**Proposed source of truth:** `App/prisma/schema.prisma` (new models). Mirrors
the conventions on [Data Model](Data-Model): monetary values are `Decimal`,
IDs are `cuid()`, every lifecycle change writes an audit row.

@ -1,5 +1,12 @@
# Crewing Design Document
> **Reconciled:** [Crewing Implementation Spec](Crewing-Implementation-Spec) is the
> authoritative build instruction set. Where this page differs, follow the spec —
> notably: **leave is Manager-approved** (not MPO); the **interview waiver is an
> explicit Manager-approved action** (never automatic); **only MPO/Manager raise
> requisitions** (site staff *request relief cover*); the recruitment board has
> **7 stages**; the **MPO has no attendance access**.
> Companion pages: [Architecture](Crewing-Architecture) ·
> [Data Model](Crewing-Data-Model) · [Workflows](Crewing-Workflows) ·
> [Use Cases](Crewing-Use-Cases) · [Roles & Permissions](Crewing-Roles-and-Permissions) ·

@ -0,0 +1,410 @@
# 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](Crewing-Design-Document#7-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.
- **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](Crewing-Roles-and-Permissions):** `decide_leave`**Manager** 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](Crewing-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](Crewing-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](Crewing-Module) / [Design Doc](Crewing-Design-Document) / [Use Cases](Crewing-Use-Cases) / [User Stories](Crewing-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](Crewing-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](Crewing-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**.
### 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](Crewing-Roles-and-Permissions#3-field-level-restrictions-pii).
---
## 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](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](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 / 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](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
1. **Foundations**`SITE_STAFF` role; crewing schema + enums; permissions; `CREWING_ENABLED` flag; nav scaffold; reference data (Ranks, RankDocRequirements).
2. **Requisitions + sign-off/experience** (Epics A, K) — incl. auto-backfill.
3. **Candidate intake + 7-stage pipeline + onboarding** (B, C, D) — incl. salary→Manager approval, explicit waiver.
4. **Crew records, PPE, leave/attendance** (E, F, G) — leave→Manager, MPO no attendance, clash auto-req + relief requests.
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₂`).

@ -1,5 +1,13 @@
# Crewing Module
> **Reconciled:** [Crewing Implementation Spec](Crewing-Implementation-Spec) is the
> authoritative build instruction set (it reconciles this design page with the
> design handoff). Where they differ, follow the spec — notably: **leave is
> Manager-approved** (not MPO); the **interview waiver is an explicit
> Manager-approved action** (never automatic); **only MPO/Manager raise
> requisitions** (site staff *request relief cover*); the recruitment board has
> **7 stages**; the **MPO has no attendance access**.
The **Crewing Module** (a.k.a. *Manning*) extends Pelagia Portal (PPMS) from a
purchasing system into a crew lifecycle system. It manages the people who run
Pelagia's dredgers and sites — from the moment a vacancy opens, through
@ -60,6 +68,7 @@ for this design were literally two notebook pages). The pain points it removes:
| Page | Purpose | Detail |
|---|---|---|
| **[Crewing Implementation Spec](Crewing-Implementation-Spec)** | **Authoritative reconciled build instructions** (design ⨝ docs) | **Start here** |
| [Crewing Design Document](Crewing-Design-Document) | Goals, scope, domain narrative, decisions | — |
| [Crewing Architecture](Crewing-Architecture) | System & component diagrams, module layout | Component diagram |
| [Crewing Data Model](Crewing-Data-Model) | Entities, enums, relationships | **ER diagram** |

@ -1,5 +1,12 @@
# Crewing Roles and Permissions
> **Reconciled:** the authoritative permission matrix is in
> [Crewing Implementation Spec § 6](Crewing-Implementation-Spec#6-roles--permissions-final-matrix).
> It corrects this page: **`decide_leave` → Manager only** (not MPO); `apply_leave`
> → Site staff + Manager; **leave removed** from `verify_site_records`;
> `raise_requisition` is **MPO/Manager only** (site staff get `request_relief_cover`);
> and new `request/approve_interview_waiver` + `record_interview_result` permissions.
Crewing extends the existing `lib/permissions.ts` map (see
[Roles and Permissions](Roles-and-Permissions)) with crewing permissions. Every
crewing Server Action calls `requirePermission(role, permission)` first; the

@ -1,5 +1,11 @@
# Crewing Use Cases
> **Reconciled:** [Crewing Implementation Spec](Crewing-Implementation-Spec) is the
> authoritative build instruction set. Where this page differs, follow the spec —
> notably: **leave is decided by the Manager** (UC-12); the **interview waiver is an
> explicit Manager-approved action** (UC-08); and **only MPO/Manager raise
> requisitions** (site staff *request relief cover*, UC-01).
Actors and the use cases each can perform. The diagram uses a flowchart to
approximate UML use-case notation (Mermaid has no native use-case diagram);
actors are on the edges, use cases are rounded nodes, grouped by area.

@ -1,5 +1,11 @@
# Crewing User Stories
> **Reconciled:** [Crewing Implementation Spec § 10](Crewing-Implementation-Spec#10-user-stories)
> carries the authoritative reconciliations to this backlog — notably **A2**
> (site staff *request relief cover*; only MPO/Manager raise requisitions),
> **G3** (the **Manager** decides leave), **C7/C8** (interview waiver is an explicit
> Manager-approved action), and **G4/I1** (the **MPO has no attendance access**).
Backlog for the Crewing Module, grouped into epics. Format:
*As a `<role>`, I want `<capability>`, so that `<value>`* + acceptance criteria
(AC). IDs are stable references for PRs/issues.

@ -1,5 +1,11 @@
# Crewing Workflows
> **Reconciled:** [Crewing Implementation Spec](Crewing-Implementation-Spec) is the
> authoritative build instruction set. Where this page differs, follow the spec —
> notably: **leave is decided by the Manager** (not MPO); ex-hands pass through
> **Interview** unless a **Manager-approved waiver** is granted (no automatic
> waiver path); and the Application pipeline has the reconciled **7 stages**.
Every crewing lifecycle is enforced by a single state-machine module (the
`po-state-machine.ts` pattern) and recorded as `CrewAction` audit rows. This
page is the authoritative behaviour spec: **state diagrams**, **transition

@ -24,6 +24,11 @@ pipeline, onboarding, site HR (attendance, leave, PPE, documents), and a monthly
wage report for Accounts. It reuses the PO module's state-machine, permission-map,
audit-trail and file-storage patterns.
**[Crewing Implementation Spec](Crewing-Implementation-Spec)** — the
authoritative, reconciled build instruction set (design handoff ⨝ wiki docs, with
the CHANGELOG as tiebreaker): reconciliation decisions, codebase changes, the
final roles/nav matrices, and the detailed screen spec.
**[Crewing Module](Crewing-Module)** — landing page with the full page map:
design document, architecture, data model, workflows, use cases, roles &
permissions, and user stories (Mermaid diagrams throughout).

@ -33,6 +33,7 @@
- [Planned Features](Planned-Features)
- [Reports Mockup](Reports-Mockup)
- [Crewing Management](Crewing-Module)
- [Crewing Implementation Spec](Crewing-Implementation-Spec)
**Quality**
- [Testing](Testing)