Skip to main content

Data Model

Prisma schema design and database structure.

Schema Configuration

generator client {
provider = "prisma-client-js"
output = "../../../../node_modules/@prisma/crm"
previewFeatures = ["fullTextSearch"]
}

datasource db {
provider = "postgresql"
url = env("CRM_DATABASE_URL")
}

Core Models

CustomerProfile

The central entity representing a single customer.

FieldTypeDescription
idUUIDPrimary key
tenantIdStringMulti-tenant isolation
authUserIdString?IDP user ID
emailString?Normalized email
phoneNumberString?E.164 format
sclMemberIdInt?SCL Member ID
teetimePlayerIdString?TeeTime Player ID
messagingContactIdString?Messaging Contact ID
statusEnumACTIVE, INACTIVE, MERGED
lifecycleStageEnumSUBSCRIBER → ADVOCATE
engagementScoreInt?0-100
churnRiskScoreInt?0-100

Activity

Timeline events for a customer.

FieldTypeDescription
idUUIDPrimary key
customerIdUUIDForeign key
typeStringEvent type
categoryEnumMEMBERSHIP, BOOKING, etc.
titleStringHuman-readable
sourceServiceStringscl, teetime, messaging
occurredAtDateTimeWhen it happened

CustomerSegment

Segment definitions.

FieldTypeDescription
idUUIDPrimary key
tenantIdStringMulti-tenant
nameStringDisplay name
typeEnumSTATIC, DYNAMIC, SMART
rulesJSONRule definition
refreshFrequencyEnumMANUAL, HOURLY, DAILY
memberCountIntDenormalized count

Campaign Models

Campaign

FieldTypeDescription
idUUIDPrimary key
tenantIdStringMulti-tenant
nameStringDisplay name
typeEnumONE_TIME, RECURRING, etc.
statusEnumDRAFT, ACTIVE, etc.
segmentIdUUID?Target segment
scheduledAtDateTime?When to send

Journey

FieldTypeDescription
idUUIDPrimary key
nameStringDisplay name
statusEnumDRAFT, ACTIVE, PAUSED
triggerTypeStringEvent type
triggerConditionsJSONEntry conditions

Social Models

SocialConnection

FieldTypeDescription
idUUIDPrimary key
tenantIdStringMulti-tenant
platformEnumFACEBOOK, INSTAGRAM, TWITTER
accountNameStringPage/account name
accessTokenStringEncrypted token
tokenExpiresAtDateTime?Token expiry

SocialPost

FieldTypeDescription
idUUIDPrimary key
connectionIdUUIDWhich account
contentStringPost text
statusEnumDRAFT, SCHEDULED, PUBLISHED
scheduledAtDateTime?When to publish
platformPostIdString?ID from platform

Design Principles

1. Multi-Tenancy

All tables include tenantId. Queries must filter by tenant.

2. Soft Deletes

Use deletedAt for reversible deletions.

3. Audit Trail

Major tables have createdAt, updatedAt, createdBy, updatedBy.

4. Denormalization

Frequently queried data stored on CustomerProfile:

  • emailOptIn, smsOptIn (from Messaging)
  • handicap, bookingCount30d (from TeeTime)
  • membershipTier, membershipStatus (from SCL)

5. JSON for Flexibility

Use JSON for evolving schemas:

  • Segment rules
  • Journey step config
  • External IDs

Index Strategy

Query PatternIndex
Find by email(tenantId, email) UNIQUE
Find by phone(tenantId, phoneNumber)
Filter by status(tenantId, status)
Timeline query(customerId, occurredAt)
Scheduled campaigns(tenantId, scheduledAt)

Migrations

# Create migration
cd libs/prisma/crm-client
npx prisma migrate dev --name <name>

# Deploy to production
npx prisma migrate deploy

# Generate client
npx prisma generate