From ac13d24c2ce4ee5f850881ed5e9427d91923ad8b Mon Sep 17 00:00:00 2001 From: MOHAN Date: Wed, 22 Jul 2026 19:24:46 +0530 Subject: [PATCH] Add fresh database migration baseline --- .../migration.sql | 299 ++++++++++++++++++ .../migration.sql | 10 + 2 files changed, 309 insertions(+) create mode 100644 prisma/migrations/20260715000000_initial_core_schema/migration.sql create mode 100644 prisma/migrations/20260722191500_align_schema_after_baseline/migration.sql diff --git a/prisma/migrations/20260715000000_initial_core_schema/migration.sql b/prisma/migrations/20260715000000_initial_core_schema/migration.sql new file mode 100644 index 0000000..680a1fb --- /dev/null +++ b/prisma/migrations/20260715000000_initial_core_schema/migration.sql @@ -0,0 +1,299 @@ +-- Baseline schema required before the incremental LedgerOne migrations. +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "passwordHash" TEXT NOT NULL, + "fullName" TEXT, + "phone" TEXT, + "companyName" TEXT, + "addressLine1" TEXT, + "addressLine2" TEXT, + "city" TEXT, + "state" TEXT, + "postalCode" TEXT, + "country" TEXT, + "emailVerified" BOOLEAN NOT NULL DEFAULT false, + "twoFactorEnabled" BOOLEAN NOT NULL DEFAULT false, + "twoFactorSecret" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "SocialAccount" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "provider" TEXT NOT NULL, + "providerAccountId" TEXT NOT NULL, + "email" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + CONSTRAINT "SocialAccount_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "Account" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "institutionName" TEXT NOT NULL, + "accountType" TEXT NOT NULL, + "mask" TEXT, + "plaidAccessToken" TEXT, + "plaidItemId" TEXT, + "plaidAccountId" TEXT, + "tellerAccessToken" TEXT, + "tellerEnrollmentId" TEXT, + "tellerAccountId" TEXT, + "currentBalance" DECIMAL(65,30), + "availableBalance" DECIMAL(65,30), + "isoCurrencyCode" TEXT, + "lastBalanceSync" TIMESTAMP(3), + "lastTransactionSync" TIMESTAMP(3), + "lastSyncAttemptAt" TIMESTAMP(3), + "syncStatus" TEXT NOT NULL DEFAULT 'idle', + "lastSyncError" TEXT, + "syncConsecutiveFailures" INTEGER NOT NULL DEFAULT 0, + "plaidWebhookCode" TEXT, + "plaidWebhookAt" TIMESTAMP(3), + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + CONSTRAINT "Account_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "PlaidWebhookEvent" ( + "id" TEXT NOT NULL, + "itemId" TEXT, + "webhookType" TEXT NOT NULL, + "webhookCode" TEXT NOT NULL, + "payload" JSONB NOT NULL, + "status" TEXT NOT NULL DEFAULT 'received', + "error" TEXT, + "receivedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "processedAt" TIMESTAMP(3), + CONSTRAINT "PlaidWebhookEvent_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "TransactionRaw" ( + "id" TEXT NOT NULL, + "accountId" TEXT NOT NULL, + "bankTransactionId" TEXT NOT NULL, + "date" TIMESTAMP(3) NOT NULL, + "amount" DECIMAL(65,30) NOT NULL, + "description" TEXT NOT NULL, + "rawPayload" JSONB NOT NULL, + "ingestedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "source" TEXT NOT NULL, + CONSTRAINT "TransactionRaw_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "TransactionDerived" ( + "id" TEXT NOT NULL, + "rawTransactionId" TEXT NOT NULL, + "userCategory" TEXT, + "userNotes" TEXT, + "isHidden" BOOLEAN NOT NULL DEFAULT false, + "modifiedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "modifiedBy" TEXT NOT NULL, + CONSTRAINT "TransactionDerived_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "CsvImportMapping" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "headerSignature" TEXT NOT NULL, + "name" TEXT, + "mapping" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "lastUsedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "CsvImportMapping_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "Rule" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "priority" INTEGER NOT NULL, + "conditions" JSONB NOT NULL, + "actions" JSONB NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "Rule_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "RuleExecution" ( + "id" TEXT NOT NULL, + "ruleId" TEXT NOT NULL, + "transactionId" TEXT NOT NULL, + "executedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "result" JSONB NOT NULL, + CONSTRAINT "RuleExecution_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "ExportLog" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "filters" JSONB NOT NULL, + "rowCount" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "ExportLog_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "AuditLog" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "action" TEXT NOT NULL, + "metadata" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "AbuseEvent" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "eventType" TEXT NOT NULL, + "riskPoints" INTEGER NOT NULL, + "severity" TEXT NOT NULL, + "ipAddress" TEXT, + "userAgent" TEXT, + "metadata" JSONB NOT NULL DEFAULT '{}', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "AbuseEvent_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "GoogleConnection" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "googleEmail" TEXT NOT NULL, + "refreshToken" TEXT NOT NULL, + "accessToken" TEXT, + "spreadsheetId" TEXT, + "isConnected" BOOLEAN NOT NULL DEFAULT true, + "connectedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "lastSyncedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + CONSTRAINT "GoogleConnection_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "EmailVerificationToken" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "EmailVerificationToken_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "PasswordResetToken" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "usedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "PasswordResetToken_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "Session" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "ipHash" TEXT NOT NULL, + "userAgentHash" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "expiresAt" TIMESTAMP(3) NOT NULL, + "revokedAt" TIMESTAMP(3), + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "RefreshToken" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "sessionId" TEXT, + "tokenHash" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "revokedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "RefreshToken_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "Subscription" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "plan" TEXT NOT NULL DEFAULT 'free', + "stripeCustomerId" TEXT, + "stripeSubId" TEXT, + "currentPeriodEnd" TIMESTAMP(3), + "cancelAtPeriodEnd" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + CONSTRAINT "Subscription_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "TaxReturn" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "taxYear" INTEGER NOT NULL, + "filingType" TEXT NOT NULL, + "jurisdictions" JSONB NOT NULL, + "status" TEXT NOT NULL DEFAULT 'draft', + "summary" JSONB NOT NULL DEFAULT '{}', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + CONSTRAINT "TaxReturn_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE "TaxDocument" ( + "id" TEXT NOT NULL, + "taxReturnId" TEXT NOT NULL, + "docType" TEXT NOT NULL, + "metadata" JSONB NOT NULL DEFAULT '{}', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "TaxDocument_pkey" PRIMARY KEY ("id") +); + +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); +CREATE INDEX "SocialAccount_userId_idx" ON "SocialAccount"("userId"); +CREATE UNIQUE INDEX "SocialAccount_provider_providerAccountId_key" ON "SocialAccount"("provider", "providerAccountId"); +CREATE UNIQUE INDEX "Account_plaidAccountId_key" ON "Account"("plaidAccountId"); +CREATE UNIQUE INDEX "Account_tellerAccountId_key" ON "Account"("tellerAccountId"); +CREATE INDEX "Account_plaidItemId_idx" ON "Account"("plaidItemId"); +CREATE INDEX "Account_tellerEnrollmentId_idx" ON "Account"("tellerEnrollmentId"); +CREATE INDEX "PlaidWebhookEvent_itemId_receivedAt_idx" ON "PlaidWebhookEvent"("itemId", "receivedAt"); +CREATE INDEX "PlaidWebhookEvent_webhookType_webhookCode_idx" ON "PlaidWebhookEvent"("webhookType", "webhookCode"); +CREATE UNIQUE INDEX "TransactionRaw_bankTransactionId_key" ON "TransactionRaw"("bankTransactionId"); +CREATE UNIQUE INDEX "TransactionDerived_rawTransactionId_key" ON "TransactionDerived"("rawTransactionId"); +CREATE INDEX "CsvImportMapping_userId_lastUsedAt_idx" ON "CsvImportMapping"("userId", "lastUsedAt"); +CREATE UNIQUE INDEX "CsvImportMapping_userId_headerSignature_key" ON "CsvImportMapping"("userId", "headerSignature"); +CREATE INDEX "AbuseEvent_userId_createdAt_idx" ON "AbuseEvent"("userId", "createdAt"); +CREATE INDEX "AbuseEvent_eventType_createdAt_idx" ON "AbuseEvent"("eventType", "createdAt"); +CREATE UNIQUE INDEX "GoogleConnection_userId_key" ON "GoogleConnection"("userId"); +CREATE UNIQUE INDEX "EmailVerificationToken_userId_key" ON "EmailVerificationToken"("userId"); +CREATE UNIQUE INDEX "EmailVerificationToken_token_key" ON "EmailVerificationToken"("token"); +CREATE UNIQUE INDEX "PasswordResetToken_token_key" ON "PasswordResetToken"("token"); +CREATE INDEX "Session_userId_revokedAt_idx" ON "Session"("userId", "revokedAt"); +CREATE UNIQUE INDEX "RefreshToken_tokenHash_key" ON "RefreshToken"("tokenHash"); +CREATE INDEX "RefreshToken_sessionId_idx" ON "RefreshToken"("sessionId"); +CREATE UNIQUE INDEX "Subscription_userId_key" ON "Subscription"("userId"); + +ALTER TABLE "SocialAccount" ADD CONSTRAINT "SocialAccount_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "TransactionRaw" ADD CONSTRAINT "TransactionRaw_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "TransactionDerived" ADD CONSTRAINT "TransactionDerived_rawTransactionId_fkey" FOREIGN KEY ("rawTransactionId") REFERENCES "TransactionRaw"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "CsvImportMapping" ADD CONSTRAINT "CsvImportMapping_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "Rule" ADD CONSTRAINT "Rule_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "RuleExecution" ADD CONSTRAINT "RuleExecution_ruleId_fkey" FOREIGN KEY ("ruleId") REFERENCES "Rule"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "RuleExecution" ADD CONSTRAINT "RuleExecution_transactionId_fkey" FOREIGN KEY ("transactionId") REFERENCES "TransactionRaw"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "ExportLog" ADD CONSTRAINT "ExportLog_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "AbuseEvent" ADD CONSTRAINT "AbuseEvent_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; +ALTER TABLE "GoogleConnection" ADD CONSTRAINT "GoogleConnection_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "EmailVerificationToken" ADD CONSTRAINT "EmailVerificationToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "PasswordResetToken" ADD CONSTRAINT "PasswordResetToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "RefreshToken" ADD CONSTRAINT "RefreshToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "RefreshToken" ADD CONSTRAINT "RefreshToken_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "Session"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE "TaxReturn" ADD CONSTRAINT "TaxReturn_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "TaxDocument" ADD CONSTRAINT "TaxDocument_taxReturnId_fkey" FOREIGN KEY ("taxReturnId") REFERENCES "TaxReturn"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260722191500_align_schema_after_baseline/migration.sql b/prisma/migrations/20260722191500_align_schema_after_baseline/migration.sql new file mode 100644 index 0000000..611d261 --- /dev/null +++ b/prisma/migrations/20260722191500_align_schema_after_baseline/migration.sql @@ -0,0 +1,10 @@ +-- Align historical incremental migrations with the current Prisma schema. +DROP INDEX IF EXISTS "ExportDownloadToken_storageKey_idx"; + +ALTER TABLE "HouseholdGoal" + ALTER COLUMN "targetAmount" TYPE DECIMAL(65,30), + ALTER COLUMN "currentAmount" TYPE DECIMAL(65,30); + +ALTER TABLE "TransactionDerived" + ALTER COLUMN "splitMinePercent" TYPE DECIMAL(65,30), + ALTER COLUMN "splitYoursPercent" TYPE DECIMAL(65,30);