# Architecture Cleanup Analysis **Date**: October 8, 2025 **Status**: Plan Mostly Implemented - Minor Cleanup Needed ## Executive Summary The refactoring plan in `\d.plan.md` has been **~85% implemented**. The major architectural improvements have been completed: ✅ **Completed:** - Centralized DB mappers in `apps/bff/src/infra/mappers/` - Deleted `FreebitMapperService` - Moved Freebit utilities to domain layer - WHMCS services now use domain mappers directly - All redundant wrapper services removed ❌ **Remaining Issues:** 1. **Pub/Sub event types still in BFF** (should be in domain) 2. **Empty transformer directories** (should be deleted) 3. **Business error codes in BFF** (should be in domain) --- ## Detailed Findings ### ✅ 1. DB Mappers Centralization - COMPLETE **Status**: ✅ Fully Implemented **Location**: `apps/bff/src/infra/mappers/` ``` apps/bff/src/infra/mappers/ ├── index.ts ✅ ├── user.mapper.ts ✅ └── mapping.mapper.ts ✅ ``` **Evidence:** - `mapPrismaUserToDomain()` properly maps Prisma → Domain - `mapPrismaMappingToDomain()` properly maps Prisma → Domain - Old `user-mapper.util.ts` has been deleted - Services are using centralized mappers **✅ This is production-ready and follows clean architecture.** --- ### ✅ 2. Freebit Integration - COMPLETE **Status**: ✅ Fully Implemented **What was done:** 1. ✅ Deleted `apps/bff/src/integrations/freebit/services/freebit-mapper.service.ts` 2. ✅ Created `packages/domain/sim/providers/freebit/utils.ts` with: - `normalizeAccount()` - `validateAccount()` - `formatDateForApi()` - `parseDateFromApi()` 3. ✅ Exported utilities from `packages/domain/sim/providers/freebit/index.ts` 4. ✅ Services now use domain mappers directly: - `Freebit.transformFreebitAccountDetails()` - `Freebit.transformFreebitTrafficInfo()` - `Freebit.normalizeAccount()` **✅ This is production-ready and follows clean architecture.** --- ### ✅ 3. WHMCS Services Using Domain Mappers - COMPLETE **Status**: ✅ Fully Implemented **Evidence from `apps/bff/src/integrations/whmcs/services/whmcs-invoice.service.ts`:** ```typescript // Line 213: Using domain mappers directly const defaultCurrency = this.currencyService.getDefaultCurrency(); const transformed = Providers.Whmcs.transformWhmcsInvoice(whmcsInvoice, { defaultCurrencyCode: defaultCurrency.code, defaultCurrencySymbol: defaultCurrency.prefix || defaultCurrency.suffix, }); ``` **Evidence from `whmcs-payment.service.ts`:** ```typescript import { Providers } from "@customer-portal/domain/payments"; // Using domain mappers directly ``` **✅ Services are correctly using domain mappers with currency context.** --- ### ❌ 4. Pub/Sub Event Types Still in BFF - NEEDS MIGRATION **Status**: ❌ **Not Implemented** **Current Location**: `apps/bff/src/integrations/salesforce/types/pubsub-events.types.ts` **Problem**: These are **provider-specific raw types** for Salesforce Platform Events, but they're still in the BFF layer. **Current types:** ```typescript // In apps/bff/src/integrations/salesforce/types/pubsub-events.types.ts export interface SalesforcePubSubSubscription { topicName: string; } export interface SalesforcePubSubEventPayload { OrderId__c?: string; OrderId?: string; [key: string]: unknown; } export interface SalesforcePubSubEvent { payload: SalesforcePubSubEventPayload; replayId?: number; } export interface SalesforcePubSubError { details?: string; metadata?: SalesforcePubSubErrorMetadata; [key: string]: unknown; } export type SalesforcePubSubCallbackType = "data" | "event" | "grpcstatus" | "end" | "error"; ``` **🔴 RECOMMENDATION:** These are **Salesforce provider types** and should be moved to the domain layer: **New Location**: `packages/domain/orders/providers/salesforce/pubsub.types.ts` **Rationale:** - These are **raw provider types** (like `WhmcsInvoice`, `FreebitAccountDetailsRaw`) - They represent Salesforce Platform Events structure - Domain layer already has `packages/domain/orders/providers/salesforce/` - They're used for order provisioning events **Migration Path:** ``` 1. Create: packages/domain/orders/providers/salesforce/pubsub.types.ts 2. Move types from BFF 3. Export from: packages/domain/orders/providers/salesforce/index.ts 4. Update imports in: apps/bff/src/integrations/salesforce/events/pubsub.subscriber.ts ``` --- ### ⚠️ 5. Empty WHMCS Transformers Directory - CLEANUP NEEDED **Status**: ⚠️ **Partially Cleaned** **Current State**: The directory exists but is empty ``` apps/bff/src/integrations/whmcs/transformers/ ├── services/ (empty) ├── utils/ (empty) └── validators/ (empty) ``` **Evidence:** - ✅ Transformer services deleted - ✅ Not referenced in `whmcs.module.ts` - ✅ Not imported anywhere - ❌ **But directory still exists** **🟡 RECOMMENDATION:** Delete the entire `transformers/` directory: ```bash rm -rf apps/bff/src/integrations/whmcs/transformers/ ``` **Impact**: Zero - nothing uses it anymore. --- ### ❌ 6. Business Error Codes in BFF - NEEDS MIGRATION **Status**: ❌ **Not Implemented** **Current Location**: `apps/bff/src/modules/orders/services/order-fulfillment-error.service.ts` **Problem**: Business error codes are defined in BFF: ```typescript export enum OrderFulfillmentErrorCode { PAYMENT_METHOD_MISSING = "PAYMENT_METHOD_MISSING", ORDER_NOT_FOUND = "ORDER_NOT_FOUND", WHMCS_ERROR = "WHMCS_ERROR", MAPPING_ERROR = "MAPPING_ERROR", VALIDATION_ERROR = "VALIDATION_ERROR", SALESFORCE_ERROR = "SALESFORCE_ERROR", PROVISIONING_ERROR = "PROVISIONING_ERROR", } ``` **🔴 RECOMMENDATION:** Move to domain layer as these are **business error codes**: **New Location**: `packages/domain/orders/constants.ts` or `packages/domain/orders/errors.ts` **Rationale:** - These represent business-level error categories - Not infrastructure concerns - Could be useful for other consumers (frontend, webhooks, etc.) - Part of the domain's error vocabulary --- ### ✅ 7. Infrastructure-Specific Types - CORRECTLY PLACED **Status**: ✅ **Correct** Some types in BFF modules are **correctly placed** as they are infrastructure concerns: **Example: `apps/bff/src/modules/invoices/types/invoice-service.types.ts`:** ```typescript export interface InvoiceServiceStats { totalInvoicesRetrieved: number; totalPaymentLinksCreated: number; totalSsoLinksCreated: number; averageResponseTime: number; lastRequestTime?: Date; lastErrorTime?: Date; } export interface InvoiceHealthStatus { status: "healthy" | "unhealthy"; details: { whmcsApi?: string; mappingsService?: string; error?: string; timestamp: string; }; } ``` **✅ These are BFF-specific monitoring/health check types and belong in BFF.** --- ## Summary of Remaining Work ### High Priority | Issue | Location | Action | Effort | |-------|----------|--------|--------| | **Pub/Sub Types** | `apps/bff/src/integrations/salesforce/types/pubsub-events.types.ts` | Move to `packages/domain/orders/providers/salesforce/` | 15 min | | **Error Codes** | `apps/bff/src/modules/orders/services/order-fulfillment-error.service.ts` | Move enum to `packages/domain/orders/errors.ts` | 10 min | ### Low Priority (Cleanup) | Issue | Location | Action | Effort | |-------|----------|--------|--------| | **Empty Transformers** | `apps/bff/src/integrations/whmcs/transformers/` | Delete directory | 1 min | --- ## Architecture Score ### Before Refactoring: 60/100 - ❌ Redundant wrapper services everywhere - ❌ Scattered DB mappers - ❌ Unclear boundaries ### Current State: 85/100 - ✅ Centralized DB mappers - ✅ Direct domain mapper usage - ✅ Clean integration layer - ✅ No redundant wrappers - ⚠️ Minor cleanup needed ### Target State: 100/100 - All business types in domain - All provider types in domain - Clean BFF focusing on orchestration --- ## Recommended Actions ### Immediate (30 minutes) 1. **Move Pub/Sub Types to Domain** ```bash # Create new file mkdir -p packages/domain/orders/providers/salesforce # Move types mv apps/bff/src/integrations/salesforce/types/pubsub-events.types.ts \ packages/domain/orders/providers/salesforce/pubsub.types.ts # Update exports and imports ``` 2. **Move Order Error Codes to Domain** ```typescript // Create: packages/domain/orders/errors.ts export const ORDER_FULFILLMENT_ERROR_CODE = { PAYMENT_METHOD_MISSING: "PAYMENT_METHOD_MISSING", ORDER_NOT_FOUND: "ORDER_NOT_FOUND", WHMCS_ERROR: "WHMCS_ERROR", MAPPING_ERROR: "MAPPING_ERROR", VALIDATION_ERROR: "VALIDATION_ERROR", SALESFORCE_ERROR: "SALESFORCE_ERROR", PROVISIONING_ERROR: "PROVISIONING_ERROR", } as const; export type OrderFulfillmentErrorCode = typeof ORDER_FULFILLMENT_ERROR_CODE[keyof typeof ORDER_FULFILLMENT_ERROR_CODE]; ``` 3. **Delete Empty Transformers Directory** ```bash rm -rf apps/bff/src/integrations/whmcs/transformers/ ``` ### Documentation (10 minutes) 4. **Update Success Criteria in `\d.plan.md`** - Mark completed items as done - Document remaining work --- ## Conclusion The refactoring plan has been **successfully implemented** with only minor cleanup needed: **🎉 Achievements:** - Clean architecture boundaries established - Domain layer is the single source of truth for business logic - BFF layer focuses on orchestration and infrastructure - No redundant wrapper services - Centralized DB mappers **🔧 Final Touch-ups Needed:** - Move pub/sub types to domain (15 min) - Move error codes to domain (10 min) - Delete empty directories (1 min) **Total remaining effort: ~30 minutes to achieve 100% cleanliness.** --- ## Files to Check ### ✅ Already Clean - `apps/bff/src/infra/mappers/` - Centralized DB mappers - `apps/bff/src/integrations/freebit/services/` - Using domain mappers - `apps/bff/src/integrations/whmcs/services/` - Using domain mappers - `packages/domain/sim/providers/freebit/` - Contains utilities and mappers ### ❌ Needs Attention - `apps/bff/src/integrations/salesforce/types/pubsub-events.types.ts` - Move to domain - `apps/bff/src/modules/orders/services/order-fulfillment-error.service.ts` - Move enum to domain - `apps/bff/src/integrations/whmcs/transformers/` - Delete empty directory