1
0
Fork 0
polaris-task-force/src/migrations/20260831_180233_assignment_transfers.ts
Z8MB1E be459cde0f feat(collections): Add AssignmentTransfers collection and migrations
Add new AssignmentTransfers collection with fields for managing assignment transfer requests:
- requestor, requestedAssignment, currentAssignment (relationships to users/assignments)
- status (pending/approved/rejected/appealed/escalated/completed/cancelled)
- rejectionReason, appealReason (for rejections and appeals)
- transferAt, approvedAt, appealedAt, completedAt (audit timestamps)
- transferLead (relationship to users, current and requested assignment leaders)
- requestMessage, appealMessage (optional context messages)

Add database migrations:
- 20260831_180233_assignment_transfers: Create the main collection table
- 20260901_014006_add_assignment_transfer_event_target: Add assignment-transfers to GameEventLogs target collections

The collection enables the assignment transfer workflow where users can request transfers,
leaders can approve/reject with reasons, and users can appeal rejections.
2026-08-31 23:40:02 -04:00

80 lines
7 KiB
TypeScript

import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TYPE "public"."enum_assignment_transfers_status" AS ENUM('pending', 'rejected', 'awaiting_superuser', 'completed', 'cancelled', 'denied');
CREATE TYPE "public"."enum_assignment_transfers_escalation_reason" AS ENUM('no_leaders', 'appeal', 'leader_changed');
CREATE TYPE "public"."enum_assignment_transfers_from_leader_decision" AS ENUM('pending', 'approved', 'rejected', 'not_required');
CREATE TYPE "public"."enum_assignment_transfers_to_leader_decision" AS ENUM('pending', 'approved', 'rejected', 'not_required');
CREATE TABLE "assignment_transfers" (
"id" serial PRIMARY KEY NOT NULL,
"requester_id" integer NOT NULL,
"from_assignment_id" integer NOT NULL,
"to_assignment_id" integer NOT NULL,
"status" "enum_assignment_transfers_status" DEFAULT 'pending' NOT NULL,
"escalation_reason" "enum_assignment_transfers_escalation_reason",
"from_leader_decision" "enum_assignment_transfers_from_leader_decision" DEFAULT 'pending' NOT NULL,
"to_leader_decision" "enum_assignment_transfers_to_leader_decision" DEFAULT 'pending' NOT NULL,
"from_decision_by_id" integer,
"to_decision_by_id" integer,
"from_decided_at" timestamp(3) with time zone,
"to_decided_at" timestamp(3) with time zone,
"from_leader_snapshot_id" integer,
"to_leader_snapshot_id" integer,
"rejection_reason" varchar,
"request_note" varchar,
"appeal_note" varchar,
"resolved_by_id" integer,
"resolution_note" varchar,
"resolved_at" timestamp(3) with time zone,
"discord_from_leader_message_id" varchar,
"discord_to_leader_message_id" varchar,
"discord_requester_message_id" varchar,
"source_notified_to_user_id_id" integer,
"destination_notified_to_user_id_id" integer,
"discord_delivered_keys" jsonb DEFAULT '[]'::jsonb,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "assignment_transfers_id" integer;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_requester_id_users_id_fk" FOREIGN KEY ("requester_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_from_assignment_id_assignments_id_fk" FOREIGN KEY ("from_assignment_id") REFERENCES "public"."assignments"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_to_assignment_id_assignments_id_fk" FOREIGN KEY ("to_assignment_id") REFERENCES "public"."assignments"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_from_decision_by_id_users_id_fk" FOREIGN KEY ("from_decision_by_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_to_decision_by_id_users_id_fk" FOREIGN KEY ("to_decision_by_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_from_leader_snapshot_id_users_id_fk" FOREIGN KEY ("from_leader_snapshot_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_to_leader_snapshot_id_users_id_fk" FOREIGN KEY ("to_leader_snapshot_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_resolved_by_id_users_id_fk" FOREIGN KEY ("resolved_by_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_source_notified_to_user_id_id_users_id_fk" FOREIGN KEY ("source_notified_to_user_id_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "assignment_transfers" ADD CONSTRAINT "assignment_transfers_destination_notified_to_user_id_id_users_id_fk" FOREIGN KEY ("destination_notified_to_user_id_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
CREATE INDEX "assignment_transfers_requester_idx" ON "assignment_transfers" USING btree ("requester_id");
CREATE INDEX "assignment_transfers_from_assignment_idx" ON "assignment_transfers" USING btree ("from_assignment_id");
CREATE INDEX "assignment_transfers_to_assignment_idx" ON "assignment_transfers" USING btree ("to_assignment_id");
CREATE INDEX "assignment_transfers_status_idx" ON "assignment_transfers" USING btree ("status");
CREATE INDEX "assignment_transfers_from_decision_by_idx" ON "assignment_transfers" USING btree ("from_decision_by_id");
CREATE INDEX "assignment_transfers_to_decision_by_idx" ON "assignment_transfers" USING btree ("to_decision_by_id");
CREATE INDEX "assignment_transfers_from_leader_snapshot_idx" ON "assignment_transfers" USING btree ("from_leader_snapshot_id");
CREATE INDEX "assignment_transfers_to_leader_snapshot_idx" ON "assignment_transfers" USING btree ("to_leader_snapshot_id");
CREATE INDEX "assignment_transfers_resolved_by_idx" ON "assignment_transfers" USING btree ("resolved_by_id");
CREATE INDEX "assignment_transfers_source_notified_to_user_id_idx" ON "assignment_transfers" USING btree ("source_notified_to_user_id_id");
CREATE INDEX "assignment_transfers_destination_notified_to_user_id_idx" ON "assignment_transfers" USING btree ("destination_notified_to_user_id_id");
CREATE INDEX "assignment_transfers_updated_at_idx" ON "assignment_transfers" USING btree ("updated_at");
CREATE INDEX "assignment_transfers_created_at_idx" ON "assignment_transfers" USING btree ("created_at");
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_assignment_transfers_fk" FOREIGN KEY ("assignment_transfers_id") REFERENCES "public"."assignment_transfers"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "payload_locked_documents_rels_assignment_transfers_id_idx" ON "payload_locked_documents_rels" USING btree ("assignment_transfers_id");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "assignment_transfers" DISABLE ROW LEVEL SECURITY;
DROP TABLE "assignment_transfers" CASCADE;
ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_assignment_transfers_fk";
DROP INDEX "payload_locked_documents_rels_assignment_transfers_id_idx";
ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "assignment_transfers_id";
DROP TYPE "public"."enum_assignment_transfers_status";
DROP TYPE "public"."enum_assignment_transfers_escalation_reason";
DROP TYPE "public"."enum_assignment_transfers_from_leader_decision";
DROP TYPE "public"."enum_assignment_transfers_to_leader_decision";`)
}