Assist_Design/packages/domain/orders/BEFORE-AFTER-COMPARISON.md

13 KiB

Orders Domain: Before vs After Restructuring

📁 File Structure Comparison

BEFORE (Current - Convoluted)

packages/domain/orders/
├── contract.ts                    ← 247 lines, EVERYTHING MIXED
│   ├── Business types
│   ├── Salesforce field maps      ← Should be in providers/
│   ├── Re-exports from schema     ← Redundant
│   └── Unclear organization
│
├── schema.ts                      ← 269 lines, okay but needs organization
│   └── Schemas + types
│
├── validation.ts                  ← 180 lines, GOOD (just created)
│   └── Business rules
│
├── providers/
│   ├── salesforce/
│   │   ├── field-map.mapper.ts   ← Odd naming
│   │   ├── raw.types.ts          ← Good
│   │   ├── query.ts              ← Good
│   │   └── index.ts
│   ├── whmcs/
│   │   ├── mapper.ts             ← Good
│   │   ├── raw.types.ts          ← Good
│   │   └── index.ts
│   └── index.ts
│
└── index.ts                       ← Mixed exports

ISSUES:
❌ contract.ts is a dumping ground (247 lines)
❌ SF field maps mixed with business types
❌ Unclear what's provider-specific
❌ Inconsistent with other domains

AFTER (Proposed - Clean)

packages/domain/orders/
├── contract.ts                    ← 50 lines, CONSTANTS ONLY ✅
│   ├── ORDER_TYPE
│   ├── ORDER_STATUS
│   └── ACTIVATION_TYPE
│
├── schema.ts                      ← 280 lines, BETTER ORGANIZED ✅
│   ├── Order schemas
│   ├── Order item schemas
│   ├── Creation schemas
│   ├── Fulfillment schemas
│   └── Query schemas
│
├── validation.ts                  ← 180 lines, BUSINESS RULES ✅
│   └── SKU validation helpers
│
├── providers/
│   ├── salesforce/
│   │   ├── raw.types.ts          ← Raw SF API types
│   │   ├── field-map.types.ts    ← SF field maps (NEW, MOVED) ✅
│   │   ├── mapper.ts             ← SF → Domain (RENAMED) ✅
│   │   ├── query.ts              ← SF queries
│   │   └── index.ts              ← Clean exports
│   ├── whmcs/
│   │   ├── raw.types.ts          ← Raw WHMCS API types
│   │   ├── mapper.ts             ← WHMCS → Domain
│   │   └── index.ts              ← Clean exports
│   └── index.ts                   ← Provider exports
│
└── index.ts                       ← CLEAN PUBLIC API ✅

BENEFITS:
✅ contract.ts = only constants (like other domains)
✅ SF field maps isolated in providers/
✅ Clear what's provider-specific
✅ Consistent with subscriptions/billing/customer
✅ Easy to navigate

📄 contract.ts Comparison

BEFORE: Mixed Concerns (247 lines)

/**
 * Orders Domain - Contract
 */

// Business types
export type OrderCreationType = "Internet" | "SIM" | "VPN" | "Other";
export type OrderStatus = string;
export type OrderType = string;
export type UserMapping = Pick<UserIdMapping, "userId" | "whmcsClientId" | "sfAccountId">;

// ❌ PROBLEM: Salesforce field maps mixed with business types
export interface SalesforceOrderMnpFieldMap {
  application: string;
  reservationNumber: string;
  expiryDate: string;
  phoneNumber: string;
  mvnoAccountNumber: string;
  portingDateOfBirth: string;
  portingFirstName: string;
  portingLastName: string;
  portingFirstNameKatakana: string;
  portingLastNameKatakana: string;
  portingGender: string;
}

export interface SalesforceOrderBillingFieldMap {
  street: string;
  city: string;
  state: string;
  postalCode: string;
  country: string;
}

export interface SalesforceOrderFieldMap {
  orderType: string;
  activationType: string;
  activationScheduledAt: string;
  activationStatus: string;
  internetPlanTier: string;
  installationType: string;
  weekendInstall: string;
  accessMode: string;
  hikariDenwa: string;
  vpnRegion: string;
  simType: string;
  eid: string;
  simVoiceMail: string;
  simCallWaiting: string;
  mnp: SalesforceOrderMnpFieldMap;
  whmcsOrderId: string;
  lastErrorCode?: string;
  lastErrorMessage?: string;
  lastAttemptAt?: string;
  addressChanged: string;
  billing: SalesforceOrderBillingFieldMap;
}

export interface SalesforceOrderItemFieldMap {
  billingCycle: string;
  whmcsServiceId: string;
}

export interface SalesforceFieldMap {
  account: SalesforceAccountFieldMap;
  product: SalesforceProductFieldMap;
  order: SalesforceOrderFieldMap;
  orderItem: SalesforceOrderItemFieldMap;
}

// ❌ PROBLEM: Re-exports from schema (redundant)
export type {
  FulfillmentOrderProduct,
  FulfillmentOrderItem,
  FulfillmentOrderDetails,
  OrderItemSummary,
  OrderItemDetails,
  OrderSummary,
  OrderDetails,
  OrderQueryParams,
  OrderConfigurationsAddress,
  OrderConfigurations,
  CreateOrderRequest,
  OrderBusinessValidation,
  SfOrderIdParam,
} from './schema';

// TOTAL: 247 lines of mixed concerns

AFTER: Clean Constants (50 lines)

/**
 * Orders Domain - Contract
 * 
 * Business constants and enums for the orders domain.
 * All validated types are derived from schemas (see schema.ts).
 */

// ============================================================================
// Order Type Constants
// ============================================================================

/**
 * Order types available in the system
 */
export const ORDER_TYPE = {
  INTERNET: "Internet",
  SIM: "SIM",
  VPN: "VPN",
  OTHER: "Other",
} as const;

export type OrderType = (typeof ORDER_TYPE)[keyof typeof ORDER_TYPE];

// ============================================================================
// Order Status Constants
// ============================================================================

/**
 * Possible order statuses
 */
export const ORDER_STATUS = {
  DRAFT: "Draft",
  ACTIVATED: "Activated",
  PENDING: "Pending",
  FAILED: "Failed",
  CANCELLED: "Cancelled",
} as const;

export type OrderStatus = (typeof ORDER_STATUS)[keyof typeof ORDER_STATUS];

// ============================================================================
// Activation Type Constants
// ============================================================================

/**
 * Order activation types
 */
export const ACTIVATION_TYPE = {
  IMMEDIATE: "Immediate",
  SCHEDULED: "Scheduled",
} as const;

export type ActivationType = (typeof ACTIVATION_TYPE)[keyof typeof ACTIVATION_TYPE];

// ============================================================================
// SIM Type Constants
// ============================================================================

/**
 * SIM card types
 */
export const SIM_TYPE = {
  ESIM: "eSIM",
  PHYSICAL: "Physical SIM",
} as const;

export type SimType = (typeof SIM_TYPE)[keyof typeof SIM_TYPE];

// TOTAL: ~50 lines of clean constants only

🆕 New File: providers/salesforce/field-map.types.ts

/**
 * Salesforce Field Mappings
 * 
 * Dynamic field mappings for Salesforce custom fields.
 * These are provider-specific configuration, NOT domain types.
 */

import type { SalesforceAccountFieldMap } from "../../../customer/contract";
import type { SalesforceProductFieldMap } from "../../../catalog/contract";

// ============================================================================
// Order MNP Field Map
// ============================================================================

export interface SalesforceOrderMnpFieldMap {
  application: string;
  reservationNumber: string;
  expiryDate: string;
  phoneNumber: string;
  mvnoAccountNumber: string;
  portingDateOfBirth: string;
  portingFirstName: string;
  portingLastName: string;
  portingFirstNameKatakana: string;
  portingLastNameKatakana: string;
  portingGender: string;
}

// ============================================================================
// Order Billing Field Map
// ============================================================================

export interface SalesforceOrderBillingFieldMap {
  street: string;
  city: string;
  state: string;
  postalCode: string;
  country: string;
}

// ============================================================================
// Order Field Map
// ============================================================================

export interface SalesforceOrderFieldMap {
  orderType: string;
  activationType: string;
  activationScheduledAt: string;
  activationStatus: string;
  internetPlanTier: string;
  installationType: string;
  weekendInstall: string;
  accessMode: string;
  hikariDenwa: string;
  vpnRegion: string;
  simType: string;
  eid: string;
  simVoiceMail: string;
  simCallWaiting: string;
  mnp: SalesforceOrderMnpFieldMap;
  whmcsOrderId: string;
  lastErrorCode?: string;
  lastErrorMessage?: string;
  lastAttemptAt?: string;
  addressChanged: string;
  billing: SalesforceOrderBillingFieldMap;
}

// ============================================================================
// Order Item Field Map
// ============================================================================

export interface SalesforceOrderItemFieldMap {
  billingCycle: string;
  whmcsServiceId: string;
}

// ============================================================================
// Complete Field Map
// ============================================================================

export interface SalesforceFieldMap {
  account: SalesforceAccountFieldMap;
  product: SalesforceProductFieldMap;
  order: SalesforceOrderFieldMap;
  orderItem: SalesforceOrderItemFieldMap;
}

📋 index.ts Comparison

BEFORE: Mixed Exports

/**
 * Orders Domain
 */

// Business types
export { type OrderCreationType, type OrderStatus, type OrderType, type UserMapping } from "./contract";

// Provider-specific types
export type {
  SalesforceOrderMnpFieldMap,        // ❌ Should be in Providers export
  SalesforceOrderBillingFieldMap,    // ❌ Should be in Providers export
  SalesforceOrderFieldMap,           // ❌ Should be in Providers export
  SalesforceOrderItemFieldMap,       // ❌ Should be in Providers export
  SalesforceFieldMap,                // ❌ Should be in Providers export
} from "./contract";

// Schemas (includes derived types)
export * from "./schema";

// Validation (extended business rules)
export * from "./validation";

// Re-export types for convenience (redundant)
export type {
  FulfillmentOrderProduct,
  FulfillmentOrderItem,
  // ... many more
} from './schema';

// Provider adapters
export * as Providers from "./providers";

// Re-export provider types for convenience
export * from "./providers/whmcs/raw.types";
export * from "./providers/salesforce/raw.types";

AFTER: Clean Public API

/**
 * Orders Domain
 * 
 * Exports all order-related contracts, schemas, validation, and provider adapters.
 */

// ============================================================================
// Constants & Enums
// ============================================================================

export * from "./contract";

// ============================================================================
// Schemas & Types (Schema-First)
// ============================================================================

export * from "./schema";

// ============================================================================
// Validation (Extended Business Rules)
// ============================================================================

export * from "./validation";

// ============================================================================
// Provider Adapters
// ============================================================================

export * as Providers from "./providers";

// For convenience, export commonly used provider types at top level
export type {
  // Salesforce
  SalesforceOrderRecord,
  SalesforceOrderItemRecord,
  SalesforceFieldMap,              // ✅ Now clearly from Providers
  // WHMCS
  WhmcsAddOrderParams,
  WhmcsOrderItem,
  WhmcsOrderResult,
} from "./providers";

🎯 Impact Summary

Aspect Before After Improvement
contract.ts 247 lines, mixed 50 lines, constants -80% size, 100% clarity
Provider separation Mixed in contract Isolated in providers/ Clear boundaries
Consistency Unique pattern Matches other domains Easy to learn
Discoverability Unclear ownership Obvious location Fast navigation
Maintainability Changes affect multiple concerns Changes isolated Safer refactoring

Key Improvements

  1. contract.ts: 247 lines → 50 lines (constants only)
  2. Provider isolation: SF field maps moved to providers/salesforce/
  3. Pattern consistency: Now matches subscriptions, billing, customer domains
  4. Clarity: Obvious where each type belongs
  5. No breaking changes: All imports still work (just internally reorganized)

🚀 Migration Path

  1. Create providers/salesforce/field-map.types.ts (non-breaking)
  2. Update mapper imports (non-breaking)
  3. Rewrite contract.ts (breaking but minimal impact)
  4. Update index.ts exports (non-breaking)
  5. Test and verify

Result: Clean, maintainable, consistent orders domain! 🎉