Assist_Design/docs/plans/2026-03-03-bilingual-address-handler-design.md
barsa 6299fbabdc refactor: enhance address handling in BFF workflows
- Integrated AddressWriterService into GuestEligibilityWorkflowService and NewCustomerSignupWorkflowService for improved address writing to Salesforce.
- Updated AddressModule to include SalesforceModule and export AddressWriterService.
- Refactored address handling in various workflows to utilize the new address structure, ensuring consistency and reliability in address processing.
- Removed deprecated address building logic from eligibility check store, streamlining address management across components.
2026-03-03 16:33:40 +09:00

8.2 KiB

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: addressFormSchemaaddress: 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.