Revert "PHP Rebuild"

This reverts commit 2ef3654841.
This commit is contained in:
Stefan Lazic committed 2026-09-05 09:32:05 +01:00
1 parent a59f998f2b
commit 2aa8405006
690 files changed
+12045 -33943

No files matched your search

@@ -0,0 +1,729 @@
-- CreateEnum
CREATE TYPE "Weekday" AS ENUM ('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY');
-- CreateEnum
CREATE TYPE "Permission" AS ENUM ('MANAGE_BUSINESS_PROFILE', 'MANAGE_BOOKING_RULES', 'MANAGE_SERVICES', 'MANAGE_STAFF', 'MANAGE_LOYALTY_PROGRAMME', 'MANAGE_NOTIFICATION_SETTINGS', 'VIEW_ALL_STAFF_APPOINTMENTS', 'MANAGE_OWN_APPOINTMENTS', 'CHECK_IN_CUSTOMERS', 'MANAGE_LOYALTY_STAMPS', 'MANAGE_OWN_AVAILABILITY', 'VIEW_CUSTOMER_DIRECTORY', 'BOOK_ON_BEHALF_OF_CUSTOMER');
-- CreateEnum
CREATE TYPE "StaffStatus" AS ENUM ('ACTIVE', 'ON_BREAK', 'INACTIVE');
-- CreateEnum
CREATE TYPE "AppointmentStatus" AS ENUM ('PENDING_APPROVAL', 'CONFIRMED', 'ARRIVED', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED', 'NO_SHOW');
-- CreateEnum
CREATE TYPE "TimeOffStatus" AS ENUM ('PENDING', 'APPROVED', 'DECLINED');
-- CreateEnum
CREATE TYPE "RewardType" AS ENUM ('PERCENTAGE', 'FIXED_AMOUNT', 'FREE_SERVICE');
-- CreateEnum
CREATE TYPE "RewardStatus" AS ENUM ('AVAILABLE', 'REDEEMED', 'EXPIRED');
-- CreateEnum
CREATE TYPE "LoyaltyTransactionType" AS ENUM ('STAMP_ADDED', 'STAMP_REMOVED', 'STAMP_EXPIRED', 'REWARD_REDEEMED');
-- CreateEnum
CREATE TYPE "NotificationCategory" AS ENUM ('BOOKING_CONFIRMATION', 'BOOKING_REMINDER', 'BOOKING_CHANGED', 'BOOKING_CANCELLED', 'LOYALTY_REWARD_EARNED', 'LOYALTY_REWARD_AVAILABLE', 'MARKETING');
-- CreateEnum
CREATE TYPE "NotificationChannel" AS ENUM ('EMAIL', 'SMS', 'PUSH');
-- CreateEnum
CREATE TYPE "NotificationStatus" AS ENUM ('PENDING', 'SENT', 'FAILED');
-- CreateTable
CREATE TABLE "Business" (
"id" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT,
"logoUrl" TEXT,
"phone" TEXT,
"email" TEXT,
"website" TEXT,
"instagramUrl" TEXT,
"facebookUrl" TEXT,
"timezone" TEXT NOT NULL DEFAULT 'Europe/London',
"currency" TEXT NOT NULL DEFAULT 'GBP',
"locale" TEXT NOT NULL DEFAULT 'en-GB',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Business_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "BusinessLocation" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"name" TEXT NOT NULL DEFAULT 'Main Location',
"addressLine1" TEXT NOT NULL,
"addressLine2" TEXT,
"city" TEXT NOT NULL,
"region" TEXT,
"postalCode" TEXT NOT NULL,
"country" TEXT NOT NULL DEFAULT 'GB',
"latitude" DECIMAL(9,6),
"longitude" DECIMAL(9,6),
"isPrimary" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "BusinessLocation_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "BusinessHours" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"dayOfWeek" "Weekday" NOT NULL,
"isClosed" BOOLEAN NOT NULL DEFAULT false,
"opensAtMinutes" INTEGER,
"closesAtMinutes" INTEGER,
CONSTRAINT "BusinessHours_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "BusinessSettings" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"cancellationPolicy" TEXT,
"lateArrivalPolicy" TEXT,
"bookingTerms" TEXT,
"privacyPolicyUrl" TEXT,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "BusinessSettings_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "BookingRule" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"minNoticeMinutes" INTEGER NOT NULL DEFAULT 120,
"maxAdvanceDays" INTEGER NOT NULL DEFAULT 60,
"cancellationWindowHours" INTEGER NOT NULL DEFAULT 24,
"rescheduleWindowHours" INTEGER NOT NULL DEFAULT 24,
"slotIntervalMinutes" INTEGER NOT NULL DEFAULT 30,
"bufferBeforeMinutes" INTEGER NOT NULL DEFAULT 0,
"bufferAfterMinutes" INTEGER NOT NULL DEFAULT 5,
"maxAppointmentsPerDay" INTEGER,
"customerCanChooseStaff" BOOLEAN NOT NULL DEFAULT true,
"allowGuestBooking" BOOLEAN NOT NULL DEFAULT true,
"requireApproval" BOOLEAN NOT NULL DEFAULT false,
"requireDeposit" BOOLEAN NOT NULL DEFAULT false,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "BookingRule_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"name" TEXT,
"email" TEXT,
"emailVerified" TIMESTAMP(3),
"phone" TEXT,
"phoneVerified" TIMESTAMP(3),
"image" TEXT,
"passwordHash" TEXT,
"isSuperAdmin" BOOLEAN NOT NULL DEFAULT false,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Account" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"providerAccountId" TEXT NOT NULL,
"refresh_token" TEXT,
"access_token" TEXT,
"expires_at" INTEGER,
"token_type" TEXT,
"scope" TEXT,
"id_token" TEXT,
"session_state" TEXT,
CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Session" (
"id" TEXT NOT NULL,
"sessionToken" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "VerificationToken" (
"identifier" TEXT NOT NULL,
"token" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL
);
-- CreateTable
CREATE TABLE "CustomerProfile" (
"id" TEXT NOT NULL,
"userId" TEXT,
"firstName" TEXT NOT NULL,
"lastName" TEXT NOT NULL,
"email" TEXT NOT NULL,
"phone" TEXT,
"isGuest" BOOLEAN NOT NULL DEFAULT true,
"preferredBarberId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "CustomerProfile_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "StaffProfile" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"bio" TEXT,
"status" "StaffStatus" NOT NULL DEFAULT 'ACTIVE',
"isBookableOnline" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "StaffProfile_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Role" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"isSystem" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Role_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "RolePermission" (
"id" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"permission" "Permission" NOT NULL,
CONSTRAINT "RolePermission_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ServiceCategory" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"displayOrder" INTEGER NOT NULL DEFAULT 0,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "ServiceCategory_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Service" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"categoryId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT,
"durationMinutes" INTEGER NOT NULL,
"price" DECIMAL(10,2) NOT NULL,
"bufferBeforeMinutes" INTEGER NOT NULL DEFAULT 0,
"bufferAfterMinutes" INTEGER NOT NULL DEFAULT 0,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"allowOnlineBooking" BOOLEAN NOT NULL DEFAULT true,
"displayOrder" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Service_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "StaffService" (
"id" TEXT NOT NULL,
"staffId" TEXT NOT NULL,
"serviceId" TEXT NOT NULL,
"priceOverride" DECIMAL(10,2),
"durationOverrideMinutes" INTEGER,
CONSTRAINT "StaffService_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "WorkingHours" (
"id" TEXT NOT NULL,
"staffId" TEXT NOT NULL,
"dayOfWeek" "Weekday" NOT NULL,
"isOff" BOOLEAN NOT NULL DEFAULT false,
"startMinutes" INTEGER,
"endMinutes" INTEGER,
CONSTRAINT "WorkingHours_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Break" (
"id" TEXT NOT NULL,
"staffId" TEXT NOT NULL,
"label" TEXT NOT NULL,
"startMinutes" INTEGER NOT NULL,
"endMinutes" INTEGER NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Break_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "BreakDay" (
"id" TEXT NOT NULL,
"breakId" TEXT NOT NULL,
"dayOfWeek" "Weekday" NOT NULL,
CONSTRAINT "BreakDay_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "TimeOff" (
"id" TEXT NOT NULL,
"staffId" TEXT NOT NULL,
"startDate" DATE NOT NULL,
"endDate" DATE NOT NULL,
"reason" TEXT,
"status" "TimeOffStatus" NOT NULL DEFAULT 'APPROVED',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "TimeOff_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Appointment" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"staffId" TEXT NOT NULL,
"status" "AppointmentStatus" NOT NULL DEFAULT 'CONFIRMED',
"startAt" TIMESTAMP(3) NOT NULL,
"endAt" TIMESTAMP(3) NOT NULL,
"notes" TEXT,
"cancellationReason" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Appointment_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "AppointmentService" (
"id" TEXT NOT NULL,
"appointmentId" TEXT NOT NULL,
"serviceId" TEXT NOT NULL,
"priceAtBooking" DECIMAL(10,2) NOT NULL,
"durationAtBookingMinutes" INTEGER NOT NULL,
CONSTRAINT "AppointmentService_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "LoyaltyProgramme" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"isEnabled" BOOLEAN NOT NULL DEFAULT false,
"stampsRequired" INTEGER NOT NULL DEFAULT 10,
"rewardType" "RewardType" NOT NULL DEFAULT 'PERCENTAGE',
"rewardValue" DECIMAL(10,2),
"rewardLabel" TEXT,
"maxRewardValue" DECIMAL(10,2),
"autoApplyReward" BOOLEAN NOT NULL DEFAULT true,
"requiresStaffApproval" BOOLEAN NOT NULL DEFAULT false,
"stampsExpireAfterDays" INTEGER,
"rewardExpiresAfterDays" INTEGER,
"earnOnCancelled" BOOLEAN NOT NULL DEFAULT false,
"earnOnNoShow" BOOLEAN NOT NULL DEFAULT false,
"cardBackgroundColor" TEXT,
"cardBackgroundImageUrl" TEXT,
"stampIcon" TEXT,
"termsLine" TEXT,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "LoyaltyProgramme_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "LoyaltyEligibleService" (
"id" TEXT NOT NULL,
"loyaltyProgrammeId" TEXT NOT NULL,
"serviceId" TEXT NOT NULL,
CONSTRAINT "LoyaltyEligibleService_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "LoyaltyEligibleStaff" (
"id" TEXT NOT NULL,
"loyaltyProgrammeId" TEXT NOT NULL,
"staffId" TEXT NOT NULL,
CONSTRAINT "LoyaltyEligibleStaff_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "LoyaltyAccount" (
"id" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"loyaltyProgrammeId" TEXT NOT NULL,
"currentStamps" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "LoyaltyAccount_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "LoyaltyTransaction" (
"id" TEXT NOT NULL,
"loyaltyAccountId" TEXT NOT NULL,
"type" "LoyaltyTransactionType" NOT NULL,
"amount" INTEGER NOT NULL,
"reason" TEXT,
"appointmentId" TEXT,
"authoredByStaffId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "LoyaltyTransaction_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "LoyaltyReward" (
"id" TEXT NOT NULL,
"loyaltyAccountId" TEXT NOT NULL,
"rewardType" "RewardType" NOT NULL,
"value" DECIMAL(10,2),
"label" TEXT NOT NULL,
"status" "RewardStatus" NOT NULL DEFAULT 'AVAILABLE',
"appliedToAppointmentId" TEXT,
"redeemedAt" TIMESTAMP(3),
"expiresAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "LoyaltyReward_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Notification" (
"id" TEXT NOT NULL,
"userId" TEXT,
"appointmentId" TEXT,
"category" "NotificationCategory" NOT NULL,
"channel" "NotificationChannel" NOT NULL,
"status" "NotificationStatus" NOT NULL DEFAULT 'PENDING',
"subject" TEXT,
"body" TEXT NOT NULL,
"sentAt" TIMESTAMP(3),
"failureReason" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Notification_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "NotificationPreference" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"category" "NotificationCategory" NOT NULL,
"channel" "NotificationChannel" NOT NULL,
"isEnabled" BOOLEAN NOT NULL DEFAULT true,
CONSTRAINT "NotificationPreference_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "CustomerNote" (
"id" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"authorStaffId" TEXT NOT NULL,
"body" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "CustomerNote_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "AuditLog" (
"id" TEXT NOT NULL,
"actorUserId" TEXT,
"action" TEXT NOT NULL,
"entityType" TEXT NOT NULL,
"entityId" TEXT NOT NULL,
"metadata" JSONB,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "Business_slug_key" ON "Business"("slug");
-- CreateIndex
CREATE INDEX "BusinessLocation_businessId_idx" ON "BusinessLocation"("businessId");
-- CreateIndex
CREATE UNIQUE INDEX "BusinessHours_businessId_dayOfWeek_key" ON "BusinessHours"("businessId", "dayOfWeek");
-- CreateIndex
CREATE UNIQUE INDEX "BusinessSettings_businessId_key" ON "BusinessSettings"("businessId");
-- CreateIndex
CREATE UNIQUE INDEX "BookingRule_businessId_key" ON "BookingRule"("businessId");
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
-- CreateIndex
CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone");
-- CreateIndex
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
-- CreateIndex
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
-- CreateIndex
CREATE UNIQUE INDEX "CustomerProfile_userId_key" ON "CustomerProfile"("userId");
-- CreateIndex
CREATE INDEX "CustomerProfile_email_idx" ON "CustomerProfile"("email");
-- CreateIndex
CREATE INDEX "CustomerProfile_phone_idx" ON "CustomerProfile"("phone");
-- CreateIndex
CREATE INDEX "CustomerProfile_preferredBarberId_idx" ON "CustomerProfile"("preferredBarberId");
-- CreateIndex
CREATE UNIQUE INDEX "StaffProfile_userId_key" ON "StaffProfile"("userId");
-- CreateIndex
CREATE INDEX "StaffProfile_businessId_idx" ON "StaffProfile"("businessId");
-- CreateIndex
CREATE UNIQUE INDEX "Role_businessId_name_key" ON "Role"("businessId", "name");
-- CreateIndex
CREATE UNIQUE INDEX "RolePermission_roleId_permission_key" ON "RolePermission"("roleId", "permission");
-- CreateIndex
CREATE INDEX "ServiceCategory_businessId_idx" ON "ServiceCategory"("businessId");
-- CreateIndex
CREATE INDEX "Service_businessId_idx" ON "Service"("businessId");
-- CreateIndex
CREATE INDEX "Service_categoryId_idx" ON "Service"("categoryId");
-- CreateIndex
CREATE UNIQUE INDEX "StaffService_staffId_serviceId_key" ON "StaffService"("staffId", "serviceId");
-- CreateIndex
CREATE UNIQUE INDEX "WorkingHours_staffId_dayOfWeek_key" ON "WorkingHours"("staffId", "dayOfWeek");
-- CreateIndex
CREATE UNIQUE INDEX "BreakDay_breakId_dayOfWeek_key" ON "BreakDay"("breakId", "dayOfWeek");
-- CreateIndex
CREATE INDEX "TimeOff_staffId_startDate_endDate_idx" ON "TimeOff"("staffId", "startDate", "endDate");
-- CreateIndex
CREATE INDEX "Appointment_staffId_startAt_idx" ON "Appointment"("staffId", "startAt");
-- CreateIndex
CREATE INDEX "Appointment_businessId_startAt_idx" ON "Appointment"("businessId", "startAt");
-- CreateIndex
CREATE INDEX "Appointment_customerId_idx" ON "Appointment"("customerId");
-- CreateIndex
CREATE INDEX "AppointmentService_appointmentId_idx" ON "AppointmentService"("appointmentId");
-- CreateIndex
CREATE UNIQUE INDEX "LoyaltyProgramme_businessId_key" ON "LoyaltyProgramme"("businessId");
-- CreateIndex
CREATE UNIQUE INDEX "LoyaltyEligibleService_loyaltyProgrammeId_serviceId_key" ON "LoyaltyEligibleService"("loyaltyProgrammeId", "serviceId");
-- CreateIndex
CREATE UNIQUE INDEX "LoyaltyEligibleStaff_loyaltyProgrammeId_staffId_key" ON "LoyaltyEligibleStaff"("loyaltyProgrammeId", "staffId");
-- CreateIndex
CREATE UNIQUE INDEX "LoyaltyAccount_customerId_loyaltyProgrammeId_key" ON "LoyaltyAccount"("customerId", "loyaltyProgrammeId");
-- CreateIndex
CREATE INDEX "LoyaltyTransaction_loyaltyAccountId_idx" ON "LoyaltyTransaction"("loyaltyAccountId");
-- CreateIndex
CREATE INDEX "LoyaltyReward_loyaltyAccountId_idx" ON "LoyaltyReward"("loyaltyAccountId");
-- CreateIndex
CREATE INDEX "Notification_userId_idx" ON "Notification"("userId");
-- CreateIndex
CREATE INDEX "Notification_appointmentId_idx" ON "Notification"("appointmentId");
-- CreateIndex
CREATE UNIQUE INDEX "NotificationPreference_userId_category_channel_key" ON "NotificationPreference"("userId", "category", "channel");
-- CreateIndex
CREATE INDEX "CustomerNote_customerId_idx" ON "CustomerNote"("customerId");
-- CreateIndex
CREATE INDEX "AuditLog_entityType_entityId_idx" ON "AuditLog"("entityType", "entityId");
-- CreateIndex
CREATE INDEX "AuditLog_actorUserId_idx" ON "AuditLog"("actorUserId");
-- AddForeignKey
ALTER TABLE "BusinessLocation" ADD CONSTRAINT "BusinessLocation_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "BusinessHours" ADD CONSTRAINT "BusinessHours_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "BusinessSettings" ADD CONSTRAINT "BusinessSettings_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "BookingRule" ADD CONSTRAINT "BookingRule_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerProfile" ADD CONSTRAINT "CustomerProfile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerProfile" ADD CONSTRAINT "CustomerProfile_preferredBarberId_fkey" FOREIGN KEY ("preferredBarberId") REFERENCES "StaffProfile"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "StaffProfile" ADD CONSTRAINT "StaffProfile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "StaffProfile" ADD CONSTRAINT "StaffProfile_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "StaffProfile" ADD CONSTRAINT "StaffProfile_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "Role"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Role" ADD CONSTRAINT "Role_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "RolePermission" ADD CONSTRAINT "RolePermission_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "Role"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ServiceCategory" ADD CONSTRAINT "ServiceCategory_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Service" ADD CONSTRAINT "Service_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Service" ADD CONSTRAINT "Service_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "ServiceCategory"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "StaffService" ADD CONSTRAINT "StaffService_staffId_fkey" FOREIGN KEY ("staffId") REFERENCES "StaffProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "StaffService" ADD CONSTRAINT "StaffService_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "WorkingHours" ADD CONSTRAINT "WorkingHours_staffId_fkey" FOREIGN KEY ("staffId") REFERENCES "StaffProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Break" ADD CONSTRAINT "Break_staffId_fkey" FOREIGN KEY ("staffId") REFERENCES "StaffProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "BreakDay" ADD CONSTRAINT "BreakDay_breakId_fkey" FOREIGN KEY ("breakId") REFERENCES "Break"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "TimeOff" ADD CONSTRAINT "TimeOff_staffId_fkey" FOREIGN KEY ("staffId") REFERENCES "StaffProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "CustomerProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_staffId_fkey" FOREIGN KEY ("staffId") REFERENCES "StaffProfile"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AppointmentService" ADD CONSTRAINT "AppointmentService_appointmentId_fkey" FOREIGN KEY ("appointmentId") REFERENCES "Appointment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "AppointmentService" ADD CONSTRAINT "AppointmentService_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyProgramme" ADD CONSTRAINT "LoyaltyProgramme_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyEligibleService" ADD CONSTRAINT "LoyaltyEligibleService_loyaltyProgrammeId_fkey" FOREIGN KEY ("loyaltyProgrammeId") REFERENCES "LoyaltyProgramme"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyEligibleService" ADD CONSTRAINT "LoyaltyEligibleService_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyEligibleStaff" ADD CONSTRAINT "LoyaltyEligibleStaff_loyaltyProgrammeId_fkey" FOREIGN KEY ("loyaltyProgrammeId") REFERENCES "LoyaltyProgramme"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyAccount" ADD CONSTRAINT "LoyaltyAccount_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "CustomerProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyAccount" ADD CONSTRAINT "LoyaltyAccount_loyaltyProgrammeId_fkey" FOREIGN KEY ("loyaltyProgrammeId") REFERENCES "LoyaltyProgramme"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyTransaction" ADD CONSTRAINT "LoyaltyTransaction_loyaltyAccountId_fkey" FOREIGN KEY ("loyaltyAccountId") REFERENCES "LoyaltyAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyTransaction" ADD CONSTRAINT "LoyaltyTransaction_appointmentId_fkey" FOREIGN KEY ("appointmentId") REFERENCES "Appointment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyTransaction" ADD CONSTRAINT "LoyaltyTransaction_authoredByStaffId_fkey" FOREIGN KEY ("authoredByStaffId") REFERENCES "StaffProfile"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyReward" ADD CONSTRAINT "LoyaltyReward_loyaltyAccountId_fkey" FOREIGN KEY ("loyaltyAccountId") REFERENCES "LoyaltyAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_appointmentId_fkey" FOREIGN KEY ("appointmentId") REFERENCES "Appointment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "NotificationPreference" ADD CONSTRAINT "NotificationPreference_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerNote" ADD CONSTRAINT "CustomerNote_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "CustomerProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerNote" ADD CONSTRAINT "CustomerNote_authorStaffId_fkey" FOREIGN KEY ("authorStaffId") REFERENCES "StaffProfile"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -0,0 +1,21 @@
-- AlterEnum
BEGIN;
CREATE TYPE "AppointmentStatus_new" AS ENUM ('PENDING', 'CONFIRMED', 'CHECKED_IN', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED', 'NO_SHOW');
ALTER TABLE "public"."Appointment" ALTER COLUMN "status" DROP DEFAULT;
ALTER TABLE "Appointment" ALTER COLUMN "status" TYPE "AppointmentStatus_new" USING ("status"::text::"AppointmentStatus_new");
ALTER TYPE "AppointmentStatus" RENAME TO "AppointmentStatus_old";
ALTER TYPE "AppointmentStatus_new" RENAME TO "AppointmentStatus";
DROP TYPE "public"."AppointmentStatus_old";
ALTER TABLE "Appointment" ALTER COLUMN "status" SET DEFAULT 'CONFIRMED';
COMMIT;
-- AlterTable
ALTER TABLE "Appointment" ADD COLUMN "cancelledAt" TIMESTAMP(3),
ADD COLUMN "cancelledByUserId" TEXT;
-- AlterTable
ALTER TABLE "BookingRule" ADD COLUMN "maxAppointmentsPerStaffPerDay" INTEGER;
-- AddForeignKey
ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_cancelledByUserId_fkey" FOREIGN KEY ("cancelledByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
@@ -0,0 +1,13 @@
-- AlterTable
ALTER TABLE "Appointment" ADD COLUMN "createdByUserId" TEXT;
-- AlterTable
ALTER TABLE "CustomerNote" ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;
-- AlterTable
ALTER TABLE "TimeOff" ADD COLUMN "endMinutes" INTEGER,
ADD COLUMN "startMinutes" INTEGER;
-- AddForeignKey
ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_createdByUserId_fkey" FOREIGN KEY ("createdByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
@@ -0,0 +1,55 @@
-- 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 "Permission" ADD VALUE 'MANAGE_ALL_APPOINTMENTS';
ALTER TYPE "Permission" ADD VALUE 'VIEW_REPORTING';
-- AlterTable
ALTER TABLE "Appointment" ADD COLUMN "discountAmount" DECIMAL(10,2);
-- AlterTable
ALTER TABLE "LoyaltyReward" ADD COLUMN "redeemedByStaffId" TEXT;
-- CreateTable
CREATE TABLE "StaffInvitation" (
"id" TEXT NOT NULL,
"businessId" TEXT NOT NULL,
"staffId" TEXT NOT NULL,
"email" TEXT NOT NULL,
"token" TEXT NOT NULL,
"invitedByUserId" TEXT,
"expiresAt" TIMESTAMP(3) NOT NULL,
"acceptedAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "StaffInvitation_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "StaffInvitation_staffId_key" ON "StaffInvitation"("staffId");
-- CreateIndex
CREATE UNIQUE INDEX "StaffInvitation_token_key" ON "StaffInvitation"("token");
-- CreateIndex
CREATE INDEX "StaffInvitation_businessId_idx" ON "StaffInvitation"("businessId");
-- AddForeignKey
ALTER TABLE "StaffInvitation" ADD CONSTRAINT "StaffInvitation_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "StaffInvitation" ADD CONSTRAINT "StaffInvitation_staffId_fkey" FOREIGN KEY ("staffId") REFERENCES "StaffProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "StaffInvitation" ADD CONSTRAINT "StaffInvitation_invitedByUserId_fkey" FOREIGN KEY ("invitedByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyReward" ADD CONSTRAINT "LoyaltyReward_appliedToAppointmentId_fkey" FOREIGN KEY ("appliedToAppointmentId") REFERENCES "Appointment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LoyaltyReward" ADD CONSTRAINT "LoyaltyReward_redeemedByStaffId_fkey" FOREIGN KEY ("redeemedByStaffId") REFERENCES "StaffProfile"("id") ON DELETE SET NULL ON UPDATE CASCADE;
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "LoyaltyProgramme" ADD COLUMN "freeServiceId" TEXT;
-- AddForeignKey
ALTER TABLE "LoyaltyProgramme" ADD CONSTRAINT "LoyaltyProgramme_freeServiceId_fkey" FOREIGN KEY ("freeServiceId") REFERENCES "Service"("id") ON DELETE SET NULL ON UPDATE CASCADE;
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
@@ -0,0 +1,665 @@
-- CreateTable
CREATE TABLE `Business` (
`id` VARCHAR(191) NOT NULL,
`slug` VARCHAR(191) NOT NULL,
`name` VARCHAR(191) NOT NULL,
`description` TEXT NULL,
`logoUrl` VARCHAR(191) NULL,
`phone` VARCHAR(191) NULL,
`email` VARCHAR(191) NULL,
`website` VARCHAR(191) NULL,
`instagramUrl` VARCHAR(191) NULL,
`facebookUrl` VARCHAR(191) NULL,
`timezone` VARCHAR(191) NOT NULL DEFAULT 'Europe/London',
`currency` VARCHAR(191) NOT NULL DEFAULT 'GBP',
`locale` VARCHAR(191) NOT NULL DEFAULT 'en-GB',
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `Business_slug_key`(`slug`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `BusinessLocation` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`name` VARCHAR(191) NOT NULL DEFAULT 'Main Location',
`addressLine1` VARCHAR(191) NOT NULL,
`addressLine2` VARCHAR(191) NULL,
`city` VARCHAR(191) NOT NULL,
`region` VARCHAR(191) NULL,
`postalCode` VARCHAR(191) NOT NULL,
`country` VARCHAR(191) NOT NULL DEFAULT 'GB',
`latitude` DECIMAL(9, 6) NULL,
`longitude` DECIMAL(9, 6) NULL,
`isPrimary` BOOLEAN NOT NULL DEFAULT true,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
INDEX `BusinessLocation_businessId_idx`(`businessId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `BusinessHours` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`dayOfWeek` ENUM('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY') NOT NULL,
`isClosed` BOOLEAN NOT NULL DEFAULT false,
`opensAtMinutes` INTEGER NULL,
`closesAtMinutes` INTEGER NULL,
UNIQUE INDEX `BusinessHours_businessId_dayOfWeek_key`(`businessId`, `dayOfWeek`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `BusinessSettings` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`cancellationPolicy` TEXT NULL,
`lateArrivalPolicy` TEXT NULL,
`bookingTerms` TEXT NULL,
`privacyPolicyUrl` VARCHAR(191) NULL,
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `BusinessSettings_businessId_key`(`businessId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `BookingRule` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`minNoticeMinutes` INTEGER NOT NULL DEFAULT 120,
`maxAdvanceDays` INTEGER NOT NULL DEFAULT 60,
`cancellationWindowHours` INTEGER NOT NULL DEFAULT 24,
`rescheduleWindowHours` INTEGER NOT NULL DEFAULT 24,
`slotIntervalMinutes` INTEGER NOT NULL DEFAULT 30,
`bufferBeforeMinutes` INTEGER NOT NULL DEFAULT 0,
`bufferAfterMinutes` INTEGER NOT NULL DEFAULT 5,
`maxAppointmentsPerDay` INTEGER NULL,
`maxAppointmentsPerStaffPerDay` INTEGER NULL,
`customerCanChooseStaff` BOOLEAN NOT NULL DEFAULT true,
`allowGuestBooking` BOOLEAN NOT NULL DEFAULT true,
`requireApproval` BOOLEAN NOT NULL DEFAULT false,
`requireDeposit` BOOLEAN NOT NULL DEFAULT false,
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `BookingRule_businessId_key`(`businessId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `User` (
`id` VARCHAR(191) NOT NULL,
`name` VARCHAR(191) NULL,
`email` VARCHAR(191) NULL,
`emailVerified` DATETIME(3) NULL,
`phone` VARCHAR(191) NULL,
`phoneVerified` DATETIME(3) NULL,
`image` VARCHAR(191) NULL,
`passwordHash` VARCHAR(191) NULL,
`isSuperAdmin` BOOLEAN NOT NULL DEFAULT false,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `User_email_key`(`email`),
UNIQUE INDEX `User_phone_key`(`phone`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `Account` (
`id` VARCHAR(191) NOT NULL,
`userId` VARCHAR(191) NOT NULL,
`type` VARCHAR(191) NOT NULL,
`provider` VARCHAR(191) NOT NULL,
`providerAccountId` VARCHAR(191) NOT NULL,
`refresh_token` TEXT NULL,
`access_token` TEXT NULL,
`expires_at` INTEGER NULL,
`token_type` VARCHAR(191) NULL,
`scope` VARCHAR(191) NULL,
`id_token` TEXT NULL,
`session_state` VARCHAR(191) NULL,
UNIQUE INDEX `Account_provider_providerAccountId_key`(`provider`, `providerAccountId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `Session` (
`id` VARCHAR(191) NOT NULL,
`sessionToken` VARCHAR(191) NOT NULL,
`userId` VARCHAR(191) NOT NULL,
`expires` DATETIME(3) NOT NULL,
UNIQUE INDEX `Session_sessionToken_key`(`sessionToken`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `VerificationToken` (
`identifier` VARCHAR(191) NOT NULL,
`token` VARCHAR(191) NOT NULL,
`expires` DATETIME(3) NOT NULL,
UNIQUE INDEX `VerificationToken_token_key`(`token`),
UNIQUE INDEX `VerificationToken_identifier_token_key`(`identifier`, `token`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `CustomerProfile` (
`id` VARCHAR(191) NOT NULL,
`userId` VARCHAR(191) NULL,
`firstName` VARCHAR(191) NOT NULL,
`lastName` VARCHAR(191) NOT NULL,
`email` VARCHAR(191) NOT NULL,
`phone` VARCHAR(191) NULL,
`isGuest` BOOLEAN NOT NULL DEFAULT true,
`preferredBarberId` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `CustomerProfile_userId_key`(`userId`),
INDEX `CustomerProfile_email_idx`(`email`),
INDEX `CustomerProfile_phone_idx`(`phone`),
INDEX `CustomerProfile_preferredBarberId_idx`(`preferredBarberId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `StaffProfile` (
`id` VARCHAR(191) NOT NULL,
`userId` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`roleId` VARCHAR(191) NOT NULL,
`bio` TEXT NULL,
`status` ENUM('ACTIVE', 'ON_BREAK', 'INACTIVE') NOT NULL DEFAULT 'ACTIVE',
`isBookableOnline` BOOLEAN NOT NULL DEFAULT true,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `StaffProfile_userId_key`(`userId`),
INDEX `StaffProfile_businessId_idx`(`businessId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `Role` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`name` VARCHAR(191) NOT NULL,
`isSystem` BOOLEAN NOT NULL DEFAULT true,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE INDEX `Role_businessId_name_key`(`businessId`, `name`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `RolePermission` (
`id` VARCHAR(191) NOT NULL,
`roleId` VARCHAR(191) NOT NULL,
`permission` ENUM('MANAGE_BUSINESS_PROFILE', 'MANAGE_BOOKING_RULES', 'MANAGE_SERVICES', 'MANAGE_STAFF', 'MANAGE_LOYALTY_PROGRAMME', 'MANAGE_NOTIFICATION_SETTINGS', 'VIEW_ALL_STAFF_APPOINTMENTS', 'MANAGE_ALL_APPOINTMENTS', 'MANAGE_OWN_APPOINTMENTS', 'CHECK_IN_CUSTOMERS', 'MANAGE_LOYALTY_STAMPS', 'MANAGE_OWN_AVAILABILITY', 'VIEW_CUSTOMER_DIRECTORY', 'BOOK_ON_BEHALF_OF_CUSTOMER', 'VIEW_REPORTING') NOT NULL,
UNIQUE INDEX `RolePermission_roleId_permission_key`(`roleId`, `permission`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `StaffInvitation` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`staffId` VARCHAR(191) NOT NULL,
`email` VARCHAR(191) NOT NULL,
`token` VARCHAR(191) NOT NULL,
`invitedByUserId` VARCHAR(191) NULL,
`expiresAt` DATETIME(3) NOT NULL,
`acceptedAt` DATETIME(3) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE INDEX `StaffInvitation_staffId_key`(`staffId`),
UNIQUE INDEX `StaffInvitation_token_key`(`token`),
INDEX `StaffInvitation_businessId_idx`(`businessId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `ServiceCategory` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`name` VARCHAR(191) NOT NULL,
`displayOrder` INTEGER NOT NULL DEFAULT 0,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
INDEX `ServiceCategory_businessId_idx`(`businessId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `Service` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`categoryId` VARCHAR(191) NOT NULL,
`name` VARCHAR(191) NOT NULL,
`description` TEXT NULL,
`durationMinutes` INTEGER NOT NULL,
`price` DECIMAL(10, 2) NOT NULL,
`bufferBeforeMinutes` INTEGER NOT NULL DEFAULT 0,
`bufferAfterMinutes` INTEGER NOT NULL DEFAULT 0,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`allowOnlineBooking` BOOLEAN NOT NULL DEFAULT true,
`displayOrder` INTEGER NOT NULL DEFAULT 0,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
INDEX `Service_businessId_idx`(`businessId`),
INDEX `Service_categoryId_idx`(`categoryId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `StaffService` (
`id` VARCHAR(191) NOT NULL,
`staffId` VARCHAR(191) NOT NULL,
`serviceId` VARCHAR(191) NOT NULL,
`priceOverride` DECIMAL(10, 2) NULL,
`durationOverrideMinutes` INTEGER NULL,
UNIQUE INDEX `StaffService_staffId_serviceId_key`(`staffId`, `serviceId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `WorkingHours` (
`id` VARCHAR(191) NOT NULL,
`staffId` VARCHAR(191) NOT NULL,
`dayOfWeek` ENUM('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY') NOT NULL,
`isOff` BOOLEAN NOT NULL DEFAULT false,
`startMinutes` INTEGER NULL,
`endMinutes` INTEGER NULL,
UNIQUE INDEX `WorkingHours_staffId_dayOfWeek_key`(`staffId`, `dayOfWeek`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `Break` (
`id` VARCHAR(191) NOT NULL,
`staffId` VARCHAR(191) NOT NULL,
`label` VARCHAR(191) NOT NULL,
`startMinutes` INTEGER NOT NULL,
`endMinutes` INTEGER NOT NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `BreakDay` (
`id` VARCHAR(191) NOT NULL,
`breakId` VARCHAR(191) NOT NULL,
`dayOfWeek` ENUM('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY') NOT NULL,
UNIQUE INDEX `BreakDay_breakId_dayOfWeek_key`(`breakId`, `dayOfWeek`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `TimeOff` (
`id` VARCHAR(191) NOT NULL,
`staffId` VARCHAR(191) NOT NULL,
`startDate` DATE NOT NULL,
`endDate` DATE NOT NULL,
`reason` VARCHAR(191) NULL,
`status` ENUM('PENDING', 'APPROVED', 'DECLINED') NOT NULL DEFAULT 'APPROVED',
`startMinutes` INTEGER NULL,
`endMinutes` INTEGER NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `TimeOff_staffId_startDate_endDate_idx`(`staffId`, `startDate`, `endDate`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `Appointment` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`customerId` VARCHAR(191) NOT NULL,
`staffId` VARCHAR(191) NOT NULL,
`status` ENUM('PENDING', 'CONFIRMED', 'CHECKED_IN', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED', 'NO_SHOW') NOT NULL DEFAULT 'CONFIRMED',
`startAt` DATETIME(3) NOT NULL,
`endAt` DATETIME(3) NOT NULL,
`notes` TEXT NULL,
`discountAmount` DECIMAL(10, 2) NULL,
`cancellationReason` VARCHAR(191) NULL,
`cancelledAt` DATETIME(3) NULL,
`cancelledByUserId` VARCHAR(191) NULL,
`createdByUserId` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
INDEX `Appointment_staffId_startAt_idx`(`staffId`, `startAt`),
INDEX `Appointment_businessId_startAt_idx`(`businessId`, `startAt`),
INDEX `Appointment_customerId_idx`(`customerId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `AppointmentService` (
`id` VARCHAR(191) NOT NULL,
`appointmentId` VARCHAR(191) NOT NULL,
`serviceId` VARCHAR(191) NOT NULL,
`priceAtBooking` DECIMAL(10, 2) NOT NULL,
`durationAtBookingMinutes` INTEGER NOT NULL,
INDEX `AppointmentService_appointmentId_idx`(`appointmentId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `LoyaltyProgramme` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`isEnabled` BOOLEAN NOT NULL DEFAULT false,
`stampsRequired` INTEGER NOT NULL DEFAULT 10,
`rewardType` ENUM('PERCENTAGE', 'FIXED_AMOUNT', 'FREE_SERVICE') NOT NULL DEFAULT 'PERCENTAGE',
`rewardValue` DECIMAL(10, 2) NULL,
`rewardLabel` VARCHAR(191) NULL,
`maxRewardValue` DECIMAL(10, 2) NULL,
`freeServiceId` VARCHAR(191) NULL,
`autoApplyReward` BOOLEAN NOT NULL DEFAULT true,
`requiresStaffApproval` BOOLEAN NOT NULL DEFAULT false,
`stampsExpireAfterDays` INTEGER NULL,
`rewardExpiresAfterDays` INTEGER NULL,
`earnOnCancelled` BOOLEAN NOT NULL DEFAULT false,
`earnOnNoShow` BOOLEAN NOT NULL DEFAULT false,
`cardBackgroundColor` VARCHAR(191) NULL,
`cardBackgroundImageUrl` VARCHAR(191) NULL,
`stampIcon` VARCHAR(191) NULL,
`termsLine` VARCHAR(191) NULL,
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `LoyaltyProgramme_businessId_key`(`businessId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `LoyaltyEligibleService` (
`id` VARCHAR(191) NOT NULL,
`loyaltyProgrammeId` VARCHAR(191) NOT NULL,
`serviceId` VARCHAR(191) NOT NULL,
UNIQUE INDEX `LoyaltyEligibleService_loyaltyProgrammeId_serviceId_key`(`loyaltyProgrammeId`, `serviceId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `LoyaltyEligibleStaff` (
`id` VARCHAR(191) NOT NULL,
`loyaltyProgrammeId` VARCHAR(191) NOT NULL,
`staffId` VARCHAR(191) NOT NULL,
UNIQUE INDEX `LoyaltyEligibleStaff_loyaltyProgrammeId_staffId_key`(`loyaltyProgrammeId`, `staffId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `LoyaltyAccount` (
`id` VARCHAR(191) NOT NULL,
`customerId` VARCHAR(191) NOT NULL,
`loyaltyProgrammeId` VARCHAR(191) NOT NULL,
`currentStamps` INTEGER NOT NULL DEFAULT 0,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `LoyaltyAccount_customerId_loyaltyProgrammeId_key`(`customerId`, `loyaltyProgrammeId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `LoyaltyTransaction` (
`id` VARCHAR(191) NOT NULL,
`loyaltyAccountId` VARCHAR(191) NOT NULL,
`type` ENUM('STAMP_ADDED', 'STAMP_REMOVED', 'STAMP_EXPIRED', 'REWARD_REDEEMED') NOT NULL,
`amount` INTEGER NOT NULL,
`reason` VARCHAR(191) NULL,
`appointmentId` VARCHAR(191) NULL,
`authoredByStaffId` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `LoyaltyTransaction_loyaltyAccountId_idx`(`loyaltyAccountId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `LoyaltyReward` (
`id` VARCHAR(191) NOT NULL,
`loyaltyAccountId` VARCHAR(191) NOT NULL,
`rewardType` ENUM('PERCENTAGE', 'FIXED_AMOUNT', 'FREE_SERVICE') NOT NULL,
`value` DECIMAL(10, 2) NULL,
`label` VARCHAR(191) NOT NULL,
`status` ENUM('AVAILABLE', 'REDEEMED', 'EXPIRED') NOT NULL DEFAULT 'AVAILABLE',
`appliedToAppointmentId` VARCHAR(191) NULL,
`redeemedAt` DATETIME(3) NULL,
`redeemedByStaffId` VARCHAR(191) NULL,
`expiresAt` DATETIME(3) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `LoyaltyReward_loyaltyAccountId_idx`(`loyaltyAccountId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `Notification` (
`id` VARCHAR(191) NOT NULL,
`userId` VARCHAR(191) NULL,
`appointmentId` VARCHAR(191) NULL,
`category` ENUM('BOOKING_CONFIRMATION', 'BOOKING_REMINDER', 'BOOKING_CHANGED', 'BOOKING_CANCELLED', 'LOYALTY_REWARD_EARNED', 'LOYALTY_REWARD_AVAILABLE', 'MARKETING') NOT NULL,
`channel` ENUM('EMAIL', 'SMS', 'PUSH') NOT NULL,
`status` ENUM('PENDING', 'SENT', 'FAILED') NOT NULL DEFAULT 'PENDING',
`subject` VARCHAR(191) NULL,
`body` TEXT NOT NULL,
`sentAt` DATETIME(3) NULL,
`failureReason` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `Notification_userId_idx`(`userId`),
INDEX `Notification_appointmentId_idx`(`appointmentId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `NotificationPreference` (
`id` VARCHAR(191) NOT NULL,
`userId` VARCHAR(191) NOT NULL,
`category` ENUM('BOOKING_CONFIRMATION', 'BOOKING_REMINDER', 'BOOKING_CHANGED', 'BOOKING_CANCELLED', 'LOYALTY_REWARD_EARNED', 'LOYALTY_REWARD_AVAILABLE', 'MARKETING') NOT NULL,
`channel` ENUM('EMAIL', 'SMS', 'PUSH') NOT NULL,
`isEnabled` BOOLEAN NOT NULL DEFAULT true,
UNIQUE INDEX `NotificationPreference_userId_category_channel_key`(`userId`, `category`, `channel`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `CustomerNote` (
`id` VARCHAR(191) NOT NULL,
`customerId` VARCHAR(191) NOT NULL,
`authorStaffId` VARCHAR(191) NOT NULL,
`body` TEXT NOT NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
INDEX `CustomerNote_customerId_idx`(`customerId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `AuditLog` (
`id` VARCHAR(191) NOT NULL,
`actorUserId` VARCHAR(191) NULL,
`action` VARCHAR(191) NOT NULL,
`entityType` VARCHAR(191) NOT NULL,
`entityId` VARCHAR(191) NOT NULL,
`metadata` JSON NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `AuditLog_entityType_entityId_idx`(`entityType`, `entityId`),
INDEX `AuditLog_actorUserId_idx`(`actorUserId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- AddForeignKey
ALTER TABLE `BusinessLocation` ADD CONSTRAINT `BusinessLocation_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `BusinessHours` ADD CONSTRAINT `BusinessHours_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `BusinessSettings` ADD CONSTRAINT `BusinessSettings_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `BookingRule` ADD CONSTRAINT `BookingRule_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Account` ADD CONSTRAINT `Account_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Session` ADD CONSTRAINT `Session_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `CustomerProfile` ADD CONSTRAINT `CustomerProfile_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `CustomerProfile` ADD CONSTRAINT `CustomerProfile_preferredBarberId_fkey` FOREIGN KEY (`preferredBarberId`) REFERENCES `StaffProfile`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `StaffProfile` ADD CONSTRAINT `StaffProfile_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `StaffProfile` ADD CONSTRAINT `StaffProfile_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `StaffProfile` ADD CONSTRAINT `StaffProfile_roleId_fkey` FOREIGN KEY (`roleId`) REFERENCES `Role`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Role` ADD CONSTRAINT `Role_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `RolePermission` ADD CONSTRAINT `RolePermission_roleId_fkey` FOREIGN KEY (`roleId`) REFERENCES `Role`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `StaffInvitation` ADD CONSTRAINT `StaffInvitation_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `StaffInvitation` ADD CONSTRAINT `StaffInvitation_staffId_fkey` FOREIGN KEY (`staffId`) REFERENCES `StaffProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `StaffInvitation` ADD CONSTRAINT `StaffInvitation_invitedByUserId_fkey` FOREIGN KEY (`invitedByUserId`) REFERENCES `User`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `ServiceCategory` ADD CONSTRAINT `ServiceCategory_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Service` ADD CONSTRAINT `Service_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Service` ADD CONSTRAINT `Service_categoryId_fkey` FOREIGN KEY (`categoryId`) REFERENCES `ServiceCategory`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `StaffService` ADD CONSTRAINT `StaffService_staffId_fkey` FOREIGN KEY (`staffId`) REFERENCES `StaffProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `StaffService` ADD CONSTRAINT `StaffService_serviceId_fkey` FOREIGN KEY (`serviceId`) REFERENCES `Service`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `WorkingHours` ADD CONSTRAINT `WorkingHours_staffId_fkey` FOREIGN KEY (`staffId`) REFERENCES `StaffProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Break` ADD CONSTRAINT `Break_staffId_fkey` FOREIGN KEY (`staffId`) REFERENCES `StaffProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `BreakDay` ADD CONSTRAINT `BreakDay_breakId_fkey` FOREIGN KEY (`breakId`) REFERENCES `Break`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `TimeOff` ADD CONSTRAINT `TimeOff_staffId_fkey` FOREIGN KEY (`staffId`) REFERENCES `StaffProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Appointment` ADD CONSTRAINT `Appointment_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Appointment` ADD CONSTRAINT `Appointment_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `CustomerProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Appointment` ADD CONSTRAINT `Appointment_staffId_fkey` FOREIGN KEY (`staffId`) REFERENCES `StaffProfile`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Appointment` ADD CONSTRAINT `Appointment_cancelledByUserId_fkey` FOREIGN KEY (`cancelledByUserId`) REFERENCES `User`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Appointment` ADD CONSTRAINT `Appointment_createdByUserId_fkey` FOREIGN KEY (`createdByUserId`) REFERENCES `User`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `AppointmentService` ADD CONSTRAINT `AppointmentService_appointmentId_fkey` FOREIGN KEY (`appointmentId`) REFERENCES `Appointment`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `AppointmentService` ADD CONSTRAINT `AppointmentService_serviceId_fkey` FOREIGN KEY (`serviceId`) REFERENCES `Service`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyProgramme` ADD CONSTRAINT `LoyaltyProgramme_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyProgramme` ADD CONSTRAINT `LoyaltyProgramme_freeServiceId_fkey` FOREIGN KEY (`freeServiceId`) REFERENCES `Service`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyEligibleService` ADD CONSTRAINT `LoyaltyEligibleService_loyaltyProgrammeId_fkey` FOREIGN KEY (`loyaltyProgrammeId`) REFERENCES `LoyaltyProgramme`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyEligibleService` ADD CONSTRAINT `LoyaltyEligibleService_serviceId_fkey` FOREIGN KEY (`serviceId`) REFERENCES `Service`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyEligibleStaff` ADD CONSTRAINT `LoyaltyEligibleStaff_loyaltyProgrammeId_fkey` FOREIGN KEY (`loyaltyProgrammeId`) REFERENCES `LoyaltyProgramme`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyAccount` ADD CONSTRAINT `LoyaltyAccount_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `CustomerProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyAccount` ADD CONSTRAINT `LoyaltyAccount_loyaltyProgrammeId_fkey` FOREIGN KEY (`loyaltyProgrammeId`) REFERENCES `LoyaltyProgramme`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyTransaction` ADD CONSTRAINT `LoyaltyTransaction_loyaltyAccountId_fkey` FOREIGN KEY (`loyaltyAccountId`) REFERENCES `LoyaltyAccount`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyTransaction` ADD CONSTRAINT `LoyaltyTransaction_appointmentId_fkey` FOREIGN KEY (`appointmentId`) REFERENCES `Appointment`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyTransaction` ADD CONSTRAINT `LoyaltyTransaction_authoredByStaffId_fkey` FOREIGN KEY (`authoredByStaffId`) REFERENCES `StaffProfile`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyReward` ADD CONSTRAINT `LoyaltyReward_loyaltyAccountId_fkey` FOREIGN KEY (`loyaltyAccountId`) REFERENCES `LoyaltyAccount`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyReward` ADD CONSTRAINT `LoyaltyReward_appliedToAppointmentId_fkey` FOREIGN KEY (`appliedToAppointmentId`) REFERENCES `Appointment`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `LoyaltyReward` ADD CONSTRAINT `LoyaltyReward_redeemedByStaffId_fkey` FOREIGN KEY (`redeemedByStaffId`) REFERENCES `StaffProfile`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Notification` ADD CONSTRAINT `Notification_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Notification` ADD CONSTRAINT `Notification_appointmentId_fkey` FOREIGN KEY (`appointmentId`) REFERENCES `Appointment`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `NotificationPreference` ADD CONSTRAINT `NotificationPreference_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `CustomerNote` ADD CONSTRAINT `CustomerNote_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `CustomerProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `CustomerNote` ADD CONSTRAINT `CustomerNote_authorStaffId_fkey` FOREIGN KEY (`authorStaffId`) REFERENCES `StaffProfile`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -0,0 +1,18 @@
-- CreateTable
CREATE TABLE `GuestAppointmentAccessToken` (
`id` VARCHAR(191) NOT NULL,
`appointmentId` VARCHAR(191) NOT NULL,
`tokenHash` VARCHAR(191) NOT NULL,
`expiresAt` DATETIME(3) NOT NULL,
`revokedAt` DATETIME(3) NULL,
`lastUsedAt` DATETIME(3) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
UNIQUE INDEX `GuestAppointmentAccessToken_appointmentId_key`(`appointmentId`),
UNIQUE INDEX `GuestAppointmentAccessToken_tokenHash_key`(`tokenHash`),
INDEX `GuestAppointmentAccessToken_expiresAt_idx`(`expiresAt`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- AddForeignKey
ALTER TABLE `GuestAppointmentAccessToken` ADD CONSTRAINT `GuestAppointmentAccessToken_appointmentId_fkey` FOREIGN KEY (`appointmentId`) REFERENCES `Appointment`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,101 @@
-- Phase 7: redesign Notification/NotificationPreference around the
-- Notification (message) / NotificationDelivery (one attempt per channel)
-- split — see prisma/schema.prisma for the full rationale. Both tables
-- were unused scaffolding from Phase 2 (confirmed via a repo-wide grep for
-- `prisma.notification`/`prisma.notificationPreference` before writing
-- this migration — zero call sites), so these are safe destructive
-- ALTERs, not a real data migration.
-- DropForeignKey
ALTER TABLE `Notification` DROP FOREIGN KEY `Notification_userId_fkey`;
-- DropForeignKey
ALTER TABLE `NotificationPreference` DROP FOREIGN KEY `NotificationPreference_userId_fkey`;
-- DropIndex
DROP INDEX `Notification_userId_idx` ON `Notification`;
-- DropIndex
DROP INDEX `NotificationPreference_userId_category_channel_key` ON `NotificationPreference`;
-- AlterTable
ALTER TABLE `Notification` DROP COLUMN `body`,
DROP COLUMN `category`,
DROP COLUMN `channel`,
DROP COLUMN `failureReason`,
DROP COLUMN `sentAt`,
DROP COLUMN `status`,
DROP COLUMN `userId`,
ADD COLUMN `bodyText` TEXT NOT NULL,
ADD COLUMN `businessId` VARCHAR(191) NOT NULL,
ADD COLUMN `deepLinkPath` VARCHAR(191) NULL,
ADD COLUMN `idempotencyKey` VARCHAR(191) NOT NULL,
ADD COLUMN `loyaltyRewardId` VARCHAR(191) NULL,
ADD COLUMN `readAt` DATETIME(3) NULL,
ADD COLUMN `recipientCustomerId` VARCHAR(191) NULL,
ADD COLUMN `recipientUserId` VARCHAR(191) NULL,
ADD COLUMN `type` ENUM('BOOKING_CONFIRMED', 'BOOKING_PENDING_APPROVAL', 'BOOKING_APPROVED', 'BOOKING_REMINDER', 'BOOKING_RESCHEDULED', 'BOOKING_CANCELLED', 'BOOKING_BARBER_CHANGED', 'BOOKING_COMPLETED', 'LOYALTY_STAMP_ADDED', 'LOYALTY_REWARD_EARNED', 'LOYALTY_REWARD_REDEEMED', 'LOYALTY_REWARD_EXPIRING', 'STAFF_NEW_APPOINTMENT', 'STAFF_APPOINTMENT_RESCHEDULED', 'STAFF_APPOINTMENT_CANCELLED', 'STAFF_APPOINTMENT_CHECKED_IN', 'STAFF_APPOINTMENT_REMINDER', 'STAFF_SCHEDULE_CHANGED', 'OWNER_NEW_BOOKING', 'OWNER_BOOKING_CANCELLED', 'OWNER_NO_SHOW', 'OWNER_STAFF_INVITATION_ACCEPTED', 'OWNER_REPEATED_DELIVERY_FAILURE') NOT NULL;
-- AlterTable
ALTER TABLE `NotificationPreference` DROP COLUMN `category`,
ADD COLUMN `type` ENUM('BOOKING_CONFIRMED', 'BOOKING_PENDING_APPROVAL', 'BOOKING_APPROVED', 'BOOKING_REMINDER', 'BOOKING_RESCHEDULED', 'BOOKING_CANCELLED', 'BOOKING_BARBER_CHANGED', 'BOOKING_COMPLETED', 'LOYALTY_STAMP_ADDED', 'LOYALTY_REWARD_EARNED', 'LOYALTY_REWARD_REDEEMED', 'LOYALTY_REWARD_EXPIRING', 'STAFF_NEW_APPOINTMENT', 'STAFF_APPOINTMENT_RESCHEDULED', 'STAFF_APPOINTMENT_CANCELLED', 'STAFF_APPOINTMENT_CHECKED_IN', 'STAFF_APPOINTMENT_REMINDER', 'STAFF_SCHEDULE_CHANGED', 'OWNER_NEW_BOOKING', 'OWNER_BOOKING_CANCELLED', 'OWNER_NO_SHOW', 'OWNER_STAFF_INVITATION_ACCEPTED', 'OWNER_REPEATED_DELIVERY_FAILURE') NOT NULL,
MODIFY `channel` ENUM('EMAIL', 'PUSH', 'IN_APP') NOT NULL;
-- CreateTable
CREATE TABLE `NotificationDelivery` (
`id` VARCHAR(191) NOT NULL,
`notificationId` VARCHAR(191) NOT NULL,
`channel` ENUM('EMAIL', 'PUSH', 'IN_APP') NOT NULL,
`status` ENUM('PENDING', 'SCHEDULED', 'PROCESSING', 'SENT', 'FAILED', 'CANCELLED', 'SKIPPED') NOT NULL DEFAULT 'PENDING',
`scheduledFor` DATETIME(3) NULL,
`attemptCount` INTEGER NOT NULL DEFAULT 0,
`lastAttemptedAt` DATETIME(3) NULL,
`providerName` VARCHAR(191) NULL,
`providerMessageId` VARCHAR(191) NULL,
`failureReason` VARCHAR(191) NULL,
`sentAt` DATETIME(3) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `NotificationDelivery_status_scheduledFor_idx`(`status`, `scheduledFor`),
UNIQUE INDEX `NotificationDelivery_notificationId_channel_key`(`notificationId`, `channel`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateIndex
CREATE UNIQUE INDEX `Notification_idempotencyKey_key` ON `Notification`(`idempotencyKey`);
-- CreateIndex
CREATE INDEX `Notification_businessId_createdAt_idx` ON `Notification`(`businessId`, `createdAt`);
-- CreateIndex
CREATE INDEX `Notification_recipientUserId_readAt_idx` ON `Notification`(`recipientUserId`, `readAt`);
-- CreateIndex
CREATE INDEX `Notification_recipientCustomerId_idx` ON `Notification`(`recipientCustomerId`);
-- CreateIndex
CREATE UNIQUE INDEX `NotificationPreference_userId_type_channel_key` ON `NotificationPreference`(`userId`, `type`, `channel`);
-- AddForeignKey
ALTER TABLE `Notification` ADD CONSTRAINT `Notification_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Notification` ADD CONSTRAINT `Notification_recipientUserId_fkey` FOREIGN KEY (`recipientUserId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Notification` ADD CONSTRAINT `Notification_recipientCustomerId_fkey` FOREIGN KEY (`recipientCustomerId`) REFERENCES `CustomerProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Notification` ADD CONSTRAINT `Notification_loyaltyRewardId_fkey` FOREIGN KEY (`loyaltyRewardId`) REFERENCES `LoyaltyReward`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `NotificationDelivery` ADD CONSTRAINT `NotificationDelivery_notificationId_fkey` FOREIGN KEY (`notificationId`) REFERENCES `Notification`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
-- Re-adds the FK this migration dropped above (to accommodate the
-- category->type column rename) but never restored — caught while writing
-- a later migration and diffing against the live dev DB, which showed
-- NotificationPreference.userId with no FK at all. Fixed here, in the
-- original migration, rather than a separate patch: this migration had
-- only ever been applied to this local dev database, never shared.
ALTER TABLE `NotificationPreference` ADD CONSTRAINT `NotificationPreference_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,11 @@
-- Adds STAFF_INVITATION_RECEIVED to NotificationType — the invite email
-- itself, sent to the person being invited (see StaffInvitationService and
-- templates/staff-emails.ts renderStaffInvitationEmail). Distinct from the
-- existing OWNER_STAFF_INVITATION_ACCEPTED, which notifies the owner once
-- accepted.
-- AlterTable
ALTER TABLE `Notification` MODIFY `type` ENUM('BOOKING_CONFIRMED', 'BOOKING_PENDING_APPROVAL', 'BOOKING_APPROVED', 'BOOKING_REMINDER', 'BOOKING_RESCHEDULED', 'BOOKING_CANCELLED', 'BOOKING_BARBER_CHANGED', 'BOOKING_COMPLETED', 'LOYALTY_STAMP_ADDED', 'LOYALTY_REWARD_EARNED', 'LOYALTY_REWARD_REDEEMED', 'LOYALTY_REWARD_EXPIRING', 'STAFF_NEW_APPOINTMENT', 'STAFF_APPOINTMENT_RESCHEDULED', 'STAFF_APPOINTMENT_CANCELLED', 'STAFF_APPOINTMENT_CHECKED_IN', 'STAFF_APPOINTMENT_REMINDER', 'STAFF_SCHEDULE_CHANGED', 'STAFF_INVITATION_RECEIVED', 'OWNER_NEW_BOOKING', 'OWNER_BOOKING_CANCELLED', 'OWNER_NO_SHOW', 'OWNER_STAFF_INVITATION_ACCEPTED', 'OWNER_REPEATED_DELIVERY_FAILURE') NOT NULL;
-- AlterTable
ALTER TABLE `NotificationPreference` MODIFY `type` ENUM('BOOKING_CONFIRMED', 'BOOKING_PENDING_APPROVAL', 'BOOKING_APPROVED', 'BOOKING_REMINDER', 'BOOKING_RESCHEDULED', 'BOOKING_CANCELLED', 'BOOKING_BARBER_CHANGED', 'BOOKING_COMPLETED', 'LOYALTY_STAMP_ADDED', 'LOYALTY_REWARD_EARNED', 'LOYALTY_REWARD_REDEEMED', 'LOYALTY_REWARD_EXPIRING', 'STAFF_NEW_APPOINTMENT', 'STAFF_APPOINTMENT_RESCHEDULED', 'STAFF_APPOINTMENT_CANCELLED', 'STAFF_APPOINTMENT_CHECKED_IN', 'STAFF_APPOINTMENT_REMINDER', 'STAFF_SCHEDULE_CHANGED', 'STAFF_INVITATION_RECEIVED', 'OWNER_NEW_BOOKING', 'OWNER_BOOKING_CANCELLED', 'OWNER_NO_SHOW', 'OWNER_STAFF_INVITATION_ACCEPTED', 'OWNER_REPEATED_DELIVERY_FAILURE') NOT NULL;
@@ -0,0 +1,28 @@
-- CreateTable
CREATE TABLE `PushSubscription` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`userId` VARCHAR(191) NULL,
`customerId` VARCHAR(191) NULL,
`endpoint` VARCHAR(500) NOT NULL,
`p256dhKey` VARCHAR(191) NOT NULL,
`authKey` VARCHAR(191) NOT NULL,
`deviceLabel` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`lastUsedAt` DATETIME(3) NULL,
`revokedAt` DATETIME(3) NULL,
UNIQUE INDEX `PushSubscription_endpoint_key`(`endpoint`),
INDEX `PushSubscription_userId_idx`(`userId`),
INDEX `PushSubscription_customerId_idx`(`customerId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- AddForeignKey
ALTER TABLE `PushSubscription` ADD CONSTRAINT `PushSubscription_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `PushSubscription` ADD CONSTRAINT `PushSubscription_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `PushSubscription` ADD CONSTRAINT `PushSubscription_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `CustomerProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,2 @@
-- RenameIndex
ALTER TABLE `Break` RENAME INDEX `Break_staffId_fkey` TO `Break_staffId_idx`;
@@ -0,0 +1,77 @@
-- AlterTable
ALTER TABLE `BookingRule` MODIFY `allowGuestBooking` BOOLEAN NOT NULL DEFAULT false;
-- AlterTable
ALTER TABLE `Business` ADD COLUMN `appIconUrl` VARCHAR(191) NULL,
ADD COLUMN `backgroundColor` VARCHAR(191) NULL,
ADD COLUMN `coverImageUrl` VARCHAR(191) NULL,
ADD COLUMN `faviconUrl` VARCHAR(191) NULL,
ADD COLUMN `shortName` VARCHAR(191) NULL,
ADD COLUMN `themeColor` VARCHAR(191) NULL;
-- CreateTable
CREATE TABLE `ApplicationInstallation` (
`id` VARCHAR(191) NOT NULL,
`status` ENUM('NOT_INSTALLED', 'INSTALLING', 'INSTALLED', 'FAILED') NOT NULL DEFAULT 'NOT_INSTALLED',
`installedAt` DATETIME(3) NULL,
`installedVersion` VARCHAR(191) NULL,
`initialAdminUserId` VARCHAR(191) NULL,
`primaryBusinessId` VARCHAR(191) NULL,
`metadata` JSON NULL,
`failureReason` TEXT NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `StaffCalendarConnection` (
`id` VARCHAR(191) NOT NULL,
`staffId` VARCHAR(191) NOT NULL,
`provider` ENUM('GOOGLE') NOT NULL DEFAULT 'GOOGLE',
`externalAccountId` VARCHAR(191) NOT NULL,
`accountEmail` VARCHAR(191) NOT NULL,
`encryptedAccessToken` TEXT NULL,
`encryptedRefreshToken` TEXT NOT NULL,
`tokenExpiresAt` DATETIME(3) NULL,
`selectedCalendarId` VARCHAR(191) NOT NULL,
`selectedCalendarName` VARCHAR(191) NOT NULL,
`connectedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`lastSyncAt` DATETIME(3) NULL,
`lastSyncError` TEXT NULL,
`revokedAt` DATETIME(3) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `StaffCalendarConnection_staffId_key`(`staffId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `AppointmentCalendarEvent` (
`id` VARCHAR(191) NOT NULL,
`appointmentId` VARCHAR(191) NOT NULL,
`connectionId` VARCHAR(191) NOT NULL,
`providerEventId` VARCHAR(191) NOT NULL,
`providerCalendarId` VARCHAR(191) NOT NULL,
`status` ENUM('SYNCED', 'PENDING', 'FAILED', 'CANCELLED') NOT NULL DEFAULT 'SYNCED',
`lastSyncedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`lastSyncError` TEXT NULL,
`sourceVersion` INTEGER NOT NULL DEFAULT 1,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
INDEX `AppointmentCalendarEvent_connectionId_idx`(`connectionId`),
UNIQUE INDEX `AppointmentCalendarEvent_appointmentId_connectionId_key`(`appointmentId`, `connectionId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- AddForeignKey
ALTER TABLE `StaffCalendarConnection` ADD CONSTRAINT `StaffCalendarConnection_staffId_fkey` FOREIGN KEY (`staffId`) REFERENCES `StaffProfile`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `AppointmentCalendarEvent` ADD CONSTRAINT `AppointmentCalendarEvent_appointmentId_fkey` FOREIGN KEY (`appointmentId`) REFERENCES `Appointment`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `AppointmentCalendarEvent` ADD CONSTRAINT `AppointmentCalendarEvent_connectionId_fkey` FOREIGN KEY (`connectionId`) REFERENCES `StaffCalendarConnection`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,88 @@
-- AlterTable
ALTER TABLE `Business` ADD COLUMN `googlePlaceId` VARCHAR(191) NULL,
ADD COLUMN `googleRating` DECIMAL(2, 1) NULL,
ADD COLUMN `googleRatingCount` INTEGER NULL,
ADD COLUMN `welcomeBackgroundDesktopUrl` VARCHAR(191) NULL,
ADD COLUMN `welcomeBackgroundMobileUrl` VARCHAR(191) NULL;
-- AlterTable
ALTER TABLE `BusinessSettings` ADD COLUMN `reviewsExcludeRatingOnly` BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN `reviewsMinRating` INTEGER NULL;
-- AlterTable
ALTER TABLE `RolePermission` MODIFY `permission` ENUM('MANAGE_BUSINESS_PROFILE', 'MANAGE_BOOKING_RULES', 'MANAGE_SERVICES', 'MANAGE_STAFF', 'MANAGE_LOYALTY_PROGRAMME', 'MANAGE_NOTIFICATION_SETTINGS', 'VIEW_ALL_STAFF_APPOINTMENTS', 'MANAGE_ALL_APPOINTMENTS', 'MANAGE_OWN_APPOINTMENTS', 'CHECK_IN_CUSTOMERS', 'MANAGE_LOYALTY_STAMPS', 'MANAGE_OWN_AVAILABILITY', 'VIEW_CUSTOMER_DIRECTORY', 'BOOK_ON_BEHALF_OF_CUSTOMER', 'VIEW_REPORTING', 'MANAGE_MEDIA_LIBRARY', 'MANAGE_REVIEWS') NOT NULL;
-- AlterTable
ALTER TABLE `Service` ADD COLUMN `imageUrl` VARCHAR(191) NULL;
-- CreateTable
CREATE TABLE `MediaAsset` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`url` VARCHAR(500) NOT NULL,
`originalFilename` VARCHAR(191) NULL,
`mimeType` VARCHAR(191) NOT NULL,
`sizeBytes` INTEGER NOT NULL,
`width` INTEGER NULL,
`height` INTEGER NULL,
`category` VARCHAR(191) NULL,
`uploadedByUserId` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `MediaAsset_businessId_category_idx`(`businessId`, `category`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `BusinessGalleryImage` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`placement` ENUM('HERO', 'PORTFOLIO') NOT NULL,
`mediaAssetId` VARCHAR(191) NULL,
`imageUrl` VARCHAR(500) NOT NULL,
`category` VARCHAR(191) NULL,
`caption` VARCHAR(191) NULL,
`displayOrder` INTEGER NOT NULL DEFAULT 0,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
INDEX `BusinessGalleryImage_businessId_placement_displayOrder_idx`(`businessId`, `placement`, `displayOrder`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- CreateTable
CREATE TABLE `Review` (
`id` VARCHAR(191) NOT NULL,
`businessId` VARCHAR(191) NOT NULL,
`externalId` VARCHAR(191) NOT NULL,
`authorName` VARCHAR(191) NOT NULL,
`authorPhotoUrl` VARCHAR(191) NULL,
`rating` INTEGER NOT NULL,
`text` TEXT NULL,
`relativeTimeDescription` VARCHAR(191) NULL,
`publishedAt` DATETIME(3) NULL,
`isHidden` BOOLEAN NOT NULL DEFAULT false,
`fetchedAt` DATETIME(3) NOT NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
INDEX `Review_businessId_isHidden_idx`(`businessId`, `isHidden`),
UNIQUE INDEX `Review_businessId_externalId_key`(`businessId`, `externalId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- AddForeignKey
ALTER TABLE `MediaAsset` ADD CONSTRAINT `MediaAsset_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `MediaAsset` ADD CONSTRAINT `MediaAsset_uploadedByUserId_fkey` FOREIGN KEY (`uploadedByUserId`) REFERENCES `User`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `BusinessGalleryImage` ADD CONSTRAINT `BusinessGalleryImage_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `BusinessGalleryImage` ADD CONSTRAINT `BusinessGalleryImage_mediaAssetId_fkey` FOREIGN KEY (`mediaAssetId`) REFERENCES `MediaAsset`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Review` ADD CONSTRAINT `Review_businessId_fkey` FOREIGN KEY (`businessId`) REFERENCES `Business`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,19 @@
-- AlterTable
ALTER TABLE `LoyaltyProgramme` ADD COLUMN `cardBorderColor` VARCHAR(191) NULL,
ADD COLUMN `cardFont` ENUM('SANS', 'SERIF', 'MONO') NOT NULL DEFAULT 'SANS',
ADD COLUMN `cardMemberNumberColor` VARCHAR(191) NULL,
ADD COLUMN `cardTopRightText` VARCHAR(191) NULL,
ADD COLUMN `cardTopRightTextColor` VARCHAR(191) NULL,
ADD COLUMN `cardTopRightTextSize` ENUM('SM', 'MD', 'LG') NOT NULL DEFAULT 'MD',
ADD COLUMN `rewardPosition` ENUM('AFTER_ALL_STAMPS', 'FINAL_SLOT_IS_REWARD') NOT NULL DEFAULT 'AFTER_ALL_STAMPS';
-- Stamp-limit enforcement (Phase 10 follow-up brief: "Valid range: 1–10").
-- Confirmed via a direct read of the live database before writing this
-- migration that no existing LoyaltyProgramme row has stampsRequired > 10
-- and no LoyaltyAccount has currentStamps > 10 — safe to add directly,
-- no data migration needed. Defense-in-depth alongside the identical
-- 1-10 check in validateProgrammeConfig() and the owner form's client
-- validation; MySQL 8.0.16+ enforces CHECK constraints (this app's
-- documented target, see schema.prisma's own header).
ALTER TABLE `LoyaltyProgramme` ADD CONSTRAINT `LoyaltyProgramme_stampsRequired_range`
CHECK (`stampsRequired` BETWEEN 1 AND 10);
@@ -0,0 +1,31 @@
-- Backfill MANAGE_MEDIA_LIBRARY and MANAGE_REVIEWS (added in Phase 9)
-- onto every role that already holds MANAGE_STAFF — the app's existing
-- definition of "owner" (see src/services/staff/staff.service.ts's
-- countOtherActiveManagers, "A role holding MANAGE_STAFF is this app's
-- definition of 'an owner'"). syncRolePermissions() only ever runs at
-- install/seed time, so any business installed before Phase 9 has its
-- Owner role stuck on the old 15-permission set — confirmed by reading
-- the actual RolePermission rows on a real installed business before
-- writing this migration.
--
-- This is what silently made /owner/settings/reviews redirect away
-- (hasPermission(..., MANAGE_REVIEWS) failing, redirecting to /staff,
-- which then renders the barber calendar — looking exactly like
-- "Reviews opens Calendar") and made Media Manager deletes silently fail
-- (MANAGE_MEDIA_LIBRARY). Not a routing bug — a missing data backfill.
--
-- Idempotent: a fresh install's Owner role already has both permissions
-- from syncRolePermissions() at install time, and INSERT IGNORE plus the
-- existing @@unique([roleId, permission]) constraint make re-running
-- this migration (or running it against an already-correct database)
-- a safe no-op.
INSERT IGNORE INTO `RolePermission` (`id`, `roleId`, `permission`)
SELECT UUID(), owner.`roleId`, 'MANAGE_MEDIA_LIBRARY'
FROM `RolePermission` owner
WHERE owner.`permission` = 'MANAGE_STAFF';
INSERT IGNORE INTO `RolePermission` (`id`, `roleId`, `permission`)
SELECT UUID(), owner.`roleId`, 'MANAGE_REVIEWS'
FROM `RolePermission` owner
WHERE owner.`permission` = 'MANAGE_STAFF';
@@ -0,0 +1,31 @@
-- Rewrite any already-stored `/media/...` URLs (the pre-Phase-10 upload
-- path, which never actually worked in production — Next.js 16's
-- `next start` does not dynamically serve files added to public/ after
-- the build; see src/lib/media/media-storage.ts's header for the full
-- account) to the new `/api/media/...` prefix served by
-- src/app/api/media/[...path]/route.ts.
--
-- Confirmed via a direct read of the live database before writing this
-- migration: exactly one MediaAsset row and its matching
-- BusinessGalleryImage row use the old prefix; every other image field
-- currently stores a full external URL (Business.logoUrl/coverImageUrl,
-- etc.) and is untouched by this. Every statement below is still
-- included for completeness/safety, covers every image column that can
-- receive a MediaPicker-sourced URL, and is a no-op wherever nothing
-- matches.
--
-- Idempotent: re-running finds nothing left matching `/media/%` (rows
-- already rewritten now start with `/api/media/%`), so this is safe to
-- apply more than once.
UPDATE `MediaAsset` SET `url` = CONCAT('/api', `url`) WHERE `url` LIKE '/media/%';
UPDATE `BusinessGalleryImage` SET `imageUrl` = CONCAT('/api', `imageUrl`) WHERE `imageUrl` LIKE '/media/%';
UPDATE `Business` SET `logoUrl` = CONCAT('/api', `logoUrl`) WHERE `logoUrl` LIKE '/media/%';
UPDATE `Business` SET `coverImageUrl` = CONCAT('/api', `coverImageUrl`) WHERE `coverImageUrl` LIKE '/media/%';
UPDATE `Business` SET `faviconUrl` = CONCAT('/api', `faviconUrl`) WHERE `faviconUrl` LIKE '/media/%';
UPDATE `Business` SET `appIconUrl` = CONCAT('/api', `appIconUrl`) WHERE `appIconUrl` LIKE '/media/%';
UPDATE `Business` SET `welcomeBackgroundDesktopUrl` = CONCAT('/api', `welcomeBackgroundDesktopUrl`) WHERE `welcomeBackgroundDesktopUrl` LIKE '/media/%';
UPDATE `Business` SET `welcomeBackgroundMobileUrl` = CONCAT('/api', `welcomeBackgroundMobileUrl`) WHERE `welcomeBackgroundMobileUrl` LIKE '/media/%';
UPDATE `LoyaltyProgramme` SET `cardBackgroundImageUrl` = CONCAT('/api', `cardBackgroundImageUrl`) WHERE `cardBackgroundImageUrl` LIKE '/media/%';
UPDATE `Service` SET `imageUrl` = CONCAT('/api', `imageUrl`) WHERE `imageUrl` LIKE '/media/%';
UPDATE `User` SET `image` = CONCAT('/api', `image`) WHERE `image` LIKE '/media/%';
@@ -0,0 +1,9 @@
-- Phase 11: the loyalty card's owner-configurable text now replaces the
-- hardcoded "Loyalty Card" title (top-left), not a secondary badge next to
-- the member number (top-right) — renamed to match, using CHANGE COLUMN so
-- any value an owner already configured (e.g. a custom title) survives the
-- rename instead of being dropped.
ALTER TABLE `LoyaltyProgramme`
CHANGE COLUMN `cardTopRightText` `cardTitleText` VARCHAR(191) NULL,
CHANGE COLUMN `cardTopRightTextSize` `cardTitleTextSize` ENUM('SM', 'MD', 'LG') NOT NULL DEFAULT 'MD',
CHANGE COLUMN `cardTopRightTextColor` `cardTitleTextColor` VARCHAR(191) NULL;
@@ -0,0 +1,7 @@
-- AlterTable
ALTER TABLE `Business` ADD COLUMN `icon192Url` VARCHAR(191) NULL,
ADD COLUMN `icon512Url` VARCHAR(191) NULL,
ADD COLUMN `maskableIcon192Url` VARCHAR(191) NULL,
ADD COLUMN `maskableIcon512Url` VARCHAR(191) NULL,
ADD COLUMN `splashScreenLandscapeUrl` VARCHAR(191) NULL,
ADD COLUMN `splashScreenPortraitUrl` VARCHAR(191) NULL;
@@ -0,0 +1,11 @@
/*
Warnings:
- You are about to drop the column `splashScreenLandscapeUrl` on the `Business` table. All the data in the column will be lost.
- You are about to drop the column `splashScreenPortraitUrl` on the `Business` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE `Business` DROP COLUMN `splashScreenLandscapeUrl`,
DROP COLUMN `splashScreenPortraitUrl`,
ADD COLUMN `splashScreens` JSON NULL;
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE `Business` ADD COLUMN `bottomNavShowLabels` BOOLEAN NOT NULL DEFAULT true;
+3
View File
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "mysql"
+1571
View File
File diff suppressed because it is too large. Load diff
+1034
View File
File diff suppressed because it is too large. Load diff