feat: schema for logistics hotels + flight tracking

Adds 2 new models for grand-finale logistics PR 2:
- Hotel: 1:1 with Program (one per edition); name + address + link + notes
- FlightDetail: 1:1 with AttendingMember; arrival + departure datetimes,
  flight numbers, airports, admin status (PENDING/CONFIRMED), admin notes

Migration is purely additive: no DROP/ALTER COLUMN/RENAME. FKs point
FROM new tables TO existing tables (Program, AttendingMember) with
ON DELETE CASCADE only firing on parent deletion.
This commit is contained in:
Matt
2026-04-28 18:17:09 +02:00
parent 95055e0dae
commit 88548cbea3
2 changed files with 92 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
-- CreateEnum
CREATE TYPE "FlightDetailStatus" AS ENUM ('PENDING', 'CONFIRMED');
-- CreateTable
CREATE TABLE "Hotel" (
"id" TEXT NOT NULL,
"programId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"address" TEXT,
"link" TEXT,
"notes" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Hotel_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "FlightDetail" (
"id" TEXT NOT NULL,
"attendingMemberId" TEXT NOT NULL,
"arrivalAt" TIMESTAMP(3),
"arrivalFlightNumber" TEXT,
"arrivalAirport" TEXT,
"departureAt" TIMESTAMP(3),
"departureFlightNumber" TEXT,
"departureAirport" TEXT,
"status" "FlightDetailStatus" NOT NULL DEFAULT 'PENDING',
"adminNotes" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "FlightDetail_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "Hotel_programId_key" ON "Hotel"("programId");
-- CreateIndex
CREATE UNIQUE INDEX "FlightDetail_attendingMemberId_key" ON "FlightDetail"("attendingMemberId");
-- CreateIndex
CREATE INDEX "FlightDetail_status_idx" ON "FlightDetail"("status");
-- AddForeignKey
ALTER TABLE "Hotel" ADD CONSTRAINT "Hotel_programId_fkey" FOREIGN KEY ("programId") REFERENCES "Program"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "FlightDetail" ADD CONSTRAINT "FlightDetail_attendingMemberId_fkey" FOREIGN KEY ("attendingMemberId") REFERENCES "AttendingMember"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -505,6 +505,7 @@ model Program {
// Grand-finale logistics
finalistSlotQuotas FinalistSlotQuota[]
waitlistEntries WaitlistEntry[]
hotel Hotel?
@@unique([name, year])
@@index([status])
@@ -2722,7 +2723,49 @@ model AttendingMember {
confirmation FinalistConfirmation @relation(fields: [confirmationId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
flightDetail FlightDetail?
@@unique([confirmationId, userId])
@@index([userId])
}
// ─────────────────────────────────────────────────────────────────────────────
// Grand-finale logistics (PR 2: hotels + flight tracking)
// ─────────────────────────────────────────────────────────────────────────────
enum FlightDetailStatus {
PENDING // team submitted details, admin not yet reviewed
CONFIRMED // admin verified booking
}
model Hotel {
id String @id @default(cuid())
programId String @unique // 1:1 — one hotel per edition
name String
address String? @db.Text
link String? // external URL to hotel page / booking confirmation
notes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
program Program @relation(fields: [programId], references: [id], onDelete: Cascade)
}
model FlightDetail {
id String @id @default(cuid())
attendingMemberId String @unique // 1:1
arrivalAt DateTime?
arrivalFlightNumber String?
arrivalAirport String?
departureAt DateTime?
departureFlightNumber String?
departureAirport String?
status FlightDetailStatus @default(PENDING)
adminNotes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
attendingMember AttendingMember @relation(fields: [attendingMemberId], references: [id], onDelete: Cascade)
@@index([status])
}