# Address System Documentation ## Overview Our address system follows a **clean, logical flow** where address is **required at signup** and managed throughout the user lifecycle. This eliminates surprises during checkout and ensures data integrity. ## 🎯 Core Logic ``` Registration → Required Address → WHMCS Storage → Order Snapshots ``` ## Architecture ```mermaid graph TD A[User Registration] --> B[Required Address Validation] B --> C[WHMCS Client Creation] C --> D[Complete Profile] D --> E[Checkout Flow] E --> F{Order Type?} F -->|Internet| G[Explicit Address Verification] F -->|Other| H[Auto-Confirm Address] G --> I[Address Snapshot] H --> I I --> J[Salesforce Order] D --> K[Profile Management] K --> L[Address Updates] L --> M[WHMCS Sync] ``` ## Key Components ### Backend - `SignupDto` - Address required at registration - `UsersService.updateBillingInfo()` - WHMCS sync - `OrderBuilder.addAddressSnapshot()` - Salesforce snapshots ### Frontend - `AddressConfirmation` - Checkout verification - `ProfileCompletionGuard` - Handles incomplete profiles - `/account/billing` - Address management ## Order Type Flows | Order Type | Address Behavior | | ----------------- | ---------------------------------------------------- | | **Internet** | ✅ Explicit verification required (technician visit) | | **SIM/VPN/Other** | ✅ Auto-confirm (exists from signup) | ## Implementation ### 1. Signup Flow (Required Address) #### Backend Validation ```typescript // apps/bff/src/auth/dto/signup.dto.ts export class AddressDto { @IsNotEmpty() line1: string; // Required @IsOptional() line2?: string; // Optional @IsNotEmpty() city: string; // Required @IsNotEmpty() state: string; // Required @IsNotEmpty() postalCode: string; // Required @IsNotEmpty() country: string; // Required } export class SignupDto { @ValidateNested() @Type(() => AddressDto) address: AddressDto; // ✅ REQUIRED - not optional } ``` #### WHMCS Client Creation ```typescript // apps/bff/src/auth/auth.service.ts await this.whmcsService.addClient({ address1: address.line1, // Required field address2: address.line2 || "", // Optional field city: address.city, // Required field state: address.state, // Required field postcode: address.postalCode, // Required field country: address.country, // Required field }); ``` ### 2. Checkout Flow #### Address Confirmation Logic ```typescript // apps/portal/src/components/checkout/address-confirmation.tsx // Since address is required at signup, it should always be complete if (requiresAddressVerification) { // Internet orders: require explicit verification setAddressConfirmed(false); onAddressIncomplete(); // Keep disabled until confirmed } else { // Other orders: auto-confirm since address exists from signup onAddressConfirmed(data.address); setAddressConfirmed(true); } ``` #### Internet Order Verification ```typescript {isInternetOrder && !addressConfirmed && (

Internet Installation Address Verification Required

Please verify this is the correct address for your internet installation. A technician will visit this location for setup.

)} ``` ### 3. Address Updates & WHMCS Sync ```typescript // apps/bff/src/users/users.service.ts async updateBillingInfo(userId: string, billingData: UpdateBillingDto): Promise { const mapping = await this.mappingsService.findByUserId(userId); // Prepare WHMCS update data const whmcsUpdateData = { address1: billingData.street, address2: billingData.streetLine2, city: billingData.city, state: billingData.state, postcode: billingData.postalCode, country: billingData.country, }; // Update in WHMCS (authoritative source) await this.whmcsService.updateClient(mapping.whmcsClientId, whmcsUpdateData); } ``` ### 4. Order Address Snapshots ```typescript // apps/bff/src/orders/services/order-builder.service.ts private async addAddressSnapshot(orderFields: Record, userId: string, body: CreateOrderBody): Promise { const billingInfo = await this.usersService.getBillingInfo(userId); const orderAddress = (body.configurations as any)?.address; const addressChanged = !!(orderAddress); const addressToUse = orderAddress || billingInfo.address; // Combine street lines for Salesforce const fullStreet = [addressToUse?.street, addressToUse?.streetLine2] .filter(Boolean) .join(", "); // Always populate billing address fields orderFields["BillToStreet"] = fullStreet || ""; orderFields["BillToCity"] = addressToUse?.city || ""; orderFields["BillToState"] = addressToUse?.state || ""; orderFields["BillToPostalCode"] = addressToUse?.postalCode || ""; orderFields["BillToCountry"] = addressToUse?.country || ""; // Set change flag orderFields["Address_Changed__c"] = addressChanged; } ``` ## Field Mapping ### WHMCS ↔ Internal ↔ Salesforce ``` WHMCS → Internal → Salesforce Order address1 → street → BillToStreet (combined) address2 → streetLine2 → BillToStreet (combined) city → city → BillToCity state → state → BillToState postcode → postalCode → BillToPostalCode country → country → BillToCountry // Change detection N/A → addressChanged → Address_Changed__c (boolean) ``` ## API Reference ### Address Management ```typescript // Get current address GET /api/users/billing Response: { address: { street: string | null; streetLine2: string | null; city: string | null; state: string | null; postalCode: string | null; country: string | null; }; isComplete: boolean; } // Update address PATCH /api/users/billing Body: { street?: string; streetLine2?: string; city?: string; state?: string; postalCode?: string; country?: string; } ``` ## Quick Patterns ### Protect Route with Profile Completion ```tsx ``` ### Handle Address in Checkout ```tsx ``` ### Check Profile Completion ```tsx const { isComplete, loading, redirectToCompletion } = useProfileCompletion(); ``` ## User Flows ### 1. New User Registration 1. User fills registration form with **required address** 2. Backend validates all address fields 3. WHMCS client created with complete address 4. User can immediately access all features ### 2. Internet Order Checkout 1. User selects Internet service 2. Address confirmation component loads 3. Shows current address with verification requirement 4. User must explicitly confirm installation address 5. Order created with address snapshot ### 3. Other Order Checkout 1. User selects SIM/VPN/Other service 2. Address confirmation component loads 3. Auto-confirms address (exists from signup) 4. Order created with address snapshot ### 4. Address Updates 1. User goes to `/account/billing` 2. Can edit and save address changes 3. Changes sync to WHMCS immediately 4. Future orders use updated address ## Testing ### Quick Commands ```bash # Test required address validation curl -X POST /api/auth/signup -d '{"address": {...}}' # Get user address curl -X GET /api/users/billing # Update address curl -X PATCH /api/users/billing -d '{"street": "New St"}' ``` ### Test Scenarios 1. **New User Signup**: Verify address is required and validated 2. **Internet Order**: Verify explicit address confirmation required 3. **SIM Order**: Verify address auto-confirmed 4. **Address Update**: Verify WHMCS sync works ## Troubleshooting ### Common Issues #### "Address not found during checkout" - **Cause**: User somehow has incomplete profile - **Solution**: `ProfileCompletionGuard` will redirect to completion #### "Internet order won't submit" - **Cause**: Address not explicitly confirmed - **Solution**: User must click "Confirm Installation Address" #### "Address changes not saving" - **Cause**: WHMCS API connection issue - **Solution**: Check WHMCS credentials and API access ### Quick Debug 1. **Address not required?** → Check `SignupDto.address` is not `@IsOptional()` 2. **Internet order auto-confirms?** → Check `orderType === "Internet"` logic 3. **Address not in Salesforce?** → Check `addAddressSnapshot()` call 4. **WHMCS not updating?** → Check API credentials and `updateClient()` method ## Configuration ### Environment Variables ```bash # WHMCS API WHMCS_API_URL=https://your-whmcs.com/includes/api.php WHMCS_API_IDENTIFIER=your_api_identifier WHMCS_API_SECRET=your_api_secret # Salesforce Field Mapping (optional overrides) ORDER_ADDRESS_CHANGED_FIELD=Address_Changed__c ORDER_BILL_TO_STREET_FIELD=BillToStreet ORDER_BILL_TO_CITY_FIELD=BillToCity ORDER_BILL_TO_STATE_FIELD=BillToState ORDER_BILL_TO_POSTAL_CODE_FIELD=BillToPostalCode ORDER_BILL_TO_COUNTRY_FIELD=BillToCountry ``` ## Benefits ### ✅ **User Experience** - No surprise address requirements during checkout - Clear completion flows for edge cases - Order-type specific verification (Internet vs Others) ### ✅ **Data Integrity** - Address required at source (signup) - Single source of truth (WHMCS) - Point-in-time snapshots (Salesforce orders) ### ✅ **Performance** - No unnecessary dashboard banners - Simplified checkout validation - Efficient profile completion checks ### ✅ **Maintainability** - Logical flow from signup to order - Reusable profile completion components - Clean separation of concerns --- _This address system provides a clean, logical, and modern approach to address management with required addresses at signup and intelligent order-type specific flows._