153 lines
8.2 KiB
Markdown
153 lines
8.2 KiB
Markdown
|
|
# Bilingual Address Handler for Registration
|
||
|
|
|
||
|
|
**Date**: 2026-03-03
|
||
|
|
**Status**: Design
|
||
|
|
|
||
|
|
## Problem
|
||
|
|
|
||
|
|
Registration flows use `addressFormSchema` (simple English-only: address1, address2, city, state, postcode). The bilingual address infrastructure exists (`bilingualAddressSchema`, `prepareWhmcsAddressFields`, `prepareSalesforceContactAddressFields`, `JapanAddressForm`, Japan Post API integration) but isn't wired into signup workflows.
|
||
|
|
|
||
|
|
Salesforce receives English address data when it should receive Japanese. Address transformation logic is scattered inline across workflows.
|
||
|
|
|
||
|
|
## Requirements
|
||
|
|
|
||
|
|
| Outcome | SF Write | WHMCS Write | Address Input |
|
||
|
|
| ------------------- | ------------------------------- | ------------------------------- | ------------------------------- |
|
||
|
|
| A (New Customer) | Japanese (at signup) | English (at signup) | JapanAddressForm |
|
||
|
|
| B (SF-Only) | Japanese (at eligibility check) | English (at account completion) | JapanAddressForm at eligibility |
|
||
|
|
| C (WHMCS Migration) | None | None | None |
|
||
|
|
| D (Portal Exists) | None | None | None |
|
||
|
|
|
||
|
|
## Key Decisions
|
||
|
|
|
||
|
|
1. **Japan Post API postal code lookup** auto-populates both JA and EN fields on the frontend.
|
||
|
|
2. **Always re-derive EN fields from postal code** via Japan Post API on the backend when writing to WHMCS. One code path regardless of whether data is in Redis (fresh) or Salesforce (days later). Avoids Redis TTL dependency.
|
||
|
|
3. **Centralized `AddressWriterService`** in BFF orchestrates all address writes.
|
||
|
|
4. **`bilingualAddressSchema` replaces `addressFormSchema`** in all signup request/session/handoff schemas.
|
||
|
|
5. **`JapanAddressForm` replaces simple address fields** in all signup frontend forms.
|
||
|
|
|
||
|
|
## Architecture
|
||
|
|
|
||
|
|
### AddressWriterService (BFF)
|
||
|
|
|
||
|
|
Location: `apps/bff/src/modules/address/address-writer.service.ts`
|
||
|
|
|
||
|
|
```
|
||
|
|
AddressWriterService
|
||
|
|
Dependencies: JapanPostFacade, SalesforceAccountService
|
||
|
|
|
||
|
|
writeToSalesforce(sfAccountId, bilingualAddress)
|
||
|
|
→ prepareSalesforceContactAddressFields(address) → SF Contact update
|
||
|
|
→ Writes: MailingStreet (JA town+street), MailingCity (JA), MailingState (JA), BuildingName__c, RoomNumber__c
|
||
|
|
|
||
|
|
resolveAndPrepareWhmcsAddress(postalCode, townJa?, streetAddress, buildingInfo)
|
||
|
|
→ Japan Post API lookup by postal code
|
||
|
|
→ Match correct result using townJa (for multi-match postal codes)
|
||
|
|
→ prepareWhmcsAddressFields() with resolved EN fields
|
||
|
|
→ Returns: WhmcsAddressFields (address1, address2, city, state, postcode, country)
|
||
|
|
```
|
||
|
|
|
||
|
|
### Schema Changes
|
||
|
|
|
||
|
|
Replace `addressFormSchema` with `bilingualAddressSchema` in:
|
||
|
|
|
||
|
|
| Schema | File | Change |
|
||
|
|
| ------------------------------------ | ------------------------------ | ---------------------------------------------------------------------------------------------------------- |
|
||
|
|
| `signupWithEligibilityRequestSchema` | `domain/get-started/schema.ts` | `address: addressFormSchema` → `address: bilingualAddressSchema` |
|
||
|
|
| `completeAccountRequestSchema` | `domain/get-started/schema.ts` | `address: addressFormSchema.optional()` → `address: bilingualAddressSchema.optional()` |
|
||
|
|
| `getStartedSessionSchema` | `domain/get-started/schema.ts` | `address: addressFormSchema.partial().optional()` → `address: bilingualAddressSchema.partial().optional()` |
|
||
|
|
| `guestHandoffTokenSchema` | `domain/get-started/schema.ts` | `address: addressFormSchema.partial().optional()` → `address: bilingualAddressSchema.partial().optional()` |
|
||
|
|
| `verifyCodeResponseSchema` prefill | `domain/get-started/schema.ts` | `address: addressFormSchema.partial().optional()` → `address: bilingualAddressSchema.partial().optional()` |
|
||
|
|
| `guestEligibilityRequestSchema` | `domain/get-started/schema.ts` | Remove `bilingualEligibilityAddressSchema`, use `bilingualAddressSchema` |
|
||
|
|
|
||
|
|
### Workflow Changes
|
||
|
|
|
||
|
|
**NewCustomerSignupWorkflowService (Outcome A)**:
|
||
|
|
|
||
|
|
- Accept `bilingualAddressSchema` from request
|
||
|
|
- After SF account creation: `addressWriter.writeToSalesforce(sfAccountId, address)` → JA to SF
|
||
|
|
- For WHMCS client: `addressWriter.resolveAndPrepareWhmcsAddress(postcode, townJa, streetAddress, building)` → EN to WHMCS
|
||
|
|
|
||
|
|
**GuestEligibilityWorkflowService (Outcome B - eligibility check)**:
|
||
|
|
|
||
|
|
- Refactor inline SF address write (lines 103-113) to use `addressWriter.writeToSalesforce()`
|
||
|
|
- Store bilingual address in handoff token (for B1 immediate flow)
|
||
|
|
|
||
|
|
**SfCompletionWorkflowService (Outcome B - account completion)**:
|
||
|
|
|
||
|
|
- Resolve address from session (may have bilingual data if B1, or JA-only + postcode if B2)
|
||
|
|
- `addressWriter.resolveAndPrepareWhmcsAddress(postcode, townJa, streetAddress, building)` → EN to WHMCS
|
||
|
|
|
||
|
|
### Frontend Changes
|
||
|
|
|
||
|
|
Replace simple address fields with `JapanAddressForm` component in:
|
||
|
|
|
||
|
|
- Signup with eligibility form (Outcome A)
|
||
|
|
- Guest eligibility form (Outcome B)
|
||
|
|
- Forms submit `bilingualAddressSchema` shape
|
||
|
|
|
||
|
|
No address form needed for:
|
||
|
|
|
||
|
|
- Complete account (Outcome B) — address from session
|
||
|
|
- WHMCS migration (Outcome C) — no address needed
|
||
|
|
- Portal exists (Outcome D) — redirect to login
|
||
|
|
|
||
|
|
### Data Flow Diagrams
|
||
|
|
|
||
|
|
**Outcome A (New Customer)**:
|
||
|
|
|
||
|
|
```
|
||
|
|
User → JapanAddressForm → postal code lookup → auto-fill JA+EN
|
||
|
|
→ Submit (bilingualAddress) → BFF
|
||
|
|
→ addressWriter.writeToSalesforce(sfAccountId, address) → SF gets JA
|
||
|
|
→ addressWriter.resolveAndPrepareWhmcsAddress(postcode, townJa, ...) → Japan Post API → WHMCS gets EN
|
||
|
|
```
|
||
|
|
|
||
|
|
**Outcome B1 (SF-Only, immediate)**:
|
||
|
|
|
||
|
|
```
|
||
|
|
User → JapanAddressForm (guest eligibility) → Submit (bilingualAddress) → BFF
|
||
|
|
→ addressWriter.writeToSalesforce(sfAccountId, address) → SF gets JA
|
||
|
|
→ Store bilingual in handoff token → Redis (30 min TTL)
|
||
|
|
→ User verifies email → complete account
|
||
|
|
→ addressWriter.resolveAndPrepareWhmcsAddress(postcode, townJa, ...) → Japan Post API → WHMCS gets EN
|
||
|
|
```
|
||
|
|
|
||
|
|
**Outcome B2 (SF-Only, returns days later)**:
|
||
|
|
|
||
|
|
```
|
||
|
|
[Days ago] Guest eligibility → SF got JA address + postal code
|
||
|
|
[Now] User verifies email → system detects SF_UNMAPPED
|
||
|
|
→ Prefill from SF: postal code, JA address fields
|
||
|
|
→ addressWriter.resolveAndPrepareWhmcsAddress(postcode, townJa, ...) → Japan Post API → WHMCS gets EN
|
||
|
|
```
|
||
|
|
|
||
|
|
## Files to Modify
|
||
|
|
|
||
|
|
### Domain (packages/domain/)
|
||
|
|
|
||
|
|
- `get-started/schema.ts` — Replace addressFormSchema references with bilingualAddressSchema
|
||
|
|
- `address/schema.ts` — May need minor additions for the resolve flow
|
||
|
|
|
||
|
|
### BFF (apps/bff/)
|
||
|
|
|
||
|
|
- **New**: `modules/address/address-writer.service.ts` — Centralized address write service
|
||
|
|
- `modules/address/address.module.ts` — Export AddressWriterService
|
||
|
|
- `modules/auth/infra/workflows/new-customer-signup-workflow.service.ts` — Use AddressWriterService
|
||
|
|
- `modules/auth/infra/workflows/guest-eligibility-workflow.service.ts` — Use AddressWriterService
|
||
|
|
- `modules/auth/infra/workflows/sf-completion-workflow.service.ts` — Use AddressWriterService
|
||
|
|
- `modules/auth/infra/workflows/steps/create-whmcs-client.step.ts` — Accept WhmcsAddressFields
|
||
|
|
- `modules/auth/infra/workflows/verification-workflow.service.ts` — Prefill bilingual address from SF
|
||
|
|
|
||
|
|
### Portal (apps/portal/)
|
||
|
|
|
||
|
|
- Signup with eligibility form — Replace address fields with JapanAddressForm
|
||
|
|
- Guest eligibility form — Ensure JapanAddressForm is used, submits bilingualAddressSchema
|
||
|
|
- API layer — Update request types to match new schemas
|
||
|
|
|
||
|
|
## Risks
|
||
|
|
|
||
|
|
- **Japan Post API availability**: If API is down during WHMCS write, registration fails. Mitigation: retry with backoff (existing retry.util), graceful error message.
|
||
|
|
- **Multi-match postal codes**: Some postal codes return multiple town entries. Mitigation: match using `townJa` from the stored/submitted address.
|
||
|
|
- **Schema migration**: Changing session/handoff schemas could affect in-flight registrations. Mitigation: make new fields optional, handle old format gracefully during rollout.
|