Skip to main content

Customer

Source: src/data/customer/

Service​

createCustomerService / CustomerService​

Factory: createCustomerService(repo: CustomerRepository) — returns CustomerService.

All business logic for customer lifecycle (create/merge/link/address management) lives here.

MethodParametersReturnsDescription
findOrCreateCustomer(ctx: RequestContext, input: FindOrCreateCustomerInput)Promise<FindOrCreateResult>Finds existing customer by Discord id or creates a new one
getCustomer(ctx: RequestContext, id: string)Promise<CustomerRecord | null>Returns a customer by id
listCustomers(ctx: RequestContext)Promise<CustomerRecord[]>Lists all customers for the tenant
updateCustomer(ctx: RequestContext, id: string, input: UpdateCustomerInput)Promise<CustomerRecord>Patches an existing customer profile
deactivateCustomer(ctx: RequestContext, id: string)Promise<CustomerRecord>Marks a customer as inactive
linkCustomerToUser(ctx: RequestContext, customerId: string, userId: string)Promise<CustomerRecord>Links a customer record to a user account
mergeCustomers(ctx: RequestContext, sourceId: string, targetId: string, reassignOrders: fn)Promise<MergeResult>Merges source customer into target: combines addresses, reassigns orders, deactivates source
addAddress(ctx: RequestContext, customerId: string, address: AddressWithId)Promise<CustomerRecord>Appends an address to the customer; auto-sets default if first
removeAddress(ctx: RequestContext, customerId: string, addressId: string)Promise<CustomerRecord>Removes an address; recalculates default if needed
setDefaultAddress(ctx: RequestContext, customerId: string, addressId: string)Promise<CustomerRecord>Sets the default address for the customer
setDmPreference(ctx: RequestContext, customerId: string, key: keyof CustomerDmPreferences, value: boolean)Promise<CustomerRecord>Patches one DM notification preference; throws NOT_FOUND when customer doesn't exist
setEmailPreference(ctx: RequestContext, customerId: string, key: keyof CustomerEmailPreferences, value: boolean)Promise<CustomerRecord>Patches one email notification preference; throws NOT_FOUND when customer doesn't exist

Repository​

CustomerRepository​

MethodParametersReturns
getById(ctx: RequestContext, id: string)Promise<CustomerRecord | null>
listByTenant(ctx: RequestContext)Promise<CustomerRecord[]>
create(ctx: RequestContext, input: Omit<CustomerRecord, 'id' | 'createdAt' | 'updatedAt'>)Promise<CustomerRecord>
update(ctx: RequestContext, id: string, patch: CustomerPatch)Promise<CustomerRecord>
delete(ctx: RequestContext, id: string)Promise<void>
findByDiscordId(ctx: RequestContext, discordId: string)Promise<CustomerRecord | null>
findByUserId(ctx: RequestContext, userId: string)Promise<CustomerRecord | null>
findByEmail(ctx: RequestContext, email: string)Promise<CustomerRecord | null>
listByCustomerIds(ctx: RequestContext, ids: string[])Promise<CustomerRecord[]>

CustomerRecord​

FieldType
idstring
tenantIdstring
userIdstring (optional)
discordIdstring
discordUsernamestring
discordDisplayNamestring
sourceCustomerSource
emailstring (optional)
phonestring (optional)
addressesAddressWithId[]
defaultAddressIdstring (optional)
notesstring (optional)
isActiveboolean
dmPreferencesCustomerDmPreferences — { orderReceived, paymentConfirmed, orderShipped, refunds } all default true
emailPreferencesCustomerEmailPreferences — { orderReceived, paymentConfirmed, orderShipped, refunds } all default true
createdAtDate
updatedAtDate

Validators​

customerSchema​

FieldTypeRequiredDefault
tenantIdstringYes—
userIdstringNo—
discordIdstringYes—
discordUsernamestringYes—
discordDisplayNamestringYes—
sourceenum('DISCORD', 'EMAIL', 'MANUAL')No'DISCORD'
emailstring (email)No—
phonestringNo—
addressesAddressWithId[]No[]
defaultAddressIdstringNo—
notesstringNo—
isActivebooleanNotrue
createdAtDate (coerced)Yes—
updatedAtDate (coerced)Yes—

findOrCreateCustomerSchema​

FieldTypeRequiredDefault
discordIdstringYes—
discordUsernamestringYes—
discordDisplayNamestringYes—
sourceenum('DISCORD', 'EMAIL', 'MANUAL')No'DISCORD'
emailstring (email)No—
phonestringNo—
userIdstringNo—

updateCustomerSchema​

FieldTypeRequiredDefault
discordUsernamestringNo—
discordDisplayNamestringNo—
emailstring (email)No—
phonestringNo—
notesstringNo—
userIdstringNo—

Inferred Types​

  • Customer — z.infer<typeof customerSchema>