Second slice of Phase 3 (stacked on 3a candidates). The gated 7-stage recruitment pipeline per Crewing-Implementation-Spec §5.1/§8.4–8.5/§8.13. Behind NEXT_PUBLIC_CREWING_ENABLED; production unchanged. What's in - Schema (crewing_pipeline migration): Application (one per requisition+candidate) + 7-stage ApplicationStage; ApplicationGate (SALARY/SELECTION/WAIVER pending = Manager queue items); ReferenceCheck; effective-dated SalaryStructure (attached to the Application now, bound to the assignment in 3c); minimal BankDetail/EpfDetail captured at DOC_VERIFICATION (PII encryption deferred to Phase 4). CrewAction += applicationId; pipeline CrewActionTypes. - State machine: lib/application-pipeline.ts — sourcing advances MPO/Manager; approve_salary + select are Manager-only; orthogonal canReject; BOARD_STAGES. - Actions: addApplication (first candidate → requisition SHORTLISTING), advanceStage, recordReferenceCheck, verifyDocuments (bank/EPF), agreeSalary→approveSalary/returnSalary, recordInterviewResult, requestInterviewWaiver→approve/decline, selectCandidate (→ requisition SELECTED)/returnSelection, rejectApplication. Waiver never automatic (R2). Notifications SALARY/SELECTION/WAIVER + CANDIDATE_PROPOSED. - Screens: pipeline board per requisition (7 columns + Add candidate); application workhorse (7-step stepper + adaptive per-stage action card); "Open pipeline" on the requisition detail. Central /approvals gains a crewing section (inline Approve/Return) for one unified Manager queue (§8.13 R8). Tests & docs - Unit: application-pipeline.test.ts (9). Integration: applications.test.ts (10) — full happy path, salary/selection/waiver approvals + Manager-only gating, failed interview, reject, site-staff lockout. type-check clean; full unit (234) + integration (163) green. - CLAUDE.md "Crewing" updated with the Phase 3b surface. Deferred: onboarding (Epic D, Phase 3c) — SELECTED → ONBOARDED, CrewAssignment, employeeId, requisition → FILLED, salary bound to the assignment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
168 lines
6.3 KiB
SQL
168 lines
6.3 KiB
SQL
-- CreateEnum
|
|
CREATE TYPE "ApplicationStage" AS ENUM ('SHORTLISTED', 'COMPETENCY_AND_REFERENCES', 'DOC_VERIFICATION', 'SALARY_AGREEMENT', 'PROPOSED', 'INTERVIEW', 'SELECTED', 'REJECTED', 'ONBOARDED');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "ApplicationGateType" AS ENUM ('COMPETENCY_REFERENCE', 'DOCUMENT', 'SALARY', 'INTERVIEW', 'WAIVER', 'SELECTION');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "GateResult" AS ENUM ('PENDING', 'VERIFIED', 'REJECTED');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "InterviewOutcome" AS ENUM ('PENDING', 'ACCEPTED', 'REJECTED');
|
|
|
|
-- CreateEnum
|
|
CREATE TYPE "SalaryRateBasis" AS ENUM ('MONTHLY', 'DAILY');
|
|
|
|
-- 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 'APPLICATION_CREATED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'GATE_PASSED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'GATE_FAILED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'REFERENCE_RECORDED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'SALARY_AGREED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'SALARY_APPROVED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'CANDIDATE_PROPOSED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'INTERVIEW_RECORDED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'WAIVER_REQUESTED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'WAIVER_APPROVED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'CANDIDATE_SELECTED';
|
|
ALTER TYPE "CrewActionType" ADD VALUE 'APPLICATION_REJECTED';
|
|
|
|
-- AlterTable
|
|
ALTER TABLE "CrewAction" ADD COLUMN "applicationId" TEXT;
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "Application" (
|
|
"id" TEXT NOT NULL,
|
|
"stage" "ApplicationStage" NOT NULL DEFAULT 'SHORTLISTED',
|
|
"type" "CandidateType" NOT NULL DEFAULT 'NEW',
|
|
"interviewResult" "InterviewOutcome" NOT NULL DEFAULT 'PENDING',
|
|
"interviewWaived" BOOLEAN NOT NULL DEFAULT false,
|
|
"rejectedReason" TEXT,
|
|
"rejectedAt" TIMESTAMP(3),
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
"requisitionId" TEXT NOT NULL,
|
|
"crewMemberId" TEXT NOT NULL,
|
|
|
|
CONSTRAINT "Application_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "ApplicationGate" (
|
|
"id" TEXT NOT NULL,
|
|
"applicationId" TEXT NOT NULL,
|
|
"gate" "ApplicationGateType" NOT NULL,
|
|
"result" "GateResult" NOT NULL DEFAULT 'PENDING',
|
|
"note" TEXT,
|
|
"decidedById" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "ApplicationGate_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "ReferenceCheck" (
|
|
"id" TEXT NOT NULL,
|
|
"applicationId" TEXT NOT NULL,
|
|
"refereeName" TEXT NOT NULL,
|
|
"refereeContact" TEXT,
|
|
"outcome" TEXT,
|
|
"note" TEXT,
|
|
"recordedById" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "ReferenceCheck_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "SalaryStructure" (
|
|
"id" TEXT NOT NULL,
|
|
"applicationId" TEXT NOT NULL,
|
|
"rateBasis" "SalaryRateBasis" NOT NULL DEFAULT 'MONTHLY',
|
|
"basic" DECIMAL(12,2) NOT NULL,
|
|
"victualingPerDay" DECIMAL(12,2) NOT NULL DEFAULT 0,
|
|
"allowances" JSONB,
|
|
"currency" TEXT NOT NULL DEFAULT 'INR',
|
|
"effectiveFrom" TIMESTAMP(3),
|
|
"effectiveTo" TIMESTAMP(3),
|
|
"approvedById" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "SalaryStructure_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "BankDetail" (
|
|
"id" TEXT NOT NULL,
|
|
"crewMemberId" TEXT NOT NULL,
|
|
"accountName" TEXT,
|
|
"accountNumber" TEXT,
|
|
"ifsc" TEXT,
|
|
"bankName" TEXT,
|
|
"verificationStatus" "GateResult" NOT NULL DEFAULT 'PENDING',
|
|
"verifiedById" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "BankDetail_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "EpfDetail" (
|
|
"id" TEXT NOT NULL,
|
|
"crewMemberId" TEXT NOT NULL,
|
|
"uan" TEXT,
|
|
"aadhaarLast4" TEXT,
|
|
"pfNumber" TEXT,
|
|
"verificationStatus" "GateResult" NOT NULL DEFAULT 'PENDING',
|
|
"verifiedById" TEXT,
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "EpfDetail_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "Application_requisitionId_crewMemberId_key" ON "Application"("requisitionId", "crewMemberId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "ApplicationGate_applicationId_gate_key" ON "ApplicationGate"("applicationId", "gate");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "BankDetail_crewMemberId_key" ON "BankDetail"("crewMemberId");
|
|
|
|
-- CreateIndex
|
|
CREATE UNIQUE INDEX "EpfDetail_crewMemberId_key" ON "EpfDetail"("crewMemberId");
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "CrewAction" ADD CONSTRAINT "CrewAction_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Application" ADD CONSTRAINT "Application_requisitionId_fkey" FOREIGN KEY ("requisitionId") REFERENCES "Requisition"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "Application" ADD CONSTRAINT "Application_crewMemberId_fkey" FOREIGN KEY ("crewMemberId") REFERENCES "CrewMember"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ApplicationGate" ADD CONSTRAINT "ApplicationGate_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "ReferenceCheck" ADD CONSTRAINT "ReferenceCheck_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "SalaryStructure" ADD CONSTRAINT "SalaryStructure_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "BankDetail" ADD CONSTRAINT "BankDetail_crewMemberId_fkey" FOREIGN KEY ("crewMemberId") REFERENCES "CrewMember"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "EpfDetail" ADD CONSTRAINT "EpfDetail_crewMemberId_fkey" FOREIGN KEY ("crewMemberId") REFERENCES "CrewMember"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|