First slice of Phase 3 (Epics B/C/D shipped as stacked sub-PRs). Adds the
CrewMember talent-pool spine and the Candidates screens. Behind
NEXT_PUBLIC_CREWING_ENABLED; production unchanged. Stacks on the requisitions
branch (Phase 2).
What's in
- Schema (crewing_candidates migration): CrewMember (spine) + CrewStatus,
CandidateType, CandidateSource enums; CrewAction gains a nullable crewMemberId;
CrewActionType += CANDIDATE_ADDED/UPDATED. employeeId is assigned at onboarding
(3c), so it's nullable here.
- Actions (crewing/candidates/actions.ts): addCandidate / updateCandidate —
guard flag + manage_candidates, write a CrewAction, optional CV upload via
buildStorageKey("cv", …) + uploadBuffer (no parsing — A2 deferred). EX_HAND
source ⇒ type/status EX_HAND; edits never downgrade an EMPLOYEE.
- Screens: /crewing/candidates (master list with search/source/rank-applied/
min-experience filters as removable chips + match count + Clear all; Add-candidate
modal) and /crewing/candidates/[id] (profile; pipeline stepper is 3b). Candidates
added to the flag-gated Crewing nav (Manager + MPO).
Tests & docs
- Integration: candidates.test.ts (7) — add/update, ex-hand derivation, employee
no-downgrade, permission gating. type-check clean; full unit (225) + integration
(153) suites green.
- CLAUDE.md "Crewing" section updated with the Phase 3a surface.
Deferred: public careers intake API (A2, §13 open question); CV parsing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
2 KiB
SQL
57 lines
2 KiB
SQL
-- CreateEnum
|
|
CREATE TYPE "CrewStatus" AS ENUM ('PROSPECT', 'CANDIDATE', 'EMPLOYEE', 'EX_HAND', 'BLACKLISTED');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "CandidateType" AS ENUM ('NEW', 'EX_HAND');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "CandidateSource" AS ENUM ('CAREERS', 'EX_HAND', 'WALK_IN', 'REFERRAL', 'OTHER');
|
|
|
|
-- AlterEnum
|
|
-- This migration adds more than one value to an enum.
|
|
-- With PostgreSQL versions 11 and earlier, this is not possible
|
|
-- in a single migration. This can be worked around by creating
|
|
-- multiple migrations, each migration adding only one value to
|
|
-- the enum.
|
|
|
|
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'CANDIDATE_ADDED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'CANDIDATE_UPDATED';
|
|
|
|
-- AlterTable
|
|
ALTER TABLE "CrewAction" ADD COLUMN "crewMemberId" TEXT;
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "CrewMember" (
|
|
"id" TEXT NOT NULL,
|
|
"employeeId" TEXT,
|
|
"name" TEXT NOT NULL,
|
|
"status" "CrewStatus" NOT NULL DEFAULT 'CANDIDATE',
|
|
"type" "CandidateType" NOT NULL DEFAULT 'NEW',
|
|
"source" "CandidateSource" NOT NULL DEFAULT 'CAREERS',
|
|
"email" TEXT,
|
|
"phone" TEXT,
|
|
"dob" TIMESTAMP(3),
|
|
"experienceMonths" INTEGER NOT NULL DEFAULT 0,
|
|
"vesselTypeExperience" TEXT,
|
|
"cvKey" TEXT,
|
|
"notes" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
"currentRankId" TEXT,
|
|
"appliedRankId" TEXT,
|
|
|
|
CONSTRAINT "CrewMember_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "CrewMember_employeeId_key" ON "CrewMember"("employeeId");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CrewAction" ADD CONSTRAINT "CrewAction_crewMemberId_fkey" FOREIGN KEY ("crewMemberId") REFERENCES "CrewMember"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CrewMember" ADD CONSTRAINT "CrewMember_currentRankId_fkey" FOREIGN KEY ("currentRankId") REFERENCES "Rank"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CrewMember" ADD CONSTRAINT "CrewMember_appliedRankId_fkey" FOREIGN KEY ("appliedRankId") REFERENCES "Rank"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|