2026-04-12 00:01:21 +05:30
import {
PrismaClient ,
UserRole ,
UserStatus ,
AuthProvider ,
FieldType ,
} from '@prisma/client' ;
2025-12-19 01:15:19 +05:30
import { PrismaPg } from '@prisma/adapter-pg' ;
import { Pool } from 'pg' ;
import * as argon2 from 'argon2' ;
2026-04-12 00:01:21 +05:30
import {
US_STATES_CO_NE_ND_SD ,
US_CITIES_CO_NE_ND_SD ,
} from './data/us-cities-co-ne-nd-sd' ;
2025-12-19 01:15:19 +05:30
async function main() {
const connectionString = process . env . DATABASE_URL ;
const pool = new Pool ( { connectionString } ) ;
const adapter = new PrismaPg ( pool ) ;
const prisma = new PrismaClient ( { adapter } ) ;
console . log ( '🌱 Starting database seeding...\n' ) ;
2026-01-20 12:16:01 +05:30
// =============================================
// Seed Agent Types
// =============================================
console . log ( '📋 Seeding Agent Types...' ) ;
const agentTypes = [
{
name : 'Professional' ,
description : 'Licensed real estate professionals' ,
icon : 'briefcase' ,
sortOrder : 1 ,
} ,
{
name : 'Lender' ,
description : 'Mortgage and loan specialists' ,
icon : 'bank' ,
sortOrder : 2 ,
} ,
] ;
for ( const agentType of agentTypes ) {
const existing = await prisma . agentType . findUnique ( {
where : { name : agentType.name } ,
} ) ;
if ( existing ) {
console . log ( ` ⚠️ Agent type " ${ agentType . name } " already exists ` ) ;
} else {
await prisma . agentType . create ( {
data : agentType ,
} ) ;
console . log ( ` ✅ Created agent type: ${ agentType . name } ` ) ;
}
}
console . log ( '' ) ;
2026-01-24 12:49:25 +05:30
// =============================================
// Seed Default Profile Sections & Fields
// =============================================
console . log ( '📋 Seeding Default Profile Sections...' ) ;
// Define default system sections with their fields
const defaultSections = [
{
name : 'Basic Information' ,
slug : 'basic-information' ,
description : 'Basic profile information' ,
icon : 'user' ,
sortOrder : 1 ,
isActive : true ,
isGlobal : true ,
isSystem : true ,
fields : [
{
name : 'First Name' ,
slug : 'first_name' ,
fieldType : FieldType.TEXT ,
description : 'Your first name' ,
placeholder : 'Enter your first name' ,
sortOrder : 1 ,
isActive : true ,
isRequired : true ,
isSearchableOnly : false ,
} ,
{
name : 'Last Name' ,
slug : 'last_name' ,
fieldType : FieldType.TEXT ,
description : 'Your last name' ,
placeholder : 'Enter your last name' ,
sortOrder : 2 ,
isActive : true ,
isRequired : true ,
isSearchableOnly : false ,
} ,
2026-01-24 21:39:14 +05:30
{
name : 'Description' ,
slug : 'description' ,
fieldType : FieldType.TEXTAREA ,
2026-04-12 00:01:21 +05:30
description :
'Tell us about yourself and your professional background' ,
placeholder :
'Enter a brief description about yourself, your experience, and what makes you unique...' ,
2026-01-24 21:39:14 +05:30
sortOrder : 3 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
validation : {
maxLength : 2000 ,
} ,
uiConfig : {
rows : 6 ,
showCharCount : true ,
} ,
} ,
2026-01-24 12:49:25 +05:30
] ,
} ,
{
name : 'Contact Information' ,
slug : 'contact-information' ,
description : 'Contact details' ,
icon : 'phone' ,
sortOrder : 2 ,
isActive : true ,
isGlobal : true ,
isSystem : true ,
fields : [
{
name : 'Email Address' ,
slug : 'email_address' ,
fieldType : FieldType.TEXT ,
description : 'Your contact email address' ,
placeholder : 'Enter your email address' ,
sortOrder : 1 ,
isActive : true ,
isRequired : true ,
isSearchableOnly : false ,
} ,
{
name : 'Phone Number' ,
slug : 'phone_number' ,
fieldType : FieldType.TEXT ,
description : 'Your contact phone number' ,
placeholder : 'Enter your phone number' ,
sortOrder : 2 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
] ,
} ,
2026-01-24 15:32:54 +05:30
{
name : 'Location' ,
slug : 'location' ,
description : 'Service areas and location information' ,
icon : 'map-pin' ,
sortOrder : 3 ,
isActive : true ,
isGlobal : true ,
isSystem : true ,
fields : [
{
name : 'State' ,
slug : 'state' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'States where you provide services' ,
placeholder : 'Select states' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
2026-04-12 00:01:21 +05:30
options : US_STATES_CO_NE_ND_SD ,
2026-01-24 15:32:54 +05:30
} ,
{
name : 'City' ,
slug : 'city' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Cities where you provide services (max 5)' ,
placeholder : 'Enter cities' ,
sortOrder : 2 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
validation : {
maxSelections : 5 ,
} ,
uiConfig : {
allowCustomOptions : true ,
maxSelections : 5 ,
} ,
2026-04-12 00:01:21 +05:30
options : US_CITIES_CO_NE_ND_SD ,
2026-01-24 15:32:54 +05:30
} ,
] ,
} ,
{
name : 'Upload Documents' ,
slug : 'upload-documents' ,
description : 'Upload licensing credentials and verification documents' ,
icon : 'document' ,
sortOrder : 4 ,
isActive : true ,
isGlobal : true ,
isSystem : true ,
fields : [
{
name : 'Documents' ,
slug : 'documents' ,
fieldType : FieldType.FILE ,
2026-04-12 00:01:21 +05:30
description :
'Upload documentation or verification for licensing credentials' ,
2026-01-24 15:32:54 +05:30
placeholder : 'Drag and drop files here or click to upload' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
validation : {
allowedTypes : [ 'pdf' , 'doc' , 'docx' , 'jpg' , 'jpeg' , 'png' ] ,
maxFileSize : 10485760 , // 10MB
maxFiles : 10 ,
} ,
uiConfig : {
acceptedFormats : '.pdf, .doc, .docx, .jpg, .png' ,
showPreview : true ,
multiple : true ,
} ,
} ,
] ,
} ,
{
name : 'Certification' ,
slug : 'certification' ,
description : 'Professional certifications and credentials' ,
icon : 'star' ,
sortOrder : 5 ,
isActive : true ,
isGlobal : true ,
isSystem : true ,
2026-01-24 22:31:12 +05:30
isRepeatable : true , // User can add multiple certifications
2026-01-24 15:32:54 +05:30
fields : [
2026-01-24 22:31:12 +05:30
{
name : 'Certification Entries' ,
slug : 'certification_entries' ,
fieldType : FieldType.REPEATER ,
description : 'All certification entries stored as JSON array' ,
sortOrder : 0 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
2026-01-24 15:32:54 +05:30
{
name : 'Certification Name' ,
slug : 'certification_name' ,
fieldType : FieldType.TEXT ,
description : 'Name of your professional certification' ,
placeholder : 'Enter certification name' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
{
name : 'Issuing Organization' ,
slug : 'issuing_organization' ,
fieldType : FieldType.TEXT ,
description : 'Organization that issued the certification' ,
placeholder : 'Enter issuing organization' ,
sortOrder : 2 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
{
name : 'Issue Date' ,
slug : 'issue_date' ,
fieldType : FieldType.DATE ,
description : 'Date the certification was issued' ,
placeholder : 'Select issue date' ,
sortOrder : 3 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
{
name : 'Expiration Date' ,
slug : 'expiration_date' ,
fieldType : FieldType.DATE ,
description : 'Date the certification expires (if applicable)' ,
placeholder : 'Select expiration date' ,
sortOrder : 4 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
{
name : 'Certification Number' ,
slug : 'certification_number' ,
fieldType : FieldType.TEXT ,
description : 'Your certification or license number' ,
placeholder : 'Enter certification number' ,
sortOrder : 5 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
] ,
} ,
{
name : 'Demographic' ,
slug : 'demographic' ,
description : 'Demographic and contact information' ,
icon : 'user' ,
sortOrder : 6 ,
isActive : true ,
isGlobal : true ,
isSystem : true ,
fields : [
{
name : 'Name' ,
slug : 'demographic_name' ,
fieldType : FieldType.TEXT ,
description : 'Your full name' ,
placeholder : 'Enter your name' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
{
name : 'Office Name' ,
slug : 'office_name' ,
fieldType : FieldType.TEXT ,
description : 'Name of your office or brokerage' ,
placeholder : 'Enter office name' ,
sortOrder : 2 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
{
name : 'Registered / Licensed' ,
slug : 'registered_licensed' ,
fieldType : FieldType.RADIO ,
description : 'Are you registered or licensed?' ,
placeholder : 'Select status' ,
sortOrder : 3 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Registered' , value : 'registered' } ,
{ label : 'Licensed' , value : 'licensed' } ,
{ label : 'Both' , value : 'both' } ,
] ,
} ,
{
name : 'Office #' ,
slug : 'office_number' ,
fieldType : FieldType.TEXT ,
description : 'Your office phone number' ,
placeholder : 'Enter office number' ,
sortOrder : 4 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
{
name : 'Cell #' ,
slug : 'cell_number' ,
fieldType : FieldType.TEXT ,
description : 'Your cell phone number' ,
placeholder : 'Enter cell number' ,
sortOrder : 5 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
{
name : 'Availability' ,
slug : 'availability' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'When are you available?' ,
placeholder : 'Select availability' ,
sortOrder : 6 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'M-F 9-5' , value : 'mf_9_5' } ,
{ label : 'Evenings' , value : 'evenings' } ,
{ label : 'Weekends' , value : 'weekends' } ,
] ,
} ,
{
name : 'Age' ,
slug : 'age' ,
fieldType : FieldType.RANGE ,
2026-04-12 00:01:21 +05:30
description :
'Your age (used for search matching only, not displayed on profile)' ,
2026-01-24 15:32:54 +05:30
placeholder : 'Select age range' ,
sortOrder : 7 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : true ,
rangeConfig : {
min : 18 ,
max : 100 ,
step : 1 ,
} ,
} ,
{
name : 'Gender' ,
slug : 'gender' ,
fieldType : FieldType.TEXT ,
2026-04-12 00:01:21 +05:30
description :
'Your gender (used for search matching only, not displayed on profile)' ,
2026-01-24 15:32:54 +05:30
placeholder : 'Enter gender' ,
sortOrder : 8 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : true ,
} ,
{
name : 'Race' ,
slug : 'race' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-04-12 00:01:21 +05:30
description :
'Your race (used for search matching only, not displayed on profile)' ,
2026-01-24 15:32:54 +05:30
placeholder : 'Select race' ,
sortOrder : 9 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : true ,
options : [
2026-04-12 00:01:21 +05:30
{
label : 'American Indian or Alaska Native' ,
value : 'american_indian_alaska_native' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'Asian' , value : 'asian' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Black or African American' ,
value : 'black_african_american' ,
} ,
{
label : 'Native Hawaiian or Other Pacific Islander' ,
value : 'native_hawaiian_pacific_islander' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'White' , value : 'white' } ,
{ label : 'Two or More Races' , value : 'two_or_more' } ,
{ label : 'Prefer not to say' , value : 'prefer_not_to_say' } ,
] ,
} ,
{
name : 'Ethnicity' ,
slug : 'ethnicity' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-04-12 00:01:21 +05:30
description :
'Your ethnicity (used for search matching only, not displayed on profile)' ,
2026-01-24 15:32:54 +05:30
placeholder : 'Select ethnicity' ,
sortOrder : 10 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : true ,
options : [
{ label : 'Hispanic or Latino' , value : 'hispanic_latino' } ,
{ label : 'Not Hispanic or Latino' , value : 'not_hispanic_latino' } ,
{ label : 'Prefer not to say' , value : 'prefer_not_to_say' } ,
] ,
} ,
{
name : 'Language' ,
slug : 'language' ,
fieldType : FieldType.TAG_INPUT ,
description : 'Languages you speak' ,
placeholder : 'Add languages' ,
sortOrder : 11 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
uiConfig : {
allowCustomOptions : true ,
2026-04-12 00:01:21 +05:30
suggestions : [
'English' ,
'Spanish' ,
'Chinese' ,
'French' ,
'Vietnamese' ,
'Korean' ,
'Tagalog' ,
'Arabic' ,
'Russian' ,
'Portuguese' ,
] ,
2026-01-24 15:32:54 +05:30
} ,
} ,
{
name : 'LGBTQ+' ,
slug : 'lgbtq' ,
fieldType : FieldType.RADIO ,
2026-04-12 00:01:21 +05:30
description :
'LGBTQ+ identification (used for search matching only, not displayed on profile)' ,
2026-01-24 15:32:54 +05:30
placeholder : 'Select option' ,
sortOrder : 12 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : true ,
options : [
{ label : 'Yes' , value : 'yes' } ,
{ label : 'No' , value : 'no' } ,
{ label : 'Prefer not to say' , value : 'prefer_not_to_say' } ,
] ,
} ,
{
name : 'Highest Education Level' ,
slug : 'highest_education_level' ,
fieldType : FieldType.RADIO ,
description : 'Your highest level of education' ,
placeholder : 'Select education level' ,
sortOrder : 13 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'High School/GED' , value : 'high_school_ged' } ,
{ label : 'Some College' , value : 'some_college' } ,
{ label : 'Associates' , value : 'associates' } ,
{ label : 'Bachelors' , value : 'bachelors' } ,
{ label : 'Masters' , value : 'masters' } ,
{ label : 'Doctoral' , value : 'doctoral' } ,
] ,
} ,
{
name : 'Veteran Status' ,
slug : 'veteran_status' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Your military/veteran status' ,
placeholder : 'Select veteran status' ,
sortOrder : 14 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Active' , value : 'active' } ,
{ label : 'Reserve' , value : 'reserve' } ,
{ label : 'Guard' , value : 'guard' } ,
{ label : 'Veteran' , value : 'veteran' } ,
] ,
} ,
{
name : 'Military Branch' ,
slug : 'military_branch' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Military branch(es) you served in' ,
placeholder : 'Select military branch' ,
sortOrder : 15 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Army' , value : 'army' } ,
{ label : 'Navy' , value : 'navy' } ,
{ label : 'Marines' , value : 'marines' } ,
{ label : 'Air Force' , value : 'air_force' } ,
{ label : 'Space Force' , value : 'space_force' } ,
{ label : 'Coast Guard' , value : 'coast_guard' } ,
] ,
} ,
] ,
} ,
2026-01-24 20:36:21 +05:30
{
name : 'Expertise' ,
slug : 'expertise' ,
description : 'Areas of expertise and specialization' ,
icon : 'star' ,
sortOrder : 7 ,
isActive : true ,
isGlobal : true ,
isSystem : true ,
fields : [
{
name : 'About Me' ,
slug : 'about_me_expertise' ,
fieldType : FieldType.TAG_INPUT ,
description : 'Add your areas of expertise' ,
placeholder : 'Add Expertise' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
uiConfig : {
allowCustomOptions : true ,
} ,
} ,
] ,
} ,
2026-01-24 15:32:54 +05:30
] ;
// Agent-type-specific sections (NOT global)
const agentTypeSections = [
{
agentTypeName : 'Professional' ,
section : {
name : 'Experience' ,
slug : 'professional-experience' ,
2026-04-12 00:01:21 +05:30
description :
'Professional experience and track record for real estate agents' ,
2026-01-24 15:32:54 +05:30
icon : 'star' ,
sortOrder : 4 ,
isActive : true ,
isGlobal : false ,
isSystem : false ,
fields : [
{
name : 'Years in Business' ,
slug : 'years_in_business' ,
fieldType : FieldType.RADIO ,
description : 'How many years have you been in real estate?' ,
placeholder : 'Select years' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Less than 2 years' , value : '<2' } ,
{ label : '2+ years' , value : '2+' } ,
{ label : '5+ years' , value : '5+' } ,
{ label : '10+ years' , value : '10+' } ,
] ,
} ,
{
name : 'Years Operated in Area' ,
slug : 'years_in_area' ,
fieldType : FieldType.RADIO ,
2026-04-12 00:01:21 +05:30
description :
'How many years have you operated in your service area?' ,
2026-01-24 15:32:54 +05:30
placeholder : 'Select years' ,
sortOrder : 2 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Less than 2 years' , value : '<2' } ,
{ label : '2+ years' , value : '2+' } ,
{ label : '5+ years' , value : '5+' } ,
{ label : '10+ years' , value : '10+' } ,
] ,
} ,
{
name : 'Number of Contracts Completed' ,
slug : 'contracts_completed' ,
fieldType : FieldType.RADIO ,
description : 'Number of contracts completed in the previous year' ,
placeholder : 'Select range' ,
sortOrder : 3 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Less than 3' , value : '<3' } ,
{ label : '3-10' , value : '3-10' } ,
{ label : '10-20' , value : '10-20' } ,
{ label : '20-50' , value : '20-50' } ,
{ label : '50+' , value : '50+' } ,
] ,
} ,
] ,
} ,
} ,
{
agentTypeName : 'Professional' ,
section : {
name : 'Specialization' ,
slug : 'professional-specialization' ,
description : 'Areas of specialization for real estate agents' ,
icon : 'briefcase' ,
sortOrder : 5 ,
isActive : true ,
isGlobal : false ,
isSystem : false ,
fields : [
{
name : 'Client Specialization' ,
slug : 'client_specialization' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Types of clients you specialize in' ,
placeholder : 'Select client types' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Buyers' , value : 'buyers' } ,
{ label : 'Sellers' , value : 'sellers' } ,
{ label : 'First Time Buyer' , value : 'first_time_buyer' } ,
{ label : 'First Time Seller' , value : 'first_time_seller' } ,
{ label : 'Divorce' , value : 'divorce' } ,
{ label : 'Estate' , value : 'estate' } ,
] ,
} ,
{
name : 'Price Point' ,
slug : 'price_point' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Price ranges you typically work with' ,
placeholder : 'Select price ranges' ,
sortOrder : 2 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Under $100K' , value : '<100K' } ,
{ label : '$100K - $300K' , value : '100-300K' } ,
{ label : '$300K - $500K' , value : '300-500K' } ,
{ label : '$500K - $700K' , value : '500-700K' } ,
{ label : '$700K - $1M' , value : '700K-1M' } ,
{ label : '$1M+' , value : '1M+' } ,
] ,
} ,
{
name : 'Property Type' ,
slug : 'property_type' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Types of properties you specialize in' ,
placeholder : 'Select property types' ,
sortOrder : 3 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'SFR (Single Family Residence)' , value : 'sfr' } ,
{ label : 'Townhome' , value : 'townhome' } ,
{ label : 'Condo' , value : 'condo' } ,
{ label : 'Manufactured' , value : 'manufactured' } ,
{ label : 'Modular' , value : 'modular' } ,
{ label : 'Urban' , value : 'urban' } ,
{ label : 'Rural' , value : 'rural' } ,
{ label : 'Luxury' , value : 'luxury' } ,
{ label : 'Retirement' , value : 'retirement' } ,
{ label : 'Agriculture' , value : 'agriculture' } ,
{ label : 'Commercial' , value : 'commercial' } ,
{ label : 'Investment / Income Producing' , value : 'investment' } ,
{ label : 'Historical' , value : 'historical' } ,
{ label : 'Mountain Property' , value : 'mountain' } ,
{ label : 'Undeveloped Land' , value : 'undeveloped_land' } ,
{ label : 'Empty Lots' , value : 'empty_lots' } ,
{ label : 'Barndaminium' , value : 'barndaminium' } ,
{ label : 'Unique Properties' , value : 'unique' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Apartment / Multifamily' ,
value : 'apartment_multifamily' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'Duplex / Tri-plex / 4-plex' , value : 'multiplex' } ,
{ label : 'New Build' , value : 'new_build' } ,
] ,
} ,
{
name : 'Loan Type' ,
slug : 'loan_type' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Loan types you are familiar with' ,
placeholder : 'Select loan types' ,
sortOrder : 4 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Conventional' , value : 'conventional' } ,
{ label : 'FHA' , value : 'fha' } ,
{ label : 'VA' , value : 'va' } ,
{ label : 'USDA' , value : 'usda' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Downpayment Assistance Programs' ,
value : 'downpayment_assistance' ,
} ,
2026-01-24 15:32:54 +05:30
] ,
} ,
{
name : 'Special Interests and Hobbies' ,
slug : 'special_interests' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Special property features you have expertise in' ,
placeholder : 'Select special interests' ,
sortOrder : 5 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Workshop / Trade / Craftspace' , value : 'workshop' } ,
{ label : 'Boating' , value : 'boating' } ,
{ label : 'Automotive' , value : 'automotive' } ,
{ label : 'Aviation' , value : 'aviation' } ,
{ label : 'Home Theater' , value : 'home_theater' } ,
{ label : 'Horses' , value : 'horses' } ,
{ label : 'RV' , value : 'rv' } ,
{ label : 'Smart Home Features' , value : 'smart_home' } ,
{ label : 'Gardening / Landscape' , value : 'gardening' } ,
{ label : 'Hobby Farm' , value : 'hobby_farm' } ,
] ,
} ,
] ,
} ,
} ,
2026-01-24 21:36:39 +05:30
// Professional - Areas in Expertise & Years Section
{
agentTypeName : 'Professional' ,
section : {
name : 'Areas in Expertise & Years' ,
slug : 'professional-expertise-years' ,
description : 'Your areas of expertise with years of experience' ,
icon : 'award' ,
sortOrder : 6 ,
isActive : true ,
isGlobal : false ,
isSystem : false ,
fields : [
{
name : 'Expertise Areas' ,
slug : 'expertise_areas' ,
fieldType : FieldType.TAG_INPUT ,
description : 'Add your areas of expertise with years of experience' ,
placeholder : '' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
] ,
} ,
} ,
// Professional - Licensing & Areas Section
{
agentTypeName : 'Professional' ,
section : {
name : 'Licensing & Areas' ,
slug : 'professional-licensing-areas' ,
description : 'Areas where you are licensed to practice' ,
icon : 'file-text' ,
sortOrder : 7 ,
isActive : true ,
isGlobal : false ,
isSystem : false ,
fields : [
{
name : 'Licensed Areas' ,
slug : 'licensed_areas' ,
fieldType : FieldType.TAG_INPUT ,
description : 'Enter areas where you are licensed to practice' ,
placeholder : 'Type area name, press Enter to add' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
] ,
} ,
} ,
2026-01-24 15:32:54 +05:30
{
agentTypeName : 'Lender' ,
section : {
name : 'Experience' ,
slug : 'lender-experience' ,
description : 'Professional experience and track record for lenders' ,
icon : 'star' ,
sortOrder : 4 ,
isActive : true ,
isGlobal : false ,
isSystem : false ,
fields : [
{
name : 'Years in Business' ,
slug : 'years_in_business' ,
fieldType : FieldType.RADIO ,
description : 'How many years have you been in lending?' ,
placeholder : 'Select years' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Less than 2 years' , value : '<2' } ,
{ label : '2+ years' , value : '2+' } ,
{ label : '5+ years' , value : '5+' } ,
{ label : '10+ years' , value : '10+' } ,
] ,
} ,
{
name : 'Years Operated in Area' ,
slug : 'years_in_area' ,
fieldType : FieldType.RADIO ,
2026-04-12 00:01:21 +05:30
description :
'How many years have you operated in your service area?' ,
2026-01-24 15:32:54 +05:30
placeholder : 'Select years' ,
sortOrder : 2 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Less than 2 years' , value : '<2' } ,
{ label : '2+ years' , value : '2+' } ,
{ label : '5+ years' , value : '5+' } ,
{ label : '10+ years' , value : '10+' } ,
] ,
} ,
{
name : 'Annual Loans' ,
slug : 'annual_loans' ,
fieldType : FieldType.RADIO ,
description : 'Total value of loans processed annually' ,
placeholder : 'Select range' ,
sortOrder : 3 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : '0-1M' , value : '0-1M' } ,
{ label : '1-5M' , value : '1-5M' } ,
{ label : '5-10M' , value : '5-10M' } ,
{ label : '10-30M' , value : '10-30M' } ,
{ label : '30M+' , value : '30M+' } ,
] ,
} ,
] ,
} ,
} ,
{
agentTypeName : 'Lender' ,
section : {
name : 'Specialization' ,
slug : 'lender-specialization' ,
description : 'Areas of specialization for lenders' ,
icon : 'briefcase' ,
sortOrder : 5 ,
isActive : true ,
isGlobal : false ,
isSystem : false ,
fields : [
{
name : 'Client Specialization' ,
slug : 'client_specialization' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Types of clients you specialize in' ,
placeholder : 'Select client types' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
2026-04-12 00:01:21 +05:30
options : [ { label : 'First Time Buyer' , value : 'first_time_buyer' } ] ,
2026-01-24 15:32:54 +05:30
} ,
{
name : 'Property Type' ,
slug : 'property_type' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Types of properties you can finance' ,
placeholder : 'Select property types' ,
sortOrder : 2 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'SFR (Single Family Residence)' , value : 'sfr' } ,
{ label : 'Townhome' , value : 'townhome' } ,
{ label : 'Condo' , value : 'condo' } ,
{ label : 'Manufactured' , value : 'manufactured' } ,
{ label : 'Modular' , value : 'modular' } ,
{ label : 'Urban' , value : 'urban' } ,
{ label : 'Rural' , value : 'rural' } ,
{ label : 'Luxury' , value : 'luxury' } ,
{ label : 'Retirement' , value : 'retirement' } ,
{ label : 'Agriculture' , value : 'agriculture' } ,
{ label : 'Commercial' , value : 'commercial' } ,
{ label : 'Investment / Income Producing' , value : 'investment' } ,
{ label : 'Undeveloped Land' , value : 'undeveloped_land' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Construction / Construction-to-Perm' ,
value : 'construction' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'Empty Lots' , value : 'empty_lots' } ,
{ label : 'Barndaminium' , value : 'barndaminium' } ,
{ label : 'Unique Properties' , value : 'unique' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Apartment / Multifamily' ,
value : 'apartment_multifamily' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'Duplex / Tri-plex / 4-plex' , value : 'multiplex' } ,
{ label : 'New Build' , value : 'new_build' } ,
] ,
} ,
{
name : 'Loan Type' ,
slug : 'loan_type' ,
2026-01-24 21:36:39 +05:30
fieldType : FieldType.CHECKBOX_GROUP ,
2026-01-24 15:32:54 +05:30
description : 'Types of loans you offer' ,
placeholder : 'Select loan types' ,
sortOrder : 3 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
options : [
{ label : 'Conventional' , value : 'conventional' } ,
{ label : 'FHA' , value : 'fha' } ,
{ label : 'VA' , value : 'va' } ,
{ label : 'USDA' , value : 'usda' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Downpayment Assistance Programs' ,
value : 'downpayment_assistance' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'Rehab Loan - FHA 203k' , value : 'rehab_fha_203k' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Rehab Loan - Conventional Home Style' ,
value : 'rehab_conventional' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'Rehab Loan - VA Reno' , value : 'rehab_va_reno' } ,
{ label : 'Debt Service Cover Ratio (DSCR)' , value : 'dscr' } ,
{ label : 'HELOC' , value : 'heloc' } ,
{ label : 'Standalone Second' , value : 'standalone_second' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Refinancing - FHA Streamline' ,
value : 'refi_fha_streamline' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'Refinancing - VA IRRL' , value : 'refi_va_irrl' } ,
2026-04-12 00:01:21 +05:30
{
label : 'Refinancing - Conventional' ,
value : 'refi_conventional' ,
} ,
2026-01-24 15:32:54 +05:30
{ label : 'Jumbo / Non-conforming' , value : 'jumbo' } ,
{ label : 'Bank Statement' , value : 'bank_statement' } ,
{ label : 'ITIN' , value : 'itin' } ,
] ,
} ,
] ,
} ,
} ,
2026-01-24 21:36:39 +05:30
// Lender - Areas in Expertise & Years Section
{
agentTypeName : 'Lender' ,
section : {
name : 'Areas in Expertise & Years' ,
slug : 'lender-expertise-years' ,
description : 'Your areas of expertise with years of experience' ,
icon : 'award' ,
sortOrder : 6 ,
isActive : true ,
isGlobal : false ,
isSystem : false ,
fields : [
{
name : 'Expertise Areas' ,
slug : 'expertise_areas' ,
fieldType : FieldType.TAG_INPUT ,
description : 'Add your areas of expertise with years of experience' ,
placeholder : '' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
] ,
} ,
} ,
// Lender - Licensing & Areas Section
{
agentTypeName : 'Lender' ,
section : {
name : 'Licensing & Areas' ,
slug : 'lender-licensing-areas' ,
description : 'Areas where you are licensed to practice' ,
icon : 'file-text' ,
sortOrder : 7 ,
isActive : true ,
isGlobal : false ,
isSystem : false ,
fields : [
{
name : 'Licensed Areas' ,
slug : 'licensed_areas' ,
fieldType : FieldType.TAG_INPUT ,
description : 'Enter areas where you are licensed to practice' ,
placeholder : 'Type area name, press Enter to add' ,
sortOrder : 1 ,
isActive : true ,
isRequired : false ,
isSearchableOnly : false ,
} ,
] ,
} ,
} ,
2026-01-24 12:49:25 +05:30
] ;
for ( const sectionData of defaultSections ) {
const { fields , . . . sectionInfo } = sectionData ;
// Check if section already exists
const existingSection = await prisma . profileSection . findUnique ( {
where : { slug : sectionInfo.slug } ,
} ) ;
if ( existingSection ) {
console . log ( ` ⚠️ Section " ${ sectionInfo . name } " already exists ` ) ;
2026-01-24 22:31:12 +05:30
// Update section properties if they've changed (like isRepeatable)
2026-04-12 00:01:21 +05:30
if (
sectionInfo . isRepeatable !== undefined &&
existingSection . isRepeatable !== sectionInfo . isRepeatable
) {
2026-01-24 22:31:12 +05:30
await prisma . profileSection . update ( {
where : { id : existingSection.id } ,
data : { isRepeatable : sectionInfo.isRepeatable } ,
} ) ;
2026-04-12 00:01:21 +05:30
console . log (
` ✅ Updated isRepeatable to ${ sectionInfo . isRepeatable } ` ,
) ;
2026-01-24 22:31:12 +05:30
}
2026-02-01 23:20:26 +05:30
// Still check and create missing fields, or update existing fields with options
2026-01-24 12:49:25 +05:30
for ( const fieldData of fields ) {
const existingField = await prisma . profileField . findFirst ( {
where : {
sectionId : existingSection.id ,
slug : fieldData.slug ,
} ,
} ) ;
if ( ! existingField ) {
await prisma . profileField . create ( {
data : {
. . . fieldData ,
sectionId : existingSection.id ,
} ,
} ) ;
console . log ( ` ✅ Created field: ${ fieldData . name } ` ) ;
2026-02-01 23:20:26 +05:30
} else {
2026-04-12 00:01:21 +05:30
// Update existing field with options if options are defined in seed but missing in DB.
// Exception: `state` and `city` options come from an Excel source of truth and should
// always overwrite DB values so re-seeding syncs fresh data.
2026-02-01 23:20:26 +05:30
const updates : Record < string , unknown > = { } ;
2026-04-12 00:01:21 +05:30
const fd = fieldData as Partial < {
options : unknown ;
validation : unknown ;
uiConfig : unknown ;
} > ;
const alwaysOverwriteOptions =
fieldData . slug === 'state' || fieldData . slug === 'city' ;
2026-02-01 23:20:26 +05:30
2026-04-12 00:01:21 +05:30
if (
fd . options &&
( alwaysOverwriteOptions ||
! existingField . options ||
( Array . isArray ( existingField . options ) &&
existingField . options . length === 0 ) )
) {
2026-02-01 23:20:26 +05:30
updates . options = fd . options ;
}
if ( fd . validation && ! existingField . validation ) {
updates . validation = fd . validation ;
}
if ( fd . uiConfig && ! existingField . uiConfig ) {
updates . uiConfig = fd . uiConfig ;
}
if ( Object . keys ( updates ) . length > 0 ) {
await prisma . profileField . update ( {
where : { id : existingField.id } ,
data : updates ,
} ) ;
2026-04-12 00:01:21 +05:30
console . log (
` ✅ Updated field: ${ fieldData . name } ( ${ Object . keys ( updates ) . join ( ', ' ) } ) ` ,
) ;
2026-02-01 23:20:26 +05:30
}
2026-01-24 12:49:25 +05:30
}
}
} else {
// Create section with fields
2026-04-12 00:01:21 +05:30
await prisma . profileSection . create ( {
2026-01-24 12:49:25 +05:30
data : {
. . . sectionInfo ,
fields : {
create : fields ,
} ,
} ,
} ) ;
2026-04-12 00:01:21 +05:30
console . log (
` ✅ Created section: ${ sectionInfo . name } with ${ fields . length } fields ` ,
) ;
2026-01-24 12:49:25 +05:30
}
}
console . log ( '' ) ;
2026-01-24 15:32:54 +05:30
// =============================================
// Seed Agent-Type-Specific Sections
// =============================================
console . log ( '📋 Seeding Agent-Type-Specific Sections...' ) ;
// First, delete old global Experience section if exists
const oldExperienceSection = await prisma . profileSection . findUnique ( {
where : { slug : 'experience' } ,
} ) ;
if ( oldExperienceSection ) {
await prisma . profileSection . delete ( {
where : { slug : 'experience' } ,
} ) ;
console . log ( ' 🗑️ Deleted old global Experience section' ) ;
}
for ( const { agentTypeName , section : sectionData } of agentTypeSections ) {
const { fields , . . . sectionInfo } = sectionData ;
// Find the agent type
const agentType = await prisma . agentType . findUnique ( {
where : { name : agentTypeName } ,
} ) ;
if ( ! agentType ) {
2026-04-12 00:01:21 +05:30
console . log (
` ⚠️ Agent type " ${ agentTypeName } " not found, skipping section ` ,
) ;
2026-01-24 15:32:54 +05:30
continue ;
}
// Check if section already exists
let section = await prisma . profileSection . findUnique ( {
where : { slug : sectionInfo.slug } ,
} ) ;
if ( section ) {
2026-04-12 00:01:21 +05:30
console . log (
` ⚠️ Section " ${ sectionInfo . name } " for ${ agentTypeName } already exists ` ,
) ;
2026-01-24 15:32:54 +05:30
2026-02-01 23:20:26 +05:30
// Still check and create missing fields, or update existing fields with options
2026-01-24 15:32:54 +05:30
for ( const fieldData of fields ) {
const existingField = await prisma . profileField . findFirst ( {
where : {
sectionId : section.id ,
slug : fieldData.slug ,
} ,
} ) ;
if ( ! existingField ) {
await prisma . profileField . create ( {
data : {
. . . fieldData ,
sectionId : section.id ,
} ,
} ) ;
console . log ( ` ✅ Created field: ${ fieldData . name } ` ) ;
2026-02-01 23:20:26 +05:30
} else {
// Update existing field with options if options are defined in seed but missing in DB
const updates : Record < string , unknown > = { } ;
2026-04-12 00:01:21 +05:30
const fd = fieldData as Partial < {
options : unknown ;
validation : unknown ;
uiConfig : unknown ;
} > ;
2026-02-01 23:20:26 +05:30
2026-04-12 00:01:21 +05:30
if (
fd . options &&
( ! existingField . options ||
( Array . isArray ( existingField . options ) &&
existingField . options . length === 0 ) )
) {
2026-02-01 23:20:26 +05:30
updates . options = fd . options ;
}
if ( fd . validation && ! existingField . validation ) {
updates . validation = fd . validation ;
}
if ( fd . uiConfig && ! existingField . uiConfig ) {
updates . uiConfig = fd . uiConfig ;
}
if ( Object . keys ( updates ) . length > 0 ) {
await prisma . profileField . update ( {
where : { id : existingField.id } ,
data : updates ,
} ) ;
2026-04-12 00:01:21 +05:30
console . log (
` ✅ Updated field: ${ fieldData . name } ( ${ Object . keys ( updates ) . join ( ', ' ) } ) ` ,
) ;
2026-02-01 23:20:26 +05:30
}
2026-01-24 15:32:54 +05:30
}
}
} else {
// Create section with fields
section = await prisma . profileSection . create ( {
data : {
. . . sectionInfo ,
fields : {
create : fields ,
} ,
} ,
} ) ;
2026-04-12 00:01:21 +05:30
console . log (
` ✅ Created section: ${ sectionInfo . name } for ${ agentTypeName } with ${ fields . length } fields ` ,
) ;
2026-01-24 15:32:54 +05:30
}
// Create AgentTypeSection assignment if not exists
const existingAssignment = await prisma . agentTypeSection . findUnique ( {
where : {
agentTypeId_sectionId : {
agentTypeId : agentType.id ,
sectionId : section.id ,
} ,
} ,
} ) ;
if ( ! existingAssignment ) {
await prisma . agentTypeSection . create ( {
data : {
agentTypeId : agentType.id ,
sectionId : section.id ,
sortOrder : sectionInfo.sortOrder ,
isRequired : false ,
} ,
} ) ;
console . log ( ` ✅ Assigned section to ${ agentTypeName } ` ) ;
}
}
console . log ( '' ) ;
2026-01-20 12:16:01 +05:30
// =============================================
// Seed Admin User
// =============================================
console . log ( '👤 Seeding Admin User...' ) ;
2026-03-18 16:49:13 +05:30
const adminEmail = process . env . ADMIN_EMAIL || 'admin@re-quest.com' ;
2025-12-19 01:15:19 +05:30
const adminPassword = process . env . ADMIN_PASSWORD || 'Admin@123456' ;
// Hash password with Argon2 (more secure than bcrypt)
const hashedPassword = await argon2 . hash ( adminPassword ) ;
// Check if admin already exists
const existingAdmin = await prisma . user . findUnique ( {
where : { email : adminEmail } ,
} ) ;
if ( existingAdmin ) {
2026-01-20 12:16:01 +05:30
console . log ( ` ⚠️ Admin user already exists: ${ adminEmail } ` ) ;
2025-12-19 01:15:19 +05:30
} else {
// Create admin user
const admin = await prisma . user . create ( {
data : {
email : adminEmail ,
password : hashedPassword ,
2026-03-20 17:05:40 +05:30
role : UserRole.SUPER_ADMIN ,
2025-12-19 01:15:19 +05:30
status : UserStatus.ACTIVE ,
emailVerified : true ,
emailVerifiedAt : new Date ( ) ,
authProvider : AuthProvider.LOCAL ,
} ,
} ) ;
2026-01-20 12:16:01 +05:30
console . log ( ' ✅ Admin user created successfully!' ) ;
2025-12-19 01:15:19 +05:30
console . log ( ' ───────────────────────────────' ) ;
console . log ( ` 📧 Email: ${ adminEmail } ` ) ;
console . log ( ` 🔑 Password: ${ adminPassword } ` ) ;
console . log ( ` 👤 Role: ${ admin . role } ` ) ;
console . log ( ` 🆔 ID: ${ admin . id } ` ) ;
console . log ( ' ───────────────────────────────\n' ) ;
}
2026-02-22 21:52:16 +05:30
// =============================================
// Seed CMS Content (Landing Page)
// =============================================
console . log ( '📄 Seeding CMS Content...' ) ;
const cmsDefaults = [
{
pageSlug : 'landing' ,
sectionKey : 'hero' ,
content : {
2026-04-12 00:01:21 +05:30
headline :
2026-04-13 23:31:36 +05:30
'Discover verified, top-rated real estate professionals to guide your buying, selling, or investing journey.' ,
2026-04-12 16:18:35 +05:30
description : '' ,
2026-04-11 22:14:07 +05:30
ctaButtonText : 'See All' ,
2026-04-12 16:18:35 +05:30
helperText : '' ,
2026-02-22 21:52:16 +05:30
} ,
} ,
{
pageSlug : 'landing' ,
sectionKey : 'features' ,
content : {
title : 'Find Trusted Real Estate Professionals On Demand' ,
2026-04-12 00:01:21 +05:30
subtitle :
'Quickly connect with the right agents exactly when you need them.' ,
2026-02-22 21:52:16 +05:30
features : [
{
iconPath : '/assets/icons/hourglass-icon.svg' ,
title : 'Hire Quickly' ,
2026-04-12 00:01:21 +05:30
description :
'Connect with experienced local real estate agents who match your needs and preferences. Our simple process helps you get started quickly and move forward without delays or unnecessary complexity.' ,
2026-02-22 21:52:16 +05:30
} ,
{
iconPath : '/assets/icons/verified-badge-icon.svg' ,
title : 'Verified Agents' ,
2026-04-12 00:01:21 +05:30
description :
'All agents are carefully identity-verified and background-checked to ensure trust and safety. You can confidently work with professionals who meet quality and reliability standards.' ,
2026-02-22 21:52:16 +05:30
} ,
{
iconPath : '/assets/icons/star-orange-icon.svg' ,
title : 'Top Rated' ,
2026-04-12 00:01:21 +05:30
description :
'Work with highly rated agents known for strong expertise and positive client feedback. Their consistent performance helps you make informed and confident property decisions.' ,
2026-02-22 21:52:16 +05:30
} ,
{
iconPath : '/assets/icons/trusted-people-icon.svg' ,
title : 'Trusted by Thousands' ,
2026-04-12 00:01:21 +05:30
description :
'Thousands of buyers, sellers, and renters trust our platform to find reliable agents. Our professionals help people navigate property journeys with confidence and ease.' ,
2026-02-22 21:52:16 +05:30
} ,
] ,
2026-03-23 11:25:56 +05:30
featuredAgents : [
{
name : 'Anderson' ,
role : 'Rental & Investment Consultant' ,
rating : '4.9' ,
location : 'New York' ,
experience : '7+ years in the real estate industry.' ,
imageUrl : '/assets/images/agent-anderson.jpg' ,
} ,
{
name : 'Deepak' ,
role : 'Rental & Investment Consultant' ,
rating : '4.9' ,
location : 'New York' ,
experience : '7+ years in the real estate industry.' ,
imageUrl : '/assets/images/agent-deepak.jpg' ,
} ,
{
name : 'Daniel' ,
role : 'Rental & Investment Consultant' ,
rating : '4.9' ,
location : 'New York' ,
experience : '7+ years in the real estate industry.' ,
imageUrl : '/assets/images/agent-daniel.jpg' ,
} ,
] ,
2026-02-22 21:52:16 +05:30
} ,
} ,
{
pageSlug : 'landing' ,
sectionKey : 'topProfessionals' ,
content : {
2026-04-11 22:10:51 +05:30
title : 'Meet top real estate professionals' ,
ctaText : 'Discover Top Real Estate Agents in Our Network' ,
2026-02-22 21:52:16 +05:30
ctaButtonText : 'Browse Experts' ,
agents : [
{
name : 'Arjun Mehta' ,
subtitle : '(Residential Property Expert)' ,
location : 'San Francisco, CA' ,
experience : '10+ years in the real estate industry.' ,
2026-04-12 00:01:21 +05:30
expertise : [
'Residential' ,
'Rental' ,
'Commercial' ,
'Inspection' ,
'Land' ,
'Rental' ,
] ,
2026-02-22 21:52:16 +05:30
imageUrl : '/assets/images/professional-1.jpg' ,
} ,
{
name : 'Arjun Mehta' ,
subtitle : '(Residential Property Expert)' ,
location : 'San Francisco, CA' ,
experience : '10+ years in the real estate industry.' ,
2026-04-12 00:01:21 +05:30
expertise : [
'Residential' ,
'Rental' ,
'Commercial' ,
'Inspection' ,
'Land' ,
'Rental' ,
] ,
2026-02-22 21:52:16 +05:30
imageUrl : '/assets/images/professional-2.jpg' ,
} ,
{
name : 'Arjun Mehta' ,
subtitle : '(Residential Property Expert)' ,
location : 'San Francisco, CA' ,
experience : '10+ years in the real estate industry.' ,
2026-04-12 00:01:21 +05:30
expertise : [
'Residential' ,
'Rental' ,
'Commercial' ,
'Inspection' ,
'Land' ,
'Rental' ,
] ,
2026-02-22 21:52:16 +05:30
imageUrl : '/assets/images/professional-3.jpg' ,
} ,
] ,
lenders : [
{
name : 'Sarah Johnson' ,
subtitle : '(Mortgage Specialist)' ,
location : 'Los Angeles, CA' ,
experience : '10+ years in mortgage lending.' ,
2026-04-12 00:01:21 +05:30
expertise : [
'FHA Loans' ,
'Conventional' ,
'VA Loans' ,
'Refinancing' ,
'Jumbo' ,
] ,
2026-02-22 21:52:16 +05:30
imageUrl : '/assets/images/professional-1.jpg' ,
} ,
{
name : 'Michael Chen' ,
subtitle : '(Senior Loan Officer)' ,
location : 'Seattle, WA' ,
experience : '7+ years in lending.' ,
2026-04-12 00:01:21 +05:30
expertise : [
'Jumbo Loans' ,
'Refinancing' ,
'Investment' ,
'First-time' ,
'USDA' ,
] ,
2026-02-22 21:52:16 +05:30
imageUrl : '/assets/images/professional-2.jpg' ,
} ,
{
name : 'Emily Davis' ,
subtitle : '(Home Loan Advisor)' ,
location : 'Austin, TX' ,
experience : '5+ years in mortgage industry.' ,
2026-04-12 00:01:21 +05:30
expertise : [
'First-time Buyers' ,
'FHA' ,
'USDA Loans' ,
'VA Loans' ,
'Conventional' ,
] ,
2026-02-22 21:52:16 +05:30
imageUrl : '/assets/images/professional-3.jpg' ,
} ,
] ,
} ,
} ,
{
pageSlug : 'landing' ,
sectionKey : 'testimonials' ,
content : {
2026-04-11 21:44:38 +05:30
title : 'Consumer Protection is Our Foundation' ,
2026-04-12 00:01:21 +05:30
subtitle :
"Buying or selling your home is one of the largest decisions you will make in your life. Don't let yourself be chased by salesmen. Find the service provider that matches your unique needs." ,
ratingInfo :
'Clients rate our real estate services 4.9 out of 5 on average, based on recent client reviews.' ,
2026-02-22 21:52:16 +05:30
stats : [
{
iconPath : '/assets/icons/cities-icon.svg' ,
2026-04-11 21:44:38 +05:30
boldText : '3 states' ,
normalText : 'and counting' ,
2026-02-22 21:52:16 +05:30
} ,
{
iconPath : '/assets/icons/properties-icon.svg' ,
2026-04-11 21:44:38 +05:30
boldText : 'Hundreds of' ,
normalText : 'Professionals' ,
2026-02-22 21:52:16 +05:30
} ,
] ,
testimonials : [
{
rating : 5 ,
2026-04-11 21:44:38 +05:30
title : 'No Longer Blood in the Water' ,
2026-04-12 00:01:21 +05:30
content :
'Using other sites to find a realtor ended with my phone ringing constantly. My number was sold off to multiple lists and it was so overwhelming. RE-Quest gave me confidence that my information was protected and I decided who I was in contact with.' ,
2026-04-11 21:44:38 +05:30
author : 'Alice T.' ,
role : '' ,
2026-02-22 21:52:16 +05:30
} ,
{
rating : 5 ,
2026-04-11 21:44:38 +05:30
title : 'Finding Someone Who Worked with Me' ,
2026-04-12 00:01:21 +05:30
content :
'RE-Quest let me narrow down my search terms, so I knew before I called that they had experience with the loan program I needed. I loved the in-app chat feature to talk to my short list before committing to a phone call.' ,
2026-04-11 21:44:38 +05:30
author : 'Kevin R.' ,
role : '' ,
2026-02-22 21:52:16 +05:30
} ,
{
rating : 5 ,
2026-04-11 21:44:38 +05:30
title : '' ,
2026-04-12 00:01:21 +05:30
content :
'The search terms on RE-Quest allowed me to show off my expertise as an agent. Now when leads reach out to me, they already have an idea of what kind of agent I am. Instant connection!' ,
2026-04-11 21:44:38 +05:30
author : 'Riley S.' ,
role : '' ,
2026-02-22 21:52:16 +05:30
} ,
] ,
} ,
} ,
2026-03-19 13:32:49 +05:30
// Contact Page
{
pageSlug : 'contact' ,
sectionKey : 'contactDetails' ,
content : {
title : 'Get In Touch' ,
2026-04-12 00:01:21 +05:30
description :
'Have a question about a property or need assistance? Fill out the form below and our team will get back to you shortly.' ,
2026-03-19 13:32:49 +05:30
email : '123support@gmail.com' ,
phone : '1234567890' ,
phoneHours : 'Mon-Fri 9am-6pm' ,
officeAddress : '123 Market Street' ,
officeCity : 'New York CA 234737' ,
mapUrl : '' ,
2026-04-12 00:01:21 +05:30
directionsUrl :
'https://maps.google.com/?q=123+Market+Street+New+York+CA+234737' ,
2026-03-19 13:32:49 +05:30
} ,
} ,
{
pageSlug : 'contact' ,
sectionKey : 'cta' ,
content : {
title : 'Ready to find an agent?' ,
2026-04-12 00:01:21 +05:30
description :
'Discover trusted agents and start your property journey with confidence.' ,
2026-03-19 13:32:49 +05:30
buttonText : 'Start Your Search' ,
buttonLink : '/user/profiles' ,
} ,
} ,
2026-02-22 21:52:16 +05:30
] ;
for ( const cms of cmsDefaults ) {
const existing = await prisma . cmsContent . findUnique ( {
where : {
pageSlug_sectionKey : {
pageSlug : cms.pageSlug ,
sectionKey : cms.sectionKey ,
} ,
} ,
} ) ;
if ( existing ) {
2026-04-11 21:44:38 +05:30
await prisma . cmsContent . update ( {
where : {
pageSlug_sectionKey : {
pageSlug : cms.pageSlug ,
sectionKey : cms.sectionKey ,
} ,
} ,
data : {
content : cms.content ,
isPublished : true ,
} ,
} ) ;
2026-04-12 00:01:21 +05:30
console . log (
` 🔄 Updated CMS content: ${ cms . pageSlug } / ${ cms . sectionKey } ` ,
) ;
2026-02-22 21:52:16 +05:30
} else {
await prisma . cmsContent . create ( {
data : {
pageSlug : cms.pageSlug ,
sectionKey : cms.sectionKey ,
content : cms.content ,
isPublished : true ,
} ,
} ) ;
2026-04-12 00:01:21 +05:30
console . log (
` ✅ Created CMS content: ${ cms . pageSlug } / ${ cms . sectionKey } ` ,
) ;
2026-02-22 21:52:16 +05:30
}
}
console . log ( '' ) ;
2026-03-07 10:09:50 +05:30
// =============================================
// Seed Subscription Plans
// =============================================
console . log ( '💳 Seeding Subscription Plans...' ) ;
const subscriptionPlans = [
{
name : 'Professional Annual' ,
description : 'Full access to all agent features' ,
2026-03-07 10:11:05 +05:30
stripePriceId : process.env.STRIPE_PRICE_ID || 'price_not_configured' ,
2026-03-07 10:09:50 +05:30
amount : 49900 ,
currency : 'usd' ,
interval : 'year' ,
features : JSON.stringify ( [
'Agent Co-Marketing' ,
'Priority 24/7 Support' ,
'Whitelabel Client Portals' ,
'Advanced CRM Tools & Analytics' ,
] ) ,
isActive : true ,
sortOrder : 1 ,
} ,
] ;
for ( const plan of subscriptionPlans ) {
const existingPlan = await prisma . subscriptionPlan . findUnique ( {
where : { stripePriceId : plan.stripePriceId } ,
} ) ;
if ( existingPlan ) {
console . log ( ` ⚠️ Plan " ${ plan . name } " already exists ` ) ;
} else {
await prisma . subscriptionPlan . create ( { data : plan } ) ;
2026-04-12 00:01:21 +05:30
console . log (
` ✅ Created plan: ${ plan . name } ( $ ${ ( plan . amount / 100 ) . toFixed ( 2 ) } / ${ plan . interval } ) ` ,
) ;
2026-03-07 10:09:50 +05:30
}
}
console . log ( '' ) ;
2026-01-20 12:16:01 +05:30
// =============================================
2025-12-19 01:15:19 +05:30
// Summary
2026-01-20 12:16:01 +05:30
// =============================================
2025-12-19 01:15:19 +05:30
const userCount = await prisma . user . count ( ) ;
2026-04-12 00:01:21 +05:30
const adminCount = await prisma . user . count ( {
where : { role : UserRole.ADMIN } ,
} ) ;
2026-01-20 12:16:01 +05:30
const agentTypeCount = await prisma . agentType . count ( ) ;
2026-01-24 12:49:25 +05:30
const sectionCount = await prisma . profileSection . count ( ) ;
const fieldCount = await prisma . profileField . count ( ) ;
2026-04-12 00:01:21 +05:30
const systemSectionCount = await prisma . profileSection . count ( {
where : { isSystem : true } ,
} ) ;
2026-01-24 15:32:54 +05:30
const agentTypeSectionCount = await prisma . agentTypeSection . count ( ) ;
2026-02-22 21:52:16 +05:30
const cmsContentCount = await prisma . cmsContent . count ( ) ;
2026-03-07 10:09:50 +05:30
const planCount = await prisma . subscriptionPlan . count ( ) ;
2025-12-19 01:15:19 +05:30
console . log ( '📊 Database Summary:' ) ;
2026-01-20 12:16:01 +05:30
console . log ( ` Total Users: ${ userCount } ` ) ;
console . log ( ` Admins: ${ adminCount } ` ) ;
console . log ( ` Agent Types: ${ agentTypeCount } ` ) ;
2026-04-12 00:01:21 +05:30
console . log (
` Profile Sections: ${ sectionCount } ( ${ systemSectionCount } system) ` ,
) ;
2026-01-24 12:49:25 +05:30
console . log ( ` Profile Fields: ${ fieldCount } ` ) ;
2026-01-24 15:32:54 +05:30
console . log ( ` Section Assignments: ${ agentTypeSectionCount } ` ) ;
2026-02-22 21:52:16 +05:30
console . log ( ` CMS Content: ${ cmsContentCount } ` ) ;
2026-03-07 10:09:50 +05:30
console . log ( ` Plans: ${ planCount } ` ) ;
2025-12-19 01:15:19 +05:30
console . log ( '\n🌱 Seeding completed!\n' ) ;
await prisma . $disconnect ( ) ;
await pool . end ( ) ;
}
2026-04-12 00:01:21 +05:30
main ( ) . catch ( ( e ) = > {
console . error ( '❌ Seeding failed:' , e ) ;
process . exit ( 1 ) ;
} ) ;