Phase 1 of the Crewing module per wiki Crewing-Implementation-Spec §12, all dark behind NEXT_PUBLIC_CREWING_ENABLED (off by default — production unchanged). - schema: add SITE_STAFF to Role; add Rank (self-referential org hierarchy, like Account) + RankDocRequirement, RankCategory & SeafarerDocType enums. - permissions: full §6 crewing grant matrix (PO_ROLE_PERMISSIONS + CREWING_ROLE_PERMISSIONS merged); SITE_STAFF row; MPO has no attendance/leave, approvals are Manager-only, manage_ranks is Manager+Admin. - feature flag: CREWING_ENABLED (opt-in "true"). - nav: flag-gated Crewing section scaffold + "Ranks & documents" under Admin. - reference data: rank-data.ts + rank-doc-data.ts seeded via shared seed-ranks.ts in both dev and prod seeds (19 ranks, 118 doc requirements). - screen: /admin/ranks — rank hierarchy card + per-rank required-documents card. - role-label/prefix maps updated for the new role. Tests: unit (permission matrix + flag), integration (ranks admin CRUD, parent linking, cycle/children guards, doc-requirement upsert/remove, permission gating). Docs: CLAUDE.md "Crewing (feature-flagged)" section + env var. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
42 lines
1.6 KiB
TypeScript
42 lines
1.6 KiB
TypeScript
// Default required-document set per rank, derived from the rank flags in
|
|
// rank-data.ts. Drives candidate vetting and crew uploads (RankDocRequirement).
|
|
// - Every crew member: Aadhaar, PAN, photograph.
|
|
// - Seafarers additionally: STCW, CDC, passport, medical fitness (mandatory);
|
|
// COC is conditional (officer/senior ranks only).
|
|
// - Driver: driving licence (mandatory).
|
|
// Editable afterwards at /admin/ranks; this is just the seeded baseline.
|
|
|
|
import type { SeafarerDocType } from "@prisma/client";
|
|
import { RANKS } from "./rank-data";
|
|
|
|
export type RankDocReq = {
|
|
rankCode: string;
|
|
docType: SeafarerDocType;
|
|
isMandatory: boolean;
|
|
note?: string;
|
|
};
|
|
|
|
const COMMON: { docType: SeafarerDocType; isMandatory: boolean }[] = [
|
|
{ docType: "AADHAAR", isMandatory: true },
|
|
{ docType: "PAN", isMandatory: true },
|
|
{ docType: "PHOTOGRAPH", isMandatory: true },
|
|
];
|
|
|
|
const SEAFARER: { docType: SeafarerDocType; isMandatory: boolean; note?: string }[] = [
|
|
{ docType: "STCW", isMandatory: true },
|
|
{ docType: "CDC", isMandatory: true },
|
|
{ docType: "PASSPORT", isMandatory: true },
|
|
{ docType: "MEDICAL_FITNESS", isMandatory: true },
|
|
{ docType: "COC", isMandatory: false, note: "Officer / senior ranks only" },
|
|
];
|
|
|
|
export const RANK_DOC_REQUIREMENTS: RankDocReq[] = RANKS.flatMap((rank) => {
|
|
const reqs: RankDocReq[] = COMMON.map((c) => ({ rankCode: rank.code, ...c }));
|
|
if (rank.isSeafarer) {
|
|
reqs.push(...SEAFARER.map((s) => ({ rankCode: rank.code, ...s })));
|
|
}
|
|
if (rank.code === "DRV") {
|
|
reqs.push({ rankCode: "DRV", docType: "DRIVING_LICENSE", isMandatory: true });
|
|
}
|
|
return reqs;
|
|
});
|