more package declarations
This commit is contained in:
@@ -0,0 +1,655 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "UserRole" AS ENUM ('user', 'family_admin', 'family_member', 'support');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "FamilyMemberRole" AS ENUM ('owner', 'admin', 'member');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SubscriptionTier" AS ENUM ('basic', 'plus', 'premium');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SubscriptionStatus" AS ENUM ('active', 'past_due', 'canceled', 'unpaid', 'trialing');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "WatchlistType" AS ENUM ('email', 'phoneNumber', 'ssn', 'address', 'domain');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ExposureSource" AS ENUM ('hibp', 'securityTrails', 'censys', 'darkWebForum', 'shodan', 'honeypot');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ExposureSeverity" AS ENUM ('info', 'warning', 'critical');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AlertType" AS ENUM ('exposure_detected', 'exposure_resolved', 'scan_complete', 'subscription_changed', 'system_warning');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AlertSeverity" AS ENUM ('info', 'warning', 'critical');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AlertChannel" AS ENUM ('email', 'push', 'sms');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "FeedbackType" AS ENUM ('initial_detection', 'user_confirmation', 'user_rejection', 'auto_learned');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "RuleType" AS ENUM ('phoneNumber', 'areaCode', 'prefix', 'pattern', 'reputation');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "RuleAction" AS ENUM ('block', 'flag', 'allow', 'challenge');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PropertyChangeType" AS ENUM ('ownership_transfer', 'deed_change', 'lien_filing', 'tax_change', 'assessment_change');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PropertyChangeSeverity" AS ENUM ('info', 'warning', 'critical');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"emailVerified" TIMESTAMP(3),
|
||||
"name" TEXT,
|
||||
"image" TEXT,
|
||||
"role" "UserRole" NOT NULL DEFAULT 'user',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Account" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"provider" TEXT NOT NULL,
|
||||
"providerAccountId" TEXT NOT NULL,
|
||||
"access_token" TEXT,
|
||||
"refresh_token" TEXT,
|
||||
"expires_at" INTEGER,
|
||||
"token_type" TEXT,
|
||||
"scope" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"sessionToken" TEXT NOT NULL,
|
||||
"expires" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FamilyGroup" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"ownerId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "FamilyGroup_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FamilyGroupMember" (
|
||||
"id" TEXT NOT NULL,
|
||||
"groupId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"role" "FamilyMemberRole" NOT NULL DEFAULT 'member',
|
||||
"joinedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "FamilyGroupMember_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Subscription" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"familyGroupId" TEXT,
|
||||
"stripeId" TEXT,
|
||||
"tier" "SubscriptionTier" NOT NULL DEFAULT 'basic',
|
||||
"status" "SubscriptionStatus" NOT NULL DEFAULT 'active',
|
||||
"currentPeriodStart" TIMESTAMP(3) NOT NULL,
|
||||
"currentPeriodEnd" TIMESTAMP(3) NOT NULL,
|
||||
"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")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "WatchlistItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"subscriptionId" TEXT NOT NULL,
|
||||
"type" "WatchlistType" NOT NULL,
|
||||
"value" TEXT NOT NULL,
|
||||
"hash" TEXT NOT NULL,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "WatchlistItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Exposure" (
|
||||
"id" TEXT NOT NULL,
|
||||
"subscriptionId" TEXT NOT NULL,
|
||||
"watchlistItemId" TEXT,
|
||||
"source" "ExposureSource" NOT NULL,
|
||||
"dataType" "WatchlistType" NOT NULL,
|
||||
"identifier" TEXT NOT NULL,
|
||||
"identifierHash" TEXT NOT NULL,
|
||||
"severity" "ExposureSeverity" NOT NULL DEFAULT 'info',
|
||||
"metadata" JSONB,
|
||||
"isFirstTime" BOOLEAN NOT NULL DEFAULT false,
|
||||
"detectedAt" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Exposure_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Alert" (
|
||||
"id" TEXT NOT NULL,
|
||||
"subscriptionId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"exposureId" TEXT,
|
||||
"type" "AlertType" NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"message" TEXT NOT NULL,
|
||||
"severity" "AlertSeverity" NOT NULL DEFAULT 'info',
|
||||
"isRead" BOOLEAN NOT NULL DEFAULT false,
|
||||
"readAt" TIMESTAMP(3),
|
||||
"channel" "AlertChannel"[],
|
||||
"propertyChangeId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Alert_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "VoiceEnrollment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"voiceHash" TEXT NOT NULL,
|
||||
"audioMetadata" JSONB,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "VoiceEnrollment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "VoiceAnalysis" (
|
||||
"id" TEXT NOT NULL,
|
||||
"enrollmentId" TEXT,
|
||||
"userId" TEXT NOT NULL,
|
||||
"audioHash" TEXT NOT NULL,
|
||||
"isSynthetic" BOOLEAN NOT NULL,
|
||||
"confidence" DOUBLE PRECISION NOT NULL,
|
||||
"analysisResult" JSONB NOT NULL,
|
||||
"audioUrl" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "VoiceAnalysis_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SpamFeedback" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"phoneNumber" TEXT NOT NULL,
|
||||
"phoneNumberHash" TEXT NOT NULL,
|
||||
"isSpam" BOOLEAN NOT NULL,
|
||||
"confidence" DOUBLE PRECISION,
|
||||
"feedbackType" "FeedbackType" NOT NULL,
|
||||
"metadata" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SpamFeedback_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SpamRule" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"isGlobal" BOOLEAN NOT NULL DEFAULT false,
|
||||
"ruleType" "RuleType" NOT NULL,
|
||||
"pattern" 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 "SpamRule_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AuditLog" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"action" TEXT NOT NULL,
|
||||
"resource" TEXT NOT NULL,
|
||||
"resourceId" TEXT,
|
||||
"changes" JSONB,
|
||||
"metadata" JSONB,
|
||||
"ipAddress" TEXT,
|
||||
"userAgent" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "KPISnapshot" (
|
||||
"id" TEXT NOT NULL,
|
||||
"date" TIMESTAMP(3) NOT NULL,
|
||||
"metricName" TEXT NOT NULL,
|
||||
"metricValue" DOUBLE PRECISION NOT NULL,
|
||||
"metadata" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "KPISnapshot_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "WaitlistEntry" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"name" TEXT,
|
||||
"source" TEXT,
|
||||
"tier" "SubscriptionTier",
|
||||
"utmSource" TEXT,
|
||||
"utmMedium" TEXT,
|
||||
"utmCampaign" TEXT,
|
||||
"metadata" JSONB,
|
||||
"convertedAt" TIMESTAMP(3),
|
||||
"convertedToUserId" TEXT,
|
||||
"convertedToSubscriptionId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "WaitlistEntry_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BlogPost" (
|
||||
"id" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"excerpt" TEXT,
|
||||
"content" TEXT NOT NULL,
|
||||
"authorName" TEXT,
|
||||
"coverImageUrl" TEXT,
|
||||
"tags" TEXT[],
|
||||
"published" BOOLEAN NOT NULL DEFAULT false,
|
||||
"publishedAt" TIMESTAMP(3),
|
||||
"viewCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "BlogPost_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PropertyWatchlistItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"subscriptionId" TEXT NOT NULL,
|
||||
"address" TEXT NOT NULL,
|
||||
"parcelId" TEXT NOT NULL,
|
||||
"ownerName" TEXT NOT NULL,
|
||||
"streetAddress" TEXT NOT NULL,
|
||||
"city" TEXT NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"zipCode" TEXT NOT NULL,
|
||||
"latitude" DOUBLE PRECISION,
|
||||
"longitude" DOUBLE PRECISION,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PropertyWatchlistItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PropertySnapshot" (
|
||||
"id" TEXT NOT NULL,
|
||||
"propertyWatchlistItemId" TEXT NOT NULL,
|
||||
"subscriptionId" TEXT NOT NULL,
|
||||
"ownerName" TEXT NOT NULL,
|
||||
"ownerAddress" TEXT,
|
||||
"assessmentValue" INTEGER,
|
||||
"assessedYear" INTEGER,
|
||||
"taxAmount" DOUBLE PRECISION,
|
||||
"taxYear" INTEGER,
|
||||
"lienData" JSONB,
|
||||
"deedData" JSONB,
|
||||
"metadata" JSONB,
|
||||
"snapshotDate" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PropertySnapshot_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PropertyChange" (
|
||||
"id" TEXT NOT NULL,
|
||||
"propertyWatchlistItemId" TEXT,
|
||||
"subscriptionId" TEXT NOT NULL,
|
||||
"snapshotId" TEXT,
|
||||
"changeType" "PropertyChangeType" NOT NULL,
|
||||
"severity" "PropertyChangeSeverity" NOT NULL DEFAULT 'info',
|
||||
"previousValue" JSONB,
|
||||
"newValue" JSONB,
|
||||
"diff" JSONB,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"isResolved" BOOLEAN NOT NULL DEFAULT false,
|
||||
"resolvedAt" TIMESTAMP(3),
|
||||
"resolvedByUserId" TEXT,
|
||||
"detectedAt" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PropertyChange_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "User_email_idx" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "User_role_idx" ON "User"("role");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Account_userId_idx" ON "Account"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Account_userId_provider_providerAccountId_key" ON "Account"("userId", "provider", "providerAccountId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Session_sessionToken_idx" ON "Session"("sessionToken");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Session_userId_idx" ON "Session"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FamilyGroup_ownerId_idx" ON "FamilyGroup"("ownerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FamilyGroup_name_idx" ON "FamilyGroup"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FamilyGroupMember_groupId_idx" ON "FamilyGroupMember"("groupId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FamilyGroupMember_userId_idx" ON "FamilyGroupMember"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "FamilyGroupMember_groupId_userId_key" ON "FamilyGroupMember"("groupId", "userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Subscription_stripeId_key" ON "Subscription"("stripeId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Subscription_userId_idx" ON "Subscription"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Subscription_familyGroupId_idx" ON "Subscription"("familyGroupId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Subscription_stripeId_idx" ON "Subscription"("stripeId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Subscription_tier_idx" ON "Subscription"("tier");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "WatchlistItem_subscriptionId_idx" ON "WatchlistItem"("subscriptionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "WatchlistItem_type_idx" ON "WatchlistItem"("type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "WatchlistItem_hash_idx" ON "WatchlistItem"("hash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "WatchlistItem_subscriptionId_type_hash_key" ON "WatchlistItem"("subscriptionId", "type", "hash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Exposure_subscriptionId_idx" ON "Exposure"("subscriptionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Exposure_watchlistItemId_idx" ON "Exposure"("watchlistItemId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Exposure_source_idx" ON "Exposure"("source");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Exposure_severity_idx" ON "Exposure"("severity");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Exposure_detectedAt_idx" ON "Exposure"("detectedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Alert_subscriptionId_idx" ON "Alert"("subscriptionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Alert_userId_idx" ON "Alert"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Alert_isRead_idx" ON "Alert"("isRead");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Alert_createdAt_idx" ON "Alert"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VoiceEnrollment_userId_idx" ON "VoiceEnrollment"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VoiceEnrollment_voiceHash_idx" ON "VoiceEnrollment"("voiceHash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VoiceAnalysis_userId_idx" ON "VoiceAnalysis"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VoiceAnalysis_enrollmentId_idx" ON "VoiceAnalysis"("enrollmentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VoiceAnalysis_audioHash_idx" ON "VoiceAnalysis"("audioHash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SpamFeedback_userId_idx" ON "SpamFeedback"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SpamFeedback_phoneNumberHash_idx" ON "SpamFeedback"("phoneNumberHash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SpamFeedback_isSpam_idx" ON "SpamFeedback"("isSpam");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SpamRule_userId_idx" ON "SpamRule"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SpamRule_isGlobal_idx" ON "SpamRule"("isGlobal");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SpamRule_ruleType_idx" ON "SpamRule"("ruleType");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AuditLog_userId_idx" ON "AuditLog"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AuditLog_action_idx" ON "AuditLog"("action");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AuditLog_resource_idx" ON "AuditLog"("resource");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AuditLog_createdAt_idx" ON "AuditLog"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "KPISnapshot_date_key" ON "KPISnapshot"("date");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "KPISnapshot_metricName_idx" ON "KPISnapshot"("metricName");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "KPISnapshot_date_idx" ON "KPISnapshot"("date");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "WaitlistEntry_email_idx" ON "WaitlistEntry"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "WaitlistEntry_source_idx" ON "WaitlistEntry"("source");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "WaitlistEntry_createdAt_idx" ON "WaitlistEntry"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "BlogPost_slug_key" ON "BlogPost"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "BlogPost_slug_idx" ON "BlogPost"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "BlogPost_published_publishedAt_idx" ON "BlogPost"("published", "publishedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "BlogPost_tags_idx" ON "BlogPost"("tags");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyWatchlistItem_subscriptionId_idx" ON "PropertyWatchlistItem"("subscriptionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyWatchlistItem_parcelId_idx" ON "PropertyWatchlistItem"("parcelId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyWatchlistItem_address_idx" ON "PropertyWatchlistItem"("address");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "PropertyWatchlistItem_subscriptionId_parcelId_key" ON "PropertyWatchlistItem"("subscriptionId", "parcelId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertySnapshot_propertyWatchlistItemId_idx" ON "PropertySnapshot"("propertyWatchlistItemId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertySnapshot_subscriptionId_idx" ON "PropertySnapshot"("subscriptionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertySnapshot_snapshotDate_idx" ON "PropertySnapshot"("snapshotDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyChange_propertyWatchlistItemId_idx" ON "PropertyChange"("propertyWatchlistItemId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyChange_subscriptionId_idx" ON "PropertyChange"("subscriptionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyChange_changeType_idx" ON "PropertyChange"("changeType");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyChange_severity_idx" ON "PropertyChange"("severity");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyChange_detectedAt_idx" ON "PropertyChange"("detectedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PropertyChange_isResolved_idx" ON "PropertyChange"("isResolved");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FamilyGroup" ADD CONSTRAINT "FamilyGroup_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FamilyGroupMember" ADD CONSTRAINT "FamilyGroupMember_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "FamilyGroup"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FamilyGroupMember" ADD CONSTRAINT "FamilyGroupMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_familyGroupId_fkey" FOREIGN KEY ("familyGroupId") REFERENCES "FamilyGroup"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "WatchlistItem" ADD CONSTRAINT "WatchlistItem_subscriptionId_fkey" FOREIGN KEY ("subscriptionId") REFERENCES "Subscription"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Exposure" ADD CONSTRAINT "Exposure_subscriptionId_fkey" FOREIGN KEY ("subscriptionId") REFERENCES "Subscription"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Exposure" ADD CONSTRAINT "Exposure_watchlistItemId_fkey" FOREIGN KEY ("watchlistItemId") REFERENCES "WatchlistItem"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Alert" ADD CONSTRAINT "Alert_subscriptionId_fkey" FOREIGN KEY ("subscriptionId") REFERENCES "Subscription"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Alert" ADD CONSTRAINT "Alert_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Alert" ADD CONSTRAINT "Alert_exposureId_fkey" FOREIGN KEY ("exposureId") REFERENCES "Exposure"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Alert" ADD CONSTRAINT "Alert_propertyChangeId_fkey" FOREIGN KEY ("propertyChangeId") REFERENCES "PropertyChange"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "VoiceEnrollment" ADD CONSTRAINT "VoiceEnrollment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "VoiceAnalysis" ADD CONSTRAINT "VoiceAnalysis_enrollmentId_fkey" FOREIGN KEY ("enrollmentId") REFERENCES "VoiceEnrollment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "VoiceAnalysis" ADD CONSTRAINT "VoiceAnalysis_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SpamFeedback" ADD CONSTRAINT "SpamFeedback_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SpamRule" ADD CONSTRAINT "SpamRule_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PropertyWatchlistItem" ADD CONSTRAINT "PropertyWatchlistItem_subscriptionId_fkey" FOREIGN KEY ("subscriptionId") REFERENCES "Subscription"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PropertySnapshot" ADD CONSTRAINT "PropertySnapshot_propertyWatchlistItemId_fkey" FOREIGN KEY ("propertyWatchlistItemId") REFERENCES "PropertyWatchlistItem"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PropertySnapshot" ADD CONSTRAINT "PropertySnapshot_subscriptionId_fkey" FOREIGN KEY ("subscriptionId") REFERENCES "Subscription"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PropertyChange" ADD CONSTRAINT "PropertyChange_propertyWatchlistItemId_fkey" FOREIGN KEY ("propertyWatchlistItemId") REFERENCES "PropertyWatchlistItem"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PropertyChange" ADD CONSTRAINT "PropertyChange_subscriptionId_fkey" FOREIGN KEY ("subscriptionId") REFERENCES "Subscription"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PropertyChange" ADD CONSTRAINT "PropertyChange_snapshotId_fkey" FOREIGN KEY ("snapshotId") REFERENCES "PropertySnapshot"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
3
packages/shared-db/prisma/migrations/migration_lock.toml
Normal file
3
packages/shared-db/prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
@@ -21,22 +21,22 @@ model User {
|
||||
name String?
|
||||
image String?
|
||||
role UserRole @default(user)
|
||||
|
||||
|
||||
// Relationships
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
familyGroups FamilyGroupMember[]
|
||||
familyGroupOwned FamilyGroup[] @relation("FamilyGroupOwner")
|
||||
subscriptions Subscription[]
|
||||
alerts Alert[]
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
familyGroups FamilyGroupMember[]
|
||||
familyGroupOwned FamilyGroup[] @relation("FamilyGroupOwner")
|
||||
subscriptions Subscription[]
|
||||
alerts Alert[]
|
||||
voiceEnrollments VoiceEnrollment[]
|
||||
voiceAnalyses VoiceAnalysis[]
|
||||
spamFeedback SpamFeedback[]
|
||||
spamRules SpamRule[]
|
||||
|
||||
voiceAnalyses VoiceAnalysis[]
|
||||
spamFeedback SpamFeedback[]
|
||||
spamRules SpamRule[]
|
||||
|
||||
// Audit
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([email])
|
||||
@@index([role])
|
||||
@@ -50,7 +50,7 @@ enum UserRole {
|
||||
}
|
||||
|
||||
model Account {
|
||||
id String @id @default(uuid())
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
provider String
|
||||
providerAccountId String
|
||||
@@ -59,11 +59,11 @@ model Account {
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([userId, provider, providerAccountId])
|
||||
@@index([userId])
|
||||
@@ -74,11 +74,11 @@ model Session {
|
||||
userId String
|
||||
sessionToken String @unique
|
||||
expires DateTime
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([sessionToken])
|
||||
@@index([userId])
|
||||
@@ -89,30 +89,30 @@ model Session {
|
||||
// ============================================
|
||||
|
||||
model FamilyGroup {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
ownerId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
owner User @relation("FamilyGroupOwner", fields: [ownerId], references: [id])
|
||||
members FamilyGroupMember[]
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
ownerId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
owner User @relation("FamilyGroupOwner", fields: [ownerId], references: [id])
|
||||
members FamilyGroupMember[]
|
||||
subscriptions Subscription[]
|
||||
|
||||
|
||||
@@index([ownerId])
|
||||
@@index([name])
|
||||
}
|
||||
|
||||
model FamilyGroupMember {
|
||||
id String @id @default(uuid())
|
||||
groupId String
|
||||
userId String
|
||||
role FamilyMemberRole @default(member)
|
||||
joinedAt DateTime @default(now())
|
||||
|
||||
group FamilyGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
id String @id @default(uuid())
|
||||
groupId String
|
||||
userId String
|
||||
role FamilyMemberRole @default(member)
|
||||
joinedAt DateTime @default(now())
|
||||
|
||||
group FamilyGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -128,25 +128,28 @@ enum FamilyMemberRole {
|
||||
}
|
||||
|
||||
model Subscription {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
familyGroupId String?
|
||||
stripeId String? @unique
|
||||
tier SubscriptionTier @default(basic)
|
||||
status SubscriptionStatus @default(active)
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
familyGroupId String?
|
||||
stripeId String? @unique
|
||||
tier SubscriptionTier @default(basic)
|
||||
status SubscriptionStatus @default(active)
|
||||
currentPeriodStart DateTime
|
||||
currentPeriodEnd DateTime
|
||||
cancelAtPeriodEnd Boolean @default(false)
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
familyGroup FamilyGroup? @relation(fields: [familyGroupId], references: [id])
|
||||
|
||||
watchlistItems WatchlistItem[]
|
||||
exposures Exposure[]
|
||||
alerts Alert[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
currentPeriodEnd DateTime
|
||||
cancelAtPeriodEnd Boolean @default(false)
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
familyGroup FamilyGroup? @relation(fields: [familyGroupId], references: [id])
|
||||
|
||||
watchlistItems WatchlistItem[]
|
||||
exposures Exposure[]
|
||||
alerts Alert[]
|
||||
propertyWatchlistItems PropertyWatchlistItem[]
|
||||
propertySnapshots PropertySnapshot[]
|
||||
propertyChanges PropertyChange[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([familyGroupId])
|
||||
@@ -173,18 +176,18 @@ enum SubscriptionStatus {
|
||||
// ============================================
|
||||
|
||||
model WatchlistItem {
|
||||
id String @id @default(uuid())
|
||||
id String @id @default(uuid())
|
||||
subscriptionId String
|
||||
type WatchlistType
|
||||
value String
|
||||
hash String // SHA-256 hash for deduplication
|
||||
isActive Boolean @default(true)
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
exposures Exposure[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
type WatchlistType
|
||||
value String
|
||||
hash String // SHA-256 hash for deduplication
|
||||
isActive Boolean @default(true)
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
exposures Exposure[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([subscriptionId, type, hash])
|
||||
@@index([subscriptionId])
|
||||
@@ -201,7 +204,7 @@ enum WatchlistType {
|
||||
}
|
||||
|
||||
model Exposure {
|
||||
id String @id @default(uuid())
|
||||
id String @id @default(uuid())
|
||||
subscriptionId String
|
||||
watchlistItemId String?
|
||||
source ExposureSource
|
||||
@@ -209,16 +212,16 @@ model Exposure {
|
||||
identifier String
|
||||
identifierHash String
|
||||
severity ExposureSeverity @default(info)
|
||||
metadata Json? // Additional source-specific data
|
||||
isFirstTime Boolean @default(false)
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
watchlistItem WatchlistItem? @relation(fields: [watchlistItemId], references: [id])
|
||||
alerts Alert[]
|
||||
|
||||
detectedAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
metadata Json? // Additional source-specific data
|
||||
isFirstTime Boolean @default(false)
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
watchlistItem WatchlistItem? @relation(fields: [watchlistItemId], references: [id])
|
||||
alerts Alert[]
|
||||
|
||||
detectedAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([subscriptionId])
|
||||
@@index([watchlistItemId])
|
||||
@@ -228,7 +231,7 @@ model Exposure {
|
||||
}
|
||||
|
||||
enum ExposureSource {
|
||||
hibp // Have I Been Pwned
|
||||
hibp // Have I Been Pwned
|
||||
securityTrails
|
||||
censys
|
||||
darkWebForum
|
||||
@@ -247,24 +250,27 @@ enum ExposureSeverity {
|
||||
// ============================================
|
||||
|
||||
model Alert {
|
||||
id String @id @default(uuid())
|
||||
subscriptionId String
|
||||
userId String
|
||||
exposureId String?
|
||||
type AlertType
|
||||
title String
|
||||
message String
|
||||
severity AlertSeverity @default(info)
|
||||
isRead Boolean @default(false)
|
||||
readAt DateTime?
|
||||
channel AlertChannel[] // Array of notification channels
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
exposure Exposure? @relation(fields: [exposureId], references: [id])
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
id String @id @default(uuid())
|
||||
subscriptionId String
|
||||
userId String
|
||||
exposureId String?
|
||||
type AlertType
|
||||
title String
|
||||
message String
|
||||
severity AlertSeverity @default(info)
|
||||
isRead Boolean @default(false)
|
||||
readAt DateTime?
|
||||
channel AlertChannel[] // Array of notification channels
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
exposure Exposure? @relation(fields: [exposureId], references: [id])
|
||||
propertyChange PropertyChange? @relation("PropertyAlerts", fields: [propertyChangeId], references: [id])
|
||||
|
||||
propertyChangeId String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([subscriptionId])
|
||||
@@index([userId])
|
||||
@@ -297,37 +303,37 @@ enum AlertChannel {
|
||||
// ============================================
|
||||
|
||||
model VoiceEnrollment {
|
||||
id String @id @default(uuid())
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
name String
|
||||
voiceHash String // FAISS embedding hash
|
||||
audioMetadata Json? // Sample rate, duration, etc.
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
analyses VoiceAnalysis[]
|
||||
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
voiceHash String // FAISS embedding hash
|
||||
audioMetadata Json? // Sample rate, duration, etc.
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
analyses VoiceAnalysis[]
|
||||
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([voiceHash])
|
||||
}
|
||||
|
||||
model VoiceAnalysis {
|
||||
id String @id @default(uuid())
|
||||
enrollmentId String?
|
||||
userId String
|
||||
audioHash String // Content hash of audio file
|
||||
isSynthetic Boolean
|
||||
confidence Float // 0.0 to 1.0
|
||||
analysisResult Json // Full ML analysis results
|
||||
audioUrl String // S3 storage URL
|
||||
|
||||
enrollment VoiceEnrollment? @relation(fields: [enrollmentId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
id String @id @default(uuid())
|
||||
enrollmentId String?
|
||||
userId String
|
||||
audioHash String // Content hash of audio file
|
||||
isSynthetic Boolean
|
||||
confidence Float // 0.0 to 1.0
|
||||
analysisResult Json // Full ML analysis results
|
||||
audioUrl String // S3 storage URL
|
||||
|
||||
enrollment VoiceEnrollment? @relation(fields: [enrollmentId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
@@index([enrollmentId])
|
||||
@@ -339,19 +345,19 @@ model VoiceAnalysis {
|
||||
// ============================================
|
||||
|
||||
model SpamFeedback {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
phoneNumber String
|
||||
phoneNumberHash String // SHA-256 hash
|
||||
isSpam Boolean
|
||||
confidence Float? // ML model confidence
|
||||
feedbackType FeedbackType
|
||||
metadata Json? // Call duration, time, etc.
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
phoneNumber String
|
||||
phoneNumberHash String // SHA-256 hash
|
||||
isSpam Boolean
|
||||
confidence Float? // ML model confidence
|
||||
feedbackType FeedbackType
|
||||
metadata Json? // Call duration, time, etc.
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([phoneNumberHash])
|
||||
@@ -366,19 +372,19 @@ enum FeedbackType {
|
||||
}
|
||||
|
||||
model SpamRule {
|
||||
id String @id @default(uuid())
|
||||
userId String?
|
||||
isGlobal Boolean @default(false)
|
||||
ruleType RuleType
|
||||
pattern String
|
||||
action RuleAction
|
||||
priority Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
id String @id @default(uuid())
|
||||
userId String?
|
||||
isGlobal Boolean @default(false)
|
||||
ruleType RuleType
|
||||
pattern String
|
||||
action RuleAction
|
||||
priority Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([isGlobal])
|
||||
@@ -405,16 +411,16 @@ enum RuleAction {
|
||||
// ============================================
|
||||
|
||||
model AuditLog {
|
||||
id String @id @default(uuid())
|
||||
userId String?
|
||||
action String
|
||||
resource String
|
||||
id String @id @default(uuid())
|
||||
userId String?
|
||||
action String
|
||||
resource String
|
||||
resourceId String?
|
||||
changes Json? // Before/after values
|
||||
metadata Json?
|
||||
ipAddress String?
|
||||
userAgent String?
|
||||
|
||||
changes Json? // Before/after values
|
||||
metadata Json?
|
||||
ipAddress String?
|
||||
userAgent String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
@@ -429,8 +435,8 @@ model KPISnapshot {
|
||||
metricName String
|
||||
metricValue Float
|
||||
metadata Json?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([metricName])
|
||||
@@index([date])
|
||||
@@ -441,23 +447,23 @@ model KPISnapshot {
|
||||
// ============================================
|
||||
|
||||
model WaitlistEntry {
|
||||
id String @id @default(uuid())
|
||||
email String
|
||||
name String?
|
||||
source String? // landing_page, blog, referral, social, paid_search
|
||||
tier SubscriptionTier? // interest level
|
||||
utmSource String?
|
||||
utmMedium String?
|
||||
utmCampaign String?
|
||||
metadata Json? // Browser, device, location, etc.
|
||||
|
||||
id String @id @default(uuid())
|
||||
email String
|
||||
name String?
|
||||
source String? // landing_page, blog, referral, social, paid_search
|
||||
tier SubscriptionTier? // interest level
|
||||
utmSource String?
|
||||
utmMedium String?
|
||||
utmCampaign String?
|
||||
metadata Json? // Browser, device, location, etc.
|
||||
|
||||
// Conversion tracking
|
||||
convertedAt DateTime?
|
||||
convertedToUserId String?
|
||||
convertedAt DateTime?
|
||||
convertedToUserId String?
|
||||
convertedToSubscriptionId String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([email])
|
||||
@@index([source])
|
||||
@@ -465,22 +471,127 @@ model WaitlistEntry {
|
||||
}
|
||||
|
||||
model BlogPost {
|
||||
id String @id @default(uuid())
|
||||
slug String @unique
|
||||
id String @id @default(uuid())
|
||||
slug String @unique
|
||||
title String
|
||||
excerpt String?
|
||||
content String
|
||||
authorName String?
|
||||
coverImageUrl String?
|
||||
tags String[] // Array of tag strings
|
||||
published Boolean @default(false)
|
||||
tags String[] // Array of tag strings
|
||||
published Boolean @default(false)
|
||||
publishedAt DateTime?
|
||||
viewCount Int @default(0)
|
||||
viewCount Int @default(0)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([slug])
|
||||
@@index([published, publishedAt])
|
||||
@@index([tags])
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Home Title Property Monitoring Models
|
||||
// ============================================
|
||||
|
||||
model PropertyWatchlistItem {
|
||||
id String @id @default(uuid())
|
||||
subscriptionId String
|
||||
address String
|
||||
parcelId String
|
||||
ownerName String
|
||||
streetAddress String
|
||||
city String
|
||||
state String
|
||||
zipCode String
|
||||
latitude Float?
|
||||
longitude Float?
|
||||
isActive Boolean @default(true)
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
snapshots PropertySnapshot[]
|
||||
changes PropertyChange[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([subscriptionId, parcelId])
|
||||
@@index([subscriptionId])
|
||||
@@index([parcelId])
|
||||
@@index([address])
|
||||
}
|
||||
|
||||
model PropertySnapshot {
|
||||
id String @id @default(uuid())
|
||||
propertyWatchlistItemId String
|
||||
subscriptionId String
|
||||
ownerName String
|
||||
ownerAddress String?
|
||||
assessmentValue Int?
|
||||
assessedYear Int?
|
||||
taxAmount Float?
|
||||
taxYear Int?
|
||||
lienData Json? // Array of liens with amounts, types, dates
|
||||
deedData Json? // Latest deed information
|
||||
metadata Json? // Additional property data from sources
|
||||
|
||||
propertyWatchlistItem PropertyWatchlistItem @relation(fields: [propertyWatchlistItemId], references: [id], onDelete: Cascade)
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
changes PropertyChange[] @relation("SnapshotChanges")
|
||||
|
||||
snapshotDate DateTime
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([propertyWatchlistItemId])
|
||||
@@index([subscriptionId])
|
||||
@@index([snapshotDate])
|
||||
}
|
||||
|
||||
model PropertyChange {
|
||||
id String @id @default(uuid())
|
||||
propertyWatchlistItemId String?
|
||||
subscriptionId String
|
||||
snapshotId String? // Reference to the snapshot where change was detected
|
||||
changeType PropertyChangeType
|
||||
severity PropertyChangeSeverity @default(info)
|
||||
previousValue Json? // Before state
|
||||
newValue Json? // After state
|
||||
diff Json? // Computed diff between states
|
||||
title String // Short description
|
||||
description String // Detailed explanation
|
||||
isResolved Boolean @default(false)
|
||||
resolvedAt DateTime?
|
||||
resolvedByUserId String?
|
||||
|
||||
propertyWatchlistItem PropertyWatchlistItem? @relation(fields: [propertyWatchlistItemId], references: [id])
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
snapshot PropertySnapshot? @relation("SnapshotChanges", fields: [snapshotId], references: [id])
|
||||
alerts Alert[] @relation("PropertyAlerts")
|
||||
|
||||
detectedAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([propertyWatchlistItemId])
|
||||
@@index([subscriptionId])
|
||||
@@index([changeType])
|
||||
@@index([severity])
|
||||
@@index([detectedAt])
|
||||
@@index([isResolved])
|
||||
}
|
||||
|
||||
enum PropertyChangeType {
|
||||
ownership_transfer
|
||||
deed_change
|
||||
lien_filing
|
||||
tax_change
|
||||
assessment_change
|
||||
}
|
||||
|
||||
enum PropertyChangeSeverity {
|
||||
info
|
||||
warning
|
||||
critical
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user