Initial Mento CRM: portal OTP, reports, SMS, and deploy for crm.montzar.ir.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "UserRole" AS ENUM ('owner', 'admin', 'sales', 'support');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Organization" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Organization_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"passwordHash" TEXT NOT NULL,
|
||||
"fullName" TEXT NOT NULL,
|
||||
"role" "UserRole" NOT NULL DEFAULT 'sales',
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Organization_slug_key" ON "Organization"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "User_organizationId_idx" ON "User"("organizationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_organizationId_email_key" ON "User"("organizationId", "email");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "User" ADD CONSTRAINT "User_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,70 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Company" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"nationalId" TEXT,
|
||||
"phone" TEXT,
|
||||
"email" TEXT,
|
||||
"website" TEXT,
|
||||
"address" TEXT,
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Company_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Person" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"companyId" TEXT,
|
||||
"firstName" TEXT NOT NULL,
|
||||
"lastName" TEXT NOT NULL,
|
||||
"email" TEXT,
|
||||
"phone" TEXT,
|
||||
"mobile" TEXT,
|
||||
"position" TEXT,
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Person_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Company_organizationId_idx" ON "Company"("organizationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Company_organizationId_name_idx" ON "Company"("organizationId", "name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Company_organizationId_email_idx" ON "Company"("organizationId", "email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Company_organizationId_phone_idx" ON "Company"("organizationId", "phone");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Person_organizationId_idx" ON "Person"("organizationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Person_organizationId_email_idx" ON "Person"("organizationId", "email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Person_organizationId_mobile_idx" ON "Person"("organizationId", "mobile");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Person_organizationId_lastName_firstName_idx" ON "Person"("organizationId", "lastName", "firstName");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Person_companyId_idx" ON "Person"("companyId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Company" ADD CONSTRAINT "Company_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Person" ADD CONSTRAINT "Person_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Person" ADD CONSTRAINT "Person_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,103 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "DealStatus" AS ENUM ('open', 'won', 'lost');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Pipeline" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"isDefault" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Pipeline_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PipelineStage" (
|
||||
"id" TEXT NOT NULL,
|
||||
"pipelineId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"position" INTEGER NOT NULL,
|
||||
"isWon" BOOLEAN NOT NULL DEFAULT false,
|
||||
"isLost" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PipelineStage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Deal" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"pipelineId" TEXT NOT NULL,
|
||||
"stageId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"amount" DECIMAL(18,2),
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"status" "DealStatus" NOT NULL DEFAULT 'open',
|
||||
"source" TEXT,
|
||||
"lostReason" TEXT,
|
||||
"notes" TEXT,
|
||||
"expectedCloseAt" TIMESTAMP(3),
|
||||
"personId" TEXT,
|
||||
"companyId" TEXT,
|
||||
"ownerId" TEXT,
|
||||
"position" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Deal_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Pipeline_organizationId_idx" ON "Pipeline"("organizationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Pipeline_organizationId_isDefault_idx" ON "Pipeline"("organizationId", "isDefault");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PipelineStage_pipelineId_position_idx" ON "PipelineStage"("pipelineId", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Deal_organizationId_idx" ON "Deal"("organizationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Deal_pipelineId_stageId_idx" ON "Deal"("pipelineId", "stageId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Deal_stageId_position_idx" ON "Deal"("stageId", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Deal_personId_idx" ON "Deal"("personId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Deal_companyId_idx" ON "Deal"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Deal_ownerId_idx" ON "Deal"("ownerId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Pipeline" ADD CONSTRAINT "Pipeline_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PipelineStage" ADD CONSTRAINT "PipelineStage_pipelineId_fkey" FOREIGN KEY ("pipelineId") REFERENCES "Pipeline"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Deal" ADD CONSTRAINT "Deal_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Deal" ADD CONSTRAINT "Deal_pipelineId_fkey" FOREIGN KEY ("pipelineId") REFERENCES "Pipeline"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Deal" ADD CONSTRAINT "Deal_stageId_fkey" FOREIGN KEY ("stageId") REFERENCES "PipelineStage"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Deal" ADD CONSTRAINT "Deal_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Deal" ADD CONSTRAINT "Deal_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Deal" ADD CONSTRAINT "Deal_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,55 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ActivityType" AS ENUM ('call', 'meeting', 'task', 'note');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ActivityStatus" AS ENUM ('open', 'done', 'canceled');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Activity" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"type" "ActivityType" NOT NULL DEFAULT 'task',
|
||||
"status" "ActivityStatus" NOT NULL DEFAULT 'open',
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"dueAt" TIMESTAMP(3),
|
||||
"completedAt" TIMESTAMP(3),
|
||||
"personId" TEXT,
|
||||
"companyId" TEXT,
|
||||
"dealId" TEXT,
|
||||
"assigneeId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Activity_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Activity_organizationId_status_dueAt_idx" ON "Activity"("organizationId", "status", "dueAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Activity_organizationId_assigneeId_idx" ON "Activity"("organizationId", "assigneeId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Activity_personId_idx" ON "Activity"("personId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Activity_companyId_idx" ON "Activity"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Activity_dealId_idx" ON "Activity"("dealId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Activity" ADD CONSTRAINT "Activity_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Activity" ADD CONSTRAINT "Activity_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Activity" ADD CONSTRAINT "Activity_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Activity" ADD CONSTRAINT "Activity_dealId_fkey" FOREIGN KEY ("dealId") REFERENCES "Deal"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Activity" ADD CONSTRAINT "Activity_assigneeId_fkey" FOREIGN KEY ("assigneeId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,52 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Note" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"title" TEXT,
|
||||
"body" TEXT NOT NULL,
|
||||
"pinned" BOOLEAN NOT NULL DEFAULT false,
|
||||
"color" TEXT DEFAULT 'default',
|
||||
"tags" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
"reminderAt" TIMESTAMP(3),
|
||||
"personId" TEXT,
|
||||
"companyId" TEXT,
|
||||
"dealId" TEXT,
|
||||
"authorId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Note_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Note_organizationId_pinned_updatedAt_idx" ON "Note"("organizationId", "pinned", "updatedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Note_organizationId_reminderAt_idx" ON "Note"("organizationId", "reminderAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Note_personId_idx" ON "Note"("personId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Note_companyId_idx" ON "Note"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Note_dealId_idx" ON "Note"("dealId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Note_authorId_idx" ON "Note"("authorId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Note" ADD CONSTRAINT "Note_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Note" ADD CONSTRAINT "Note_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Note" ADD CONSTRAINT "Note_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Note" ADD CONSTRAINT "Note_dealId_fkey" FOREIGN KEY ("dealId") REFERENCES "Deal"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Note" ADD CONSTRAINT "Note_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,41 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CustomFieldEntity" AS ENUM ('person', 'company', 'deal');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CustomFieldType" AS ENUM ('text', 'number', 'date', 'boolean', 'select');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Company" ADD COLUMN "customFields" JSONB NOT NULL DEFAULT '{}';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Deal" ADD COLUMN "customFields" JSONB NOT NULL DEFAULT '{}';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Person" ADD COLUMN "customFields" JSONB NOT NULL DEFAULT '{}';
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CustomFieldDefinition" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"entityType" "CustomFieldEntity" NOT NULL,
|
||||
"key" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"fieldType" "CustomFieldType" NOT NULL DEFAULT 'text',
|
||||
"options" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
"required" BOOLEAN NOT NULL DEFAULT false,
|
||||
"position" 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 "CustomFieldDefinition_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CustomFieldDefinition_organizationId_entityType_position_idx" ON "CustomFieldDefinition"("organizationId", "entityType", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "CustomFieldDefinition_organizationId_entityType_key_key" ON "CustomFieldDefinition"("organizationId", "entityType", "key");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CustomFieldDefinition" ADD CONSTRAINT "CustomFieldDefinition_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Deal" ADD COLUMN "isRotten" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "isStale" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "tags" TEXT[] DEFAULT ARRAY[]::TEXT[];
|
||||
@@ -0,0 +1,52 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Product" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"sku" TEXT,
|
||||
"description" TEXT,
|
||||
"unitPrice" DECIMAL(18,2),
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Product_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DealLineItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"dealId" TEXT NOT NULL,
|
||||
"productId" TEXT,
|
||||
"name" TEXT NOT NULL,
|
||||
"quantity" DECIMAL(18,2) NOT NULL DEFAULT 1,
|
||||
"unitPrice" DECIMAL(18,2) NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"position" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "DealLineItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Product_organizationId_name_idx" ON "Product"("organizationId", "name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Product_organizationId_isActive_idx" ON "Product"("organizationId", "isActive");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DealLineItem_dealId_position_idx" ON "DealLineItem"("dealId", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DealLineItem_productId_idx" ON "DealLineItem"("productId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Product" ADD CONSTRAINT "Product_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DealLineItem" ADD CONSTRAINT "DealLineItem_dealId_fkey" FOREIGN KEY ("dealId") REFERENCES "Deal"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DealLineItem" ADD CONSTRAINT "DealLineItem_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,31 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Notification" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"body" TEXT,
|
||||
"link" TEXT,
|
||||
"entityType" TEXT,
|
||||
"entityId" TEXT,
|
||||
"readAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Notification_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Notification_userId_readAt_createdAt_idx" ON "Notification"("userId", "readAt", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Notification_organizationId_createdAt_idx" ON "Notification"("organizationId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Notification_userId_type_entityId_idx" ON "Notification"("userId", "type", "entityId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Note" ADD COLUMN "noteType" TEXT NOT NULL DEFAULT 'general';
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Note_organizationId_noteType_updatedAt_idx" ON "Note"("organizationId", "noteType", "updatedAt");
|
||||
@@ -0,0 +1,32 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "NoteAttachment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"noteId" TEXT NOT NULL,
|
||||
"fileName" TEXT NOT NULL,
|
||||
"mimeType" TEXT NOT NULL,
|
||||
"sizeBytes" INTEGER NOT NULL,
|
||||
"storageKey" TEXT NOT NULL,
|
||||
"uploadedById" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "NoteAttachment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "NoteAttachment_noteId_createdAt_idx" ON "NoteAttachment"("noteId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "NoteAttachment_organizationId_idx" ON "NoteAttachment"("organizationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "NoteAttachment_uploadedById_idx" ON "NoteAttachment"("uploadedById");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "NoteAttachment" ADD CONSTRAINT "NoteAttachment_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "NoteAttachment" ADD CONSTRAINT "NoteAttachment_noteId_fkey" FOREIGN KEY ("noteId") REFERENCES "Note"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "NoteAttachment" ADD CONSTRAINT "NoteAttachment_uploadedById_fkey" FOREIGN KEY ("uploadedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,52 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "LeadForm" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"publicToken" TEXT NOT NULL,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createPerson" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createDeal" BOOLEAN NOT NULL DEFAULT true,
|
||||
"pipelineId" TEXT,
|
||||
"source" TEXT,
|
||||
"thankYouMessage" TEXT,
|
||||
"redirectUrl" TEXT,
|
||||
"assigneeIds" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
"roundRobinIndex" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "LeadForm_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LeadFormField" (
|
||||
"id" TEXT NOT NULL,
|
||||
"formId" TEXT NOT NULL,
|
||||
"key" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"fieldType" TEXT NOT NULL DEFAULT 'text',
|
||||
"required" BOOLEAN NOT NULL DEFAULT false,
|
||||
"mapTo" TEXT NOT NULL,
|
||||
"position" INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
CONSTRAINT "LeadFormField_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "LeadForm_publicToken_key" ON "LeadForm"("publicToken");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "LeadForm_organizationId_updatedAt_idx" ON "LeadForm"("organizationId", "updatedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "LeadFormField_formId_position_idx" ON "LeadFormField"("formId", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "LeadFormField_formId_key_key" ON "LeadFormField"("formId", "key");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "LeadForm" ADD CONSTRAINT "LeadForm_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "LeadFormField" ADD CONSTRAINT "LeadFormField_formId_fkey" FOREIGN KEY ("formId") REFERENCES "LeadForm"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,83 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "QuoteStatus" AS ENUM ('draft', 'sent', 'accepted', 'rejected', 'expired');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Quote" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"number" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"status" "QuoteStatus" NOT NULL DEFAULT 'draft',
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"notes" TEXT,
|
||||
"validUntil" TIMESTAMP(3),
|
||||
"personId" TEXT,
|
||||
"companyId" TEXT,
|
||||
"dealId" TEXT,
|
||||
"ownerId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Quote_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "QuoteLineItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"quoteId" TEXT NOT NULL,
|
||||
"productId" TEXT,
|
||||
"name" TEXT NOT NULL,
|
||||
"quantity" DECIMAL(18,2) NOT NULL DEFAULT 1,
|
||||
"unitPrice" DECIMAL(18,2) NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"position" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "QuoteLineItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Quote_organizationId_status_updatedAt_idx" ON "Quote"("organizationId", "status", "updatedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Quote_personId_idx" ON "Quote"("personId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Quote_companyId_idx" ON "Quote"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Quote_dealId_idx" ON "Quote"("dealId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Quote_ownerId_idx" ON "Quote"("ownerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Quote_organizationId_number_key" ON "Quote"("organizationId", "number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "QuoteLineItem_quoteId_position_idx" ON "QuoteLineItem"("quoteId", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "QuoteLineItem_productId_idx" ON "QuoteLineItem"("productId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Quote" ADD CONSTRAINT "Quote_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Quote" ADD CONSTRAINT "Quote_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Quote" ADD CONSTRAINT "Quote_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Quote" ADD CONSTRAINT "Quote_dealId_fkey" FOREIGN KEY ("dealId") REFERENCES "Deal"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Quote" ADD CONSTRAINT "Quote_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "QuoteLineItem" ADD CONSTRAINT "QuoteLineItem_quoteId_fkey" FOREIGN KEY ("quoteId") REFERENCES "Quote"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "QuoteLineItem" ADD CONSTRAINT "QuoteLineItem_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,153 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "InvoiceStatus" AS ENUM ('draft', 'issued', 'partially_paid', 'paid', 'canceled');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PaymentMethod" AS ENUM ('cash', 'transfer', 'card', 'check', 'other');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "InstallmentStatus" AS ENUM ('pending', 'paid', 'canceled');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Invoice" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"number" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"status" "InvoiceStatus" NOT NULL DEFAULT 'draft',
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"notes" TEXT,
|
||||
"issuedAt" TIMESTAMP(3),
|
||||
"dueDate" TIMESTAMP(3),
|
||||
"personId" TEXT,
|
||||
"companyId" TEXT,
|
||||
"dealId" TEXT,
|
||||
"quoteId" TEXT,
|
||||
"ownerId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Invoice_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "InvoiceLineItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"invoiceId" TEXT NOT NULL,
|
||||
"productId" TEXT,
|
||||
"name" TEXT NOT NULL,
|
||||
"quantity" DECIMAL(18,2) NOT NULL DEFAULT 1,
|
||||
"unitPrice" DECIMAL(18,2) NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"position" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "InvoiceLineItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Payment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"invoiceId" TEXT NOT NULL,
|
||||
"amount" DECIMAL(18,2) NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"method" "PaymentMethod" NOT NULL DEFAULT 'transfer',
|
||||
"paidAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"notes" TEXT,
|
||||
"installmentId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Payment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "InvoiceInstallment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"invoiceId" TEXT NOT NULL,
|
||||
"position" INTEGER NOT NULL DEFAULT 0,
|
||||
"dueDate" TIMESTAMP(3) NOT NULL,
|
||||
"amount" DECIMAL(18,2) NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"status" "InstallmentStatus" NOT NULL DEFAULT 'pending',
|
||||
"paidAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "InvoiceInstallment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_organizationId_status_updatedAt_idx" ON "Invoice"("organizationId", "status", "updatedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_personId_idx" ON "Invoice"("personId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_companyId_idx" ON "Invoice"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_dealId_idx" ON "Invoice"("dealId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_quoteId_idx" ON "Invoice"("quoteId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_ownerId_idx" ON "Invoice"("ownerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Invoice_organizationId_number_key" ON "Invoice"("organizationId", "number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "InvoiceLineItem_invoiceId_position_idx" ON "InvoiceLineItem"("invoiceId", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "InvoiceLineItem_productId_idx" ON "InvoiceLineItem"("productId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Payment_installmentId_key" ON "Payment"("installmentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Payment_invoiceId_paidAt_idx" ON "Payment"("invoiceId", "paidAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "InvoiceInstallment_invoiceId_position_idx" ON "InvoiceInstallment"("invoiceId", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "InvoiceInstallment_invoiceId_dueDate_idx" ON "InvoiceInstallment"("invoiceId", "dueDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "InvoiceInstallment_status_dueDate_idx" ON "InvoiceInstallment"("status", "dueDate");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_dealId_fkey" FOREIGN KEY ("dealId") REFERENCES "Deal"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_quoteId_fkey" FOREIGN KEY ("quoteId") REFERENCES "Quote"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "InvoiceLineItem" ADD CONSTRAINT "InvoiceLineItem_invoiceId_fkey" FOREIGN KEY ("invoiceId") REFERENCES "Invoice"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "InvoiceLineItem" ADD CONSTRAINT "InvoiceLineItem_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Payment" ADD CONSTRAINT "Payment_invoiceId_fkey" FOREIGN KEY ("invoiceId") REFERENCES "Invoice"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Payment" ADD CONSTRAINT "Payment_installmentId_fkey" FOREIGN KEY ("installmentId") REFERENCES "InvoiceInstallment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "InvoiceInstallment" ADD CONSTRAINT "InvoiceInstallment_invoiceId_fkey" FOREIGN KEY ("invoiceId") REFERENCES "Invoice"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,17 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Company" ADD COLUMN "ownerId" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Person" ADD COLUMN "ownerId" TEXT;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Company_ownerId_idx" ON "Company"("ownerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Person_ownerId_idx" ON "Person"("ownerId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Company" ADD CONSTRAINT "Company_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Person" ADD CONSTRAINT "Person_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,28 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "SalesGoal" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"title" TEXT NOT NULL,
|
||||
"periodStart" TIMESTAMP(3) NOT NULL,
|
||||
"periodEnd" TIMESTAMP(3) NOT NULL,
|
||||
"targetAmount" DECIMAL(18,2) NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SalesGoal_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SalesGoal_organizationId_periodStart_periodEnd_idx" ON "SalesGoal"("organizationId", "periodStart", "periodEnd");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SalesGoal_userId_idx" ON "SalesGoal"("userId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SalesGoal" ADD CONSTRAINT "SalesGoal_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SalesGoal" ADD CONSTRAINT "SalesGoal_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Organization" ADD COLUMN "baseCurrency" TEXT NOT NULL DEFAULT 'IRR',
|
||||
ADD COLUMN "enabledCurrencies" TEXT[] DEFAULT ARRAY['IRR', 'USD', 'EUR']::TEXT[];
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ExchangeRate" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"currency" TEXT NOT NULL,
|
||||
"rateToBase" DECIMAL(24,6) NOT NULL,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ExchangeRate_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ExchangeRate_organizationId_idx" ON "ExchangeRate"("organizationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ExchangeRate_organizationId_currency_key" ON "ExchangeRate"("organizationId", "currency");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ExchangeRate" ADD CONSTRAINT "ExchangeRate_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,89 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TicketStatus" AS ENUM ('open', 'in_progress', 'waiting', 'resolved', 'closed');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TicketPriority" AS ENUM ('low', 'normal', 'high', 'urgent');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Ticket" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"number" TEXT NOT NULL,
|
||||
"subject" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"status" "TicketStatus" NOT NULL DEFAULT 'open',
|
||||
"priority" "TicketPriority" NOT NULL DEFAULT 'normal',
|
||||
"personId" TEXT,
|
||||
"companyId" TEXT,
|
||||
"dealId" TEXT,
|
||||
"assigneeId" TEXT,
|
||||
"reporterId" TEXT,
|
||||
"resolvedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Ticket_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TicketMessage" (
|
||||
"id" TEXT NOT NULL,
|
||||
"ticketId" TEXT NOT NULL,
|
||||
"authorId" TEXT,
|
||||
"body" TEXT NOT NULL,
|
||||
"isInternal" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "TicketMessage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Ticket_organizationId_status_updatedAt_idx" ON "Ticket"("organizationId", "status", "updatedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Ticket_assigneeId_idx" ON "Ticket"("assigneeId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Ticket_reporterId_idx" ON "Ticket"("reporterId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Ticket_personId_idx" ON "Ticket"("personId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Ticket_companyId_idx" ON "Ticket"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Ticket_dealId_idx" ON "Ticket"("dealId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Ticket_organizationId_number_key" ON "Ticket"("organizationId", "number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TicketMessage_ticketId_createdAt_idx" ON "TicketMessage"("ticketId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TicketMessage_authorId_idx" ON "TicketMessage"("authorId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_dealId_fkey" FOREIGN KEY ("dealId") REFERENCES "Deal"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_assigneeId_fkey" FOREIGN KEY ("assigneeId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_reporterId_fkey" FOREIGN KEY ("reporterId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TicketMessage" ADD CONSTRAINT "TicketMessage_ticketId_fkey" FOREIGN KEY ("ticketId") REFERENCES "Ticket"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TicketMessage" ADD CONSTRAINT "TicketMessage_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,30 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Ticket" ADD COLUMN "csatAt" TIMESTAMP(3),
|
||||
ADD COLUMN "csatComment" TEXT,
|
||||
ADD COLUMN "csatScore" INTEGER,
|
||||
ADD COLUMN "firstRespondedAt" TIMESTAMP(3),
|
||||
ADD COLUMN "slaDueAt" TIMESTAMP(3);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FaqArticle" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"question" TEXT NOT NULL,
|
||||
"answer" TEXT NOT NULL,
|
||||
"category" TEXT,
|
||||
"isPublished" BOOLEAN NOT NULL DEFAULT true,
|
||||
"position" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "FaqArticle_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaqArticle_organizationId_isPublished_position_idx" ON "FaqArticle"("organizationId", "isPublished", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Ticket_organizationId_slaDueAt_idx" ON "Ticket"("organizationId", "slaDueAt");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FaqArticle" ADD CONSTRAINT "FaqArticle_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,21 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "PortalOtp" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"mobile" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"consumedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "PortalOtp_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PortalOtp_organizationId_mobile_createdAt_idx" ON "PortalOtp"("organizationId", "mobile", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PortalOtp_expiresAt_idx" ON "PortalOtp"("expiresAt");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PortalOtp" ADD CONSTRAINT "PortalOtp_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE 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,738 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
owner
|
||||
admin
|
||||
sales
|
||||
support
|
||||
}
|
||||
|
||||
enum DealStatus {
|
||||
open
|
||||
won
|
||||
lost
|
||||
}
|
||||
|
||||
enum ActivityType {
|
||||
call
|
||||
meeting
|
||||
task
|
||||
note
|
||||
}
|
||||
|
||||
enum ActivityStatus {
|
||||
open
|
||||
done
|
||||
canceled
|
||||
}
|
||||
|
||||
enum CustomFieldEntity {
|
||||
person
|
||||
company
|
||||
deal
|
||||
}
|
||||
|
||||
enum CustomFieldType {
|
||||
text
|
||||
number
|
||||
date
|
||||
boolean
|
||||
select
|
||||
}
|
||||
|
||||
enum QuoteStatus {
|
||||
draft
|
||||
sent
|
||||
accepted
|
||||
rejected
|
||||
expired
|
||||
}
|
||||
|
||||
enum InvoiceStatus {
|
||||
draft
|
||||
issued
|
||||
partially_paid
|
||||
paid
|
||||
canceled
|
||||
}
|
||||
|
||||
enum PaymentMethod {
|
||||
cash
|
||||
transfer
|
||||
card
|
||||
check
|
||||
other
|
||||
}
|
||||
|
||||
enum InstallmentStatus {
|
||||
pending
|
||||
paid
|
||||
canceled
|
||||
}
|
||||
|
||||
enum TicketStatus {
|
||||
open
|
||||
in_progress
|
||||
waiting
|
||||
resolved
|
||||
closed
|
||||
}
|
||||
|
||||
enum TicketPriority {
|
||||
low
|
||||
normal
|
||||
high
|
||||
urgent
|
||||
}
|
||||
|
||||
model Organization {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String @unique
|
||||
baseCurrency String @default("IRR")
|
||||
enabledCurrencies String[] @default(["IRR", "USD", "EUR"])
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
users User[]
|
||||
companies Company[]
|
||||
people Person[]
|
||||
pipelines Pipeline[]
|
||||
deals Deal[]
|
||||
activities Activity[]
|
||||
notes Note[]
|
||||
customFields CustomFieldDefinition[]
|
||||
products Product[]
|
||||
notifications Notification[]
|
||||
noteAttachments NoteAttachment[]
|
||||
leadForms LeadForm[]
|
||||
quotes Quote[]
|
||||
invoices Invoice[]
|
||||
salesGoals SalesGoal[]
|
||||
exchangeRates ExchangeRate[]
|
||||
tickets Ticket[]
|
||||
faqArticles FaqArticle[]
|
||||
portalOtps PortalOtp[]
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
email String
|
||||
passwordHash String
|
||||
fullName String
|
||||
role UserRole @default(sales)
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
ownedDeals Deal[] @relation("DealOwner")
|
||||
ownedQuotes Quote[] @relation("QuoteOwner")
|
||||
ownedInvoices Invoice[] @relation("InvoiceOwner")
|
||||
ownedPeople Person[] @relation("PersonOwner")
|
||||
ownedCompanies Company[] @relation("CompanyOwner")
|
||||
activities Activity[] @relation("ActivityAssignee")
|
||||
notes Note[] @relation("NoteAuthor")
|
||||
noteAttachments NoteAttachment[] @relation("NoteAttachmentUploader")
|
||||
notifications Notification[]
|
||||
salesGoals SalesGoal[] @relation("SalesGoalUser")
|
||||
assignedTickets Ticket[] @relation("TicketAssignee")
|
||||
reportedTickets Ticket[] @relation("TicketReporter")
|
||||
ticketMessages TicketMessage[] @relation("TicketMessageAuthor")
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([organizationId, email])
|
||||
@@index([organizationId])
|
||||
}
|
||||
|
||||
model Company {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
nationalId String?
|
||||
phone String?
|
||||
email String?
|
||||
website String?
|
||||
address String?
|
||||
notes String?
|
||||
customFields Json @default("{}")
|
||||
people Person[]
|
||||
deals Deal[]
|
||||
activities Activity[]
|
||||
smartNotes Note[]
|
||||
quotes Quote[]
|
||||
invoices Invoice[]
|
||||
ownerId String?
|
||||
owner User? @relation("CompanyOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
||||
tickets Ticket[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId])
|
||||
@@index([organizationId, name])
|
||||
@@index([organizationId, email])
|
||||
@@index([organizationId, phone])
|
||||
@@index([ownerId])
|
||||
}
|
||||
|
||||
model Person {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
companyId String?
|
||||
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
||||
firstName String
|
||||
lastName String
|
||||
email String?
|
||||
phone String?
|
||||
mobile String?
|
||||
position String?
|
||||
notes String?
|
||||
customFields Json @default("{}")
|
||||
deals Deal[]
|
||||
activities Activity[]
|
||||
smartNotes Note[]
|
||||
quotes Quote[]
|
||||
invoices Invoice[]
|
||||
ownerId String?
|
||||
owner User? @relation("PersonOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
||||
tickets Ticket[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId])
|
||||
@@index([organizationId, email])
|
||||
@@index([organizationId, mobile])
|
||||
@@index([organizationId, lastName, firstName])
|
||||
@@index([companyId])
|
||||
@@index([ownerId])
|
||||
}
|
||||
|
||||
model Pipeline {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
isDefault Boolean @default(false)
|
||||
stages PipelineStage[]
|
||||
deals Deal[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId])
|
||||
@@index([organizationId, isDefault])
|
||||
}
|
||||
|
||||
model PipelineStage {
|
||||
id String @id @default(cuid())
|
||||
pipelineId String
|
||||
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
position Int
|
||||
isWon Boolean @default(false)
|
||||
isLost Boolean @default(false)
|
||||
deals Deal[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([pipelineId, position])
|
||||
}
|
||||
|
||||
model Deal {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
pipelineId String
|
||||
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
||||
stageId String
|
||||
stage PipelineStage @relation(fields: [stageId], references: [id], onDelete: Restrict)
|
||||
title String
|
||||
amount Decimal? @db.Decimal(18, 2)
|
||||
currency String @default("IRR")
|
||||
status DealStatus @default(open)
|
||||
source String?
|
||||
lostReason String?
|
||||
notes String?
|
||||
tags String[] @default([])
|
||||
isStale Boolean @default(false)
|
||||
isRotten Boolean @default(false)
|
||||
customFields Json @default("{}")
|
||||
expectedCloseAt DateTime?
|
||||
personId String?
|
||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
||||
companyId String?
|
||||
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
||||
ownerId String?
|
||||
owner User? @relation("DealOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
||||
position Int @default(0)
|
||||
activities Activity[]
|
||||
smartNotes Note[]
|
||||
lineItems DealLineItem[]
|
||||
quotes Quote[]
|
||||
invoices Invoice[]
|
||||
tickets Ticket[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId])
|
||||
@@index([pipelineId, stageId])
|
||||
@@index([stageId, position])
|
||||
@@index([personId])
|
||||
@@index([companyId])
|
||||
@@index([ownerId])
|
||||
}
|
||||
|
||||
model Activity {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
type ActivityType @default(task)
|
||||
status ActivityStatus @default(open)
|
||||
title String
|
||||
description String?
|
||||
dueAt DateTime?
|
||||
completedAt DateTime?
|
||||
personId String?
|
||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
||||
companyId String?
|
||||
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
||||
dealId String?
|
||||
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
||||
assigneeId String?
|
||||
assignee User? @relation("ActivityAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, status, dueAt])
|
||||
@@index([organizationId, assigneeId])
|
||||
@@index([personId])
|
||||
@@index([companyId])
|
||||
@@index([dealId])
|
||||
}
|
||||
|
||||
model Note {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
title String?
|
||||
body String
|
||||
noteType String @default("general")
|
||||
pinned Boolean @default(false)
|
||||
color String? @default("default")
|
||||
tags String[] @default([])
|
||||
reminderAt DateTime?
|
||||
personId String?
|
||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
||||
companyId String?
|
||||
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
||||
dealId String?
|
||||
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
||||
authorId String?
|
||||
author User? @relation("NoteAuthor", fields: [authorId], references: [id], onDelete: SetNull)
|
||||
attachments NoteAttachment[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, pinned, updatedAt])
|
||||
@@index([organizationId, noteType, updatedAt])
|
||||
@@index([organizationId, reminderAt])
|
||||
@@index([personId])
|
||||
@@index([companyId])
|
||||
@@index([dealId])
|
||||
@@index([authorId])
|
||||
}
|
||||
|
||||
model NoteAttachment {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
noteId String
|
||||
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
||||
fileName String
|
||||
mimeType String
|
||||
sizeBytes Int
|
||||
storageKey String
|
||||
uploadedById String?
|
||||
uploadedBy User? @relation("NoteAttachmentUploader", fields: [uploadedById], references: [id], onDelete: SetNull)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([noteId, createdAt])
|
||||
@@index([organizationId])
|
||||
@@index([uploadedById])
|
||||
}
|
||||
|
||||
model CustomFieldDefinition {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
entityType CustomFieldEntity
|
||||
key String
|
||||
label String
|
||||
fieldType CustomFieldType @default(text)
|
||||
options String[] @default([])
|
||||
required Boolean @default(false)
|
||||
position Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([organizationId, entityType, key])
|
||||
@@index([organizationId, entityType, position])
|
||||
}
|
||||
|
||||
model Product {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
sku String?
|
||||
description String?
|
||||
unitPrice Decimal? @db.Decimal(18, 2)
|
||||
currency String @default("IRR")
|
||||
isActive Boolean @default(true)
|
||||
lineItems DealLineItem[]
|
||||
quoteLineItems QuoteLineItem[]
|
||||
invoiceLineItems InvoiceLineItem[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, name])
|
||||
@@index([organizationId, isActive])
|
||||
}
|
||||
|
||||
model DealLineItem {
|
||||
id String @id @default(cuid())
|
||||
dealId String
|
||||
deal Deal @relation(fields: [dealId], references: [id], onDelete: Cascade)
|
||||
productId String?
|
||||
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
|
||||
name String
|
||||
quantity Decimal @default(1) @db.Decimal(18, 2)
|
||||
unitPrice Decimal @db.Decimal(18, 2)
|
||||
currency String @default("IRR")
|
||||
position Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([dealId, position])
|
||||
@@index([productId])
|
||||
}
|
||||
|
||||
model Notification {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
type String
|
||||
title String
|
||||
body String?
|
||||
link String?
|
||||
entityType String?
|
||||
entityId String?
|
||||
readAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId, readAt, createdAt])
|
||||
@@index([organizationId, createdAt])
|
||||
@@index([userId, type, entityId])
|
||||
}
|
||||
|
||||
model LeadForm {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
publicToken String @unique @default(cuid())
|
||||
isActive Boolean @default(true)
|
||||
createPerson Boolean @default(true)
|
||||
createDeal Boolean @default(true)
|
||||
pipelineId String?
|
||||
source String?
|
||||
thankYouMessage String?
|
||||
redirectUrl String?
|
||||
assigneeIds String[] @default([])
|
||||
roundRobinIndex Int @default(0)
|
||||
fields LeadFormField[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, updatedAt])
|
||||
}
|
||||
|
||||
model LeadFormField {
|
||||
id String @id @default(cuid())
|
||||
formId String
|
||||
form LeadForm @relation(fields: [formId], references: [id], onDelete: Cascade)
|
||||
key String
|
||||
label String
|
||||
fieldType String @default("text")
|
||||
required Boolean @default(false)
|
||||
mapTo String
|
||||
position Int @default(0)
|
||||
|
||||
@@unique([formId, key])
|
||||
@@index([formId, position])
|
||||
}
|
||||
|
||||
model Quote {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
number String
|
||||
title String
|
||||
status QuoteStatus @default(draft)
|
||||
currency String @default("IRR")
|
||||
notes String?
|
||||
validUntil DateTime?
|
||||
personId String?
|
||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
||||
companyId String?
|
||||
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
||||
dealId String?
|
||||
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
||||
ownerId String?
|
||||
owner User? @relation("QuoteOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
||||
lineItems QuoteLineItem[]
|
||||
invoices Invoice[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([organizationId, number])
|
||||
@@index([organizationId, status, updatedAt])
|
||||
@@index([personId])
|
||||
@@index([companyId])
|
||||
@@index([dealId])
|
||||
@@index([ownerId])
|
||||
}
|
||||
|
||||
model QuoteLineItem {
|
||||
id String @id @default(cuid())
|
||||
quoteId String
|
||||
quote Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
|
||||
productId String?
|
||||
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
|
||||
name String
|
||||
quantity Decimal @default(1) @db.Decimal(18, 2)
|
||||
unitPrice Decimal @db.Decimal(18, 2)
|
||||
currency String @default("IRR")
|
||||
position Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([quoteId, position])
|
||||
@@index([productId])
|
||||
}
|
||||
|
||||
model Invoice {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
number String
|
||||
title String
|
||||
status InvoiceStatus @default(draft)
|
||||
currency String @default("IRR")
|
||||
notes String?
|
||||
issuedAt DateTime?
|
||||
dueDate DateTime?
|
||||
personId String?
|
||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
||||
companyId String?
|
||||
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
||||
dealId String?
|
||||
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
||||
quoteId String?
|
||||
quote Quote? @relation(fields: [quoteId], references: [id], onDelete: SetNull)
|
||||
ownerId String?
|
||||
owner User? @relation("InvoiceOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
||||
lineItems InvoiceLineItem[]
|
||||
payments Payment[]
|
||||
installments InvoiceInstallment[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([organizationId, number])
|
||||
@@index([organizationId, status, updatedAt])
|
||||
@@index([personId])
|
||||
@@index([companyId])
|
||||
@@index([dealId])
|
||||
@@index([quoteId])
|
||||
@@index([ownerId])
|
||||
}
|
||||
|
||||
model InvoiceLineItem {
|
||||
id String @id @default(cuid())
|
||||
invoiceId String
|
||||
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
||||
productId String?
|
||||
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
|
||||
name String
|
||||
quantity Decimal @default(1) @db.Decimal(18, 2)
|
||||
unitPrice Decimal @db.Decimal(18, 2)
|
||||
currency String @default("IRR")
|
||||
position Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([invoiceId, position])
|
||||
@@index([productId])
|
||||
}
|
||||
|
||||
model Payment {
|
||||
id String @id @default(cuid())
|
||||
invoiceId String
|
||||
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
||||
amount Decimal @db.Decimal(18, 2)
|
||||
currency String @default("IRR")
|
||||
method PaymentMethod @default(transfer)
|
||||
paidAt DateTime @default(now())
|
||||
notes String?
|
||||
installmentId String? @unique
|
||||
installment InvoiceInstallment? @relation(fields: [installmentId], references: [id], onDelete: SetNull)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([invoiceId, paidAt])
|
||||
}
|
||||
|
||||
model InvoiceInstallment {
|
||||
id String @id @default(cuid())
|
||||
invoiceId String
|
||||
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
||||
position Int @default(0)
|
||||
dueDate DateTime
|
||||
amount Decimal @db.Decimal(18, 2)
|
||||
currency String @default("IRR")
|
||||
status InstallmentStatus @default(pending)
|
||||
paidAt DateTime?
|
||||
payment Payment?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([invoiceId, position])
|
||||
@@index([invoiceId, dueDate])
|
||||
@@index([status, dueDate])
|
||||
}
|
||||
|
||||
model SalesGoal {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
/// null = هدف سازمانی / تیمی
|
||||
userId String?
|
||||
user User? @relation("SalesGoalUser", fields: [userId], references: [id], onDelete: Cascade)
|
||||
title String
|
||||
periodStart DateTime
|
||||
periodEnd DateTime
|
||||
targetAmount Decimal @db.Decimal(18, 2)
|
||||
currency String @default("IRR")
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, periodStart, periodEnd])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model ExchangeRate {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
/// ارز مبدأ؛ ۱ واحد این ارز = rateToBase واحد ارز پایه
|
||||
currency String
|
||||
rateToBase Decimal @db.Decimal(24, 6)
|
||||
updatedAt DateTime @updatedAt
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([organizationId, currency])
|
||||
@@index([organizationId])
|
||||
}
|
||||
|
||||
model Ticket {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
number String
|
||||
subject String
|
||||
description String?
|
||||
status TicketStatus @default(open)
|
||||
priority TicketPriority @default(normal)
|
||||
personId String?
|
||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
||||
companyId String?
|
||||
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
||||
dealId String?
|
||||
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
||||
assigneeId String?
|
||||
assignee User? @relation("TicketAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
|
||||
reporterId String?
|
||||
reporter User? @relation("TicketReporter", fields: [reporterId], references: [id], onDelete: SetNull)
|
||||
resolvedAt DateTime?
|
||||
/// مهلت پاسخ اول بر اساس اولویت
|
||||
slaDueAt DateTime?
|
||||
firstRespondedAt DateTime?
|
||||
csatScore Int?
|
||||
csatComment String?
|
||||
csatAt DateTime?
|
||||
messages TicketMessage[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([organizationId, number])
|
||||
@@index([organizationId, status, updatedAt])
|
||||
@@index([organizationId, slaDueAt])
|
||||
@@index([assigneeId])
|
||||
@@index([reporterId])
|
||||
@@index([personId])
|
||||
@@index([companyId])
|
||||
@@index([dealId])
|
||||
}
|
||||
|
||||
model TicketMessage {
|
||||
id String @id @default(cuid())
|
||||
ticketId String
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
authorId String?
|
||||
author User? @relation("TicketMessageAuthor", fields: [authorId], references: [id], onDelete: SetNull)
|
||||
body String
|
||||
isInternal Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([ticketId, createdAt])
|
||||
@@index([authorId])
|
||||
}
|
||||
|
||||
model FaqArticle {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
question String
|
||||
answer String
|
||||
category String?
|
||||
isPublished Boolean @default(true)
|
||||
position Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, isPublished, position])
|
||||
}
|
||||
|
||||
/// کد یکبارمصرف ورود پرتال مشتری (موبایل)
|
||||
model PortalOtp {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
mobile String
|
||||
code String
|
||||
expiresAt DateTime
|
||||
consumedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([organizationId, mobile, createdAt])
|
||||
@@index([expiresAt])
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user