Assist_Design/DOMAIN_VIOLATIONS_REPORT.md
barsa e5ce4e166c Refactor mappers and services for improved type safety and code clarity
- Updated export statements in user and mapping mappers for consistency.
- Enhanced FreebitAuthService to explicitly define response types for better type inference.
- Refactored various services to improve error handling and response structure.
- Cleaned up unused code and comments across multiple files to enhance readability.
- Improved type annotations in invoice and subscription services for better validation and consistency.
2025-10-22 10:58:16 +09:00

375 lines
11 KiB
Markdown

# Domain Violations Report
**Customer Portal - BFF and Portal Domain Violations Analysis**
---
## Executive Summary
This report identifies cases where the BFF (Backend for Frontend) and Portal applications are not following the domain package as the single source of truth for types, validation, and business logic. The analysis reveals several categories of violations that need to be addressed to maintain clean architecture principles.
## Architecture Overview
The customer portal follows a clean architecture pattern with:
- **Domain Package** (`packages/domain/`): Single source of truth for types, schemas, and business logic
- **BFF** (`apps/bff/`): NestJS backend that should consume domain types
- **Portal** (`apps/portal/`): Next.js frontend that should consume domain types
## Key Findings
### ✅ **Good Practices Found**
1. **Domain Package Structure**: Well-organized with clear separation of concerns
2. **Type Imports**: Most services correctly import domain types
3. **Validation Patterns**: Many components properly extend domain schemas
4. **Provider Adapters**: Clean separation between domain contracts and provider implementations
### ❌ **Domain Violations Identified**
## 1. BFF Layer Violations
### 1.1 Duplicate Validation Schemas
**Location**: `apps/bff/src/modules/orders/services/order-fulfillment-validator.service.ts`
```typescript
// ❌ VIOLATION: Duplicate validation schema
const salesforceAccountIdSchema = z.string().min(1, "Salesforce AccountId is required");
```
**Issue**: Creating local Zod schemas instead of using domain validation
**Impact**: Duplication of validation logic, potential inconsistencies
### 1.2 Infrastructure-Specific Types
**Location**: `apps/bff/src/modules/orders/services/order-fulfillment-validator.service.ts`
```typescript
// ❌ VIOLATION: BFF-specific interface that could be domain type
export interface OrderFulfillmentValidationResult {
sfOrder: SalesforceOrderRecord;
clientId: number;
isAlreadyProvisioned: boolean;
whmcsOrderId?: string;
}
```
**Issue**: Business logic types defined in BFF instead of domain
**Impact**: Business logic scattered across layers
### 1.3 Local Type Definitions
**Location**: `apps/bff/src/modules/invoices/services/invoice-retrieval.service.ts`
```typescript
// ❌ VIOLATION: Local interface instead of domain type
interface UserMappingInfo {
userId: string;
whmcsClientId: number;
}
```
**Issue**: Infrastructure types that could be standardized in domain
**Impact**: Inconsistent type definitions across services
### 1.4 Response Schema Definitions
**Location**: `apps/bff/src/modules/orders/orders.controller.ts`
```typescript
// ❌ VIOLATION: Controller-specific response schema
private readonly createOrderResponseSchema = apiSuccessResponseSchema(
z.object({
sfOrderId: z.string(),
status: z.string(),
message: z.string(),
})
);
```
**Issue**: Response schemas defined in controllers instead of domain
**Impact**: API contract not centralized
### 1.5 SOQL Utility Schemas
**Location**: `apps/bff/src/integrations/salesforce/utils/soql.util.ts`
```typescript
// ❌ VIOLATION: Utility-specific schemas
const nonEmptyStringSchema = z.string().min(1, "Value cannot be empty").trim();
const soqlFieldNameSchema = z.string().trim().regex(/^[A-Za-z0-9_.]+$/, "Invalid SOQL field name");
```
**Issue**: Common validation patterns not centralized
**Impact**: Repeated validation logic
## 2. Portal Layer Violations
### 2.1 Component-Specific Types
**Location**: `apps/portal/src/features/catalog/components/base/PricingDisplay.tsx`
```typescript
// ❌ VIOLATION: UI-specific types that could be domain types
export interface PricingTier {
name: string;
price: number;
billingCycle: "Monthly" | "Onetime" | "Annual";
description?: string;
features?: string[];
isRecommended?: boolean;
originalPrice?: number;
}
```
**Issue**: Business concepts defined in UI components
**Impact**: Business logic in presentation layer
### 2.2 Checkout-Specific Types
**Location**: `apps/portal/src/features/checkout/hooks/useCheckout.ts`
```typescript
// ❌ VIOLATION: Business logic types in UI layer
type CheckoutItemType = "plan" | "installation" | "addon" | "activation" | "vpn";
interface CheckoutItem extends CatalogProductBase {
quantity: number;
itemType: CheckoutItemType;
autoAdded?: boolean;
}
interface CheckoutTotals {
monthlyTotal: number;
oneTimeTotal: number;
}
```
**Issue**: Business domain types defined in UI hooks
**Impact**: Business logic scattered across layers
### 2.3 Catalog Utility Types
**Location**: `apps/portal/src/features/catalog/utils/catalog.utils.ts`
```typescript
// ❌ VIOLATION: TODO comment indicates missing domain type
// TODO: Define CatalogFilter type properly
type CatalogFilter = {
category?: string;
priceMin?: number;
priceMax?: number;
search?: string;
};
```
**Issue**: Explicitly acknowledged missing domain type
**Impact**: Business concepts not properly modeled
### 2.4 Form Extension Patterns
**Location**: `apps/portal/src/features/auth/components/SignupForm/SignupForm.tsx`
```typescript
// ⚠️ ACCEPTABLE: Extending domain schema with UI concerns
export const signupFormSchema = signupInputSchema
.extend({
confirmPassword: z.string().min(1, "Please confirm your password"),
})
.refine(data => data.acceptTerms === true, {
message: "You must accept the terms and conditions",
path: ["acceptTerms"],
})
```
**Status**: This is actually a good pattern - extending domain schemas with UI-specific fields
## 3. Cross-Cutting Concerns
### 3.1 Environment Configuration
**Location**: `apps/bff/src/core/config/env.validation.ts`
```typescript
// ⚠️ ACCEPTABLE: Infrastructure configuration
export const envSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
// ... many environment variables
});
```
**Status**: Environment configuration is appropriately infrastructure-specific
### 3.2 Database Mapping Types
**Location**: `apps/bff/src/infra/mappers/mapping.mapper.ts`
```typescript
// ✅ GOOD: Infrastructure mapping with clear documentation
export function mapPrismaMappingToDomain(mapping: PrismaIdMapping): UserIdMapping {
// Maps Prisma entity to Domain type
}
```
**Status**: Proper infrastructure-to-domain mapping
## Recommendations
### 1. Immediate Actions (High Priority)
#### 1.1 Move Business Types to Domain
**Action**: Move the following types to appropriate domain modules:
```typescript
// Move to packages/domain/orders/
export interface OrderFulfillmentValidationResult {
sfOrder: SalesforceOrderRecord;
clientId: number;
isAlreadyProvisioned: boolean;
whmcsOrderId?: string;
}
// Move to packages/domain/catalog/
export interface PricingTier {
name: string;
price: number;
billingCycle: "Monthly" | "Onetime" | "Annual";
description?: string;
features?: string[];
isRecommended?: boolean;
originalPrice?: number;
}
// Move to packages/domain/orders/
export interface CheckoutItem {
// Define based on CatalogProductBase + quantity + itemType
}
```
#### 1.2 Centralize Validation Schemas
**Action**: Move common validation patterns to domain:
```typescript
// Add to packages/domain/common/schema.ts
export const salesforceAccountIdSchema = z.string().min(1, "Salesforce AccountId is required");
export const nonEmptyStringSchema = z.string().min(1, "Value cannot be empty").trim();
export const soqlFieldNameSchema = z.string().trim().regex(/^[A-Za-z0-9_.]+$/, "Invalid SOQL field name");
```
#### 1.3 Define Missing Domain Types
**Action**: Complete the TODO items and define missing types:
```typescript
// Add to packages/domain/catalog/
export interface CatalogFilter {
category?: string;
priceMin?: number;
priceMax?: number;
search?: string;
}
// Add to packages/domain/orders/
export interface OrderCreateResponse {
sfOrderId: string;
status: string;
message: string;
}
```
### 2. Medium Priority Actions
#### 2.1 Standardize Response Types
**Action**: Create standardized API response types in domain:
```typescript
// Add to packages/domain/common/
export interface OrderCreateResponse {
sfOrderId: string;
status: string;
message: string;
}
export const orderCreateResponseSchema = z.object({
sfOrderId: z.string(),
status: z.string(),
message: z.string(),
});
```
#### 2.2 Refactor Checkout Logic
**Action**: Move checkout business logic to domain:
```typescript
// Add to packages/domain/orders/
export interface CheckoutCart {
items: CheckoutItem[];
totals: CheckoutTotals;
configuration: OrderConfigurations;
}
export function calculateCheckoutTotals(items: CheckoutItem[]): CheckoutTotals {
// Move calculation logic from Portal to Domain
}
```
### 3. Long-term Improvements
#### 3.1 Domain Service Layer
**Action**: Consider creating domain services for complex business logic:
```typescript
// Add to packages/domain/orders/services/
export class OrderValidationService {
static validateFulfillmentRequest(
sfOrderId: string,
idempotencyKey: string
): Promise<OrderFulfillmentValidationResult> {
// Move validation logic from BFF to Domain
}
}
```
#### 3.2 Type Safety Improvements
**Action**: Enhance type safety across layers:
```typescript
// Ensure all domain types are properly exported
// Add runtime validation for all domain types
// Implement proper error handling with domain error types
```
## Implementation Plan
### Phase 1: Critical Violations (Week 1-2)
1. Move `OrderFulfillmentValidationResult` to domain
2. Move `PricingTier` to domain
3. Centralize validation schemas
4. Define missing `CatalogFilter` type
### Phase 2: Business Logic Consolidation (Week 3-4)
1. Move checkout types to domain
2. Standardize API response types
3. Refactor validation services
4. Update imports across applications
### Phase 3: Architecture Improvements (Week 5-6)
1. Create domain service layer
2. Implement proper error handling
3. Add comprehensive type exports
4. Update documentation
## Success Metrics
- **Type Reuse**: 90%+ of business types defined in domain
- **Validation Consistency**: Single validation schema per business rule
- **Import Clarity**: Clear domain imports in BFF and Portal
- **Documentation**: Updated architecture documentation
## Conclusion
The analysis reveals that while the domain package is well-structured, there are several violations where business logic and types are scattered across the BFF and Portal layers. The recommended actions will help establish the domain package as the true single source of truth, improving maintainability and consistency across the application.
The violations are primarily in business logic types and validation schemas that should be centralized in the domain layer. The form extension patterns in the Portal are actually good examples of how to properly extend domain schemas with UI-specific concerns.
---
**Report Generated**: $(date)
**Analysis Scope**: BFF and Portal applications
**Domain Package**: `packages/domain/`