Skip to content

Domain Model

Both entities are defined in @nx/core under the outreach PostgreSQL schema and re-exported into this package. There are no foreign keys between them — each is an independent capture table.

1. Full ERD

2. Entities

Inquiry

PropertyValue
Tableoutreach.Inquiry
Sourcepackages/core/src/models/schemas/outreach/inquiry/schema.ts
Soft-deleteyes (deletedAt)
Owner ID column— (global, not merchant-scoped)
Hidden propertiesdeletedAt

Fields:

FieldTypeRequiredDefaultDescription
idtextSnowflakePrimary key
typetext000_CONSULTSource channel — see enum
statustextNEWPipeline state — see enum
firstNametextContact first name
lastNametextContact last name
emailtextContact email (indexed)
phonetextContact phone
businessNametextLead's business
businessTypetextBusiness category
locationCounttextLead qualification
estimatedRevenuetextLead qualification
subjecttextMessage subject
messagetextFree-text body
assignedTotextOwning admin/user id
repliedAttimestamptzFirst-reply timestamp
repliedBytextReplying user id
convertedAttimestamptzConversion timestamp
lostReasontextLost-deal reason
notetextInternal note
createdAttimestamptznow()

Type enum (InquiryTypes):

ValueDescription
000_CONSULTGeneral consultation / unknown source (default)
100_CONTACTContact form (/contact)
200_SALESSales inquiry (/contact-sales)
300_DEMODemo request (/demo)
400_PARTNERPartner application (/partners)

Status enum (InquiryStatuses, IGNIS Statuses):

ValueDescription
NEWJust submitted
PROCESSINGPicked up by admin
COMPLETEDConverted
CLOSEDResolved without conversion
CANCELLEDSpam / invalid / abandoned

Indexes & constraints:

NameColumnsType
PK_InquiryidPrimary key
IDX_Inquiry_typetypeBtree
IDX_Inquiry_statusstatusBtree
IDX_Inquiry_emailemailBtree

Relations: none.

Subscriber

PropertyValue
Tableoutreach.Subscriber
Sourcepackages/core/src/models/schemas/outreach/subscriber/schema.ts
Soft-deleteyes (deletedAt)
Owner ID column— (global)
Hidden propertiesdeletedAt, unsubscribeToken (never returned by the model API)

Fields:

FieldTypeRequiredDefaultDescription
idtextSnowflakePrimary key
emailtextUnique (partial, where not deleted)
localetextviNewsletter language (vi / en)
topicsjsonb (string[])['all']Topic preferences
statustextACTIVATEDSee enum
unsubscribeTokentextSnowflake ($defaultFn)Token for unsubscribe link; hidden from API
subscribedAttimestamptznow()First/last subscribe time
unsubscribedAttimestamptzSet on unsubscribe, cleared on re-subscribe
createdAttimestamptznow()

Status enum (SubscriberStatuses, IGNIS Statuses):

ValueDescription
ACTIVATEDActive subscription
DEACTIVATEDUnsubscribed
ARCHIVEDAdmin-archived (valid status, not produced by the service flow)

Indexes & constraints:

NameColumnsType
PK_SubscriberidPrimary key
UPI_Subscriber_emailemail (where deletedAt IS NULL)Unique partial index
IDX_Subscriber_statusstatusBtree
IDX_Subscriber_unsubscribeTokenunsubscribeTokenBtree

Relations: none.

3. Cross-entity Invariants

InvariantEnforcement
One live Subscriber per emailUnique partial index UPI_Subscriber_email (where deletedAt IS NULL) + SubscriberService.subscribe() find-then-reactivate
unsubscribeToken unique enough to be unguessableSnowflake $defaultFn (64-bit, worker 10) — see ADR-0001
Re-subscribe clears unsubscribedAtSubscriberService.subscribe() sets unsubscribedAt: null on reactivate

4. Soft-delete Behavior

BehaviorDetail
Read defaultdeletedAt IS NULL (model defaultFilter)
Hard-deleteNever by default; admin CRUD deleteById performs soft-delete
RestoreNot exposed via API
Email uniquenessEnforced only over non-deleted rows (partial unique index)

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.