From a710496f8f7a7e1a929e539df8dab2eb8160415e Mon Sep 17 00:00:00 2001 From: Hyunkyung Date: Sat, 20 Jun 2026 16:59:28 +0200 Subject: [PATCH] use shema for this project --- .../20260604153106_init/migration.sql | 331 --------------- .../migration.sql | 22 - .../migration.sql | 10 - .../migration.sql | 31 -- .../migration.sql | 398 ++++++++++++++++++ apps/web/prisma/schema.prisma | 40 +- 6 files changed, 437 insertions(+), 395 deletions(-) delete mode 100644 apps/web/prisma/migrations/20260604153106_init/migration.sql delete mode 100644 apps/web/prisma/migrations/20260604161850_add_email_verification/migration.sql delete mode 100644 apps/web/prisma/migrations/20260604170859_add_quote_estimate_fields/migration.sql delete mode 100644 apps/web/prisma/migrations/20260609163527_add_appointment_scheduling/migration.sql create mode 100644 apps/web/prisma/migrations/20260620000002_init_ecowoods_schema/migration.sql diff --git a/apps/web/prisma/migrations/20260604153106_init/migration.sql b/apps/web/prisma/migrations/20260604153106_init/migration.sql deleted file mode 100644 index 6affc23..0000000 --- a/apps/web/prisma/migrations/20260604153106_init/migration.sql +++ /dev/null @@ -1,331 +0,0 @@ --- CreateEnum -CREATE TYPE "UserRole" AS ENUM ('USER', 'ADMIN'); - --- CreateEnum -CREATE TYPE "QuoteStatus" AS ENUM ('PENDING', 'QUOTED', 'ACCEPTED', 'REJECTED'); - --- CreateEnum -CREATE TYPE "ProjectStatus" AS ENUM ('DRAFT', 'CONTRACT_SENT', 'SIGNED', 'DEPOSIT_PAID', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED'); - --- CreateEnum -CREATE TYPE "InvoiceStatus" AS ENUM ('DRAFT', 'SENT', 'PAID', 'OVERDUE', 'VOID'); - --- CreateEnum -CREATE TYPE "InvoiceStage" AS ENUM ('DEPOSIT', 'MIDPOINT', 'FINAL', 'CUSTOM'); - --- CreateEnum -CREATE TYPE "PaymentMethod" AS ENUM ('STRIPE', 'BANK_TRANSFER', 'PLAID', 'CASH'); - --- CreateEnum -CREATE TYPE "PaymentStatus" AS ENUM ('PENDING', 'COMPLETED', 'FAILED', 'REFUNDED'); - --- CreateEnum -CREATE TYPE "InquiryStatus" AS ENUM ('NEW', 'IN_PROGRESS', 'RESOLVED', 'CLOSED'); - --- CreateTable -CREATE TABLE "User" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "email" TEXT NOT NULL, - "name" TEXT, - "phone" TEXT, - "passwordHash" TEXT, - "role" "UserRole" NOT NULL DEFAULT 'USER', - "emailVerified" BOOLEAN NOT NULL DEFAULT false, - "image" TEXT, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Account" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "userId" UUID 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, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "Account_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Session" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "sessionToken" TEXT NOT NULL, - "userId" UUID NOT NULL, - "expires" TIMESTAMPTZ NOT NULL, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "Session_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "VerificationToken" ( - "identifier" TEXT NOT NULL, - "token" TEXT NOT NULL, - "expires" TIMESTAMPTZ NOT NULL -); - --- CreateTable -CREATE TABLE "QuoteRequest" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "phone" TEXT, - "city" TEXT, - "province" TEXT, - "address" TEXT, - "species" JSONB, - "squareFeet" INTEGER, - "projectType" TEXT, - "timeline" TEXT, - "budgetRange" TEXT, - "service" TEXT, - "notes" TEXT, - "attachments" JSONB, - "status" "QuoteStatus" NOT NULL DEFAULT 'PENDING', - "adminNotes" TEXT, - "userId" UUID, - "projectId" UUID, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "QuoteRequest_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Project" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "userId" UUID NOT NULL, - "title" TEXT NOT NULL, - "description" TEXT, - "address" TEXT, - "city" TEXT, - "province" TEXT, - "species" JSONB, - "squareFeet" INTEGER, - "startDate" TIMESTAMPTZ, - "endDate" TIMESTAMPTZ, - "status" "ProjectStatus" NOT NULL DEFAULT 'DRAFT', - "contractPdfUrl" TEXT, - "signedContractPdfUrl" TEXT, - "contractSignedAt" TIMESTAMPTZ, - "depositPct" NUMERIC(5,2) DEFAULT 30.00, - "midpointPct" NUMERIC(5,2) DEFAULT 40.00, - "finalPct" NUMERIC(5,2) DEFAULT 30.00, - "taxRate" NUMERIC(5,2) DEFAULT 13.00, - "contractValue" NUMERIC(12,2), - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "Project_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "ProjectNote" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "projectId" UUID NOT NULL, - "content" TEXT NOT NULL, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "ProjectNote_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Invoice" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "number" TEXT, - "projectId" UUID NOT NULL, - "stage" "InvoiceStage", - "status" "InvoiceStatus" NOT NULL DEFAULT 'DRAFT', - "subtotal" NUMERIC(12,2) NOT NULL DEFAULT 0, - "discountPct" NUMERIC(5,2) NOT NULL DEFAULT 0, - "surchargePct" NUMERIC(5,2) NOT NULL DEFAULT 0, - "taxRate" NUMERIC(5,2) NOT NULL DEFAULT 0, - "total" NUMERIC(12,2) NOT NULL DEFAULT 0, - "lineItems" JSONB NOT NULL DEFAULT '[]', - "description" TEXT, - "dueDate" TIMESTAMPTZ, - "issuedAt" TIMESTAMPTZ, - "paidAt" TIMESTAMPTZ, - "pdfUrl" TEXT, - "stripePaymentIntentId" TEXT, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "Invoice_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Payment" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "invoiceId" UUID NOT NULL, - "userId" UUID, - "amount" NUMERIC(12,2) NOT NULL, - "method" "PaymentMethod", - "status" "PaymentStatus" NOT NULL DEFAULT 'PENDING', - "stripePaymentIntentId" TEXT, - "stripeCharged" BOOLEAN NOT NULL DEFAULT false, - "bankReference" TEXT, - "bankConfirmedAt" TIMESTAMPTZ, - "bankConfirmedByNote" TEXT, - "plaidTransactionId" TEXT, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "Payment_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Inquiry" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "userId" UUID, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "phone" TEXT, - "subject" TEXT, - "message" TEXT NOT NULL, - "status" "InquiryStatus" NOT NULL DEFAULT 'NEW', - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "Inquiry_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "InquiryReply" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "inquiryId" UUID NOT NULL, - "fromAdmin" BOOLEAN NOT NULL DEFAULT false, - "content" TEXT NOT NULL, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "InquiryReply_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Settings" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "defaultDepositPct" NUMERIC(5,2) NOT NULL DEFAULT 30, - "defaultMidpointPct" NUMERIC(5,2) NOT NULL DEFAULT 40, - "defaultFinalPct" NUMERIC(5,2) NOT NULL DEFAULT 30, - "defaultTaxRate" NUMERIC(5,2) NOT NULL DEFAULT 13, - "companyName" TEXT, - "companyAddress" TEXT, - "companyPhone" TEXT, - "companyEmail" TEXT, - "companyNumberHst" TEXT, - "companyLogoUrl" TEXT, - "aiEnabled" BOOLEAN NOT NULL DEFAULT true, - "aiBankTransferInstructions" TEXT, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "Settings_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); - --- CreateIndex -CREATE INDEX "User_email_idx" ON "User"("email"); - --- 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 "QuoteRequest_projectId_key" ON "QuoteRequest"("projectId"); - --- CreateIndex -CREATE INDEX "QuoteRequest_email_idx" ON "QuoteRequest"("email"); - --- CreateIndex -CREATE INDEX "QuoteRequest_status_idx" ON "QuoteRequest"("status"); - --- CreateIndex -CREATE INDEX "QuoteRequest_userId_idx" ON "QuoteRequest"("userId"); - --- CreateIndex -CREATE INDEX "Project_userId_idx" ON "Project"("userId"); - --- CreateIndex -CREATE INDEX "Project_status_idx" ON "Project"("status"); - --- CreateIndex -CREATE UNIQUE INDEX "Invoice_number_key" ON "Invoice"("number"); - --- CreateIndex -CREATE INDEX "Invoice_projectId_idx" ON "Invoice"("projectId"); - --- CreateIndex -CREATE INDEX "Invoice_status_idx" ON "Invoice"("status"); - --- CreateIndex -CREATE INDEX "Invoice_number_idx" ON "Invoice"("number"); - --- CreateIndex -CREATE INDEX "Payment_invoiceId_idx" ON "Payment"("invoiceId"); - --- CreateIndex -CREATE INDEX "Payment_status_idx" ON "Payment"("status"); - --- CreateIndex -CREATE INDEX "Inquiry_email_idx" ON "Inquiry"("email"); - --- CreateIndex -CREATE INDEX "Inquiry_status_idx" ON "Inquiry"("status"); - --- CreateIndex -CREATE INDEX "Inquiry_userId_idx" ON "Inquiry"("userId"); - --- 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 "QuoteRequest" ADD CONSTRAINT "QuoteRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "QuoteRequest" ADD CONSTRAINT "QuoteRequest_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Project" ADD CONSTRAINT "Project_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "ProjectNote" ADD CONSTRAINT "ProjectNote_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Payment" ADD CONSTRAINT "Payment_invoiceId_fkey" FOREIGN KEY ("invoiceId") REFERENCES "Invoice"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Payment" ADD CONSTRAINT "Payment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Inquiry" ADD CONSTRAINT "Inquiry_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "InquiryReply" ADD CONSTRAINT "InquiryReply_inquiryId_fkey" FOREIGN KEY ("inquiryId") REFERENCES "Inquiry"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/web/prisma/migrations/20260604161850_add_email_verification/migration.sql b/apps/web/prisma/migrations/20260604161850_add_email_verification/migration.sql deleted file mode 100644 index 2cae960..0000000 --- a/apps/web/prisma/migrations/20260604161850_add_email_verification/migration.sql +++ /dev/null @@ -1,22 +0,0 @@ --- CreateTable -CREATE TABLE "EmailVerificationToken" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "email" TEXT NOT NULL, - "name" TEXT, - "phone" TEXT, - "passwordHash" TEXT, - "token" TEXT NOT NULL DEFAULT gen_random_uuid()::text, - "expiresAt" TIMESTAMPTZ NOT NULL, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "EmailVerificationToken_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "EmailVerificationToken_token_key" ON "EmailVerificationToken"("token"); - --- CreateIndex -CREATE INDEX "EmailVerificationToken_token_idx" ON "EmailVerificationToken"("token"); - --- CreateIndex -CREATE INDEX "EmailVerificationToken_email_idx" ON "EmailVerificationToken"("email"); diff --git a/apps/web/prisma/migrations/20260604170859_add_quote_estimate_fields/migration.sql b/apps/web/prisma/migrations/20260604170859_add_quote_estimate_fields/migration.sql deleted file mode 100644 index d46520a..0000000 --- a/apps/web/prisma/migrations/20260604170859_add_quote_estimate_fields/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- AlterTable -ALTER TABLE "QuoteRequest" -ADD COLUMN "stripeCheckoutSessionId" TEXT, -ADD COLUMN "quoteIssuedAt" TIMESTAMPTZ, -ADD COLUMN "quoteLineItems" JSONB NOT NULL DEFAULT '[]', -ADD COLUMN "quoteNotes" TEXT, -ADD COLUMN "quotePdfUrl" TEXT, -ADD COLUMN "quoteTaxRate" NUMERIC(5,2), -ADD COLUMN "quoteValidUntil" TIMESTAMPTZ, -ADD COLUMN "quotedAmount" NUMERIC(12,2); diff --git a/apps/web/prisma/migrations/20260609163527_add_appointment_scheduling/migration.sql b/apps/web/prisma/migrations/20260609163527_add_appointment_scheduling/migration.sql deleted file mode 100644 index 2513776..0000000 --- a/apps/web/prisma/migrations/20260609163527_add_appointment_scheduling/migration.sql +++ /dev/null @@ -1,31 +0,0 @@ --- CreateEnum -CREATE TYPE "AppointmentStatus" AS ENUM ('SCHEDULED', 'COMPLETED', 'CANCELLED'); - --- CreateTable -CREATE TABLE "Appointment" ( - "id" UUID NOT NULL DEFAULT gen_random_uuid(), - "quoteRequestId" UUID NOT NULL, - "startsAt" TIMESTAMPTZ NOT NULL, - "durationMinutes" INTEGER NOT NULL DEFAULT 60, - "status" "AppointmentStatus" NOT NULL DEFAULT 'SCHEDULED', - "customerName" TEXT, - "customerEmail" TEXT, - "customerPhone" TEXT, - "notes" TEXT, - "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMPTZ NOT NULL, - - CONSTRAINT "Appointment_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE INDEX "Appointment_startsAt_idx" ON "Appointment"("startsAt"); - --- CreateIndex -CREATE INDEX "Appointment_status_idx" ON "Appointment"("status"); - --- CreateIndex -CREATE INDEX "Appointment_quoteRequestId_idx" ON "Appointment"("quoteRequestId"); - --- AddForeignKey -ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_quoteRequestId_fkey" FOREIGN KEY ("quoteRequestId") REFERENCES "QuoteRequest"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/web/prisma/migrations/20260620000002_init_ecowoods_schema/migration.sql b/apps/web/prisma/migrations/20260620000002_init_ecowoods_schema/migration.sql new file mode 100644 index 0000000..d35769f --- /dev/null +++ b/apps/web/prisma/migrations/20260620000002_init_ecowoods_schema/migration.sql @@ -0,0 +1,398 @@ +-- CreateSchema +CREATE SCHEMA IF NOT EXISTS "ecowoods"; + +-- CreateEnum +CREATE TYPE "ecowoods"."UserRole" AS ENUM ('USER', 'ADMIN'); + +-- CreateEnum +CREATE TYPE "ecowoods"."QuoteStatus" AS ENUM ('PENDING', 'QUOTED', 'ACCEPTED', 'REJECTED'); + +-- CreateEnum +CREATE TYPE "ecowoods"."ProjectStatus" AS ENUM ('DRAFT', 'CONTRACT_SENT', 'SIGNED', 'DEPOSIT_PAID', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED'); + +-- CreateEnum +CREATE TYPE "ecowoods"."InvoiceStatus" AS ENUM ('DRAFT', 'SENT', 'PAID', 'OVERDUE', 'VOID'); + +-- CreateEnum +CREATE TYPE "ecowoods"."PaymentMethod" AS ENUM ('STRIPE', 'BANK_TRANSFER', 'PLAID', 'CASH'); + +-- CreateEnum +CREATE TYPE "ecowoods"."PaymentStatus" AS ENUM ('PENDING', 'COMPLETED', 'FAILED', 'REFUNDED'); + +-- CreateEnum +CREATE TYPE "ecowoods"."InquiryStatus" AS ENUM ('NEW', 'IN_PROGRESS', 'RESOLVED', 'CLOSED'); + +-- CreateEnum +CREATE TYPE "ecowoods"."InvoiceStage" AS ENUM ('DEPOSIT', 'MIDPOINT', 'FINAL', 'CUSTOM'); + +-- CreateEnum +CREATE TYPE "ecowoods"."AppointmentStatus" AS ENUM ('SCHEDULED', 'COMPLETED', 'CANCELLED'); + +-- CreateTable +CREATE TABLE "ecowoods"."User" ( + "id" UUID NOT NULL, + "email" TEXT NOT NULL, + "name" TEXT, + "phone" TEXT, + "passwordHash" TEXT, + "role" "ecowoods"."UserRole" NOT NULL DEFAULT 'USER', + "emailVerified" BOOLEAN NOT NULL DEFAULT false, + "image" TEXT, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."EmailVerificationToken" ( + "id" UUID NOT NULL, + "email" TEXT NOT NULL, + "name" TEXT, + "phone" TEXT, + "passwordHash" TEXT, + "token" TEXT NOT NULL, + "expiresAt" TIMESTAMPTZ NOT NULL, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "EmailVerificationToken_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."Account" ( + "id" UUID NOT NULL, + "userId" UUID 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, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "Account_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."Session" ( + "id" UUID NOT NULL, + "sessionToken" TEXT NOT NULL, + "userId" UUID NOT NULL, + "expires" TIMESTAMPTZ NOT NULL, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."VerificationToken" ( + "identifier" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expires" TIMESTAMPTZ NOT NULL +); + +-- CreateTable +CREATE TABLE "ecowoods"."QuoteRequest" ( + "id" UUID NOT NULL, + "name" TEXT NOT NULL, + "email" TEXT NOT NULL, + "phone" TEXT, + "city" TEXT, + "province" TEXT, + "address" TEXT, + "species" JSONB, + "squareFeet" INTEGER, + "projectType" TEXT, + "timeline" TEXT, + "budgetRange" TEXT, + "service" TEXT, + "notes" TEXT, + "attachments" JSONB, + "status" "ecowoods"."QuoteStatus" NOT NULL DEFAULT 'PENDING', + "adminNotes" TEXT, + "stripeCheckoutSessionId" TEXT, + "quotedAmount" DECIMAL(12,2), + "quoteTaxRate" DECIMAL(5,2), + "quoteLineItems" JSONB NOT NULL DEFAULT '[]', + "quoteNotes" TEXT, + "quoteValidUntil" TIMESTAMPTZ, + "quoteIssuedAt" TIMESTAMPTZ, + "quotePdfUrl" TEXT, + "userId" UUID, + "projectId" UUID, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "QuoteRequest_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."Project" ( + "id" UUID NOT NULL, + "userId" UUID NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "address" TEXT, + "city" TEXT, + "province" TEXT, + "species" JSONB, + "squareFeet" INTEGER, + "startDate" TIMESTAMPTZ, + "endDate" TIMESTAMPTZ, + "status" "ecowoods"."ProjectStatus" NOT NULL DEFAULT 'DRAFT', + "contractPdfUrl" TEXT, + "signedContractPdfUrl" TEXT, + "contractSignedAt" TIMESTAMPTZ, + "depositPct" DECIMAL(5,2) DEFAULT 30.00, + "midpointPct" DECIMAL(5,2) DEFAULT 40.00, + "finalPct" DECIMAL(5,2) DEFAULT 30.00, + "taxRate" DECIMAL(5,2) DEFAULT 13.00, + "contractValue" DECIMAL(12,2), + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "Project_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."ProjectNote" ( + "id" UUID NOT NULL, + "projectId" UUID NOT NULL, + "content" TEXT NOT NULL, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "ProjectNote_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."Invoice" ( + "id" UUID NOT NULL, + "number" TEXT, + "projectId" UUID NOT NULL, + "stage" "ecowoods"."InvoiceStage", + "status" "ecowoods"."InvoiceStatus" NOT NULL DEFAULT 'DRAFT', + "subtotal" DECIMAL(12,2) NOT NULL DEFAULT 0, + "discountPct" DECIMAL(5,2) NOT NULL DEFAULT 0, + "surchargePct" DECIMAL(5,2) NOT NULL DEFAULT 0, + "taxRate" DECIMAL(5,2) NOT NULL DEFAULT 0, + "total" DECIMAL(12,2) NOT NULL DEFAULT 0, + "lineItems" JSONB NOT NULL DEFAULT '[]', + "description" TEXT, + "dueDate" TIMESTAMPTZ, + "issuedAt" TIMESTAMPTZ, + "paidAt" TIMESTAMPTZ, + "pdfUrl" TEXT, + "stripePaymentIntentId" TEXT, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "Invoice_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."Payment" ( + "id" UUID NOT NULL, + "invoiceId" UUID NOT NULL, + "userId" UUID, + "amount" DECIMAL(12,2) NOT NULL, + "method" "ecowoods"."PaymentMethod", + "status" "ecowoods"."PaymentStatus" NOT NULL DEFAULT 'PENDING', + "stripePaymentIntentId" TEXT, + "stripeCharged" BOOLEAN NOT NULL DEFAULT false, + "bankReference" TEXT, + "bankConfirmedAt" TIMESTAMPTZ, + "bankConfirmedByNote" TEXT, + "plaidTransactionId" TEXT, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "Payment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."Inquiry" ( + "id" UUID NOT NULL, + "userId" UUID, + "name" TEXT NOT NULL, + "email" TEXT NOT NULL, + "phone" TEXT, + "subject" TEXT, + "message" TEXT NOT NULL, + "status" "ecowoods"."InquiryStatus" NOT NULL DEFAULT 'NEW', + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "Inquiry_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."InquiryReply" ( + "id" UUID NOT NULL, + "inquiryId" UUID NOT NULL, + "fromAdmin" BOOLEAN NOT NULL DEFAULT false, + "content" TEXT NOT NULL, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "InquiryReply_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."Settings" ( + "id" UUID NOT NULL, + "defaultDepositPct" DECIMAL(5,2) NOT NULL DEFAULT 30, + "defaultMidpointPct" DECIMAL(5,2) NOT NULL DEFAULT 40, + "defaultFinalPct" DECIMAL(5,2) NOT NULL DEFAULT 30, + "defaultTaxRate" DECIMAL(5,2) NOT NULL DEFAULT 13, + "companyName" TEXT, + "companyAddress" TEXT, + "companyPhone" TEXT, + "companyEmail" TEXT, + "companyNumberHst" TEXT, + "companyLogoUrl" TEXT, + "aiEnabled" BOOLEAN NOT NULL DEFAULT true, + "aiBankTransferInstructions" TEXT, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "Settings_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ecowoods"."Appointment" ( + "id" UUID NOT NULL, + "quoteRequestId" UUID NOT NULL, + "startsAt" TIMESTAMPTZ NOT NULL, + "durationMinutes" INTEGER NOT NULL DEFAULT 60, + "status" "ecowoods"."AppointmentStatus" NOT NULL DEFAULT 'SCHEDULED', + "customerName" TEXT, + "customerEmail" TEXT, + "customerPhone" TEXT, + "notes" TEXT, + "createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMPTZ NOT NULL, + + CONSTRAINT "Appointment_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "ecowoods"."User"("email"); + +-- CreateIndex +CREATE INDEX "User_email_idx" ON "ecowoods"."User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "EmailVerificationToken_token_key" ON "ecowoods"."EmailVerificationToken"("token"); + +-- CreateIndex +CREATE INDEX "EmailVerificationToken_token_idx" ON "ecowoods"."EmailVerificationToken"("token"); + +-- CreateIndex +CREATE INDEX "EmailVerificationToken_email_idx" ON "ecowoods"."EmailVerificationToken"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "ecowoods"."Account"("provider", "providerAccountId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_sessionToken_key" ON "ecowoods"."Session"("sessionToken"); + +-- CreateIndex +CREATE UNIQUE INDEX "VerificationToken_token_key" ON "ecowoods"."VerificationToken"("token"); + +-- CreateIndex +CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "ecowoods"."VerificationToken"("identifier", "token"); + +-- CreateIndex +CREATE UNIQUE INDEX "QuoteRequest_projectId_key" ON "ecowoods"."QuoteRequest"("projectId"); + +-- CreateIndex +CREATE INDEX "QuoteRequest_email_idx" ON "ecowoods"."QuoteRequest"("email"); + +-- CreateIndex +CREATE INDEX "QuoteRequest_status_idx" ON "ecowoods"."QuoteRequest"("status"); + +-- CreateIndex +CREATE INDEX "QuoteRequest_userId_idx" ON "ecowoods"."QuoteRequest"("userId"); + +-- CreateIndex +CREATE INDEX "Project_userId_idx" ON "ecowoods"."Project"("userId"); + +-- CreateIndex +CREATE INDEX "Project_status_idx" ON "ecowoods"."Project"("status"); + +-- CreateIndex +CREATE UNIQUE INDEX "Invoice_number_key" ON "ecowoods"."Invoice"("number"); + +-- CreateIndex +CREATE INDEX "Invoice_projectId_idx" ON "ecowoods"."Invoice"("projectId"); + +-- CreateIndex +CREATE INDEX "Invoice_status_idx" ON "ecowoods"."Invoice"("status"); + +-- CreateIndex +CREATE INDEX "Invoice_number_idx" ON "ecowoods"."Invoice"("number"); + +-- CreateIndex +CREATE INDEX "Payment_invoiceId_idx" ON "ecowoods"."Payment"("invoiceId"); + +-- CreateIndex +CREATE INDEX "Payment_status_idx" ON "ecowoods"."Payment"("status"); + +-- CreateIndex +CREATE INDEX "Inquiry_email_idx" ON "ecowoods"."Inquiry"("email"); + +-- CreateIndex +CREATE INDEX "Inquiry_status_idx" ON "ecowoods"."Inquiry"("status"); + +-- CreateIndex +CREATE INDEX "Inquiry_userId_idx" ON "ecowoods"."Inquiry"("userId"); + +-- CreateIndex +CREATE INDEX "Appointment_startsAt_idx" ON "ecowoods"."Appointment"("startsAt"); + +-- CreateIndex +CREATE INDEX "Appointment_status_idx" ON "ecowoods"."Appointment"("status"); + +-- CreateIndex +CREATE INDEX "Appointment_quoteRequestId_idx" ON "ecowoods"."Appointment"("quoteRequestId"); + +-- AddForeignKey +ALTER TABLE "ecowoods"."Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "ecowoods"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "ecowoods"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."QuoteRequest" ADD CONSTRAINT "QuoteRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "ecowoods"."User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."QuoteRequest" ADD CONSTRAINT "QuoteRequest_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "ecowoods"."Project"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."Project" ADD CONSTRAINT "Project_userId_fkey" FOREIGN KEY ("userId") REFERENCES "ecowoods"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."ProjectNote" ADD CONSTRAINT "ProjectNote_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "ecowoods"."Project"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."Invoice" ADD CONSTRAINT "Invoice_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "ecowoods"."Project"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."Payment" ADD CONSTRAINT "Payment_invoiceId_fkey" FOREIGN KEY ("invoiceId") REFERENCES "ecowoods"."Invoice"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."Payment" ADD CONSTRAINT "Payment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "ecowoods"."User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."Inquiry" ADD CONSTRAINT "Inquiry_userId_fkey" FOREIGN KEY ("userId") REFERENCES "ecowoods"."User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."InquiryReply" ADD CONSTRAINT "InquiryReply_inquiryId_fkey" FOREIGN KEY ("inquiryId") REFERENCES "ecowoods"."Inquiry"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ecowoods"."Appointment" ADD CONSTRAINT "Appointment_quoteRequestId_fkey" FOREIGN KEY ("quoteRequestId") REFERENCES "ecowoods"."QuoteRequest"("id") ON DELETE CASCADE ON UPDATE CASCADE; + diff --git a/apps/web/prisma/schema.prisma b/apps/web/prisma/schema.prisma index 442847d..073256b 100644 --- a/apps/web/prisma/schema.prisma +++ b/apps/web/prisma/schema.prisma @@ -5,13 +5,15 @@ // ============================================================ generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" + previewFeatures = ["multiSchema"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") directUrl = env("DIRECT_URL") + schemas = ["ecowoods"] } // ───────────────────────────────────────────── @@ -21,6 +23,8 @@ datasource db { enum UserRole { USER ADMIN + + @@schema("ecowoods") } enum QuoteStatus { @@ -28,6 +32,8 @@ enum QuoteStatus { QUOTED ACCEPTED REJECTED + + @@schema("ecowoods") } enum ProjectStatus { @@ -38,6 +44,8 @@ enum ProjectStatus { IN_PROGRESS COMPLETED CANCELLED + + @@schema("ecowoods") } enum InvoiceStatus { @@ -46,6 +54,8 @@ enum InvoiceStatus { PAID OVERDUE VOID + + @@schema("ecowoods") } enum PaymentMethod { @@ -53,6 +63,8 @@ enum PaymentMethod { BANK_TRANSFER PLAID CASH + + @@schema("ecowoods") } enum PaymentStatus { @@ -60,6 +72,8 @@ enum PaymentStatus { COMPLETED FAILED REFUNDED + + @@schema("ecowoods") } enum InquiryStatus { @@ -67,6 +81,8 @@ enum InquiryStatus { IN_PROGRESS RESOLVED CLOSED + + @@schema("ecowoods") } enum InvoiceStage { @@ -74,12 +90,16 @@ enum InvoiceStage { MIDPOINT FINAL CUSTOM + + @@schema("ecowoods") } enum AppointmentStatus { SCHEDULED COMPLETED CANCELLED + + @@schema("ecowoods") } // ───────────────────────────────────────────── @@ -106,6 +126,7 @@ model User { sessions Session[] @@index([email]) + @@schema("ecowoods") } model EmailVerificationToken { @@ -120,6 +141,7 @@ model EmailVerificationToken { @@index([token]) @@index([email]) + @@schema("ecowoods") } // next-auth adapter models @@ -142,6 +164,7 @@ model Account { user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([provider, providerAccountId]) + @@schema("ecowoods") } model Session { @@ -153,6 +176,8 @@ model Session { updatedAt DateTime @updatedAt @db.Timestamptz user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@schema("ecowoods") } model VerificationToken { @@ -161,6 +186,7 @@ model VerificationToken { expires DateTime @db.Timestamptz @@unique([identifier, token]) + @@schema("ecowoods") } // ───────────────────────────────────────────── @@ -209,6 +235,7 @@ model QuoteRequest { @@index([email]) @@index([status]) @@index([userId]) + @@schema("ecowoods") } // ───────────────────────────────────────────── @@ -250,6 +277,7 @@ model Project { @@index([userId]) @@index([status]) + @@schema("ecowoods") } model ProjectNote { @@ -258,6 +286,8 @@ model ProjectNote { project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) content String @db.Text createdAt DateTime @default(now()) @db.Timestamptz + + @@schema("ecowoods") } // ───────────────────────────────────────────── @@ -296,6 +326,7 @@ model Invoice { @@index([projectId]) @@index([status]) @@index([number]) + @@schema("ecowoods") } // ───────────────────────────────────────────── @@ -327,6 +358,7 @@ model Payment { @@index([invoiceId]) @@index([status]) + @@schema("ecowoods") } // ───────────────────────────────────────────── @@ -352,6 +384,7 @@ model Inquiry { @@index([email]) @@index([status]) @@index([userId]) + @@schema("ecowoods") } model InquiryReply { @@ -361,6 +394,8 @@ model InquiryReply { fromAdmin Boolean @default(false) content String @db.Text createdAt DateTime @default(now()) @db.Timestamptz + + @@schema("ecowoods") } // ───────────────────────────────────────────── @@ -387,6 +422,8 @@ model Settings { aiBankTransferInstructions String? @db.Text updatedAt DateTime @updatedAt @db.Timestamptz + + @@schema("ecowoods") } // ───────────────────────────────────────────── @@ -414,4 +451,5 @@ model Appointment { @@index([startsAt]) @@index([status]) @@index([quoteRequestId]) + @@schema("ecowoods") }