Skip to content

Customer Management v1.0.0

Source: src/services/customer.service.ts · src/controllers/customer/customer.controller.ts

Key Facts

PropertyValue
Route/customers
ScopeOrganizer only (NOT merchant-scoped)
Auto Role010_customer (priority 10)
Auto StatusACTIVATED
AuthJWT + Basic
Mapping1 PolicyDefinition: USER→ORGANIZER

Customers are Users with the fixed CUSTOMER role. No username, no password, no merchant mapping.

Data Model

PolicyDefinition Records per Customer

#variantsubjectType → targetTypetargetIdCreated By
1groupUserRole010_customer role IDUserService.create()
2groupUserOrganizerorganizer IDCustomerService._createUserPolicies()

Creation Flow

Update Flow

Delete

Soft-delete via UserRepository.deleteById() — sets deletedAt timestamp.

Request / Response Schemas

CreateCustomerRequest

Derived from CreateUserRequest with omitted fields:

FieldTypeRequiredNotes
emailsstring[]Yesmin 1
phonesstring[]Yesmin 1, E.164
profileobjectYesfirstName, lastName, birthday?, locale?
organizerIdstringYesLinks customer to organizer

roleIds, username, credential, status are omitted — auto-handled by CustomerService.

UpdateByIdCustomerRequest

FieldTypeNotes
emailsstring[]?min 1 if provided
phonesstring[]?min 1 if provided
profileobject?partial update

roleIds and status are omitted — customers always keep CUSTOMER role.

CreateCustomerResponse

typescript
{
  id: string,
  status: 'ACTIVATED',
  isActive: boolean,
  createdAt: string,
  modifiedAt: string,
  profile?: {
    firstName, lastName, emails[], phones[],
    birthday?, locale, metadata?
  }
}

Controller Authorization

All customer operations are scoped via UserRepository.findIdsByPoliciesForCurrentUser() with roleIdentifiers: ['011_customer'].

OperationScoping
find / count / findOneFilter by policy-scoped IDs + optional organizerId query param
findById / deleteByIdVerify ID in policy-scoped set
createValidates organizer ownership via PolicyDefinition
updateByIdValidates organizer co-membership via PolicyDefinition
deleteByApplies id IN scoped IDs filter

API Endpoints

MethodPathDescription
GET/customersList (organizer-scoped, paginated)
GET/customers/countCount (organizer-scoped)
GET/customers/find-oneFind one (organizer-scoped)
GET/customers/:idGet by ID
POST/customersCreate customer
PUT/customers/:idUpdate customer
DELETE/customers/:idSoft-delete
DELETE/customersBulk delete (organizer-scoped)

Example Requests

Create

http
POST /v1/api/identity/customers
Authorization: Bearer <token>

{
  "emails": ["customer@example.com"],
  "phones": ["+84901234567"],
  "profile": {
    "firstName": "Nguyen",
    "lastName": "Van A",
    "birthday": "1990-05-15",
    "locale": "vi-VN"
  },
  "organizerId": "org-123"
}

Update

http
PUT /v1/api/identity/customers/cust-456
Authorization: Bearer <token>

{
  "profile": { "lastName": "Van B" },
  "phones": ["+84907654321"]
}

Dependencies

Design Decisions

DecisionRationale
Customer = User + roleReuses identity infrastructure; consistent auth model
Organizer-scoped onlyCustomers belong to organizers, not individual merchants
No login credentialsusername + credential omitted from request
Soft deletePreserves transaction history via deletedAt

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