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>
22 lines
662 B
TypeScript
22 lines
662 B
TypeScript
export const ROLE_PREFIX: Record<string, string> = {
|
|
TECHNICAL: "TCH",
|
|
MANNING: "MAN",
|
|
ACCOUNTS: "ACC",
|
|
MANAGER: "MGR",
|
|
SUPERUSER: "SUP",
|
|
AUDITOR: "AUD",
|
|
ADMIN: "ADM",
|
|
SITE_STAFF: "SIT",
|
|
};
|
|
|
|
/** Find max existing number for prefix and return prefix-(max+1), zero-padded to 3 digits */
|
|
export function nextId(prefix: string, existingIds: (string | null | undefined)[]): string {
|
|
const re = new RegExp(`^${prefix}-(\\d+)$`, "i");
|
|
let max = 0;
|
|
for (const id of existingIds) {
|
|
if (!id) continue;
|
|
const m = id.match(re);
|
|
if (m) max = Math.max(max, parseInt(m[1], 10));
|
|
}
|
|
return `${prefix}-${String(max + 1).padStart(3, "0")}`;
|
|
}
|