# New Domain Architecture ## Overview The `@customer-portal/domain` package is now a **unified domain layer** following the **Provider-Aware Structure** pattern. It consolidates all types, schemas, and provider-specific logic into a single, well-organized package. ## 🎯 Goals 1. **Single Source of Truth**: One place for all domain contracts, schemas, and transformations 2. **Provider Isolation**: Raw provider types and mappers co-located within each domain 3. **Clean Exports**: Simple, predictable import paths 4. **Type Safety**: Runtime validation with Zod + TypeScript inference 5. **Maintainability**: Easy to find and update domain logic ## 📁 Structure ``` packages/domain/ ├── billing/ │ ├── contract.ts # Invoice, InvoiceItem, InvoiceList │ ├── schema.ts # Zod schemas │ ├── providers/ │ │ └── whmcs/ │ │ ├── raw.types.ts # WHMCS-specific types │ │ └── mapper.ts # Transform WHMCS → Invoice │ └── index.ts # Public exports ├── subscriptions/ │ ├── contract.ts # Subscription, SubscriptionList │ ├── schema.ts │ ├── providers/ │ │ └── whmcs/ │ │ ├── raw.types.ts │ │ └── mapper.ts │ └── index.ts ├── payments/ │ ├── contract.ts # PaymentMethod, PaymentGateway │ ├── schema.ts │ ├── providers/ │ │ └── whmcs/ │ │ ├── raw.types.ts │ │ └── mapper.ts │ └── index.ts ├── sim/ │ ├── contract.ts # SimDetails, SimUsage, SimTopUpHistory │ ├── schema.ts │ ├── providers/ │ │ └── freebit/ │ │ ├── raw.types.ts │ │ └── mapper.ts │ └── index.ts ├── orders/ │ ├── contract.ts # OrderSummary, OrderDetails, FulfillmentOrder │ ├── schema.ts │ ├── providers/ │ │ ├── whmcs/ │ │ │ ├── raw.types.ts # WHMCS AddOrder API types │ │ │ └── mapper.ts # Transform FulfillmentOrder → WHMCS │ │ └── salesforce/ │ │ ├── raw.types.ts # Salesforce Order/OrderItem │ │ └── mapper.ts # Transform Salesforce → OrderDetails │ └── index.ts ├── catalog/ │ ├── contract.ts # CatalogProduct, InternetPlan, SimProduct, VpnProduct │ ├── schema.ts │ ├── providers/ │ │ └── salesforce/ │ │ ├── raw.types.ts # Salesforce Product2 │ │ └── mapper.ts # Transform Product2 → CatalogProduct │ └── index.ts ├── common/ │ ├── types.ts # IsoDateTimeString, branded types, API wrappers │ └── index.ts ├── toolkit/ │ ├── formatting/ # Currency, date, phone, text formatters │ ├── validation/ # Email, URL, string validators │ ├── typing/ # Type guards, assertions, helpers │ └── index.ts ├── package.json ├── tsconfig.json └── index.ts # Main entry point ``` ## 📦 Usage ### Import Contracts ```typescript // Import domain contracts import type { Invoice, InvoiceList } from "@customer-portal/domain/billing"; import type { Subscription } from "@customer-portal/domain/subscriptions"; import type { SimDetails } from "@customer-portal/domain/sim"; import type { OrderSummary } from "@customer-portal/domain/orders"; import type { CatalogProduct } from "@customer-portal/domain/services"; ``` ### Import Schemas ```typescript // Import Zod schemas for runtime validation import { invoiceSchema, invoiceListSchema } from "@customer-portal/domain/billing"; import { simDetailsSchema } from "@customer-portal/domain/sim"; // Validate at runtime const invoice = invoiceSchema.parse(rawData); ``` ### Import Provider Mappers ```typescript // Import provider-specific mappers import { WhmcsBillingMapper } from "@customer-portal/domain/billing"; import { FreebitSimMapper } from "@customer-portal/domain/sim"; import { WhmcsOrderMapper, SalesforceOrderMapper } from "@customer-portal/domain/orders"; // Transform provider data to normalized domain contracts const invoice = WhmcsBillingMapper.transformWhmcsInvoice(whmcsInvoiceData); const simDetails = FreebitSimMapper.transformFreebitAccountDetails(freebitAccountData); const order = SalesforceOrderMapper.transformOrderToDetails(salesforceOrderRecord, items); ``` ### Import Utilities ```typescript // Import toolkit utilities import { Formatting, Validation, Typing } from "@customer-portal/domain/toolkit"; // Use formatters const formatted = Formatting.formatCurrency(10000, "JPY"); const date = Formatting.formatDate(isoString); // Use validators const isValid = Validation.isValidEmail(email); // Use type guards if (Typing.isDefined(value)) { // TypeScript knows value is not null/undefined } ``` ## 🔄 Data Flow ### Inbound (Provider → Domain) ``` External API Response ↓ Raw Provider Types (providers/*/raw.types.ts) ↓ Provider Mapper (providers/*/mapper.ts) ↓ Zod Schema Validation (schema.ts) ↓ Domain Contract (contract.ts) ↓ Application Code (BFF, Portal) ``` ### Outbound (Domain → Provider) ``` Application Intent ↓ Domain Contract (contract.ts) ↓ Provider Mapper (providers/*/mapper.ts) ↓ Raw Provider Payload (providers/*/raw.types.ts) ↓ External API Request ``` ## 🎨 Design Principles ### 1. **Co-location** - Domain contracts, schemas, and provider logic live together - Easy to find related code - Clear ownership and responsibility ### 2. **Provider Isolation** - Raw types and mappers nested in `providers/` subfolder - Each provider is self-contained - Easy to add/remove providers ### 3. **Type Safety** - Zod schemas for runtime validation - TypeScript types inferred from schemas - Branded types for stronger type checking ### 4. **Clean Exports** - Barrel exports (`index.ts`) control public API - Provider mappers exported as namespaces (`WhmcsBillingMapper.*`) - Predictable import paths ### 5. **Minimal Dependencies** - Only depends on `zod` for runtime validation - No circular dependencies - Self-contained domain logic ## 📋 Domain Reference ### Billing - **Contracts**: `Invoice`, `InvoiceItem`, `InvoiceList` - **Providers**: WHMCS - **Use Cases**: Display invoices, payment history, invoice details ### Subscriptions - **Contracts**: `Subscription`, `SubscriptionList` - **Providers**: WHMCS - **Use Cases**: Display active services, manage subscriptions ### Payments - **Contracts**: `PaymentMethod`, `PaymentGateway` - **Providers**: WHMCS - **Use Cases**: Payment method management, gateway configuration ### SIM - **Contracts**: `SimDetails`, `SimUsage`, `SimTopUpHistory` - **Providers**: Freebit - **Use Cases**: SIM management, usage tracking, top-up history ### Orders - **Contracts**: `OrderSummary`, `OrderDetails`, `FulfillmentOrderDetails` - **Providers**: WHMCS (provisioning), Salesforce (order management) - **Use Cases**: Order fulfillment, order history, order details ### Catalog - **Contracts**: `InternetPlanCatalogItem`, `SimCatalogProduct`, `VpnCatalogProduct` - **Providers**: Salesforce (Product2) - **Use Cases**: Product catalog display, product selection ### Common - **Types**: `IsoDateTimeString`, `UserId`, `AccountId`, `OrderId`, `ApiResponse`, `PaginatedResponse` - **Use Cases**: Shared utility types across all domains ### Toolkit - **Formatting**: Currency, date, phone, text formatters - **Validation**: Email, URL, string validators - **Typing**: Type guards, assertions, helpers - **Use Cases**: UI formatting, input validation, type safety ## 🚀 Migration Guide ### From Old Structure **Before:** ```typescript import type { Invoice } from "@customer-portal/contracts/billing"; import { invoiceSchema } from "@customer-portal/schemas/business/billing.schema"; import { transformWhmcsInvoice } from "@customer-portal/integrations-whmcs/mappers/billing.mapper"; ``` **After:** ```typescript import type { Invoice } from "@customer-portal/domain/billing"; import { invoiceSchema } from "@customer-portal/domain/billing"; import { WhmcsBillingMapper } from "@customer-portal/domain/billing"; const invoice = WhmcsBillingMapper.transformWhmcsInvoice(data); ``` ### Benefits - **Fewer imports**: Everything in one package - **Clearer intent**: Mapper namespace indicates provider - **Better DX**: Autocomplete shows all related exports - **Type safety**: Contracts + schemas + mappers always in sync ## ✅ Completed Domains - ✅ Billing (WHMCS provider) - ✅ Subscriptions (WHMCS provider) - ✅ Payments (WHMCS provider) - ✅ SIM (Freebit provider) - ✅ Orders (WHMCS + Salesforce providers) - ✅ Catalog (Salesforce provider) - ✅ Common (shared types) - ✅ Toolkit (utilities) ## 📝 Next Steps 1. **Update BFF imports** to use `@customer-portal/domain/*` 2. **Update Portal imports** to use `@customer-portal/domain/*` 3. **Delete old packages**: `contracts`, `schemas`, `integrations` 4. **Update ESLint rules** to prevent imports from old packages 5. **Update documentation** to reference new structure ## 🔗 Related Documentation - [Provider-Aware Structure](./DOMAIN-STRUCTURE.md) - [Type Cleanup Summary](./TYPE-CLEANUP-SUMMARY.md) - [Architecture Overview](./ARCHITECTURE.md)