Assist_Design/.cursor/plans/d-67f8fea5.plan.md
barsa 1b944f57aa Update Configuration Files and Refactor Code Structure
- Adjusted .prettierrc to ensure consistent formatting with a newline at the end of the file.
- Reformatted eslint.config.mjs for improved readability by aligning array elements.
- Updated pnpm-lock.yaml to use single quotes for consistency across dependencies.
- Simplified worktree setup in .cursor/worktrees.json for cleaner configuration.
- Enhanced documentation in .cursor/plans to clarify architecture refactoring.
- Refactored various service files for improved readability and maintainability, including rate-limiting and auth services.
- Updated imports and exports across multiple files for consistency and clarity.
- Improved error handling and logging in service methods to enhance debugging capabilities.
- Streamlined utility functions for better performance and maintainability across the domain packages.
2025-12-25 17:30:02 +09:00

11 KiB

Domain & BFF Clean Architecture Refactoring

Overview

Establish clean separation between domain (business logic) and BFF (infrastructure) layers by:

  1. Removing redundant mapper service wrappers in BFF
  2. Moving query builders from domain to BFF integration
  3. Using domain mappers directly in BFF services
  4. Eliminating unnecessary transformation layers

Current Issues

1. Query Builders in Wrong Layer

Location: packages/domain/orders/providers/salesforce/query.ts

  • buildOrderSelectFields(), buildOrderItemSelectFields(), buildOrderItemProduct2Fields()
  • These are SOQL infrastructure concerns, not business logic
  • Domain should not know about Salesforce query language

2. Redundant Mapper Service Wrapper

Location: apps/bff/src/modules/orders/services/order-whmcs-mapper.service.ts

  • Just wraps Providers.Whmcs.mapFulfillmentOrderItems() from domain
  • Adds logging but no transformation logic
  • Creates confusion about where mapping lives

3. Double Transformation Pattern

Current Flow:

BFF query → Raw SF data → Domain mapper → Domain type → BFF mapper??? → Same type

Should Be:

BFF query → Raw SF data → Domain mapper → Domain type → Use directly

4. Catalog Services Do It Correctly

Good Example: apps/bff/src/modules/catalog/services/sim-catalog.service.ts

const product = CatalogProviders.Salesforce.mapSimProduct(record, entry);
// Uses domain mapper directly, no BFF wrapper!

Architecture Principles

Domain Layer (packages/domain/)

Contains:

  • Business types (OrderDetails, OrderSummary)
  • Raw provider types (SalesforceOrderRecord)
  • Validation schemas (Zod)
  • Transformation mappers (Raw → Domain)
  • Business validation functions

Does NOT Contain:

  • Query builders (SOQL, GraphQL)
  • Field configuration
  • HTTP/API concerns

BFF Integration Layer (apps/bff/src/integrations/)

Contains:

  • Query builders (SOQL construction)
  • Connection services
  • Integration services that:
    • Build queries
    • Execute queries
    • Use domain mappers
    • Return domain types

Does NOT Contain:

  • Additional mapping logic
  • Business validation

BFF Application Layer (apps/bff/src/modules/)

Contains:

  • Orchestrators (workflow coordination)
  • Controllers (HTTP endpoints)
  • Uses integration services
  • Uses domain types directly

Does NOT Contain:

  • Direct Salesforce queries
  • Mapper service wrappers
  • Double transformations

Refactoring Steps

Phase 1: Create Salesforce Integration Services

1.1 Create SalesforceOrderService

File: apps/bff/src/integrations/salesforce/services/salesforce-order.service.ts

Encapsulates all Salesforce order operations:

  • getOrderById(orderId): Promise<OrderDetails | null>
  • getOrdersForAccount(accountId): Promise<OrderSummary[]>
  • Builds queries internally
  • Uses domain mappers for transformation
  • Returns domain types

Benefits:

  • Encapsulation of SF-specific logic
  • Easy to test
  • Easy to swap providers
  • No SF details leak to application layer

1.2 Update OrderOrchestrator

  • Remove direct this.sf.query() calls
  • Inject and use SalesforceOrderService
  • Remove query building logic
  • Just coordinate workflows

Phase 2: Move Query Builders

2.1 Move Query Builders to BFF

From: packages/domain/orders/providers/salesforce/query.ts

To: apps/bff/src/integrations/salesforce/utils/order-query-builder.ts

Move these functions:

  • buildOrderSelectFields()
  • buildOrderItemSelectFields()
  • buildOrderItemProduct2Fields()

2.2 Clean Domain Exports

Remove query builder exports from:

  • packages/domain/orders/providers/salesforce/index.ts
  • packages/domain/orders/providers/index.ts
  • packages/domain/orders/index.ts

Phase 3: Remove Redundant Mapper Services

3.1 Delete OrderWhmcsMapper Service

File to DELETE: apps/bff/src/modules/orders/services/order-whmcs-mapper.service.ts

It only wraps domain mappers - provides no value.

3.2 Update OrderFulfillmentOrchestrator

Replace:

constructor(private orderWhmcsMapper: OrderWhmcsMapper) {}
const result = this.orderWhmcsMapper.mapOrderItemsToWhmcs(items);

With:

import { Providers } from "@customer-portal/domain/orders";
const result = Providers.Whmcs.mapFulfillmentOrderItems(items);

Direct domain mapper usage - single transformation!

3.3 Update orders.module.ts

  • Remove OrderWhmcsMapper from providers
  • Remove import statement

Phase 4: Verify Catalog Pattern Consistency

Catalog services already follow the clean pattern - verify they continue to:

  • Build queries in BFF service layer
  • Use CatalogProviders.Salesforce.mapXXXProduct() directly
  • Return domain types without additional mapping

Phase 5: Clean Up Field Configuration (If Unused)

Investigation needed: Check if SalesforceFieldConfigService is actually used.

If NOT used in order/catalog flows:

  • Consider removing or documenting as future feature
  • Field names are already defined in raw types

Phase 6: Documentation Updates

6.1 Update Domain README

  • Clarify that query builders don't belong in domain
  • Add architecture diagram showing clear boundaries

6.2 Create Integration Layer Guide

Document:

  • When to create integration services
  • Pattern: Query → Transform → Return domain type
  • No additional mapping in BFF

6.3 Update ORDERS-ARCHITECTURE-REVIEW.md

  • Mark query builders as moved
  • Mark mapper wrappers as removed
  • Show final clean architecture

File Changes Summary

Files to CREATE

  1. apps/bff/src/integrations/salesforce/services/salesforce-order.service.ts
  2. apps/bff/src/integrations/salesforce/utils/order-query-builder.ts

Files to MODIFY

  1. apps/bff/src/modules/orders/services/order-orchestrator.service.ts - Use SalesforceOrderService
  2. apps/bff/src/modules/orders/services/order-fulfillment-orchestrator.service.ts - Use domain mapper directly
  3. apps/bff/src/modules/orders/orders.module.ts - Update providers
  4. apps/bff/src/integrations/salesforce/salesforce.module.ts - Export new service
  5. packages/domain/orders/providers/salesforce/index.ts - Remove query exports
  6. packages/domain/orders/providers/index.ts - Remove query exports
  7. packages/domain/orders/index.ts - Remove query exports

Files to DELETE

  1. apps/bff/src/modules/orders/services/order-whmcs-mapper.service.ts
  2. packages/domain/orders/providers/salesforce/query.ts

Documentation to UPDATE

  1. packages/domain/README.md
  2. ORDERS-ARCHITECTURE-REVIEW.md
  3. Create: docs/BFF-INTEGRATION-PATTERNS.md

Expected Outcomes

Architecture Cleanliness

  • Single source of truth for transformations (domain mappers)
  • Clear separation: domain = business, BFF = infrastructure
  • No redundant mapping layers
  • Query logic in correct layer (BFF integration)

Code Quality

  • Easier to test (clear boundaries)
  • Easier to maintain (no duplication)
  • Easier to understand (one transformation path)
  • Easier to swap providers (integration services encapsulate)

Developer Experience

  • Clear patterns to follow
  • No confusion about where code goes
  • Consistent with catalog services
  • Self-documenting architecture

Migration Notes

Breaking Changes

None for consumers - All changes are internal refactoring

Testing

  • Unit test new SalesforceOrderService
  • Verify order creation flow still works
  • Verify order fulfillment flow still works
  • Verify catalog fetching still works

Rollback Plan

Git history preserves old structure - can revert commits if issues arise.

Success Criteria

  • Query builders moved to BFF integration layer
  • OrderWhmcsMapper service deleted
  • SalesforceOrderService created and used
  • OrderOrchestrator no longer builds SOQL queries
  • OrderFulfillmentOrchestrator uses domain mapper directly
  • Domain exports cleaned (no query builders)
  • Documentation updated
  • All tests passing (no linting errors)
  • Order creation works end-to-end (ready for testing)
  • Order fulfillment works end-to-end (ready for testing)

Final Architecture:

┌─────────────────────────────────────────┐
│ Controller (HTTP)                       │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│ Orchestrator (Application)              │
│  - Coordinates workflows                │
│  - Uses Integration Services            │
│  - Works with Domain Types              │
└──────────────┬──────────────────────────┘
               │
    ┌──────────┴──────────┐
    │                     │
┌───▼───────────┐  ┌──────▼──────────────┐
│ Domain        │  │ Integration         │
│ (Business)    │  │ (Infrastructure)    │
│               │  │                     │
│ • Types       │  │ • SF OrderService   │
│ • Schemas     │  │ • Query Builders    │
│ • Mappers ────┼──┤ • Connections       │
│ • Validators  │  │ • Field Mapping     │
└───────────────┘  └─────────────────────┘

Flow: Query (BFF) → Raw Data → Domain Mapper → Domain Type → Use Directly
      └─ One transformation, no duplication ─┘

To-dos

  • Create SalesforceOrderService in BFF integration layer with methods: getOrderById, getOrdersForAccount
  • Move query builders from packages/domain/orders/providers/salesforce/query.ts to apps/bff/src/integrations/salesforce/utils/order-query-builder.ts
  • Update OrderOrchestrator to use SalesforceOrderService instead of direct SF queries
  • Delete redundant OrderWhmcsMapper service wrapper
  • Update OrderFulfillmentOrchestrator to use domain Providers.Whmcs mapper directly
  • Remove query builder exports from domain package index files
  • Update orders.module.ts and salesforce.module.ts with new services
  • Verify catalog services follow same clean pattern (already correct)
  • Update domain README and architecture documentation with clean patterns
  • Test order creation and fulfillment flows end-to-end