Quản lý Khách hàng v1.0.0
Mã nguồn: src/services/customer.service.ts · src/controllers/customer/customer.controller.ts
Thông tin chính
| Thuộc tính | Giá trị |
|---|---|
| Route | /customers |
| Phạm vi | Chỉ Organizer (KHÔNG giới hạn theo merchant) |
| Role tự động | 010_customer (priority 10) |
| Trạng thái tự động | ACTIVATED |
| Auth | JWT + Basic |
| Mapping | 1 PolicyDefinition: USER→ORGANIZER |
Customer là User với role cố định
CUSTOMER. Không có username, không có password, không có mapping với merchant.
Mô hình dữ liệu
Bản ghi PolicyDefinition cho mỗi Customer
| # | variant | subjectType → targetType | targetId | Tạo bởi |
|---|---|---|---|---|
| 1 | group | User → Role | role ID 010_customer | UserService.create() |
| 2 | group | User → Organizer | organizer ID | CustomerService._createUserPolicies() |
Luồng tạo mới
Luồng cập nhật
Xóa
Soft-delete thông qua UserRepository.deleteById() — gán giá trị timestamp cho deletedAt.
Schema Request / Response
CreateCustomerRequest
Kế thừa từ CreateUserRequest với một số trường được loại bỏ:
| Trường | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
emails | string[] | Có | tối thiểu 1 |
phones | string[] | Có | tối thiểu 1, định dạng E.164 |
profile | object | Có | firstName, lastName, birthday?, locale? |
organizerId | string | Có | Liên kết customer với organizer |
roleIds,username,credential,statusđược loại bỏ — CustomerService tự xử lý.
UpdateByIdCustomerRequest
| Trường | Kiểu | Ghi chú |
|---|---|---|
emails | string[]? | tối thiểu 1 nếu cung cấp |
phones | string[]? | tối thiểu 1 nếu cung cấp |
profile | object? | cập nhật một phần |
roleIdsvàstatusđược loại bỏ — customer luôn giữ roleCUSTOMER.
CreateCustomerResponse
typescript
{
id: string,
status: 'ACTIVATED',
isActive: boolean,
createdAt: string,
modifiedAt: string,
profile?: {
firstName, lastName, emails[], phones[],
birthday?, locale, metadata?
}
}Phân quyền tại Controller
Tất cả thao tác với customer được giới hạn phạm vi qua UserRepository.findIdsByPoliciesForCurrentUser() với roleIdentifiers: ['010_customer'].
| Thao tác | Phạm vi |
|---|---|
find / count / findOne | Lọc theo các ID đã giới hạn theo policy + tham số organizerId tùy chọn |
findById / deleteById | Kiểm tra ID có nằm trong tập đã giới hạn theo policy |
create | Xác thực quyền sở hữu organizer thông qua PolicyDefinition |
updateById | Xác thực việc cùng thuộc một organizer thông qua PolicyDefinition |
deleteBy | Áp dụng bộ lọc id IN scoped IDs |
API Endpoints
| Method | Path | Mô tả |
|---|---|---|
GET | /customers | Danh sách (giới hạn theo organizer, phân trang) |
GET | /customers/count | Đếm số lượng (giới hạn theo organizer) |
GET | /customers/find-one | Tìm một bản ghi (giới hạn theo organizer) |
GET | /customers/:id | Lấy theo ID |
POST | /customers | Tạo customer |
PUT | /customers/:id | Cập nhật customer |
DELETE | /customers/:id | Soft-delete |
DELETE | /customers | Xóa hàng loạt (giới hạn theo organizer) |
Ví dụ Request
Tạo mới
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"
}Cập nhật
http
PUT /v1/api/identity/customers/cust-456
Authorization: Bearer <token>
{
"profile": { "lastName": "Van B" },
"phones": ["+84907654321"]
}Phụ thuộc
Quyết định Thiết kế
| Quyết định | Lý do |
|---|---|
| Customer = User + role | Tái sử dụng hạ tầng identity; mô hình auth nhất quán |
| Chỉ giới hạn theo organizer | Customer thuộc về organizer, không thuộc về từng merchant riêng lẻ |
| Không có thông tin đăng nhập | username + credential được loại bỏ khỏi request |
| Soft delete | Bảo toàn lịch sử giao dịch thông qua deletedAt |
Trang liên quan
- User Management — Chi tiết về UserService.create()
- RBAC — Mô hình PolicyDefinition, các role cố định
- Authentication — Luồng JWT
- Tổng quan Identity — Kiến trúc