5.1 KiB
5.1 KiB
Priority 2: Business Validation Consolidation Plan
Objective: Move business validation logic from service layers to domain schemas where appropriate.
🎯 Analysis Summary
Current State
Validation logic is scattered across multiple layers:
-
✅ Already in Domain (Good)
- Basic schema validation (format, required fields)
- Some business rules in
orderBusinessValidationSchema - Type validation
-
⚠️ In BFF Services (Should be moved)
- Order SKU business rules (
validateBusinessRules) - Invoice status validation
- Pagination limits
- SIM validation logic
- Order SKU business rules (
-
✅ Should Stay in Services (Infrastructure concerns)
- External API calls (WHMCS, Salesforce)
- Database lookups
- Payment method verification
- User mapping validation
- Duplicate order checks
📋 What Should Move to Domain
1. Order Business Rules (High Priority)
Current: apps/bff/src/modules/orders/services/order-validator.service.ts:176-228
validateBusinessRules(orderType: string, skus: string[]): void {
switch (orderType) {
case "SIM": {
// Check for SIM service plan
const hasSimService = skus.some(...);
// Check for activation fee
const hasActivation = skus.some(...);
}
case "VPN": {
// VPN activation check
}
case "Internet": {
// Internet service check
}
}
}
Should be: Extended validation in packages/domain/orders/schema.ts
2. Invoice Validation Constants (Medium Priority)
Current: apps/bff/src/modules/invoices/validators/invoice-validator.service.ts:14-23
private readonly validStatuses: readonly InvoiceStatus[] = [
"Paid", "Unpaid", "Cancelled", "Overdue", "Collections"
] as const;
private readonly maxLimit = 100;
private readonly minLimit = 1;
Should be: In packages/domain/billing/schema.ts
3. Common Validation Utilities
- ID validation helpers
- Pagination limits
- Status validation
❌ What Should NOT Move to Domain
Infrastructure/External Dependencies:
- User Mapping Validation - requires DB lookup
- Payment Method Validation - requires WHMCS API call
- Internet Duplication Check - requires WHMCS API call
- SKU Existence Check - requires Salesforce API call
- SIM Account Extraction - complex WHMCS integration logic
These involve:
- External API calls
- Database queries
- Caching
- Rate limiting
- Retry logic
- Logging infrastructure
🔄 Implementation Plan
Phase 1: Order Validation (High Priority)
- Create advanced order validation schemas in domain
- Move SKU business rules to domain
- Update OrderValidator service to use domain schemas
- Remove duplicate validation logic
Phase 2: Invoice Validation (Medium Priority)
- Move invoice constants to domain
- Enhance invoice query schemas
- Update InvoiceValidator to use domain constants
Phase 3: Common Patterns (Low Priority)
- Create shared validation helpers in domain/toolkit
- Standardize pagination schemas
- Create reusable validation utilities
📊 Expected Benefits
- Reusability: Frontend can use same validation logic
- Consistency: Same rules enforced everywhere
- Testability: Pure validation logic easy to unit test
- Maintainability: Single place to update business rules
- Type Safety: TypeScript infers from schema
🚦 Decision Matrix
| Validation Type | Move to Domain? | Reason |
|---|---|---|
| SKU format rules | ✅ Yes | Pure business logic |
| Order type rules | ✅ Yes | Domain constraint |
| Invoice status list | ✅ Yes | Domain constant |
| Pagination limits | ✅ Yes | Application constant |
| User exists check | ❌ No | Database query |
| Payment method exists | ❌ No | External API |
| SKU exists in SF | ❌ No | External API |
| Internet duplication | ❌ No | External API |
| SIM account extraction | ❌ No | Complex integration |
📝 Implementation Notes
Pattern: Domain Schema with Complex Validation
// packages/domain/orders/validation.ts (NEW FILE)
import { z } from "zod";
import { orderBusinessValidationSchema } from "./schema";
/**
* Extended order validation with SKU business rules
*/
export const orderWithSkuValidationSchema = orderBusinessValidationSchema.refine(
(data) => {
if (data.orderType === "SIM") {
const hasSimService = data.skus.some(/* logic */);
return hasSimService;
}
return true;
},
{ message: "SIM orders must include a service plan", path: ["skus"] }
);
Pattern: Domain Constants
// packages/domain/billing/constants.ts (NEW FILE)
export const INVOICE_VALIDATION = {
PAGINATION: {
MIN_LIMIT: 1,
MAX_LIMIT: 100,
DEFAULT_LIMIT: 10,
},
VALID_STATUSES: ["Paid", "Unpaid", "Cancelled", "Overdue", "Collections"] as const,
} as const;
✅ Success Criteria
- Order SKU validation rules in domain
- Invoice constants in domain
- Frontend can reuse validation schemas
- Services delegate to domain schemas
- No duplication of business rules
- All tests pass