- Add JapanAddressForm component for complete Japanese address input. - Integrate ZipCodeInput for automatic address population via Japan Post API. - Create hooks for ZIP code lookup and address service status. - Define address-related types and constants in the domain package. - Document the feature, including environment variables and API endpoints. - Implement mapping functions for WHMCS and Salesforce address formats.
9.1 KiB
Japan Post ZIP Code Address Lookup
This feature provides Japanese address auto-completion using the Japan Post Digital Address API. When users enter a ZIP code, the system automatically looks up and populates prefecture, city, and town fields in both Japanese and romanized (English) formats.
Environment Variables
Add these to your .env file:
# Japan Post Digital Address API
JAPAN_POST_API_URL=https://api.da.posta.japanpost.jp
JAPAN_POST_CLIENT_ID=your_client_id
JAPAN_POST_CLIENT_SECRET=your_client_secret
JAPAN_POST_TIMEOUT=10000 # Optional, defaults to 10000ms
Contact Japan Post to obtain API credentials for the Digital Address service.
Architecture Overview
┌─────────────────────────────────────────────────────────────────────┐
│ Portal (Next.js) │
├─────────────────────────────────────────────────────────────────────┤
│ ZipCodeInput ─► useZipCodeLookup ─► addressService.lookupByZipCode │
│ │ │ │
│ ▼ ▼ │
│ JapanAddressForm GET /api/address/lookup/zip/:zip│
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ BFF (NestJS) │
├─────────────────────────────────────────────────────────────────────┤
│ AddressController ─► JapanPostAddressService │
│ │ │ │
│ │ ▼ │
│ │ JapanPostConnectionService │
│ │ (OAuth token caching) │
│ │ │ │
│ ▼ ▼ │
│ PATCH /me/address/bilingual Japan Post API │
│ │ │
│ ▼ │
│ UserProfileService.updateBilingualAddress() │
│ │ │
│ ├──► WHMCS (English address - source of truth) │
│ └──► Salesforce (Japanese address - secondary) │
└─────────────────────────────────────────────────────────────────────┘
API Endpoints
Public Endpoints (No Auth Required)
| Endpoint | Method | Description | Rate Limit |
|---|---|---|---|
/api/address/lookup/zip/:zipCode |
GET | Look up address by ZIP code | 30/min |
/api/address/status |
GET | Check service availability | - |
Authenticated Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/me/address/bilingual |
PATCH | Update address with dual-write to WHMCS + Salesforce |
Field Mappings
WHMCS (English/Romanized)
| WHMCS Field | Source |
|---|---|
address1 |
{buildingName} {roomNumber} (for apartments) or {buildingName} |
address2 |
town (romanized street/block) |
city |
city (romanized) |
state |
prefecture (romanized) |
postcode |
ZIP code |
country |
"JP" |
Salesforce Contact (Japanese)
| Salesforce Field | Source |
|---|---|
MailingStreet |
townJa (Japanese) |
MailingCity |
cityJa (Japanese) |
MailingState |
prefectureJa (Japanese) |
MailingPostalCode |
ZIP code |
MailingCountry |
"Japan" |
BuildingName__c |
Building name (English) |
RoomNumber__c |
Room number |
Components
ZipCodeInput
Auto-lookup ZIP code input with visual feedback.
import { ZipCodeInput } from "@/features/address";
<ZipCodeInput
value={zipCode}
onChange={setZipCode}
onAddressFound={address => {
// address contains both Japanese and romanized fields
console.log(address.prefecture, address.prefectureJa);
}}
/>;
JapanAddressForm
Complete address form with residence type selection.
import { JapanAddressForm } from "@/features/address";
<JapanAddressForm
onChange={(data, isComplete) => {
// data is BilingualAddress type
// isComplete is true when all required fields are filled
}}
/>;
AddressStepJapan
Drop-in replacement for signup/registration flows.
import { AddressStepJapan } from "@/features/address";
<AddressStepJapan
form={form}
onJapaneseAddressChange={bilingualData => {
// Capture Japanese fields for Salesforce sync
}}
/>;
Dual-Write Behavior
When updating addresses via PATCH /me/address/bilingual:
- WHMCS Update (Blocking): English address is written to WHMCS as source of truth
- Salesforce Update (Non-Blocking): Japanese address is written to Salesforce
- If Salesforce update fails, it's logged but doesn't fail the request
- If no Salesforce mapping exists, update is skipped silently
Residence Type
Users select either:
- House: Building name optional, no room number
- Apartment/Mansion: Building name optional, room number required
The address1 field format changes based on residence type:
- House:
{buildingName}or empty - Apartment:
{buildingName} {roomNumber}
Manual Address Entry
If users skip ZIP code lookup and enter addresses manually:
| Scenario | WHMCS | Salesforce |
|---|---|---|
| ZIP lookup used | English fields filled | Japanese fields filled |
| Manual entry (no ZIP) | English fields filled | Japanese fields empty |
| Manual then ZIP lookup used | English updated | Japanese fields populated from lookup |
Important: Manual address entry will work for WHMCS but Salesforce will receive empty Japanese address fields. The system does NOT perform reverse lookups on manually entered addresses.
Recommendation: Encourage users to enter ZIP code first to get proper Japanese address data for Salesforce.
Residence Type Selection
Users must explicitly choose their residence type:
- House: Building name optional, no room number field shown
- Apartment/Mansion: Building name optional, room number required
The form does not default to either option - users must select one to proceed.
Configuration Validation
On BFF startup, the service validates environment variables and logs errors:
# Missing configuration example log:
ERROR Japan Post API configuration is invalid. Address lookup will be unavailable.
errors: [
{ envVar: "JAPAN_POST_API_URL", message: "Missing required environment variable" },
{ envVar: "JAPAN_POST_CLIENT_ID", message: "Missing required environment variable" }
]
hint: "Add the required environment variables to your .env file"
The service will throw clear errors if called without proper configuration.
Error Handling
- Invalid ZIP codes return empty results (no error)
- Japan Post API timeouts return 500 error
- Rate limiting returns 429 with retry-after header
- Missing/invalid configuration throws descriptive error on API call