diff --git a/Crewing-Architecture.md b/Crewing-Architecture.md
new file mode 100644
index 0000000..8780522
--- /dev/null
+++ b/Crewing-Architecture.md
@@ -0,0 +1,188 @@
+# Crewing Architecture
+
+The Crewing Module is **not a new application** — it is a feature area inside the
+existing Pelagia Portal. It adopts the same stack and the same patterns
+documented in [Architecture](Architecture); this page only describes what
+crewing *adds*.
+
+## 1. Where it lives in the stack
+
+```
+┌─────────────────────────────────────────────┐
+│ Browser — React 19 + shadcn/ui + Tailwind │
+│ Crewing pages: requisitions, candidates, │
+│ crew, leave planner, attendance, payroll │
+└───────────────────┬──────────────────────────┘
+ │ HTTPS
+┌───────────────────▼──────────────────────────┐
+│ Next.js 15 App Server │
+│ RSC pages (read) │ Server Actions (write) │
+│ ┌──────────────────────────────────────────┐│
+│ │ requisition-state-machine ││
+│ │ application-pipeline (candidate gates) ││
+│ │ onboarding side-effects ││
+│ │ wage-report generator ││
+│ │ permissions (extended) · crew-notifier ││
+│ └──────────────────────────────────────────┘│
+└───────┬───────────────┬───────────────┬───────┘
+ │ │ │
+┌───────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
+│ PostgreSQL │ │ R2 / local │ │ Resend │
+│ (Prisma) │ │ docs, CVs, │ │ (email) │
+│ crew tables │ │ PPE, signs │ │ │
+└──────────────┘ └─────────────┘ └─────────────┘
+ ▲
+┌───────┴──────────────────────────────────────┐
+│ (future) CvParseService · EpfoService │
+│ best-effort CV extraction; UAN/Aadhaar check │
+│ same out-of-process pattern as GstService │
+└───────────────────────────────────────────────┘
+```
+
+Reused as-is: NextAuth v5 session/auth, `lib/storage.ts` (file storage),
+`lib/notifier.ts` (email + `Notification` rows), `Vessel`/`Site`/`User`,
+Recharts for dashboards.
+
+## 2. Component diagram
+
+```mermaid
+flowchart TB
+ subgraph UI["UI — app/(portal)/crewing/*"]
+ REQ["Requisitions
/crewing/requisitions"]
+ CAND["Candidates & Pipeline
/crewing/candidates"]
+ CREW["Crew Directory
/crewing/crew/[id]"]
+ PLAN["Leave Planner
/crewing/leave"]
+ ATT["Attendance
/crewing/attendance"]
+ PPE["PPE Register
/crewing/ppe"]
+ APPR["Appraisals
/crewing/appraisals"]
+ PAY["Wage Reports
/crewing/payroll"]
+ VERI["Office Verification
/crewing/verify"]
+ APPLY["Public Apply
/careers/apply"]
+ end
+
+ subgraph SA["Server Actions — actions.ts (mutations)"]
+ A1["requisition actions"]
+ A2["application/pipeline actions"]
+ A3["onboarding action"]
+ A4["crew-record actions
(docs/bank/epf/nok)"]
+ A5["ppe actions"]
+ A6["leave + attendance actions"]
+ A7["appraisal actions"]
+ A8["payroll actions"]
+ A9["verification actions"]
+ end
+
+ subgraph LIB["Domain logic — lib/"]
+ SM1["requisition-state-machine.ts"]
+ SM2["application-pipeline.ts"]
+ SM3["assignment-lifecycle.ts"]
+ SM4["appraisal-lifecycle.ts"]
+ ON["onboarding.ts (side-effects)"]
+ WR["wage-report.ts (generator)"]
+ PERM["permissions.ts (extended)"]
+ NOT["crew-notifier.ts → notifier.ts"]
+ REQDOC["rank-doc-requirements.ts"]
+ end
+
+ subgraph RH["Route Handlers — api/ (non-mutations)"]
+ H1["/api/careers/apply (public POST)"]
+ H2["/api/crewing/cv-parse"]
+ H3["/api/crewing/payroll/[id]/export"]
+ H4["/api/files/sign (reused)"]
+ end
+
+ subgraph DATA["Persistence"]
+ DB[("PostgreSQL
Prisma crew models")]
+ FS[("File storage
CVs · docs · PPE · signatures")]
+ end
+
+ subgraph EXT["External / future"]
+ CVP["CvParseService"]
+ EPFO["EpfoService"]
+ MAIL["Resend / console"]
+ end
+
+ REQ --> A1 --> SM1 --> DB
+ CAND --> A2 --> SM2 --> DB
+ CAND --> A3 --> ON --> DB
+ ON --> SM3
+ APPLY --> H1 --> H2 --> CVP
+ H1 --> DB
+ CREW --> A4 --> DB
+ A4 --> REQDOC
+ PPE --> A5 --> DB
+ PLAN --> A6
+ ATT --> A6 --> DB
+ APPR --> A7 --> SM4 --> DB
+ PAY --> A8 --> WR --> DB
+ PAY --> H3
+ VERI --> A9 --> DB
+ A9 --> EPFO
+
+ A1 & A2 & A3 & A7 & A8 --> NOT --> MAIL
+ A1 & A2 & A3 & A4 & A5 & A6 & A7 & A8 & A9 --> PERM
+ A4 & A5 & H1 --> FS
+ WR -.reads.-> DB
+```
+
+## 3. Module layout
+
+```
+app/(portal)/crewing/
+├── requisitions/ # list, new, [id] (vacancies)
+├── candidates/ # pipeline board, [id] (per-candidate gates)
+│ └── [id]/onboard/ # joining formalities → CrewAssignment
+├── crew/ # directory, crew/[id] (records, docs, bank, epf, ppe)
+├── leave/ # site leave planner + apply
+├── attendance/ # daily capture per site
+├── ppe/ # PPE issue register
+├── appraisals/ # raise / verify / approve
+├── payroll/ # monthly wage reports
+└── verify/ # office verification queue (MPO / Accounts)
+
+app/careers/apply/ # public candidate application (CV upload)
+
+app/api/
+├── careers/apply/ # public POST (rate-limited)
+├── crewing/cv-parse/ # CV → extracted fields
+└── crewing/payroll/[id]/export/ # XLSX/PDF wage report
+
+lib/
+├── requisition-state-machine.ts # vacancy transitions + roles
+├── application-pipeline.ts # candidate gate transitions
+├── assignment-lifecycle.ts # active ↔ on-leave → signed-off
+├── appraisal-lifecycle.ts # draft → verified → approved
+├── onboarding.ts # the side-effecting onboard step
+├── wage-report.ts # crew × salary × days generator
+├── rank-doc-requirements.ts # which docs a rank needs
+├── crew-notifier.ts # crew events → notifier.ts
+└── permissions.ts # + crewing permissions
+```
+
+This mirrors the PO module's split: **Server Actions for every mutation**,
+**route handlers only** for the public apply endpoint, CV parsing, file signing
+and report export. State changes go through a single state-machine module and
+are recorded as `CrewAction` rows.
+
+## 4. Cross-cutting concerns
+
+| Concern | Approach (reused) |
+|---|---|
+| **Auth** | NextAuth v5 session; public apply route is unauthenticated + rate-limited. |
+| **Authorisation** | `requirePermission(role, permission)` at the top of every Server Action; RSC pages gate whole segments. See [Crewing Roles & Permissions](Crewing-Roles-and-Permissions). |
+| **Audit** | `CrewAction` rows (actor, type, note, metadata) — the `POAction` pattern. |
+| **Files** | `lib/storage.ts` signed uploads (R2 prod / local dev) for CVs, documents, PPE proofs, signatures. |
+| **Email / in-app** | `lib/notifier.ts`; events persisted as `Notification`. |
+| **Decimals** | salary/victualing are `Decimal`; convert with `Number()` before crossing into Client Components (same gotcha as PO line items). |
+| **Feature flag** | whole surface behind `NEXT_PUBLIC_CREWING_ENABLED` for staged rollout. |
+| **Migrations** | new models = new Prisma migration, reviewed in a PR; never edit `schema.prisma` without one. |
+
+## 5. Integration points with the PO module
+
+- **Cost centre** — crew assignments reference the same `Vessel`/`Site` used by
+ POs, so crew cost and PO spend share a cost-centre axis for reporting.
+- **PPE as inventory (optional)** — if the [inventory flag](Inventory-and-Catalogue)
+ is on, PPE issues can draw down `ItemInventory` at a site, reusing the
+ consumption model.
+- **Notifications & dashboard** — crew events surface in the same notification
+ bell; the dashboard gains crewing stat cards.
diff --git a/Crewing-Data-Model.md b/Crewing-Data-Model.md
new file mode 100644
index 0000000..37d487a
--- /dev/null
+++ b/Crewing-Data-Model.md
@@ -0,0 +1,349 @@
+# Crewing Data Model
+
+**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. Enums
+
+```prisma
+// who/what kind of vacancy
+enum RequisitionReason { LEAVE END_OF_CONTRACT TERMINATION MEDICAL OTHER }
+enum RequisitionStatus { OPEN SHORTLISTING PROPOSING INTERVIEWING SELECTED FILLED CANCELLED }
+
+// candidate progress against a requisition (the gated pipeline)
+enum CandidateType { EX_HAND NEW }
+enum ApplicationStage {
+ SHORTLISTED COMPETENCY_CHECK DOC_VERIFICATION REFERENCE_CHECK
+ SALARY_AGREEMENT PROPOSED INTERVIEW SELECTED REJECTED JOINING ONBOARDED
+}
+
+// the person's overall status
+enum CrewStatus { PROSPECT CANDIDATE EMPLOYEE EX_HAND BLACKLISTED }
+
+// an onboarded tour of duty
+enum AssignmentStatus { ACTIVE ON_LEAVE SIGNED_OFF }
+
+// site HR
+enum AttendanceStatus { PRESENT ABSENT HALF_DAY ON_LEAVE SIGN_OFF }
+enum LeaveType { ANNUAL MEDICAL EMERGENCY UNPAID OTHER }
+enum LeaveStatus { APPLIED APPROVED REJECTED CANCELLED }
+
+// PPE kit
+enum PpeItem {
+ BOILER_SUIT SAFETY_SHOES HELMET VEST GLOVES MASK GOGGLES
+ TIFFIN TORCH WALKIE_TALKIE
+}
+
+// documents
+enum SeafarerDocType {
+ STCW AADHAAR PAN PASSPORT CDC COC PHOTOGRAPH
+ DRIVING_LICENSE MEDICAL_FITNESS CONTRACT_LETTER
+}
+enum VerificationStatus { PENDING VERIFIED REJECTED EXPIRED }
+
+// appraisal + payroll
+enum AppraisalStatus { DRAFT SUBMITTED MPO_VERIFIED MANAGER_APPROVED REJECTED }
+enum WageReportStatus { DRAFT GENERATED MANAGER_APPROVED SENT_TO_ACCOUNTS }
+
+// audit
+enum CrewActionType {
+ REQUISITION_RAISED REQUISITION_CANCELLED REQUISITION_FILLED
+ CANDIDATE_SHORTLISTED GATE_PASSED GATE_FAILED PROPOSED INTERVIEWED
+ SELECTED REJECTED ONBOARDED SIGNED_OFF
+ RECORD_UPDATED RECORD_VERIFIED RECORD_REJECTED
+ PPE_ISSUED PPE_RETURNED LEAVE_APPLIED LEAVE_DECIDED
+ APPRAISAL_SUBMITTED APPRAISAL_VERIFIED APPRAISAL_APPROVED
+ WAGE_REPORT_GENERATED WAGE_REPORT_APPROVED WAGE_REPORT_SENT
+}
+```
+
+## 2. Rank — the org hierarchy
+
+`Rank` is reference data with a self-relation (parent/children), exactly like the
+3-level `Account` accounting-code hierarchy. It drives requisition criteria,
+required documents per rank, and the org chart. Captured from
+`Crewing.excalidraw`:
+
+```mermaid
+flowchart TB
+ PM["PM"] --> APM["Ass. PM"]
+ APM --> ACC["Accountant"]
+ APM --> DRV["Driver"]
+ APM --> COOK["Cook"]
+ COOK --> CH["Cook Helper"]
+ APM --> SIC["Site in-charge"]
+ SIC --> DIC["Dredger in-charge"]
+ DIC --> SDO["Sr. Dredge Op."]
+ SDO --> PLS["Pipeline Supervisor"]
+ PLS --> PLA["Pipeline Ass."]
+ SDO --> JDO["Jr. Dredge Op."]
+ JDO --> ERO["Engine Room Op."]
+ ERO --> DH["Deck Hand"]
+ DH --> TR["Trainee"]
+ DH --> MB["Mess Boy"]
+ SDO --> ELE["Electrician"]
+ SDO --> FAB["Sr. Fab"]
+ FAB --> FW["Fab / Welder"]
+
+ classDef sup fill:#eef,stroke:#88a;
+ class ACC,DRV,COOK,CH sup;
+```
+
+Ranks carry a `category` (e.g. `OPERATIONAL` vs `SUPPORT`) and an
+`isSeafarer` flag (drives which document set applies). `Driver` additionally
+requires a driving licence (`RankDocRequirement`).
+
+## 3. Entity-relationship diagram
+
+```mermaid
+erDiagram
+ USER ||--o{ CREW_ACTION : actor
+ USER ||--o{ REQUISITION : raised_by
+ USER ||--o{ APPRAISAL : "added/verified/approved"
+
+ RANK ||--o{ RANK : parent
+ RANK ||--o{ REQUISITION : for_rank
+ RANK ||--o{ CREW_ASSIGNMENT : in_rank
+ RANK ||--o{ RANK_DOC_REQUIREMENT : requires
+
+ VESSEL ||--o{ REQUISITION : cost_centre
+ VESSEL ||--o{ CREW_ASSIGNMENT : on
+ SITE ||--o{ WAGE_REPORT : for_site
+
+ REQUISITION ||--o{ APPLICATION : receives
+ REQUISITION ||--o| CREW_ASSIGNMENT : filled_by
+ REQUISITION }o--|| CREW_MEMBER : vacated_by
+
+ CREW_MEMBER ||--o{ APPLICATION : applies
+ CREW_MEMBER ||--o{ CREW_ASSIGNMENT : has
+ CREW_MEMBER ||--o{ SEAFARER_DOCUMENT : holds
+ CREW_MEMBER ||--o| BANK_DETAIL : has
+ CREW_MEMBER ||--o| EPF_DETAIL : has
+ CREW_MEMBER ||--o{ NEXT_OF_KIN : has
+ CREW_MEMBER ||--o{ EMERGENCY_CONTACT : has
+ CREW_MEMBER ||--o{ EXPERIENCE_RECORD : has
+
+ APPLICATION ||--o{ APPLICATION_GATE : evaluated_by
+ APPLICATION ||--o{ REFERENCE_CHECK : has
+
+ CREW_ASSIGNMENT ||--o| SALARY_STRUCTURE : paid_by
+ CREW_ASSIGNMENT ||--o| CONTRACT_LETTER : documented_by
+ CREW_ASSIGNMENT ||--o{ ATTENDANCE : records
+ CREW_ASSIGNMENT ||--o{ LEAVE_REQUEST : has
+ CREW_ASSIGNMENT ||--o{ PPE_ISSUE : issued
+ CREW_ASSIGNMENT ||--o{ APPRAISAL : appraised
+ CREW_ASSIGNMENT ||--o{ WAGE_LINE : billed
+
+ WAGE_REPORT ||--o{ WAGE_LINE : contains
+
+ CREW_MEMBER {
+ string id PK
+ string employeeId "unique, set at onboard"
+ string name
+ date dob
+ string phone
+ string email
+ enum status "CrewStatus"
+ enum type "EX_HAND|NEW"
+ string cvKey "storage key"
+ string currentRankId FK
+ }
+ REQUISITION {
+ string id PK
+ string vesselId FK
+ string rankId FK
+ enum reason "RequisitionReason"
+ enum status "RequisitionStatus"
+ string vacatedByCrewId FK
+ int minExperienceMonths
+ string vesselTypeCriteria
+ string raisedById FK
+ bool autoRaised
+ date neededBy
+ }
+ APPLICATION {
+ string id PK
+ string requisitionId FK
+ string candidateId FK
+ enum type "CandidateType"
+ enum stage "ApplicationStage"
+ decimal proposedSalary
+ string remarks
+ bool interviewWaived
+ }
+ APPLICATION_GATE {
+ string id PK
+ string applicationId FK
+ string gate "competency|document|experience|reference|salary|interview"
+ enum result "PENDING|VERIFIED|REJECTED"
+ string note
+ string decidedById FK
+ }
+ CREW_ASSIGNMENT {
+ string id PK
+ string crewMemberId FK
+ string vesselId FK
+ string rankId FK
+ string requisitionId FK
+ date signOnDate
+ date signOffDate
+ enum status "AssignmentStatus"
+ }
+ SALARY_STRUCTURE {
+ string id PK
+ string assignmentId FK
+ decimal basic
+ decimal victualingPerDay
+ json allowances
+ string currency
+ string approvedById FK "Manager"
+ }
+ CONTRACT_LETTER {
+ string id PK
+ string assignmentId FK
+ string fileKey
+ bool salaryRestricted "hide salary from site staff"
+ }
+ ATTENDANCE {
+ string id PK
+ string assignmentId FK
+ date date
+ enum status "AttendanceStatus"
+ string recordedById FK
+ }
+ LEAVE_REQUEST {
+ string id PK
+ string assignmentId FK
+ enum type "LeaveType"
+ date fromDate
+ date toDate
+ enum status "LeaveStatus"
+ string appliedById FK
+ }
+ PPE_ISSUE {
+ string id PK
+ string assignmentId FK
+ enum item "PpeItem"
+ string size "for boiler suit / shoes"
+ int quantity
+ date issuedDate
+ date returnedDate
+ string issuedById FK
+ }
+ SEAFARER_DOCUMENT {
+ string id PK
+ string crewMemberId FK
+ enum docType "SeafarerDocType"
+ string number "masked"
+ string fileKey
+ date issueDate
+ date expiryDate
+ enum verificationStatus "VerificationStatus"
+ string verifiedById FK "MPO"
+ }
+ BANK_DETAIL {
+ string id PK
+ string crewMemberId FK
+ string accountName
+ string accountNumberEnc "encrypted"
+ string ifsc
+ string bankName
+ enum verificationStatus "by Accounts"
+ string verifiedById FK
+ }
+ EPF_DETAIL {
+ string id PK
+ string crewMemberId FK
+ string uan
+ string aadhaarLast4
+ string pfNumber
+ enum verificationStatus "EPFO check by Accounts"
+ string verifiedById FK
+ }
+ EXPERIENCE_RECORD {
+ string id PK
+ string crewMemberId FK
+ string vesselType
+ string rankId FK
+ date fromDate
+ date toDate
+ int durationMonths
+ string source "internal|declared"
+ }
+ APPRAISAL {
+ string id PK
+ string assignmentId FK
+ string period
+ json ratings
+ string comments
+ enum status "AppraisalStatus"
+ string addedById FK "PM"
+ string verifiedById FK "MPO"
+ string approvedById FK "Manager"
+ }
+ WAGE_REPORT {
+ string id PK
+ string siteId FK
+ string period "YYYY-MM"
+ enum status "WageReportStatus"
+ decimal totalAmount
+ string generatedById FK
+ string approvedById FK
+ }
+ WAGE_LINE {
+ string id PK
+ string wageReportId FK
+ string assignmentId FK
+ int daysAttended
+ decimal dailyRate
+ decimal victualing
+ decimal lineTotal
+ }
+ CREW_ACTION {
+ string id PK
+ string entityType "requisition|application|assignment|..."
+ string entityId
+ enum actionType "CrewActionType"
+ string actorId FK
+ string note
+ json metadata
+ datetime createdAt
+ }
+```
+
+## 4. Model notes
+
+- **`CrewMember`** is the spine: a row exists from the first application
+ (`PROSPECT`/`CANDIDATE`) and persists as `EMPLOYEE` then `EX_HAND`. This is
+ what makes "ex-hand preferred" cheap — their experience and documents are
+ already on file. `employeeId` is assigned at onboarding.
+- **`Application` vs `Requisition`** — one requisition, many applications;
+ `APPLICATION_GATE` rows are the audit of each vetting gate (the columns in
+ notebook page 2: competency, document, experience, reference, salary,
+ interview). `interviewWaived` is set true for ex-hands.
+- **`CrewAssignment`** is a single tour of duty. Onboarding creates it and
+ flips the requisition to `FILLED`. Sign-off sets `signOffDate`/`SIGNED_OFF`,
+ appends an `EXPERIENCE_RECORD`, and triggers a backfill requisition.
+- **Verification is a field** — `verificationStatus + verifiedById` on
+ documents, bank and EPF. Routing rule (from the notebook): site-entered data →
+ **MPO**; bank + EPF → **Accounts**; attendance is operational (no separate
+ verify gate).
+- **`SalaryStructure`** holds `basic`, `victualingPerDay`, and a JSON
+ `allowances`; approved by a Manager. Salary is the restricted field on the
+ contract letter for site staff.
+- **`WageReport` / `WageLine`** are the generated monthly artefact:
+ `lineTotal = daysAttended × dailyRate + victualing`; the report
+ `totalAmount` is the sum. Exportable to XLSX/PDF like a PO.
+- **PPE as inventory** — when the inventory flag is on, a `PPE_ISSUE` can also
+ decrement `ItemInventory` at the site (optional integration).
+
+## 5. Relationship to existing models
+
+| Existing model | Crewing relationship |
+|---|---|
+| `Vessel` (cost centre) | `Requisition.vesselId`, `CrewAssignment.vesselId` |
+| `Site` | `WageReport.siteId`; site grouping for attendance & leave planner; optional PPE inventory |
+| `User` | actors on every `CrewAction`; raisers/verifiers/approvers |
+| `Notification` | crew events reuse the in-app bell + email log |
+| `ItemInventory` (flagged) | optional PPE draw-down |
diff --git a/Crewing-Design-Document.md b/Crewing-Design-Document.md
new file mode 100644
index 0000000..8600ba6
--- /dev/null
+++ b/Crewing-Design-Document.md
@@ -0,0 +1,164 @@
+# 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).
diff --git a/Crewing-Module.md b/Crewing-Module.md
new file mode 100644
index 0000000..65fc775
--- /dev/null
+++ b/Crewing-Module.md
@@ -0,0 +1,72 @@
+# Crewing Module
+
+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
+recruitment and onboarding, to day-to-day site HR (attendance, leave, PPE,
+documents) and finally to the monthly wage report that feeds Accounts.
+
+It reuses the platform primitives already proven by the [PO module](Purchase-Orders):
+a single **state machine** per lifecycle, a centralised **permission map**, an
+**audit trail** of actions, **file storage** for documents, and the **notifier**
+for email/in-app events.
+
+## Why software
+
+Today crewing lives in notebooks, WhatsApp, and spreadsheets (the source notes
+for this design were literally two notebook pages). The pain points it removes:
+
+- **Vacancies are reactive and untracked.** A sign-off or leave creates a gap
+ that nobody formally owns until a vessel is short-handed. → Auto-raised
+ **Requisitions** on sign-off / end-of-contract.
+- **Candidate vetting is ad-hoc.** Competency, document, reference and salary
+ checks happen over chat with no record of who cleared what. → A gated
+ **Candidate Pipeline** with an event log.
+- **Site data and office verification are disconnected.** PMs hold PPE/leave/doc
+ data on paper; the office can't see or verify it. → Site-entered records with
+ an explicit **MPO / Accounts verification** step.
+- **Wage calculation is manual.** Days-attended × salary is re-derived by hand
+ every month. → A generated **Wage Report** per site.
+
+## What it does (salient features)
+
+| Area | Capability |
+|---|---|
+| **Requisitions** | Auto- or manually-raised vacancy for a rank on a vessel/site; reason (leave / end-of-contract / termination / medical / other). |
+| **Candidate pipeline** | Shortlist (ex-hand preferred) → competency → document verification → reference check → salary agreement → proposal → interview (optional for ex-hands) → selection / rejection with remarks. |
+| **CV intake** | Self-apply on the Pelagia site or MPO upload; CV parsed for age, vessel type, rank and experience, with manual fallback. |
+| **Onboarding** | One selection event starts salary, victualing, attendance, experience accrual, PF tracking and the PPE issue checklist. |
+| **Crew records** | Bank details, EPF/UAN, next of kin, emergency contact, contract letter, and role-based seafarer documents (STCW, Aadhaar, PAN, Passport, CDC, COC, photo, licence, medical fitness). |
+| **PPE issue register** | Boiler-suit & shoe sizes plus issue tracking for the full PPE kit. |
+| **Leave & attendance** | Site-level leave planner (contracts + leaves on one timeline) and daily attendance capture. |
+| **Appraisal** | PM raises → MPO verifies → Manager approves. |
+| **Sign-off** | Updates experience, closes the assignment, and auto-raises the backfill requisition. |
+| **Wage report** | Monthly, per site: crew × salary × days attended (+ victualing), generated and sent to Accounts. |
+| **Verification** | Office sign-off: MPO verifies everything except attendance; bank + EPF verified by Accounts. |
+
+## How it fits PPMS
+
+- **Same stack** — Next.js 15 App Router, Prisma + PostgreSQL, NextAuth v5,
+ Tailwind v4, shadcn/ui. See [Crewing Architecture](Crewing-Architecture).
+- **Same patterns** — `lib/requisition-state-machine.ts` and
+ `lib/application-pipeline.ts` mirror `lib/po-state-machine.ts`; a `CrewAction`
+ audit row mirrors `POAction`; verification/permission gating reuses
+ `requirePermission`.
+- **Shared entities** — `Vessel` (cost centre), `Site`, `User`, `Notification`
+ are reused; crew salary cost is attributable to the same cost-centre concept
+ used by POs.
+
+## Page map
+
+| Page | Purpose | Detail |
+|---|---|---|
+| [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** |
+| [Crewing Workflows](Crewing-Workflows) | Lifecycles & flows | **Sequence + state diagrams** |
+| [Crewing Use Cases](Crewing-Use-Cases) | Actors × use cases | **Use-case diagram** |
+| [Crewing Roles and Permissions](Crewing-Roles-and-Permissions) | Permission matrix extension | — |
+| [Crewing User Stories](Crewing-User-Stories) | Backlog by epic with acceptance criteria | — |
+
+> **Status:** design proposal. Entity, route and permission names are
+> proposals to be confirmed in review (see [Open Questions](Crewing-Design-Document#open-questions)).
diff --git a/Crewing-Roles-and-Permissions.md b/Crewing-Roles-and-Permissions.md
new file mode 100644
index 0000000..7f67576
--- /dev/null
+++ b/Crewing-Roles-and-Permissions.md
@@ -0,0 +1,102 @@
+# Crewing Roles and 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
+relevant state machine adds the status+role gate on top.
+
+## 1. Role mapping
+
+| Crewing actor | PPMS role | Notes |
+|---|---|---|
+| PM / APM / Site In-charge | **`SITE_STAFF`** (new, proposed) | apply-only leave, attendance, PPE issue, doc upload, view-only contract (except salary) & bank |
+| MPO | **`MANNING`** (existing — "crew-management staff") | recruitment + verifies all site data except bank/EPF |
+| Accounts | **`ACCOUNTS`** | verifies bank + EPF; consumes wage report |
+| Manager | **`MANAGER`** | approves salary structures, candidate list, appraisals, wage reports |
+| 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.
+
+## 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` | ✓ | ✓ | | ✓ | ✓ | | |
+| `cancel_requisition` | | ✓ | | ✓ | ✓ | | |
+| `view_requisitions` | ✓ | ✓ | | ✓ | ✓ | ✓ | ✓ |
+| `manage_candidates` (shortlist/vetting) | | ✓ | | ✓ | ✓ | | |
+| `record_reference_check` | | ✓ | | ✓ | ✓ | | |
+| `propose_interview` | | ✓ | | ✓ | ✓ | | |
+| `approve_salary_structure` | | | | ✓ | ✓ | | |
+| `select_candidate` | | ✓ | | ✓ | ✓ | | |
+| `onboard_crew` | | ✓ | | ✓ | ✓ | | |
+| `sign_off_crew` | ✓ | ✓ | | ✓ | ✓ | | |
+| `view_crew_records` | ✓¹ | ✓ | ✓² | ✓ | ✓ | ✓ | ✓ |
+| `upload_crew_records` (docs/NoK/emergency/EPF) | ✓ | ✓ | | ✓ | ✓ | | |
+| `issue_ppe` | ✓ | ✓ | | ✓ | ✓ | | |
+| `apply_leave` | ✓ | ✓ | | ✓ | ✓ | | |
+| `decide_leave` | | ✓ | | ✓ | ✓ | | |
+| `record_attendance` | ✓ | ✓ | | ✓ | ✓ | | |
+| `verify_site_records` (docs/PPE/leave/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.
+
+## 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).
+- 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
+
+```ts
+// 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.**
diff --git a/Crewing-Use-Cases.md b/Crewing-Use-Cases.md
new file mode 100644
index 0000000..7363d4e
--- /dev/null
+++ b/Crewing-Use-Cases.md
@@ -0,0 +1,107 @@
+# Crewing Use Cases
+
+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. Use-case diagram
+
+```mermaid
+flowchart LR
+ SS([Site staff
PM / APM / Site I-C])
+ MPO([MPO])
+ ACC([Accounts])
+ MGR([Manager])
+ CAND([Candidate])
+ ADM([Admin])
+
+ subgraph Requisition
+ U1(["Raise requisition"])
+ U2(["Sign off crew → auto-requisition"])
+ U3(["Cancel requisition"])
+ end
+ subgraph Recruitment
+ U4(["Apply with CV"])
+ U5(["Shortlist candidates"])
+ U6(["Run vetting gates"])
+ U7(["Reference check"])
+ U8(["Propose & interview"])
+ U9(["Select / reject with remarks"])
+ U10(["Approve salary structure & list"])
+ U11(["Onboard candidate"])
+ end
+ subgraph SiteHR["Site HR"]
+ U12(["Apply for leave"])
+ U13(["View leave planner"])
+ U14(["Record attendance"])
+ U15(["Issue PPE (sizes)"])
+ U16(["Upload documents / EPF / NoK"])
+ end
+ subgraph Verify["Office verification"]
+ U17(["Verify docs / PPE / leave"])
+ U18(["Verify bank & EPF"])
+ end
+ subgraph Appraisal
+ U19(["Raise appraisal"])
+ U20(["Verify appraisal"])
+ U21(["Approve appraisal"])
+ end
+ subgraph Payroll
+ U22(["Generate wage report"])
+ U23(["Approve wage report"])
+ U24(["View / export wage report"])
+ end
+ subgraph Admin
+ U25(["Manage ranks & doc requirements"])
+ end
+
+ SS --- U1 & U2 & U12 & U13 & U14 & U15 & U16 & U19
+ CAND --- U4
+ MPO --- U5 & U6 & U7 & U8 & U9 & U11 & U17 & U20
+ MGR --- U3 & U9 & U10 & U11 & U21 & U22 & U23 & U24
+ ACC --- U18 & U24
+ ADM --- U25
+```
+
+## 2. Use-case catalogue
+
+| ID | Use case | Primary actor | Pre-condition | Main success outcome |
+|---|---|---|---|---|
+| UC-01 | Raise requisition | Site staff / MPO | a rank is or will be vacant | `Requisition(OPEN)` created, MPO notified |
+| UC-02 | Auto-requisition on sign-off | System | crew member signed off | requisition raised automatically; experience updated |
+| UC-03 | Cancel requisition | Manager | requisition not yet filled | `CANCELLED` with reason |
+| UC-04 | Apply with CV | Candidate | careers form reachable | `CrewMember(PROSPECT)` + application; CV parsed or manual |
+| UC-05 | Shortlist candidates | MPO | requisition `OPEN` | applications `SHORTLISTED`; ex-hands preferred |
+| UC-06 | Run vetting gates | MPO | candidate shortlisted | competency/document/experience gates recorded |
+| UC-07 | Reference check | MPO | candidate in vetting | reference result recorded |
+| UC-08 | Propose & interview | MPO | gates cleared | proposal sent; interview recorded (waived for ex-hands) |
+| UC-09 | Select / reject with remarks | MPO / Manager | interview done / waived | `SELECTED` or `REJECTED` + remarks |
+| UC-10 | Approve salary structure & candidate list | Manager | candidate proposed | salary structure approved |
+| UC-11 | Onboard candidate | MPO / Manager | candidate selected | `CrewAssignment(ACTIVE)`; salary/victualing/attendance/experience/PF/PPE started; employeeId issued; requisition `FILLED` |
+| UC-12 | Apply for leave | Site staff | active assignment | `LeaveRequest(APPLIED)` |
+| UC-13 | View leave planner | Site staff / MPO / Manager | — | timeline of contracts + leaves per site |
+| UC-14 | Record attendance | Site staff | active assignment | daily `Attendance` rows |
+| UC-15 | Issue PPE | Site staff | active assignment | `PpeIssue` with size (boiler suit/shoes) |
+| UC-16 | Upload documents / EPF / next-of-kin / emergency | Site staff | crew exists | records created `PENDING` verification |
+| UC-17 | Verify docs / PPE / leave | MPO | pending records exist | `VERIFIED` (everything except attendance) |
+| UC-18 | Verify bank & EPF | Accounts | pending bank/EPF | `VERIFIED`; UAN/Aadhaar checked vs EPFO |
+| UC-19 | Raise appraisal | Site staff (PM) | active assignment | `Appraisal(SUBMITTED)` |
+| UC-20 | Verify appraisal | MPO | appraisal submitted | `MPO_VERIFIED` |
+| UC-21 | Approve appraisal | Manager | appraisal verified | `MANAGER_APPROVED` |
+| UC-22 | Generate wage report | Manager / system | month end | `WageReport(GENERATED)` per site |
+| UC-23 | Approve wage report | Manager | report generated | `MANAGER_APPROVED` → `SENT_TO_ACCOUNTS` |
+| UC-24 | View / export wage report | Accounts / Manager | report sent | XLSX/PDF export for disbursement |
+| UC-25 | Manage ranks & doc requirements | Admin | — | rank hierarchy + per-rank required documents |
+
+## 3. Notable extensions / alternates
+
+- **UC-04 alt** — CV not parseable → manual field entry (never blocks intake).
+- **UC-06/07/09 alt** — any gate fails → `REJECTED` with remarks; application
+ ends, requisition stays open for other candidates.
+- **UC-08 alt** — ex-hand → interview waived (`interviewWaived = true`).
+- **UC-11 alt** — joining formalities incomplete (no signed contract / unapproved
+ salary) → onboarding blocked.
+- **UC-16/17 alt** — verifier rejects a record → back to `PENDING` with remarks
+ for the site to correct.
+- **UC-22 alt** — attendance gaps flagged before generation; report can be
+ regenerated until approved.
diff --git a/Crewing-User-Stories.md b/Crewing-User-Stories.md
new file mode 100644
index 0000000..e78f057
--- /dev/null
+++ b/Crewing-User-Stories.md
@@ -0,0 +1,329 @@
+# Crewing User Stories
+
+Backlog for the Crewing Module, grouped into epics. Format:
+*As a ``, I want ``, so that ``* + acceptance criteria
+(AC). IDs are stable references for PRs/issues.
+
+---
+
+## Epic A — Requisitions (vacancy management)
+
+**A1 — Auto-requisition on sign-off**
+As an **MPO**, I want a requisition raised automatically when a crew member
+signs off, so that no vacancy goes untracked.
+- AC1: signing off an assignment creates a `Requisition(OPEN, autoRaised)` for
+ the same rank + vessel.
+- AC2: the requisition records the reason (EOC / medical / termination / other).
+- AC3: the MPO receives an email + in-app notification.
+- AC4: a `CrewAction(REQUISITION_RAISED)` is written.
+
+**A2 — Manual requisition**
+As **site staff / MPO**, I want to raise a requisition manually (e.g. planned
+leave), so that I can pre-empt a gap.
+- AC1: I select vessel, rank, reason, needed-by date, and min-experience criteria.
+- AC2: the requisition appears in the MPO shortlist queue.
+
+**A3 — Requisition list & detail**
+As an **MPO/Manager**, I want a filterable list of requisitions by
+vessel/rank/status, so that I can prioritise sourcing.
+- AC1: filters for status, vessel, rank, reason, needed-by.
+- AC2: each row shows candidate count and days open.
+
+**A4 — Cancel requisition**
+As a **Manager**, I want to cancel a requisition with a reason, so that
+withdrawn vacancies don't clutter the pipeline.
+- AC1: only non-`FILLED` requisitions can be cancelled.
+- AC2: reason is required and audited.
+
+---
+
+## Epic B — Candidate intake
+
+**B1 — Public application with CV**
+As a **candidate**, I want to apply on the Pelagia site and upload my CV, so
+that I'm considered without re-typing everything.
+- AC1: the form accepts personal details + CV upload (signed upload to storage).
+- AC2: the CV is parsed for age, vessel type, current/past rank, experience.
+- AC3: parsed fields pre-fill a draft I can correct before submitting.
+- AC4: if parsing fails, I can enter all fields manually (intake never blocks).
+- AC5: submission creates a `CrewMember(PROSPECT)` + application(s).
+
+**B2 — MPO manual candidate upload**
+As an **MPO**, I want to add a candidate and their CV directly, so that
+walk-ins/referrals enter the same pipeline.
+- AC1: same parse-or-manual flow as B1.
+- AC2: the candidate is attachable to one or more open requisitions.
+
+**B3 — Ex-hand recognition**
+As an **MPO**, I want ex-hands flagged and preferred in shortlisting, so that
+proven crew are surfaced first.
+- AC1: candidates matching an existing `CrewMember(EX_HAND)` are tagged.
+- AC2: ex-hands sort above new candidates by default.
+- AC3: ex-hand experience/documents are pre-populated from history.
+
+---
+
+## Epic C — Recruitment pipeline (vetting)
+
+**C1 — Shortlist to a requisition**
+As an **MPO**, I want to shortlist candidates against a requisition, so that
+vetting can begin.
+- AC1: shortlisting moves the requisition to `SHORTLISTING` and the application
+ to `SHORTLISTED`.
+
+**C2 — Competency check**
+As an **MPO**, I want to record a competency result against the rank's minimum
+criteria, so that unqualified candidates are filtered early.
+- AC1: pass advances to document verification; fail → `REJECTED` + remarks.
+
+**C3 — Document verification (vetting)**
+As an **MPO**, I want to verify a candidate's seafarer documents during vetting,
+so that only documented candidates proceed.
+- AC1: missing/expired required docs (per rank) block advancement.
+- AC2: result recorded as an `APPLICATION_GATE`.
+
+**C4 — Experience check**
+As an **MPO**, I want to verify experience (vessel type, time-in-rank, total
+duration) against the requisition's criteria, so that the candidate fits the seat.
+- AC1: criteria comparison shown; shortfall flagged.
+
+**C5 — Reference check**
+As an **MPO**, I want to record reference-check outcomes, so that prior conduct
+is confirmed.
+- AC1: at least one reference result recorded before proposal.
+
+**C6 — Salary agreement**
+As an **MPO**, I want to record an agreed salary structure (basic, victualing,
+allowances), so that the proposal has terms.
+- AC1: structure captured; visible only to office roles (not site staff).
+
+**C7 — Proposal & interview**
+As an **MPO**, I want to propose to the candidate and record an interview, so
+that selection is informed.
+- AC1: new candidates require an interview record.
+- AC2: ex-hands can have the interview **waived** (`interviewWaived`).
+
+**C8 — Selection / rejection with remarks**
+As an **MPO/Manager**, I want to select or reject with remarks, so that the
+decision and its reason are on record.
+- AC1: rejection requires remarks.
+- AC2: selection requires all prior gates cleared.
+
+**C9 — Pipeline board**
+As an **MPO**, I want a board showing each candidate's stage per requisition, so
+that I can see the funnel at a glance.
+- AC1: columns map to `ApplicationStage`; cards show candidate + last gate.
+
+---
+
+## Epic D — Onboarding
+
+**D1 — Approve salary structure & candidate list**
+As a **Manager**, I want to approve the proposed salary structure and selected
+candidate, so that onboarding can proceed.
+- AC1: onboarding is blocked until the structure is `MANAGER_APPROVED`.
+
+**D2 — Joining formalities & onboard**
+As an **MPO/Manager**, I want to complete joining formalities and onboard the
+candidate, so that they become an employee.
+- AC1: a contract letter is attached; salary confirmed.
+- AC2: onboarding creates a `CrewAssignment(ACTIVE)`, assigns an `employeeId`,
+ and sets `CrewMember.status = EMPLOYEE`.
+- AC3: the filled requisition flips to `FILLED`.
+
+**D3 — Onboarding side-effects**
+As the **system**, I want onboarding to start salary, victualing, attendance,
+experience, PF and PPE in one transaction, so that nothing is missed.
+- AC1: all six are initialised atomically.
+- AC2: a single `CrewAction(ONBOARDED)` records the created IDs in `metadata`.
+
+---
+
+## Epic E — Crew records & documents
+
+**E1 — Crew directory & profile**
+As an **MPO**, I want a crew directory with a per-member profile, so that I can
+find anyone's records.
+- AC1: profile groups documents, bank, EPF, next-of-kin, emergency, PPE,
+ experience, appraisals.
+
+**E2 — Upload seafarer documents**
+As **site staff**, I want to upload role-based documents (STCW, Aadhaar, PAN,
+passport, CDC, COC, photo, licence, medical fitness), so that the office can
+verify them.
+- AC1: required set is driven by rank (`RankDocRequirement`); driver requires a
+ driving licence.
+- AC2: documents store issue/expiry dates; uploads start `PENDING`.
+
+**E3 — Document expiry warnings**
+As an **MPO**, I want upcoming-expiry warnings, so that crew don't sail on
+expired documents.
+- AC1: docs expiring within N days are flagged on the profile and a queue.
+
+**E4 — Bank / EPF / next-of-kin / emergency**
+As **site staff**, I want to record bank details, EPF (UAN/Aadhaar), next-of-kin
+and emergency contacts, so that payroll and welfare are covered.
+- AC1: bank account number stored masked/encrypted; site staff see it
+ **view-only**.
+- AC2: contract letter is **view-only-except-salary** for site staff.
+
+---
+
+## Epic F — PPE issue register
+
+**F1 — Capture sizes**
+As **site staff**, I want to record boiler-suit and safety-shoe sizes, so that
+the right kit is issued.
+- AC1: size is captured on the relevant PPE issue.
+
+**F2 — Issue PPE kit**
+As **site staff**, I want to issue PPE items (boiler suit, shoes, helmet, vest,
+gloves, mask, goggles, tiffin, torch, walkie-talkie), so that issuance is logged.
+- AC1: each issue records item, quantity, size?, date, issuer.
+- AC2: (flag on) optionally decrements site `ItemInventory`.
+
+**F3 — Returns**
+As **site staff**, I want to record PPE returns, so that the register is current.
+- AC1: a `returnedDate` closes the issue.
+
+---
+
+## Epic G — Leave & attendance
+
+**G1 — Site leave planner**
+As **site staff / MPO / Manager**, I want a planner showing every crew member's
+contract span and leaves on one timeline, so that I can plan cover.
+- AC1: timeline per site with contract bars + leave bars.
+- AC2: overlapping absences for the same rank are highlighted.
+
+**G2 — Apply for leave**
+As **site staff**, I want to apply for leave (apply-only), so that the office can
+approve it.
+- AC1: I cannot self-approve; status starts `APPLIED`.
+
+**G3 — Decide leave**
+As an **MPO**, I want to approve/reject leave with a note, so that the planner
+stays accurate.
+- AC1: approval moves the assignment to `ON_LEAVE` for the period.
+
+**G4 — Record attendance**
+As **site staff**, I want to record daily attendance, so that wages can be
+computed.
+- AC1: one row per assignment per day; statuses present/absent/half/leave/sign-off.
+- AC2: no verification gate (operational).
+
+---
+
+## Epic H — Appraisal
+
+**H1 — Raise appraisal**
+As a **PM (site staff)**, I want to raise an appraisal for a crew member, so that
+performance is recorded.
+- AC1: appraisal starts `DRAFT`, submits to `SUBMITTED`.
+
+**H2 — Verify appraisal**
+As an **MPO**, I want to verify a submitted appraisal, so that the Manager
+reviews vetted input.
+- AC1: verify → `MPO_VERIFIED`; return → `REJECTED` + remarks.
+
+**H3 — Approve appraisal**
+As a **Manager**, I want to approve a verified appraisal, so that it's final.
+- AC1: only `MPO_VERIFIED` appraisals can be approved.
+
+---
+
+## Epic I — Office verification
+
+**I1 — MPO verification queue**
+As an **MPO**, I want a queue of pending site records (documents, PPE, leave,
+next-of-kin), so that I can verify everything except attendance.
+- AC1: verify sets `VERIFIED` + me as `verifiedBy`; reject returns with remarks.
+
+**I2 — Accounts bank/EPF verification**
+As **Accounts**, I want to verify bank details and EPF (UAN/Aadhaar vs EPFO), so
+that payments go to the right verified account.
+- AC1: only Accounts can verify bank/EPF.
+- AC2: EPFO check result is recorded.
+
+---
+
+## Epic J — Payroll / wage report
+
+**J1 — Generate wage report**
+As a **Manager (or month-end job)**, I want a per-site wage report
+(`crew × salary × days-attended + victualing`), so that Accounts can pay.
+- AC1: one `WageLine` per active assignment; `lineTotal` computed.
+- AC2: attendance gaps flagged before generation.
+
+**J2 — Approve & send**
+As a **Manager**, I want to approve the report and send it to Accounts, so that
+disbursement is authorised.
+- AC1: `MANAGER_APPROVED` → `SENT_TO_ACCOUNTS`.
+
+**J3 — Accounts view & export**
+As **Accounts**, I want to view and export the wage report (XLSX/PDF), so that I
+can disburse.
+- AC1: export reuses the PO export mechanism.
+
+---
+
+## Epic K — Sign-off & experience
+
+**K1 — Sign off crew**
+As **site staff / MPO**, I want to sign off a crew member, so that the tour
+closes cleanly.
+- AC1: assignment → `SIGNED_OFF` with `signOffDate`.
+- AC2: an `EXPERIENCE_RECORD` is appended (vessel type, rank, duration).
+- AC3: a backfill requisition is auto-raised (links to A1).
+
+**K2 — Experience history**
+As an **MPO**, I want a crew member's accumulated experience on file, so that
+ex-hand vetting is instant.
+- AC1: internal tours appear automatically; declared experience can be added.
+
+---
+
+## Epic L — Reference data & admin
+
+**L1 — Manage ranks**
+As an **Admin/Manager**, I want to manage the rank hierarchy, so that
+requisitions and the org chart are correct.
+- AC1: ranks form a self-hierarchy with category + `isSeafarer`.
+
+**L2 — Manage rank document requirements**
+As an **Admin/Manager**, I want to set which documents each rank requires, so
+that vetting and uploads enforce the right set.
+- AC1: e.g. driver → driving licence; deck/engine → STCW/CDC/COC/medical.
+
+---
+
+## Epic M — Cross-cutting
+
+**M1 — Crewing dashboard**
+As a **Manager**, I want crewing stat cards (open requisitions, candidates in
+pipeline, expiring documents, crew on leave), so that I see status at a glance.
+
+**M2 — Notifications**
+As any **actor**, I want email + in-app notifications on the events relevant to
+me (requisition raised, proposal, appraisal verified, wage report ready), so
+that I act promptly.
+
+**M3 — Audit trail**
+As an **Auditor**, I want every crewing transition recorded with actor/time/note,
+so that the process is fully traceable.
+- AC1: `CrewAction` rows for all lifecycle and verification events.
+
+**M4 — Feature flag**
+As an **operator**, I want the crewing surface behind `NEXT_PUBLIC_CREWING_ENABLED`,
+so that it can be rolled out gradually.
+
+---
+
+### Suggested delivery order
+
+1. Reference data (L1, L2) + data model + permissions.
+2. Requisitions (A) + sign-off/experience (K).
+3. Candidate intake (B) + pipeline (C) + onboarding (D).
+4. Crew records (E), PPE (F), leave/attendance (G).
+5. Verification (I), appraisal (H).
+6. Payroll (J), dashboard/notifications (M).
diff --git a/Crewing-Workflows.md b/Crewing-Workflows.md
new file mode 100644
index 0000000..b8c8932
--- /dev/null
+++ b/Crewing-Workflows.md
@@ -0,0 +1,291 @@
+# Crewing Workflows
+
+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
+tables**, and **sequence diagrams** for the end-to-end flows.
+
+---
+
+## 1. Requisition lifecycle
+
+The vacancy. Raised automatically on sign-off / end-of-contract, or manually.
+
+```mermaid
+stateDiagram-v2
+ [*] --> OPEN : raise (auto on sign-off / manual)
+ OPEN --> SHORTLISTING : add candidates
+ SHORTLISTING --> PROPOSING : a candidate clears vetting
+ PROPOSING --> INTERVIEWING : interview scheduled
+ PROPOSING --> SELECTED : ex-hand, interview waived
+ INTERVIEWING --> SELECTED : candidate selected
+ INTERVIEWING --> SHORTLISTING : all rejected, re-source
+ SELECTED --> FILLED : onboarded (assignment created)
+ OPEN --> CANCELLED : vacancy withdrawn
+ SHORTLISTING --> CANCELLED
+ FILLED --> [*]
+ CANCELLED --> [*]
+```
+
+| From | Action | To | Roles | Side-effect |
+|---|---|---|---|---|
+| — | `raise` | OPEN | system (sign-off) / SITE_STAFF / MANNING | email MPO |
+| OPEN | `start_shortlist` | SHORTLISTING | MANNING | — |
+| SHORTLISTING | `propose` | PROPOSING | MANNING | email Manager |
+| PROPOSING | `schedule_interview` | INTERVIEWING | MANNING | email candidate |
+| PROPOSING | `select` (ex-hand) | SELECTED | MANNING, MANAGER | email candidate |
+| INTERVIEWING | `select` | SELECTED | MANNING, MANAGER | email candidate |
+| INTERVIEWING | `reject_all` | SHORTLISTING | MANNING | — |
+| SELECTED | `onboard` | FILLED | MANNING, MANAGER | **onboarding side-effects** |
+| OPEN/SHORTLISTING | `cancel` | CANCELLED | MANAGER | — |
+
+---
+
+## 2. Candidate pipeline (Application)
+
+The per-candidate gated vetting from notebook page 2. Many applications run per
+requisition; one ends in `ONBOARDED`. **Ex-hands skip the interview** (optional).
+Any gate can end in **rejection with remarks**.
+
+```mermaid
+stateDiagram-v2
+ [*] --> SHORTLISTED
+ SHORTLISTED --> COMPETENCY_CHECK
+ COMPETENCY_CHECK --> DOC_VERIFICATION : pass
+ DOC_VERIFICATION --> REFERENCE_CHECK : pass
+ REFERENCE_CHECK --> SALARY_AGREEMENT : pass
+ SALARY_AGREEMENT --> PROPOSED : agreed
+ PROPOSED --> INTERVIEW : new candidate
+ PROPOSED --> SELECTED : ex-hand (interview waived)
+ INTERVIEW --> SELECTED : pass
+ SELECTED --> JOINING : joining formalities
+ JOINING --> ONBOARDED : contract + salary confirmed
+ COMPETENCY_CHECK --> REJECTED : fail (remarks)
+ DOC_VERIFICATION --> REJECTED : fail (remarks)
+ REFERENCE_CHECK --> REJECTED : fail (remarks)
+ SALARY_AGREEMENT --> REJECTED : not agreed
+ INTERVIEW --> REJECTED : fail (remarks)
+ ONBOARDED --> [*]
+ REJECTED --> [*]
+```
+
+Each transition writes an `APPLICATION_GATE` row (`gate`, `result`, `note`,
+`decidedById`) so the office can see exactly who cleared what and why a
+candidate was rejected.
+
+---
+
+## 3. Assignment lifecycle
+
+An onboarded tour of duty.
+
+```mermaid
+stateDiagram-v2
+ [*] --> ACTIVE : onboard
+ ACTIVE --> ON_LEAVE : leave approved
+ ON_LEAVE --> ACTIVE : return
+ ACTIVE --> SIGNED_OFF : sign-off
+ ON_LEAVE --> SIGNED_OFF : sign-off (EOC / medical / etc.)
+ SIGNED_OFF --> [*]
+```
+
+`onboard` starts salary + victualing + attendance + experience + PF + PPE.
+`sign-off` closes the tour, appends an `EXPERIENCE_RECORD`, and **auto-raises a
+backfill Requisition** for the same rank/vessel.
+
+---
+
+## 4. Appraisal lifecycle
+
+```mermaid
+stateDiagram-v2
+ [*] --> DRAFT : PM starts
+ DRAFT --> SUBMITTED : PM submits
+ SUBMITTED --> MPO_VERIFIED : MPO verifies
+ SUBMITTED --> REJECTED : MPO returns (remarks)
+ MPO_VERIFIED --> MANAGER_APPROVED : Manager approves
+ MPO_VERIFIED --> REJECTED : Manager returns
+ MANAGER_APPROVED --> [*]
+ REJECTED --> DRAFT : revise
+```
+
+---
+
+## 5. Wage report status
+
+```mermaid
+stateDiagram-v2
+ [*] --> DRAFT : month-end trigger
+ DRAFT --> GENERATED : lines computed
+ GENERATED --> MANAGER_APPROVED : Manager approves
+ MANAGER_APPROVED --> SENT_TO_ACCOUNTS : dispatched
+ SENT_TO_ACCOUNTS --> [*]
+```
+
+---
+
+## 6. Sequence — sign-off → auto-requisition → fill
+
+```mermaid
+sequenceDiagram
+ actor SS as Site staff (PM)
+ participant SYS as App / state machines
+ actor MPO
+ actor MGR as Manager
+ participant DB as PostgreSQL
+ participant N as Notifier
+
+ SS->>SYS: sign off crew member (EOC)
+ SYS->>DB: assignment → SIGNED_OFF
+ SYS->>DB: append EXPERIENCE_RECORD
+ SYS->>DB: create Requisition (autoRaised, OPEN)
+ SYS->>N: notify MPO "vacancy: on "
+ N-->>MPO: email + bell
+ MPO->>SYS: start shortlist, add candidates
+ SYS->>DB: applications (SHORTLISTED)
+ Note over MPO,SYS: candidate pipeline (see §7)
+ MPO->>SYS: select candidate → onboard
+ SYS->>SYS: onboarding side-effects
+ SYS->>DB: requisition → FILLED, assignment ACTIVE
+```
+
+---
+
+## 7. Sequence — candidate self-apply + CV parse
+
+```mermaid
+sequenceDiagram
+ actor C as Candidate
+ participant WEB as /careers/apply (public)
+ participant API as /api/crewing/cv-parse
+ participant CVP as CvParseService
+ participant FS as File storage
+ participant DB as PostgreSQL
+ actor MPO
+
+ C->>WEB: fill form + upload CV
+ WEB->>FS: store CV (signed upload)
+ WEB->>API: parse CV
+ API->>CVP: extract age, vessel type, rank, experience
+ CVP-->>API: fields (best-effort)
+ alt extracted
+ API-->>WEB: pre-filled draft
+ else not extractable
+ API-->>WEB: empty draft (manual entry)
+ end
+ C->>WEB: confirm / correct details
+ WEB->>DB: CrewMember (PROSPECT) + Application(s)
+ WEB-->>MPO: appears in shortlist queue
+```
+
+Manual MPO upload follows the same path minus the public form: MPO uploads the
+CV and confirms the parsed fields.
+
+---
+
+## 8. Sequence — recruitment pipeline (vetting → onboard)
+
+```mermaid
+sequenceDiagram
+ actor MPO
+ participant SYS as application-pipeline
+ actor MGR as Manager
+ actor C as Candidate
+ participant DB as PostgreSQL
+
+ MPO->>SYS: competency check
+ SYS->>DB: gate(competency)=VERIFIED
+ MPO->>SYS: document verification
+ SYS->>DB: gate(document)=VERIFIED
+ MPO->>SYS: reference check
+ SYS->>DB: gate(reference)=VERIFIED
+ MPO->>SYS: salary agreement (propose structure)
+ SYS->>DB: gate(salary)=VERIFIED, proposedSalary
+ MPO->>C: proposal
+ alt new candidate
+ MPO->>SYS: schedule + record interview
+ SYS->>DB: gate(interview)=VERIFIED
+ else ex-hand
+ Note over MPO,SYS: interview waived
+ end
+ MGR->>SYS: approve salary structure + select
+ SYS->>DB: application SELECTED
+ MGR->>SYS: onboard (joining formalities)
+ SYS->>DB: CrewAssignment ACTIVE, contract letter, employeeId
+ Note over SYS,DB: salary+victualing+attendance+experience+PF+PPE started
+```
+
+Any failed gate → `gate=REJECTED` + remarks → application `REJECTED`
+(visible to the office with the reason).
+
+---
+
+## 9. Sequence — site data entry & office verification
+
+```mermaid
+sequenceDiagram
+ actor SS as Site staff
+ participant SYS as App
+ participant DB as PostgreSQL
+ actor MPO
+ actor ACC as Accounts
+
+ SS->>SYS: upload documents / PPE issue / leave / next-of-kin / EPF
+ SYS->>DB: records (verificationStatus=PENDING)
+ par MPO verifies (all except attendance)
+ MPO->>SYS: verify document / PPE / leave / NoK
+ SYS->>DB: VERIFIED (verifiedById=MPO)
+ and Accounts verifies bank + EPF
+ ACC->>SYS: verify bank detail
+ ACC->>SYS: verify EPF (UAN/Aadhaar vs EPFO)
+ SYS->>DB: VERIFIED (verifiedById=Accounts)
+ end
+ SS->>SYS: record attendance (no verify gate)
+ SYS->>DB: attendance rows
+```
+
+Site staff see contract letters **view-only except salary** and bank details
+**view-only**; salary and full account numbers are gated.
+
+---
+
+## 10. Sequence — monthly wage report
+
+```mermaid
+sequenceDiagram
+ participant CRON as Month-end trigger
+ participant WR as wage-report.ts
+ participant DB as PostgreSQL
+ actor MGR as Manager
+ actor ACC as Accounts
+ participant EXP as /payroll/[id]/export
+
+ CRON->>WR: generate for site, period YYYY-MM
+ WR->>DB: read assignments + attendance + salary
+ WR->>DB: WageLine = days × dailyRate + victualing
+ WR->>DB: WageReport (GENERATED, totalAmount)
+ WR-->>MGR: notify "wage report ready"
+ MGR->>DB: approve → MANAGER_APPROVED
+ MGR->>DB: send → SENT_TO_ACCOUNTS
+ DB-->>ACC: appears in Accounts queue
+ ACC->>EXP: export XLSX/PDF for disbursement
+```
+
+---
+
+## 11. Side-effects of onboarding (the one event that starts everything)
+
+| Side-effect | What it creates / starts |
+|---|---|
+| Salary | activates the approved `SalaryStructure` |
+| Victualing | begins per-day messing accrual |
+| Attendance | opens daily attendance for the assignment |
+| Experience | begins accrual on this vessel/rank (closed into `EXPERIENCE_RECORD` at sign-off) |
+| PF | enables EPF tracking against the crew member's UAN |
+| PPE | seeds the PPE issue checklist for the kit |
+| Identity | assigns `employeeId`, sets `CrewMember.status = EMPLOYEE` |
+| Requisition | flips the filled requisition to `FILLED` |
+
+All recorded as a single `ONBOARDED` `CrewAction` with the created IDs in
+`metadata` — the same "one transition, one audit row, declared side-effects"
+discipline as PO approval.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..baa5e61
--- /dev/null
+++ b/README.md
@@ -0,0 +1,36 @@
+# Crewing wiki bundle
+
+Design documentation for the **Crewing / Manning Module** of Pelagia Portal
+(PPMS). Drop these pages into the Forgejo wiki repo root and push.
+
+## Pages
+
+| File | Wiki page | Contains |
+|---|---|---|
+| `Crewing-Module.md` | Crewing Module | Landing page / feature overview |
+| `Crewing-Design-Document.md` | Crewing Design Document | Goals, scope, domain narrative, decisions, open questions |
+| `Crewing-Architecture.md` | Crewing Architecture | System + **component diagram**, module layout |
+| `Crewing-Data-Model.md` | Crewing Data Model | Enums, rank hierarchy, **ER diagram** |
+| `Crewing-Workflows.md` | Crewing Workflows | **State machines** + **sequence diagrams** |
+| `Crewing-Use-Cases.md` | Crewing Use Cases | **Use-case diagram** + catalogue |
+| `Crewing-Roles-and-Permissions.md` | Crewing Roles and Permissions | Permission matrix extension |
+| `Crewing-User-Stories.md` | Crewing User Stories | Backlog by epic with acceptance criteria |
+
+## Diagrams
+
+All diagrams are **Mermaid** fenced code blocks (` ```mermaid `), which Forgejo
+renders natively — no screenshot pipeline needed (unlike the script-based
+mockups). If a target renderer doesn't support Mermaid, the blocks degrade to
+readable text. The `images/crewing/` folder is reserved for any future static
+captures and currently empty.
+
+## Cross-links
+
+Pages link to each other and to existing wiki pages (`Architecture`,
+`Data-Model`, `Roles-and-Permissions`, `PO-Lifecycle`, `File-Storage`,
+`Inventory-and-Catalogue`) using Forgejo's `[Text](Page-Name)` wiki-link form.
+
+## Source
+
+Derived from the director meeting notes, two notebook pages (site-staff record
+permissions; recruitment flow), and `Crewing.excalidraw` (rank hierarchy).