6.2 KiB
Architecture Fixes Summary
Date: October 9, 2025
Status: In Progress
✅ Completed Fixes
1. Fixed Circular Dependency
- Issue:
common/index.tstried to re-exportAddressfromcustomerdomain - Fix: Removed circular import.
Addressshould be imported directly from@customer-portal/domain/customer
2. Added Missing Utility Functions
- getCurrencyLocale() in
toolkit/formatting/currency.ts - AsyncState types in
toolkit/typing/helpers.ts(createLoadingState, isSuccess, etc.) - response-helpers.ts in portal (getNullableData, etc.)
3. Fixed Domain Exports
- Added
ProfileEditFormData,ProfileDisplayData,UserProfile,AuthenticatedUserto customer domain - Added
profileEditFormSchemaandprofileFormToRequest()helper - Added Address field helpers:
getStreet(),getStreetLine2(),getPostalCode()
4. Corrected Import Paths (60+ files)
- ❌ Before: Everything imported from
@customer-portal/domain/billing - ✅ After: Imports from correct domains:
Address→@customer-portal/domain/customerSubscription→@customer-portal/domain/subscriptionsPaymentMethod→@customer-portal/domain/paymentsformatCurrency→@customer-portal/domain/toolkit- Catalog types →
@customer-portal/domain/catalog
5. Normalized User Field Names
- Issue: User schema had mixed naming (snake_case from WHMCS vs camelCase)
- Fix: Normalized to proper camelCase in User schema:
firstname→firstNamelastname→lastNamephonenumber→phoneNumberfullname→fullNamecompanyname→companyName
- Mapping:
combineToUser()now maps WHMCS snake_case → User camelCase at the boundary
6. Improved formatCurrency Signature
- Old:
formatCurrency(amount, currency, options)- rigid signature - New:
formatCurrency(amount, currencyOrOptions?, options?)- flexible:formatCurrency(1000, "JPY")- pass currency stringformatCurrency(1000, user.currencyCode)- use user's currency from profileformatCurrency(1000, { showSymbol: false })- pass options only
7. Address Field Strategy
- Decision: Keep WHMCS field names (
address1,address2,postcode) in Address type - Reason: These match backend/database, avoiding unnecessary mapping
- Helpers: Provided
getStreet(),getPostalCode()for backwards compatibility where needed
🔧 Issues Identified (Pending Fixes)
1. ⚠️ Business Logic in Frontend (CRITICAL)
Location: apps/portal/src/features/catalog/utils/catalog.utils.ts
Issue: Pricing calculations (monthly price, setup fees, etc.) are being done in the frontend utils.
Why This Is Wrong:
- Business logic should be in the BFF or domain layer
- Frontend should only display data, not calculate it
- Makes it harder to ensure pricing consistency
- Violates separation of concerns
Correct Approach:
// ❌ BAD: Frontend calculates pricing
const monthlyPrice = getMonthlyPrice(product); // In catalog.utils.ts
// ✅ GOOD: BFF sends pre-calculated prices
const monthlyPrice = product.monthlyPrice; // Already calculated by BFF
Action Required:
- Move pricing logic to BFF catalog service
- Have BFF calculate and include all display prices in API response
- Frontend just displays
product.monthlyPrice,product.setupFee, etc. - Delete
getMonthlyPrice()and similar functions from frontend utils
2. Field Name Inconsistencies (Remaining ~40 errors)
User Fields: Need to update all portal code using User type:
- Change
user.firstName→user.firstName✅ (now correct) - Change
user.phone→user.phoneNumber(still needs updates in portal)
Address Fields: Components expecting different field names:
- Some code expects
address.street→ should useaddress.address1orgetStreet(address) - Some code expects
address.postalCode→ should useaddress.postcodeorgetPostalCode(address)
3. formatCurrency Call Sites (~10 errors)
Many components still passing currency as object instead of string:
// ❌ Current (wrong)
formatCurrency(amount, { currency: "JPY", locale: "ja-JP" })
// ✅ Should be
formatCurrency(amount, "JPY", { locale: "ja-JP" })
// OR simply
formatCurrency(amount, invoice.currency)
📋 Remaining Work
High Priority
- Fix all
user.firstName/user.phoneNumberreferences in portal - Fix all
formatCurrencycall signatures - Fix remaining catalog component imports
Medium Priority
- Move pricing logic from frontend to BFF (architectural fix)
- Add missing schema properties (scheduledAt, billingCycle, SIM properties)
- Fix Address field references (use helpers or direct WHMCS names)
Low Priority
- Update any remaining documentation
- Add tests for new helper functions
Design Decisions Made
1. Single Field Naming Convention
Decision: Normalize to camelCase at the domain boundary
Rationale:
- TypeScript/JavaScript convention
- Single transformation point (domain mapper)
- Consistent with frontend expectations
- Clear separation: WHMCS uses snake_case, domain exposes camelCase
2. Address Field Names
Decision: Keep WHMCS names (address1, postcode)
Rationale:
- Matches backend/database structure
- Avoids unnecessary mapping layer
- Provides helpers for backwards compatibility
3. Currency Handling
Decision: Get from User.currencyCode, not pass everywhere
Rationale:
- Currency is user property (from WHMCS profile)
- Reduces parameter passing
- Single source of truth
4. Business Logic Location
Decision: Pricing calculations belong in BFF
Rationale:
- Separation of concerns
- Frontend displays, doesn't calculate
- Easier to maintain consistency
- Follows clean architecture principles
Next Steps
- Complete remaining type error fixes (~40 errors)
- Run full type check to verify
- Move pricing logic to BFF (separate task/PR)
- Test thoroughly
Progress: 10/16 major tasks completed (62%)
Estimated Remaining: 50-80 file edits for full type safety