feat: add prisma migrations for p1/digest models, hybrid AI, outbox, and org layer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
ALTER TYPE "RuleAction" ADD VALUE 'P1';
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "DigestConfig" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"tenantId" TEXT NOT NULL,
|
||||||
|
"targetGroupJid" TEXT NOT NULL,
|
||||||
|
"targetAccountId" TEXT NOT NULL,
|
||||||
|
"scheduleHour" INTEGER NOT NULL DEFAULT 20,
|
||||||
|
"scheduleMinute" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"lastSentAt" TIMESTAMP(3),
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "DigestConfig_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Digest" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"tenantId" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"messageIds" TEXT[],
|
||||||
|
"digestDate" TIMESTAMP(3) NOT NULL,
|
||||||
|
"sentAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "Digest_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "DigestConfig_tenantId_key" ON "DigestConfig"("tenantId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Digest_tenantId_idx" ON "Digest"("tenantId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Digest_tenantId_digestDate_key" ON "Digest"("tenantId", "digestDate");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "DigestConfig" ADD CONSTRAINT "DigestConfig_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Digest" ADD CONSTRAINT "Digest_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
-- Adding RAW and DNC values to MessageStatus enum.
|
||||||
|
-- NOTE: SET DEFAULT 'RAW' intentionally omitted — PostgreSQL cannot use new enum values
|
||||||
|
-- as column defaults in the same transaction. Status is always set explicitly in code.
|
||||||
|
|
||||||
|
ALTER TYPE "MessageStatus" ADD VALUE IF NOT EXISTS 'RAW';
|
||||||
|
ALTER TYPE "MessageStatus" ADD VALUE IF NOT EXISTS 'DNC';
|
||||||
|
|
||||||
|
-- AlterTable: add new columns to Message
|
||||||
|
ALTER TABLE "Message" ADD COLUMN IF NOT EXISTS "expiresAt" TIMESTAMP(3),
|
||||||
|
ADD COLUMN IF NOT EXISTS "quotedPlatformMsgId" TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS "threadId" TEXT;
|
||||||
|
|
||||||
|
-- CreateTable: Thread
|
||||||
|
CREATE TABLE IF NOT EXISTS "Thread" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"tenantId" TEXT NOT NULL,
|
||||||
|
"sourceGroupId" TEXT NOT NULL,
|
||||||
|
"lastActivityAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"messageCount" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"topic" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "Thread_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX IF NOT EXISTS "Thread_tenantId_idx" ON "Thread"("tenantId");
|
||||||
|
CREATE INDEX IF NOT EXISTS "Thread_sourceGroupId_lastActivityAt_idx" ON "Thread"("sourceGroupId", "lastActivityAt");
|
||||||
|
CREATE INDEX IF NOT EXISTS "Message_status_expiresAt_idx" ON "Message"("status", "expiresAt");
|
||||||
|
CREATE INDEX IF NOT EXISTS "Message_threadId_idx" ON "Message"("threadId");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Message" DROP CONSTRAINT IF EXISTS "Message_threadId_fkey";
|
||||||
|
ALTER TABLE "Message" ADD CONSTRAINT "Message_threadId_fkey" FOREIGN KEY ("threadId") REFERENCES "Thread"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE "Thread" DROP CONSTRAINT IF EXISTS "Thread_tenantId_fkey";
|
||||||
|
ALTER TABLE "Thread" ADD CONSTRAINT "Thread_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE "Thread" DROP CONSTRAINT IF EXISTS "Thread_sourceGroupId_fkey";
|
||||||
|
ALTER TABLE "Thread" ADD CONSTRAINT "Thread_sourceGroupId_fkey" FOREIGN KEY ("sourceGroupId") REFERENCES "Group"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "OutboxEvent" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"type" TEXT NOT NULL,
|
||||||
|
"payload" JSONB NOT NULL,
|
||||||
|
"attempts" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"lastError" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "OutboxEvent_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "OutboxEvent_attempts_createdAt_idx" ON "OutboxEvent"("attempts", "createdAt");
|
||||||
|
|
||||||
|
-- LISTEN/NOTIFY trigger: fires pg_notify('outbox_event', NEW.id) after each INSERT
|
||||||
|
-- The worker holds an open pg.Client with LISTEN outbox_event to receive these events.
|
||||||
|
-- AFTER INSERT ensures NOTIFY fires only after the transaction commits.
|
||||||
|
CREATE OR REPLACE FUNCTION notify_outbox_event()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
PERFORM pg_notify('outbox_event', NEW.id);
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER outbox_event_notify
|
||||||
|
AFTER INSERT ON "OutboxEvent"
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION notify_outbox_event();
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "OrgAdminRole" AS ENUM ('ORG_OWNER', 'ORG_ADMIN');
|
||||||
|
|
||||||
|
-- CreateTable: Organization
|
||||||
|
CREATE TABLE "Organization" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"slug" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"settings" JSONB NOT NULL DEFAULT '{}',
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Organization_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "Organization_slug_key" ON "Organization"("slug");
|
||||||
|
|
||||||
|
-- CreateTable: OrgAdmin
|
||||||
|
CREATE TABLE "OrgAdmin" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"organizationId" TEXT NOT NULL,
|
||||||
|
"email" TEXT NOT NULL,
|
||||||
|
"passwordHash" TEXT NOT NULL,
|
||||||
|
"name" TEXT,
|
||||||
|
"role" "OrgAdminRole" NOT NULL DEFAULT 'ORG_ADMIN',
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "OrgAdmin_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "OrgAdmin_organizationId_email_key" ON "OrgAdmin"("organizationId", "email");
|
||||||
|
CREATE INDEX "OrgAdmin_organizationId_idx" ON "OrgAdmin"("organizationId");
|
||||||
|
|
||||||
|
ALTER TABLE "OrgAdmin" ADD CONSTRAINT "OrgAdmin_organizationId_fkey"
|
||||||
|
FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- CreateTable: OrgRule
|
||||||
|
CREATE TABLE "OrgRule" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"organizationId" TEXT NOT NULL,
|
||||||
|
"matchType" "RuleMatchType" NOT NULL,
|
||||||
|
"matchValue" TEXT NOT NULL,
|
||||||
|
"action" "RuleAction" NOT NULL,
|
||||||
|
"priority" 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 "OrgRule_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "OrgRule_organizationId_matchType_matchValue_key" ON "OrgRule"("organizationId", "matchType", "matchValue");
|
||||||
|
CREATE INDEX "OrgRule_organizationId_isActive_idx" ON "OrgRule"("organizationId", "isActive");
|
||||||
|
|
||||||
|
ALTER TABLE "OrgRule" ADD CONSTRAINT "OrgRule_organizationId_fkey"
|
||||||
|
FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AlterTable: Tenant — add nullable organizationId FK
|
||||||
|
ALTER TABLE "Tenant" ADD COLUMN "organizationId" TEXT;
|
||||||
|
|
||||||
|
ALTER TABLE "Tenant" ADD CONSTRAINT "Tenant_organizationId_fkey"
|
||||||
|
FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
Reference in New Issue
Block a user