Files
backend/docs/data-model.md
Sathish c9b38dc6ab fix(security): resolve audit findings — secrets, env contract, migrations
Removes hardcoded fallback secrets and makes a misconfigured deploy fail
loudly instead of silently falling back to development defaults.

- Remove insecure JWT fallback secrets (messages.module, configuration)
- Remove the 'default-secret' fallback for the 2FA TOTP encryption key and
  allow a dedicated TWO_FACTOR_ENCRYPTION_KEY so rotating JWT_SECRET no
  longer locks out every 2FA user (see docs/2fa-key-rotation.md)
- Require EMAIL_API_URL; drop the hardcoded vendor email endpoint
- Drive WebSocket CORS from CORS_ORIGINS instead of origin:'*'
- Load .env before any Nest module is imported (src/load-env.ts). Decorator
  arguments evaluate at import time, so the gateway previously froze its CORS
  config to the localhost fallback even when CORS_ORIGINS was set
- Add boot-time env validation: missing required vars, weak JWT_SECRET, and
  inverted access/refresh token lifetimes now abort startup
- Enable Redis TLS certificate verification
- Require ADMIN_EMAIL/ADMIN_PASSWORD for the seed; remove the published
  default super-admin credentials and stop printing them
- Add the initial Prisma migration and stop gitignoring prisma/migrations
- Make .env.example an accurate configuration contract (admin bootstrap,
  REDIS_TLS, S3_ENDPOINT, 2FA key, Firebase path; drop the dead SMTP block)
- Add handover documentation: architecture, ER model, sequence and data-flow
  diagrams, 2FA key rotation runbook

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 16:03:08 +05:30

19 KiB
Raw Permalink Blame History

Data model (entityrelationship)

Generated from backend/prisma/schema.prisma — 24 entities. Regenerate after any schema change; the schema is the source of truth.

ER diagram

erDiagram
    AgentProfile ||--o{ AgentProfileFieldValue : agentProfile
    AgentProfile ||--o{ ConnectionRequest : agentProfile
    AgentProfile ||--o{ Conversation : agentProfile
    AgentProfile ||--o{ Testimonial : agentProfile
    AgentProfile ||--o{ VerificationHistory : agentProfile
    AgentSubscription o|--o{ Payment : subscription
    AgentType o|--o{ AgentProfile : agentType
    AgentType ||--o{ AgentTypeSection : agentType
    Conversation ||--o{ Message : conversation
    ProfileField ||--o{ AgentProfileFieldValue : field
    ProfileSection ||--o{ AgentTypeSection : section
    ProfileSection ||--o{ ProfileField : section
    SubscriptionPlan ||--o{ AgentSubscription : plan
    SupportChat ||--o{ SupportMessage : chat
    User o|--o{ AuditLog : actor
    User o|--o{ VerificationHistory : admin
    User ||--o{ AgentSubscription : user
    User ||--o{ ConnectionRequest : user
    User ||--o{ Conversation : user
    User ||--o{ Message : sender
    User ||--o{ Notification : user
    User ||--o{ Payment : user
    User ||--o{ Session : user
    User ||--o{ SupportChat : user
    User ||--o{ UserReport : reportedUser
    User ||--o{ UserReport : reporter
    User ||--o| AgentProfile : user
    User ||--o| UserProfile : user

Entities

AgentProfile

Field Type Notes
id String PK, default uuid(
userId String unique
slug String unique
agentTypeId String?
firstName String?
lastName String?
phone String?
avatar String?
bio String?
headline String?
city String?
state String?
country String?
address String?
zipCode String?
latitude Float?
longitude Float?
yearsOfExperience Int?
licenseNumber String?
companyName String?
website String?
facebookUrl String?
twitterUrl String?
linkedinUrl String?
instagramUrl String?
isVerified Boolean default false
verificationStatus VerificationStatus enum, default NONE
verificationNote String? Admin note (rejection reason)
verifiedAt DateTime?
verifiedBy String? Admin user ID who verified
isProfileComplete Boolean default false
profileCompleteness Int default 0
isPublic Boolean default true
isFeatured Boolean default false
isAvailable Boolean default true, Agent availability status for connect requests
subscriptionStatus String? "ACTIVE", "NONE", etc.
totalReviews Int default 0
averageRating Float default 0
createdAt DateTime default now(
updatedAt DateTime
user User FK, relation
agentType AgentType? FK, relation
fieldValues AgentProfileFieldValue[] relation
testimonialToken String? unique
connectionRequests ConnectionRequest[] relation
conversations Conversation[] relation
testimonials Testimonial[] relation
verificationHistory VerificationHistory[] relation

AgentProfileFieldValue

Field Type Notes
id String PK, default uuid(
agentProfileId String
fieldId String
textValue String? For TEXT, TEXTAREA
numberValue Float? For NUMBER, RANGE
booleanValue Boolean? For single CHECKBOX
jsonValue Json? For MULTI_SELECT, RADIO, complex data
dateValue DateTime? For DATE
createdAt DateTime default now(
updatedAt DateTime
agentProfile AgentProfile FK, relation
field ProfileField FK, relation

AgentSubscription

Field Type Notes
id String PK, default uuid(
userId String
planId String
stripeCustomerId String cus_xxx
stripeSubscriptionId String? unique, sub_xxx
status SubscriptionStatus enum, default INCOMPLETE
currentPeriodStart DateTime?
currentPeriodEnd DateTime?
cancelAtPeriodEnd Boolean default false
canceledAt DateTime?
createdAt DateTime default now(
updatedAt DateTime
user User FK, relation
plan SubscriptionPlan FK, relation
payments Payment[] relation

AgentType

Field Type Notes
id String PK, default uuid(
name String unique
description String?
icon String?
isActive Boolean default true
sortOrder Int default 0
createdAt DateTime default now(
updatedAt DateTime
agents AgentProfile[] relation
agentTypeSections AgentTypeSection[] relation

AgentTypeSection

Field Type Notes
id String PK, default uuid(
agentTypeId String
sectionId String
sortOrder Int default 0, Order specific to this agent type
isRequired Boolean default false, Is this section required for this type
createdAt DateTime default now(
updatedAt DateTime
agentType AgentType FK, relation
section ProfileSection FK, relation

AuditLog

Field Type Notes
id String PK, default uuid(
actorId String? null = system / unauthenticated
actorRole String? USER, AGENT, ADMIN, SUPER_ADMIN, SYSTEM
action String see AuditAction enum in audit.constants.ts
resourceType String? User, AgentProfile, Subscription, Payment, etc.
resourceId String?
metadata Json? { before, after, reason, params, ... }
ipAddress String?
userAgent String?
createdAt DateTime default now(
actor User? FK, relation

CmsContent

Field Type Notes
id String PK, default uuid(
pageSlug String
sectionKey String
content Json
isPublished Boolean default true
createdAt DateTime default now(
updatedAt DateTime

ConnectionRequest

Field Type Notes
id String PK, default uuid(
userId String User sending the request
agentProfileId String Agent receiving the request
status ConnectionStatus enum, default PENDING
message String? Optional message from user
createdAt DateTime default now(
updatedAt DateTime
respondedAt DateTime? When agent responded
user User FK, relation
agentProfile AgentProfile FK, relation

ContactMessage

Field Type Notes
id String PK, default uuid(
name String
email String
phone String?
message String
isRead Boolean default false
createdAt DateTime default now(

Conversation

Field Type Notes
id String PK, default uuid(
userId String Regular user in the conversation
agentProfileId String Agent in the conversation
lastMessageAt DateTime?
lastMessageText String?
userUnreadCount Int default 0, Unread count for the user
agentUnreadCount Int default 0, Unread count for the agent
userMuted Boolean default false
agentMuted Boolean default false
userFavorited Boolean default false
agentFavorited Boolean default false
userClearedAt DateTime?
agentClearedAt DateTime?
userDeletedAt DateTime?
agentDeletedAt DateTime?
createdAt DateTime default now(
updatedAt DateTime
user User FK, relation
agentProfile AgentProfile FK, relation
messages Message[] relation

Message

Field Type Notes
id String PK, default uuid(
conversationId String
senderId String User ID of the sender (can be user or agent's user)
content String
messageType MessageType enum, default TEXT
fileUrl String?
fileName String?
fileSize Int? File size in bytes
mimeType String?
status MessageStatus enum, default SENT
deliveredAt DateTime?
readAt DateTime?
createdAt DateTime default now(
updatedAt DateTime
conversation Conversation FK, relation
sender User FK, relation

Notification

Field Type Notes
id String PK, default uuid(
userId String
type String 'connection', 'message', 'system', 'update', 'request'
title String
description String
read Boolean default false
actionUrl String?
data Json? Extra metadata (conversationId, connectionRequestId, etc.)
createdAt DateTime default now(
user User FK, relation

Payment

Field Type Notes
id String PK, default uuid(
subscriptionId String?
userId String
stripePaymentIntentId String? unique, pi_xxx
stripeInvoiceId String? unique, in_xxx
amount Int cents
currency String default "usd"
status String "succeeded", "failed", "pending"
receiptUrl String?
createdAt DateTime default now(
subscription AgentSubscription? FK, relation
user User FK, relation

ProfileField

Field Type Notes
id String PK, default uuid(
sectionId String
name String e.g., "State", "Years in Business"
slug String Unique within section: e.g., "state", "years_in_business"
fieldType FieldType enum
description String? Help text shown to user
placeholder String? Placeholder text for input
defaultValue String? Default value (JSON for complex types)
sortOrder Int default 0
isActive Boolean default true
isRequired Boolean default false
isSearchableOnly Boolean default false, If true, shown in edit form & search, but hidden on public profile
validation Json? { min, max, minLength, maxLength, pattern, etc. }
options Json? [{ value: "...", label: "...", sortOrder: 0 }]
rangeConfig Json? { min: 0, max: 100, step: 1 }
uiConfig Json? { columns: 2, showInPreview: true, etc. }
createdAt DateTime default now(
updatedAt DateTime
section ProfileSection FK, relation
fieldValues AgentProfileFieldValue[] relation

ProfileSection

Field Type Notes
id String PK, default uuid(
name String e.g., "Location", "Experience", "Specialization"
slug String unique, URL-friendly identifier
description String?
icon String? Icon name or URL
sortOrder Int default 0
isActive Boolean default true
isGlobal Boolean default false, If true, applies to ALL agent types
isSystem Boolean default false, If true, section cannot be deleted (system default)
isRepeatable Boolean default false, If true, user can add multiple entries (e.g., certifications)
createdAt DateTime default now(
updatedAt DateTime
fields ProfileField[] relation
agentTypeSections AgentTypeSection[] relation

Session

Field Type Notes
id String PK, default uuid(
userId String
token String unique
refreshToken String? unique
userAgent String?
ipAddress String?
expiresAt DateTime
createdAt DateTime default now(
user User FK, relation

SubscriptionPlan

Field Type Notes
id String PK, default uuid(
name String "Professional Annual"
description String?
stripePriceId String unique, Stripe Price ID (price_xxx)
amount Int Amount in cents (49900)
currency String default "usd"
interval String default "year", "month"
features Json? ["Feature 1", "Feature 2"]
isActive Boolean default true
sortOrder Int default 0
createdAt DateTime default now(
updatedAt DateTime
subscriptions AgentSubscription[] relation

SupportChat

Field Type Notes
id String PK, default uuid(
userId String
status SupportChatStatus enum, default OPEN
lastMessageAt DateTime?
lastMessageText String?
userUnreadCount Int default 0
adminUnreadCount Int default 0
createdAt DateTime default now(
updatedAt DateTime
user User FK, relation
messages SupportMessage[] relation

SupportMessage

Field Type Notes
id String PK, default uuid(
chatId String
senderId String
senderRole String "USER" or "ADMIN"
content String
createdAt DateTime default now(
chat SupportChat FK, relation

Testimonial

Field Type Notes
id String PK, default uuid(
agentProfileId String
rating Int 1-5
text String
authorName String
authorRole String "Home Buyer", "Investor", etc.
isPublished Boolean default true
createdAt DateTime default now(
updatedAt DateTime
agentProfile AgentProfile FK, relation

User

Field Type Notes
id String PK, default uuid(
email String unique
password String? Null for social login users
role UserRole enum, default USER
status UserStatus enum, default ACTIVE
emailVerified Boolean default false
emailVerifiedAt DateTime?
avatar String? Profile picture URL
authProvider AuthProvider enum, default LOCAL
googleId String? unique
facebookId String? unique
twitterId String? unique
appleId String? unique
twoFactorEnabled Boolean default false
twoFactorSecret String? Encrypted TOTP secret
twoFactorBackupCodes String? JSON array of hashed backup codes
twoFactorVerifiedAt DateTime? When 2FA was enabled
notificationPreferences Json? { email: {...}, push: {...} }
privacyPreferences Json? { privacySettings: {...}, dataSettings: {...} }
fcmTokens Json? [{ token, device, createdAt }]
createdAt DateTime default now(
updatedAt DateTime
lastLoginAt DateTime?
isOnline Boolean default false
lastSeenAt DateTime?
userProfile UserProfile? relation
agentProfile AgentProfile? relation
sessions Session[] relation
connectionRequests ConnectionRequest[] relation
conversations Conversation[] relation
messages Message[] relation
notifications Notification[] relation
supportChats SupportChat[] relation
subscriptions AgentSubscription[] relation
payments Payment[] relation
reportsSubmitted UserReport[] relation
reportsReceived UserReport[] relation
verificationActions VerificationHistory[] relation
auditLogs AuditLog[] relation

UserProfile

Field Type Notes
id String PK, default uuid(
userId String unique
firstName String?
lastName String?
phone String?
avatar String?
city String?
state String?
country String?
createdAt DateTime default now(
updatedAt DateTime
user User FK, relation

UserReport

Field Type Notes
id String PK, default uuid(
reporterId String
reportedUserId String
conversationId String?
reason String
description String?
status ReportStatus enum, default PENDING
adminNotes String?
createdAt DateTime default now(
updatedAt DateTime
reporter User FK, relation
reportedUser User FK, relation

VerificationHistory

Field Type Notes
id String PK, default uuid(
agentProfileId String
status VerificationStatus enum
note String?
adminId String?
submittedData Json? Snapshot of agent profile + documents at submission time
createdAt DateTime default now(
agentProfile AgentProfile FK, relation
admin User? FK, relation

Enums

  • AuthProvider: LOCAL, GOOGLE, FACEBOOK, TWITTER, APPLE
  • ConnectionStatus: PENDING, ACCEPTED, REJECTED
  • FieldType: TEXT // Single line text input, TEXTAREA // Multi-line text area, CHECKBOX // Single checkbox (Yes/No), CHECKBOX_GROUP // Multiple checkboxes in grid (select multiple), RADIO // Radio buttons (select one), SELECT // Dropdown (select one), MULTI_SELECT // Dropdown with multi-select, RANGE // Slider with min/max, NUMBER // Number input, DATE // Date picker, TAG_INPUT // Tag input (add custom tags), FILE // File upload (documents, images), REPEATER // Repeatable group of fields (e.g., certification + years)
  • MessageStatus: SENT, DELIVERED, READ
  • MessageType: TEXT, FILE, IMAGE, SYSTEM // For system messages like "connection accepted"
  • ReportStatus: PENDING, REVIEWED, RESOLVED, DISMISSED
  • SubscriptionStatus: ACTIVE, PAST_DUE, CANCELED, UNPAID, TRIALING, INCOMPLETE
  • SupportChatStatus: OPEN, CLOSED
  • UserRole: USER, AGENT, ADMIN, SUPER_ADMIN
  • UserStatus: ACTIVE, INACTIVE, SUSPENDED, PENDING_VERIFICATION
  • VerificationStatus: NONE // Agent hasn't uploaded documents, PENDING_REVIEW // Documents uploaded, awaiting admin review, APPROVED // Admin approved verification, REJECTED // Admin rejected verification