4.0 KiB
4.0 KiB
Order Services Architecture Recommendation
Recommended Structure: Enhanced Separation of Concerns
1. Controller Layer (orders.controller.ts)
Responsibility: API contract and basic validation
- DTO validation (format, types, required fields)
- Authentication/authorization
- HTTP response handling
- Minimal business logic
2. Orchestrator Layer (order-orchestrator.service.ts)
Responsibility: Workflow coordination and transaction management
- Coordinates the order creation flow
- Manages transaction boundaries
- Handles high-level error scenarios
- Calls other services in correct sequence
3. Validator Layer (order-validator.service.ts)
Responsibility: ALL validation logic (business + technical)
class OrderValidator {
// API-level validation (move from DTO)
validateRequestFormat(body: any): CreateOrderBody
// Business validation (current)
validateUserMapping(userId: string): Promise<UserMapping>
validatePaymentMethod(userId: string, clientId: number): Promise<void>
validateSKUs(skus: string[], pricebookId: string): Promise<void>
validateBusinessRules(orderType: string, skus: string[]): void
validateInternetDuplication(userId: string, clientId: number): Promise<void>
// Complete validation (orchestrates all checks)
async validateCompleteOrder(userId: string, body: any): Promise<{
validatedBody: CreateOrderBody,
userMapping: UserMapping
}>
}
4. Builder Layer (order-builder.service.ts)
Responsibility: Data transformation and mapping
- Transform business data to Salesforce format
- Apply business rules to field mapping
- Handle conditional field logic
5. ItemBuilder Layer (order-item-builder.service.ts)
Responsibility: Order item creation and pricing
- Create order line items
- Handle pricing calculations
- Manage product metadata
Benefits of This Structure:
✅ Single Responsibility Principle
- Each service has one clear purpose
- Easy to test and maintain
- Clear boundaries
✅ Validator as Single Source of Truth
- All validation logic in one place
- Easy to find and modify validation rules
- Consistent error handling
✅ Orchestrator for Workflow Management
- Clear sequence of operations
- Transaction management
- Error recovery logic
✅ Testability
- Each layer can be unit tested independently
- Mock dependencies easily
- Clear input/output contracts
Implementation Changes:
Move DTO validation to Validator:
// Before: Controller has DTO validation
@Body() body: CreateOrderDto
// After: Controller accepts any, Validator validates
@Body() body: any
Enhanced Validator:
async validateCompleteOrder(userId: string, rawBody: any) {
// 1. Format validation (was DTO)
const body = this.validateRequestFormat(rawBody);
// 2. Business validation (current)
const userMapping = await this.validateUserMapping(userId);
await this.validatePaymentMethod(userId, userMapping.whmcsClientId);
// 3. SKU validation (move here)
const pricebookId = await this.findPricebookId();
await this.validateSKUs(body.skus, pricebookId);
this.validateBusinessRules(body.orderType, body.skus);
// 4. Order-specific validation
if (body.orderType === "Internet") {
await this.validateInternetDuplication(userId, userMapping.whmcsClientId);
}
return { validatedBody: body, userMapping, pricebookId };
}
Simplified Orchestrator:
async createOrder(userId: string, rawBody: any) {
// 1. Complete validation
const { validatedBody, userMapping, pricebookId } =
await this.validator.validateCompleteOrder(userId, rawBody);
// 2. Build order
const orderFields = this.builder.buildOrderFields(validatedBody, userMapping, pricebookId);
// 3. Create in Salesforce
const created = await this.sf.sobject("Order").create(orderFields);
// 4. Create items
await this.itemBuilder.createOrderItemsFromSKUs(created.id, validatedBody.skus, pricebookId);
return { sfOrderId: created.id, status: "Created" };
}