good forst commit

This commit is contained in:
2026-06-09 02:02:40 +05:30
parent 801c1d7121
commit 249d759e6a
215 changed files with 15425 additions and 1240 deletions
@@ -0,0 +1,101 @@
-- CreateEnum
CREATE TYPE "AdminRole" AS ENUM ('OWNER', 'ADMIN', 'VIEWER');
-- CreateEnum
CREATE TYPE "ActorType" AS ENUM ('ADMIN', 'SYSTEM', 'ADAPTER');
-- CreateTable: Tenant (must come first — referenced by everything else)
CREATE TABLE "Tenant" (
"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 "Tenant_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "Tenant_slug_key" ON "Tenant"("slug");
-- Insert default tenant so existing rows can be backfilled
INSERT INTO "Tenant" ("id", "slug", "name", "settings", "updatedAt")
VALUES ('default', 'default', 'Default Tenant', '{}', CURRENT_TIMESTAMP);
-- Add tenantId columns as nullable first
ALTER TABLE "Account" ADD COLUMN "tenantId" TEXT;
ALTER TABLE "Approval" ADD COLUMN "tenantId" TEXT;
ALTER TABLE "ConsentRecord" ADD COLUMN "tenantId" TEXT;
ALTER TABLE "Group" ADD COLUMN "tenantId" TEXT;
ALTER TABLE "Message" ADD COLUMN "tenantId" TEXT;
ALTER TABLE "SyncRoute" ADD COLUMN "tenantId" TEXT;
-- Backfill all existing rows to the default tenant
UPDATE "Account" SET "tenantId" = 'default';
UPDATE "Approval" SET "tenantId" = 'default';
UPDATE "ConsentRecord" SET "tenantId" = 'default';
UPDATE "Group" SET "tenantId" = 'default';
UPDATE "Message" SET "tenantId" = 'default';
UPDATE "SyncRoute" SET "tenantId" = 'default';
-- Now enforce NOT NULL
ALTER TABLE "Account" ALTER COLUMN "tenantId" SET NOT NULL;
ALTER TABLE "Approval" ALTER COLUMN "tenantId" SET NOT NULL;
ALTER TABLE "ConsentRecord" ALTER COLUMN "tenantId" SET NOT NULL;
ALTER TABLE "Group" ALTER COLUMN "tenantId" SET NOT NULL;
ALTER TABLE "Message" ALTER COLUMN "tenantId" SET NOT NULL;
ALTER TABLE "SyncRoute" ALTER COLUMN "tenantId" SET NOT NULL;
-- CreateTable: Admin (new — NOT NULL tenantId is fine, we'll seed default admin later)
CREATE TABLE "Admin" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"email" TEXT NOT NULL,
"passwordHash" TEXT NOT NULL,
"role" "AdminRole" NOT NULL DEFAULT 'ADMIN',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Admin_pkey" PRIMARY KEY ("id")
);
-- CreateTable: AuditEvent (new — NOT NULL tenantId is fine)
CREATE TABLE "AuditEvent" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"actorType" "ActorType" NOT NULL,
"actorId" TEXT,
"action" TEXT NOT NULL,
"resourceType" TEXT NOT NULL,
"resourceId" TEXT NOT NULL,
"payload" JSONB NOT NULL DEFAULT '{}',
"traceId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "AuditEvent_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "Admin_tenantId_idx" ON "Admin"("tenantId");
CREATE UNIQUE INDEX "Admin_tenantId_email_key" ON "Admin"("tenantId", "email");
CREATE INDEX "AuditEvent_tenantId_createdAt_idx" ON "AuditEvent"("tenantId", "createdAt");
CREATE INDEX "AuditEvent_resourceType_resourceId_idx" ON "AuditEvent"("resourceType", "resourceId");
CREATE INDEX "Account_tenantId_idx" ON "Account"("tenantId");
CREATE INDEX "Approval_tenantId_idx" ON "Approval"("tenantId");
CREATE INDEX "ConsentRecord_tenantId_idx" ON "ConsentRecord"("tenantId");
CREATE INDEX "Group_tenantId_idx" ON "Group"("tenantId");
CREATE INDEX "Message_tenantId_idx" ON "Message"("tenantId");
CREATE INDEX "SyncRoute_tenantId_idx" ON "SyncRoute"("tenantId");
-- AddForeignKey
ALTER TABLE "Admin" ADD CONSTRAINT "Admin_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "AuditEvent" ADD CONSTRAINT "AuditEvent_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "Group" ADD CONSTRAINT "Group_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "Message" ADD CONSTRAINT "Message_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "Approval" ADD CONSTRAINT "Approval_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "SyncRoute" ADD CONSTRAINT "SyncRoute_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "ConsentRecord" ADD CONSTRAINT "ConsentRecord_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "Account" ADD CONSTRAINT "Account_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -0,0 +1,201 @@
-- CreateEnum
CREATE TYPE "GroupClaimStatus" AS ENUM ('PENDING_CLAIM', 'CLAIMED', 'RELEASED', 'EXPIRED');
-- CreateEnum
CREATE TYPE "ConsentScope" AS ENUM ('INGEST', 'ARCHIVE', 'REPLICATE', 'DISPLAY');
-- CreateEnum
CREATE TYPE "ConsentStatus" AS ENUM ('GRANTED', 'REVOKED');
-- CreateEnum
CREATE TYPE "MemberOptOutReason" AS ENUM ('STOP_KEYWORD', 'SELF_PORTAL', 'ADMIN_ACTION');
-- AlterEnum
ALTER TYPE "AccountStatus" ADD VALUE 'PAIRING';
-- AlterEnum
ALTER TYPE "ActorType" ADD VALUE 'MEMBER';
-- DropForeignKey
ALTER TABLE "Account" DROP CONSTRAINT "Account_tenantId_fkey";
-- DropForeignKey
ALTER TABLE "Group" DROP CONSTRAINT "Group_tenantId_fkey";
-- DropIndex
DROP INDEX "Account_tenantId_idx";
-- DropIndex
DROP INDEX "ConsentRecord_groupId_memberJid_consentType_key";
-- DropIndex
DROP INDEX "ConsentRecord_tenantId_idx";
-- AlterTable
ALTER TABLE "Account" DROP COLUMN "tenantId",
ADD COLUMN "isBot" BOOLEAN NOT NULL DEFAULT true,
ADD COLUMN "pairingExpiresAt" TIMESTAMP(3),
ADD COLUMN "pairingToken" TEXT;
-- AlterTable
ALTER TABLE "ConsentRecord" DROP COLUMN "consentType",
DROP COLUMN "grantedAt",
DROP COLUMN "memberJid",
ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "effectiveAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "policyVersion" TEXT NOT NULL,
ADD COLUMN "proofEventId" TEXT NOT NULL,
ADD COLUMN "retentionDays" INTEGER NOT NULL DEFAULT 90,
ADD COLUMN "scopes" "ConsentScope"[],
ADD COLUMN "status" "ConsentStatus" NOT NULL DEFAULT 'GRANTED',
ADD COLUMN "userId" TEXT NOT NULL;
-- AlterTable
ALTER TABLE "Group" ADD COLUMN "claimExpiresAt" TIMESTAMP(3),
ADD COLUMN "claimStatus" "GroupClaimStatus" NOT NULL DEFAULT 'PENDING_CLAIM',
ADD COLUMN "claimedAt" TIMESTAMP(3),
ADD COLUMN "claimedByAdminId" TEXT,
ALTER COLUMN "tenantId" DROP NOT NULL;
-- AlterTable
ALTER TABLE "Message" ADD COLUMN "senderTowerUserId" TEXT;
-- CreateTable
CREATE TABLE "TenantBot" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"accountId" TEXT NOT NULL,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "TenantBot_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "TowerUser" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"phoneHash" TEXT NOT NULL,
"jid" TEXT NOT NULL,
"displayName" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "TowerUser_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "TowerSession" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"tokenHash" TEXT NOT NULL,
"expiresAt" TIMESTAMP(3) NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "TowerSession_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "MemberOptOut" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"groupId" TEXT,
"reason" "MemberOptOutReason" NOT NULL,
"notes" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "MemberOptOut_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "TenantBot_accountId_idx" ON "TenantBot"("accountId");
-- CreateIndex
CREATE UNIQUE INDEX "TenantBot_tenantId_accountId_key" ON "TenantBot"("tenantId", "accountId");
-- CreateIndex
CREATE INDEX "TowerUser_phoneHash_idx" ON "TowerUser"("phoneHash");
-- CreateIndex
CREATE INDEX "TowerUser_tenantId_idx" ON "TowerUser"("tenantId");
-- CreateIndex
CREATE INDEX "TowerUser_jid_idx" ON "TowerUser"("jid");
-- CreateIndex
CREATE UNIQUE INDEX "TowerUser_tenantId_phoneHash_key" ON "TowerUser"("tenantId", "phoneHash");
-- CreateIndex
CREATE UNIQUE INDEX "TowerSession_tokenHash_key" ON "TowerSession"("tokenHash");
-- CreateIndex
CREATE INDEX "TowerSession_userId_idx" ON "TowerSession"("userId");
-- CreateIndex
CREATE INDEX "TowerSession_expiresAt_idx" ON "TowerSession"("expiresAt");
-- CreateIndex
CREATE INDEX "MemberOptOut_tenantId_userId_idx" ON "MemberOptOut"("tenantId", "userId");
-- CreateIndex
CREATE INDEX "MemberOptOut_groupId_idx" ON "MemberOptOut"("groupId");
-- CreateIndex
CREATE INDEX "MemberOptOut_userId_idx" ON "MemberOptOut"("userId");
-- CreateIndex
CREATE UNIQUE INDEX "Account_pairingToken_key" ON "Account"("pairingToken");
-- CreateIndex
CREATE INDEX "Account_isBot_idx" ON "Account"("isBot");
-- CreateIndex
CREATE INDEX "Account_status_idx" ON "Account"("status");
-- CreateIndex
CREATE INDEX "ConsentRecord_tenantId_groupId_userId_idx" ON "ConsentRecord"("tenantId", "groupId", "userId");
-- CreateIndex
CREATE INDEX "ConsentRecord_status_idx" ON "ConsentRecord"("status");
-- CreateIndex
CREATE INDEX "ConsentRecord_userId_idx" ON "ConsentRecord"("userId");
-- CreateIndex
CREATE INDEX "Group_claimStatus_idx" ON "Group"("claimStatus");
-- CreateIndex
CREATE INDEX "Message_senderTowerUserId_idx" ON "Message"("senderTowerUserId");
-- AddForeignKey
ALTER TABLE "TenantBot" ADD CONSTRAINT "TenantBot_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "TenantBot" ADD CONSTRAINT "TenantBot_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Group" ADD CONSTRAINT "Group_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Group" ADD CONSTRAINT "Group_claimedByAdminId_fkey" FOREIGN KEY ("claimedByAdminId") REFERENCES "Admin"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Message" ADD CONSTRAINT "Message_senderTowerUserId_fkey" FOREIGN KEY ("senderTowerUserId") REFERENCES "TowerUser"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "TowerUser" ADD CONSTRAINT "TowerUser_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "TowerSession" ADD CONSTRAINT "TowerSession_userId_fkey" FOREIGN KEY ("userId") REFERENCES "TowerUser"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ConsentRecord" ADD CONSTRAINT "ConsentRecord_userId_fkey" FOREIGN KEY ("userId") REFERENCES "TowerUser"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "MemberOptOut" ADD CONSTRAINT "MemberOptOut_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "MemberOptOut" ADD CONSTRAINT "MemberOptOut_userId_fkey" FOREIGN KEY ("userId") REFERENCES "TowerUser"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -0,0 +1,28 @@
-- CreateTable
CREATE TABLE "OtpChallenge" (
"id" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"jid" TEXT NOT NULL,
"phoneHash" TEXT NOT NULL,
"code" TEXT NOT NULL,
"scopes" "ConsentScope"[],
"retentionDays" INTEGER NOT NULL DEFAULT 90,
"policyVersion" TEXT NOT NULL,
"groupId" TEXT NOT NULL,
"expiresAt" TIMESTAMP(3) NOT NULL,
"consumedAt" TIMESTAMP(3),
"sentAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "OtpChallenge_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "OtpChallenge_tenantId_jid_idx" ON "OtpChallenge"("tenantId", "jid");
-- CreateIndex
CREATE INDEX "OtpChallenge_expiresAt_idx" ON "OtpChallenge"("expiresAt");
-- CreateIndex
CREATE INDEX "OtpChallenge_sentAt_idx" ON "OtpChallenge"("sentAt");
@@ -0,0 +1,18 @@
-- AlterTable
ALTER TABLE "Tenant" ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true,
ADD COLUMN "isForwardingPaused" BOOLEAN NOT NULL DEFAULT false;
-- CreateTable
CREATE TABLE "SuperAdmin" (
"id" TEXT NOT NULL,
"email" TEXT NOT NULL,
"passwordHash" TEXT NOT NULL,
"name" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "SuperAdmin_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "SuperAdmin_email_key" ON "SuperAdmin"("email");
@@ -0,0 +1,32 @@
-- CreateEnum
CREATE TYPE "RuleMatchType" AS ENUM ('HASHTAG', 'PREFIX', 'REACTION_EMOJI');
-- CreateEnum
CREATE TYPE "RuleAction" AS ENUM ('FLAG', 'AUTO_APPROVE', 'SKIP', 'REJECT');
-- CreateTable
CREATE TABLE "TenantRule" (
"id" TEXT NOT NULL,
"tenantId" 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 "TenantRule_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "TenantRule_tenantId_isActive_idx" ON "TenantRule"("tenantId", "isActive");
-- CreateIndex
CREATE INDEX "TenantRule_tenantId_matchType_idx" ON "TenantRule"("tenantId", "matchType");
-- CreateIndex
CREATE UNIQUE INDEX "TenantRule_tenantId_matchType_matchValue_key" ON "TenantRule"("tenantId", "matchType", "matchValue");
-- AddForeignKey
ALTER TABLE "TenantRule" ADD CONSTRAINT "TenantRule_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -0,0 +1,38 @@
-- CreateTable: GroupClaimToken
CREATE TABLE "GroupClaimToken" (
"id" TEXT NOT NULL,
"groupId" TEXT NOT NULL,
"token" TEXT NOT NULL,
"creatorJid" TEXT NOT NULL,
"expiresAt" TIMESTAMP(3) NOT NULL,
"consumedAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "GroupClaimToken_pkey" PRIMARY KEY ("id")
);
-- CreateTable: GroupAccess
CREATE TABLE "GroupAccess" (
"id" TEXT NOT NULL,
"groupId" TEXT NOT NULL,
"tenantId" TEXT NOT NULL,
"grantedBy" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "GroupAccess_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "GroupClaimToken_token_key" ON "GroupClaimToken"("token");
CREATE INDEX "GroupClaimToken_expiresAt_idx" ON "GroupClaimToken"("expiresAt");
-- CreateIndex
CREATE UNIQUE INDEX "GroupAccess_groupId_tenantId_key" ON "GroupAccess"("groupId", "tenantId");
CREATE INDEX "GroupAccess_tenantId_idx" ON "GroupAccess"("tenantId");
-- AddForeignKey
ALTER TABLE "GroupClaimToken" ADD CONSTRAINT "GroupClaimToken_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Group"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "GroupAccess" ADD CONSTRAINT "GroupAccess_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Group"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "GroupAccess" ADD CONSTRAINT "GroupAccess_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE RESTRICT ON UPDATE CASCADE;