mirror of
https://github.com/Since-3/Kuma.git
synced 2026-10-12 20:51:18 +00:00
added floor plan to rooms
This commit is contained in:
parent
9fa335ea40
commit
a8db32bf24
33 changed files with 2695 additions and 61 deletions
|
|
@ -0,0 +1,34 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Course" ADD COLUMN "spotBooking" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "CourseBooking" ADD COLUMN "spotId" TEXT,
|
||||
ADD COLUMN "spotLabel" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Room" ADD COLUMN "floorPlan" JSONB;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CourseSpotHold" (
|
||||
"id" TEXT NOT NULL,
|
||||
"courseId" TEXT NOT NULL,
|
||||
"spotId" TEXT NOT NULL,
|
||||
"holderKey" TEXT NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "CourseSpotHold_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CourseSpotHold_courseId_idx" ON "CourseSpotHold"("courseId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "CourseSpotHold_courseId_spotId_key" ON "CourseSpotHold"("courseId", "spotId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CourseBooking_spotId_idx" ON "CourseBooking"("spotId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CourseSpotHold" ADD CONSTRAINT "CourseSpotHold_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "Course"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
|
|
@ -172,9 +172,13 @@ model Course {
|
|||
createdBy String // Manager ID who created the course
|
||||
businessId String?
|
||||
coverImage String?
|
||||
// Kunden wählen beim Buchen ein Gerät aus dem Grundriss des Raums. Wirkt nur,
|
||||
// solange der Raum buchbare Geräte hat - sonst wird ganz normal ohne Platz gebucht.
|
||||
spotBooking Boolean @default(false)
|
||||
business Business? @relation(fields: [businessId], references: [id], onDelete: SetNull)
|
||||
bookings CourseBooking[]
|
||||
waitlistEntries CourseWaitlistEntry[]
|
||||
spotHolds CourseSpotHold[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
|
|
@ -190,6 +194,10 @@ model Room {
|
|||
id String @id @default(uuid())
|
||||
name String
|
||||
createdBy String // Manager ID who created the room
|
||||
// Grundriss mit Geräten: { width, depth, items: [{ id, type, x, y, rotation, label }] }.
|
||||
// Format und Gerätekatalog siehe src/modules/rooms/lib/floor-plan.ts. null = kein Grundriss.
|
||||
// Die item-IDs sind stabil und stehen als CourseBooking.spotId an Buchungen.
|
||||
floorPlan Json?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
|
|
@ -226,6 +234,8 @@ model CourseBooking {
|
|||
cancellationReason String?
|
||||
discountCodeId String? // Gesetzt, sobald bei der Buchung ein gültiger Rabattcode eingelöst wurde
|
||||
discountAmount Int? // Tatsächlich gewährter Rabatt in Cents (Snapshot, unabhängig von späteren Code-Änderungen)
|
||||
spotId String? // Gerät aus dem Raum-Grundriss (Room.floorPlan.items[].id), nur bei Kursen mit Platzwahl. Belegt ist ein Platz, solange die Buchung "paid" ist.
|
||||
spotLabel String? // Anzeigename des Platzes als Momentaufnahme, z.B. "Reformer 3" - bleibt lesbar, auch wenn der Grundriss sich später ändert
|
||||
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
guestLead GuestLead? @relation(fields: [guestLeadId], references: [id], onDelete: SetNull)
|
||||
|
|
@ -238,6 +248,28 @@ model CourseBooking {
|
|||
@@index([userId])
|
||||
@@index([guestLeadId])
|
||||
@@index([discountCodeId])
|
||||
@@index([spotId])
|
||||
}
|
||||
|
||||
// Hält einen Platz frei, während der Kunde im Stripe-Checkout bezahlt - analog
|
||||
// zur DiscountRedemption-Reservierung. Ohne sie könnten zwei Kunden gleichzeitig
|
||||
// mit demselben Reformer zur Kasse gehen. Entsteht beim Checkout-Start, wird im
|
||||
// Webhook nach der Zahlung gelöscht (dann belegt die Buchung den Platz) oder bei
|
||||
// abgelaufener Session freigegeben. Abgelaufene Holds (expiresAt < jetzt) zählen
|
||||
// nicht und werden beim nächsten Reservieren aufgeräumt.
|
||||
// holderKey = "user:<id>" oder "guest:<email>": pro Person und Kurs gibt es höchstens
|
||||
// einen Hold - wer zurück geht und einen anderen Platz wählt, gibt den alten frei.
|
||||
model CourseSpotHold {
|
||||
id String @id @default(uuid())
|
||||
courseId String
|
||||
spotId String
|
||||
holderKey String
|
||||
expiresAt DateTime
|
||||
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([courseId, spotId])
|
||||
@@index([courseId])
|
||||
}
|
||||
|
||||
// Bewusst nur für registrierte User (kein guestEmail-Feld): ein
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue