9.9 KiB
9.9 KiB
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
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 registrationUsersService.updateAddress()- WHMCS syncOrderBuilder.addAddressSnapshot()- Salesforce snapshots
Frontend
AddressConfirmation- Checkout verificationProfileCompletionGuard- 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
// 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
// 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
// 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
{isInternetOrder && !addressConfirmed && (
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-4">
<p className="text-sm text-blue-800">
<strong>Internet Installation Address Verification Required</strong>
</p>
<p className="text-sm text-blue-700 mt-1">
Please verify this is the correct address for your internet installation.
A technician will visit this location for setup.
</p>
</div>
)}
3. Address Updates & WHMCS Sync
// apps/bff/src/users/users.service.ts
async updateAddress(userId: string, address: UpdateAddressDto): Promise<void> {
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
// apps/bff/src/orders/services/order-builder.service.ts
private async addAddressSnapshot(orderFields: Record<string, unknown>, userId: string, body: CreateOrderBody): Promise<void> {
const address = await this.usersService.getAddress(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
// 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
<ProfileCompletionGuard requireComplete={true}>
<YourComponent />
</ProfileCompletionGuard>
Handle Address in Checkout
<AddressConfirmation
onAddressConfirmed={handleConfirmed}
onAddressIncomplete={handleIncomplete}
orderType={orderType}
/>
Check Profile Completion
const { isComplete, loading, redirectToCompletion } = useProfileCompletion();
User Flows
1. New User Registration
- User fills registration form with required address
- Backend validates all address fields
- WHMCS client created with complete address
- User can immediately access all features
2. Internet Order Checkout
- User selects Internet service
- Address confirmation component loads
- Shows current address with verification requirement
- User must explicitly confirm installation address
- Order created with address snapshot
3. Other Order Checkout
- User selects SIM/VPN/Other service
- Address confirmation component loads
- Auto-confirms address (exists from signup)
- Order created with address snapshot
4. Address Updates
- User goes to
/account/billing - Can edit and save address changes
- Changes sync to WHMCS immediately
- Future orders use updated address
Testing
Quick Commands
# 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
- New User Signup: Verify address is required and validated
- Internet Order: Verify explicit address confirmation required
- SIM Order: Verify address auto-confirmed
- Address Update: Verify WHMCS sync works
Troubleshooting
Common Issues
"Address not found during checkout"
- Cause: User somehow has incomplete profile
- Solution:
ProfileCompletionGuardwill 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
- Address not required? → Check
SignupDto.addressis not@IsOptional() - Internet order auto-confirms? → Check
orderType === "Internet"logic - Address not in Salesforce? → Check
addAddressSnapshot()call - WHMCS not updating? → Check API credentials and
updateClient()method
Configuration
Environment Variables
# 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.