Assist_Design/docs/guides/ADDRESS_SYSTEM.md

378 lines
9.9 KiB
Markdown

# 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.updateAddress()` - 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 && (
<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
```typescript
// 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
```typescript
// 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
```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
<ProfileCompletionGuard requireComplete={true}>
<YourComponent />
</ProfileCompletionGuard>
```
### Handle Address in Checkout
```tsx
<AddressConfirmation
onAddressConfirmed={handleConfirmed}
onAddressIncomplete={handleIncomplete}
orderType={orderType}
/>
```
### 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._