// Real Estate Agent Platform - Database Schema // Milestone 1 & 2: Foundation, Authentication & Agent Features generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" } // =========================================== // ENUMS // =========================================== enum UserRole { USER AGENT ADMIN } enum UserStatus { ACTIVE INACTIVE SUSPENDED PENDING_VERIFICATION } enum AuthProvider { LOCAL GOOGLE FACEBOOK TWITTER } enum VerificationStatus { PENDING APPROVED REJECTED } enum VerificationDocType { LICENSE ID_CARD CERTIFICATE OTHER } // =========================================== // USER - Authentication Only // =========================================== model User { id String @id @default(uuid()) email String @unique password String? // Null for social login users role UserRole @default(USER) status UserStatus @default(ACTIVE) emailVerified Boolean @default(false) emailVerifiedAt DateTime? avatar String? // Profile picture URL // Social Auth authProvider AuthProvider @default(LOCAL) googleId String? @unique facebookId String? @unique twitterId String? @unique // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt lastLoginAt DateTime? // Relations - Profile based on role userProfile UserProfile? agentProfile AgentProfile? // Auth Relations sessions Session[] @@index([email]) @@index([role]) @@index([status]) @@map("users") } // =========================================== // USER PROFILE - Normal Users // =========================================== model UserProfile { id String @id @default(uuid()) userId String @unique firstName String? lastName String? phone String? avatar String? // Location city String? state String? country String? // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@map("user_profiles") } // =========================================== // AGENT PROFILE - Agents/Subscribers // =========================================== model AgentProfile { id String @id @default(uuid()) userId String @unique slug String @unique // Basic Info firstName String? lastName String? phone String? avatar String? bio String? @db.Text headline String? // Location city String? state String? country String? address String? zipCode String? latitude Float? longitude Float? // Professional Info yearsOfExperience Int? licenseNumber String? companyName String? website String? // Social Links facebookUrl String? twitterUrl String? linkedinUrl String? instagramUrl String? // Verification Status isVerified Boolean @default(false) verifiedAt DateTime? // Profile Status isProfileComplete Boolean @default(false) profileCompleteness Int @default(0) isPublic Boolean @default(true) isFeatured Boolean @default(false) // Stats (denormalized for performance) totalReviews Int @default(0) averageRating Float @default(0) // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) specializations AgentSpecialization[] verificationRequests VerificationRequest[] @@index([userId]) @@index([slug]) @@index([city, state]) @@index([isVerified]) @@index([isPublic]) @@index([isFeatured]) @@map("agent_profiles") } // =========================================== // CATEGORY - Main categories for agents // =========================================== model Category { id String @id @default(uuid()) name String @unique slug String @unique description String? icon String? image String? isActive Boolean @default(true) sortOrder Int @default(0) // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations specializations Specialization[] @@index([slug]) @@index([isActive]) @@map("categories") } // =========================================== // SPECIALIZATION - Sub-categories under Category // =========================================== model Specialization { id String @id @default(uuid()) categoryId String name String slug String @unique description String? isActive Boolean @default(true) sortOrder Int @default(0) // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade) agents AgentSpecialization[] @@unique([categoryId, name]) @@index([categoryId]) @@index([slug]) @@map("specializations") } // =========================================== // AGENT SPECIALIZATION - Many-to-Many pivot // =========================================== model AgentSpecialization { id String @id @default(uuid()) agentProfileId String specializationId String // Timestamps createdAt DateTime @default(now()) // Relations agentProfile AgentProfile @relation(fields: [agentProfileId], references: [id], onDelete: Cascade) specialization Specialization @relation(fields: [specializationId], references: [id], onDelete: Cascade) @@unique([agentProfileId, specializationId]) @@index([agentProfileId]) @@index([specializationId]) @@map("agent_specializations") } // =========================================== // VERIFICATION REQUEST - Agent verification // =========================================== model VerificationRequest { id String @id @default(uuid()) agentProfileId String // Document Info documentType VerificationDocType documentUrl String documentName String? notes String? @db.Text // Status status VerificationStatus @default(PENDING) reviewedAt DateTime? reviewedBy String? // Admin user ID adminNotes String? @db.Text rejectionReason String? // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Relations agentProfile AgentProfile @relation(fields: [agentProfileId], references: [id], onDelete: Cascade) @@index([agentProfileId]) @@index([status]) @@map("verification_requests") } // =========================================== // SESSION - JWT Token Management // =========================================== model Session { id String @id @default(uuid()) userId String token String @unique refreshToken String? @unique userAgent String? ipAddress String? expiresAt DateTime createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([token]) @@map("sessions") }