207 lines
9.1 KiB
Markdown
207 lines
9.1 KiB
Markdown
|
|
# 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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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.
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
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.
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
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.
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
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`:
|
||
|
|
|
||
|
|
1. **WHMCS Update (Blocking)**: English address is written to WHMCS as source of truth
|
||
|
|
2. **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
|