more package declarations

This commit is contained in:
2026-05-17 21:52:38 -04:00
parent a8a5930ced
commit f118d3a4f3
44 changed files with 14019 additions and 1918 deletions

View File

@@ -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;

View 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"

View File

@@ -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
}

View File

@@ -1,5 +1,5 @@
// Re-export Prisma client
export { prisma } from './client';
export { prisma } from './client.js';
// Export types
export type {
@@ -18,4 +18,4 @@ export type {
SpamRule,
AuditLog,
KPISnapshot,
} from './client';
} from './client.js';