# 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"; { // 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"; { // 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"; { // 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