3 Crewing Architecture
Hardik edited this page 2026-06-22 11:59:08 +05:30
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Crewing Architecture

Authoritative build spec: Crewing Implementation Spec carries the full reconciled instructions (codebase changes, roles/nav matrices, screen spec). This page is the module/layer layout, aligned with that spec.

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; 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

flowchart TB
  subgraph UI["UI — app/(portal)/crewing/*"]
    REQ["Requisitions<br/>/crewing/requisitions"]
    CAND["Candidates &amp; Pipeline<br/>/crewing/candidates"]
    CREW["Crew Directory<br/>/crewing/crew/[id]"]
    PLAN["Leave Planner<br/>/crewing/leave"]
    ATT["Attendance<br/>/crewing/attendance"]
    PPE["PPE Register<br/>/crewing/ppe"]
    APPR["Appraisals<br/>/crewing/appraisals"]
    PAY["Wage Reports<br/>/crewing/payroll"]
    VERI["Office Verification<br/>/crewing/verify"]
    APPLY["Public Apply<br/>/careers/apply"]
  end

  subgraph SA["Server Actions — actions.ts (mutations)"]
    A1["requisition actions"]
    A2["application/pipeline actions"]
    A3["onboarding action"]
    A4["crew-record actions<br/>(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<br/>Prisma crew models")]
    FS[("File storage<br/>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
  A6 -.leave clash.-> SM1
  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.
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 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.