2025-08-29 14:05:33 +09:00
# 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]
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
D --> E[Checkout Flow]
E --> F{Order Type?}
F -->|Internet| G[Explicit Address Verification]
F -->|Other| H[Auto-Confirm Address]
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
G --> I[Address Snapshot]
H --> I
I --> J[Salesforce Order]
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
D --> K[Profile Management]
K --> L[Address Updates]
L --> M[WHMCS Sync]
```
## Key Components
### Backend
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
- `SignupDto` - Address required at registration
2025-09-17 18:43:43 +09:00
- `UsersService.updateAddress()` - WHMCS sync
2025-08-29 14:05:33 +09:00
- `OrderBuilder.addAddressSnapshot()` - Salesforce snapshots
2025-09-09 18:19:54 +09:00
### Frontend
2025-08-29 14:05:33 +09:00
- `AddressConfirmation` - Checkout verification
- `ProfileCompletionGuard` - Handles incomplete profiles
- `/account/billing` - Address management
## Order Type Flows
2025-09-09 18:19:54 +09:00
| Order Type | Address Behavior |
| ----------------- | ---------------------------------------------------- |
| **Internet** | ✅ Explicit verification required (technician visit) |
| **SIM/VPN/Other** | ✅ Auto-confirm (exists from signup) |
2025-08-29 14:05:33 +09:00
## Implementation
### 1. Signup Flow (Required Address)
#### Backend Validation
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```typescript
// apps/bff/src/auth/dto/signup.dto.ts
export class AddressDto {
2025-09-09 18:19:54 +09:00
@IsNotEmpty () line1: string; // Required
@IsOptional () line2?: string; // Optional
@IsNotEmpty () city: string; // Required
@IsNotEmpty () state: string; // Required
2025-08-29 14:05:33 +09:00
@IsNotEmpty () postalCode: string; // Required
2025-09-09 18:19:54 +09:00
@IsNotEmpty () country: string; // Required
2025-08-29 14:05:33 +09:00
}
export class SignupDto {
@ValidateNested ()
@Type (() => AddressDto)
address: AddressDto; // ✅ REQUIRED - not optional
}
```
#### WHMCS Client Creation
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```typescript
// apps/bff/src/auth/auth.service.ts
await this.whmcsService.addClient({
2025-09-09 18:19:54 +09:00
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
2025-08-29 14:05:33 +09:00
});
```
### 2. Checkout Flow
#### Address Confirmation Logic
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```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
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```typescript
{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" >
2025-09-09 18:19:54 +09:00
Please verify this is the correct address for your internet installation.
2025-08-29 14:05:33 +09:00
A technician will visit this location for setup.
< / p >
< / div >
)}
```
### 3. Address Updates & WHMCS Sync
```typescript
// apps/bff/src/users/users.service.ts
2025-09-17 18:43:43 +09:00
async updateAddress(userId: string, address: UpdateAddressDto): Promise< void > {
2025-08-29 14:05:33 +09:00
const mapping = await this.mappingsService.findByUserId(userId);
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
// 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< string , unknown > , userId: string, body: CreateOrderBody): Promise< void > {
2025-09-17 18:43:43 +09:00
const address = await this.usersService.getAddress(userId);
2025-08-29 14:05:33 +09:00
const orderAddress = (body.configurations as any)?.address;
const addressChanged = !!(orderAddress);
const addressToUse = orderAddress || billingInfo.address;
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
// Combine street lines for Salesforce
const fullStreet = [addressToUse?.street, addressToUse?.streetLine2]
.filter(Boolean)
.join(", ");
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
// Always populate billing address fields
orderFields["BillToStreet"] = fullStreet || "";
orderFields["BillToCity"] = addressToUse?.city || "";
orderFields["BillToState"] = addressToUse?.state || "";
orderFields["BillToPostalCode"] = addressToUse?.postalCode || "";
orderFields["BillToCountry"] = addressToUse?.country || "";
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
// Set change flag
orderFields["Address_Changed__c"] = addressChanged;
}
```
## Field Mapping
### WHMCS ↔ Internal ↔ Salesforce
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```
WHMCS → Internal → Salesforce Order
address1 → street → BillToStreet (combined)
2025-09-09 18:19:54 +09:00
address2 → streetLine2 → BillToStreet (combined)
2025-08-29 14:05:33 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```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
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```tsx
< ProfileCompletionGuard requireComplete = {true} >
< YourComponent / >
< / ProfileCompletionGuard >
```
### Handle Address in Checkout
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```tsx
< AddressConfirmation
onAddressConfirmed={handleConfirmed}
onAddressIncomplete={handleIncomplete}
orderType={orderType}
/>
```
### Check Profile Completion
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```tsx
const { isComplete, loading, redirectToCompletion } = useProfileCompletion();
```
## User Flows
### 1. New User Registration
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```bash
# Test required address validation
curl -X POST /api/auth/signup -d '{"address": {...}}'
2025-09-09 18:19:54 +09:00
# Get user address
2025-08-29 14:05:33 +09:00
curl -X GET /api/users/billing
# Update address
curl -X PATCH /api/users/billing -d '{"street": "New St"}'
```
### Test Scenarios
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
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"
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
- **Cause**: User somehow has incomplete profile
- **Solution**: `ProfileCompletionGuard` will redirect to completion
#### "Internet order won't submit"
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
- **Cause**: Address not explicitly confirmed
- **Solution**: User must click "Confirm Installation Address"
#### "Address changes not saving"
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
- **Cause**: WHMCS API connection issue
- **Solution**: Check WHMCS credentials and API access
### Quick Debug
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
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
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
```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**
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
- No surprise address requirements during checkout
- Clear completion flows for edge cases
- Order-type specific verification (Internet vs Others)
### ✅ **Data Integrity**
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
- Address required at source (signup)
- Single source of truth (WHMCS)
- Point-in-time snapshots (Salesforce orders)
### ✅ **Performance**
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
- No unnecessary dashboard banners
- Simplified checkout validation
- Efficient profile completion checks
### ✅ **Maintainability**
2025-09-09 18:19:54 +09:00
2025-08-29 14:05:33 +09:00
- Logical flow from signup to order
- Reusable profile completion components
- Clean separation of concerns
---
2025-09-09 18:19:54 +09:00
_This address system provides a clean, logical, and modern approach to address management with required addresses at signup and intelligent order-type specific flows._