# Invoice System Optimization Design

**Date:** 2026-03-05
**Status:** Approved

## Problem

Subscription invoice fetching is slow due to an N+1 query pattern. When viewing a subscription's invoices, the BFF:

1. Fetches ALL client invoices page by page (full table scan)
2. For each invoice, makes an individual `GetInvoice` WHMCS API call to get line items
3. Filters in-memory by `item.serviceId === subscriptionId`

For a client with 19 invoices: 1 list call + 19 individual detail calls = 20 WHMCS API calls with batching delays.

## Decision

**Remove subscription-specific invoice fetching entirely.** Most billing portals (Stripe, AWS, DigitalOcean) don't offer per-subscription invoice lists. The WHMCS `GetInvoices` API doesn't support filtering by service/subscription ID, making this fundamentally expensive.

Instead:

- Subscription detail page shows billing summary (already available on subscription object) + link to main invoices page
- Main invoices page uses efficient single `GetInvoices` call (already working well)
- Individual invoice detail already shows which subscription each line item belongs to

Additionally, clean up the billing service layer by removing the pass-through `BillingOrchestrator`.

## Changes

### Files to DELETE

1. `apps/bff/src/modules/billing/services/billing-orchestrator.service.ts` - zero-logic pass-through

### BFF Files to EDIT

2. **`subscriptions-orchestrator.service.ts`** - Remove:
   - `getSubscriptionInvoices()`, `tryGetCachedInvoices()`, `fetchAllRelatedInvoices()`, `paginateInvoices()`, `cacheInvoiceResults()` (~150 lines)
   - Related type imports (`InvoiceItem`, `InvoiceList`)
   - `WhmcsInvoiceService` dependency (if no other method uses it)

3. **`subscriptions.controller.ts`** - Remove:
   - `GET :id/invoices` endpoint
   - `SubscriptionInvoiceQueryDto`, `InvoiceListDto` DTOs
   - `invoiceListSchema`, `InvoiceList`, `Validation` imports
   - `subscriptionInvoiceQuerySchema`

4. **`whmcs-invoice.service.ts`** - Remove:
   - `getInvoicesWithItems()` method (~70 lines)
   - `chunkArray`, `sleep` imports (if unused after removal)

5. **`whmcs-cache.service.ts`** - Remove:
   - `subscriptionInvoices` + `subscriptionInvoicesAll` cache configs
   - `getSubscriptionInvoices()`, `setSubscriptionInvoices()`, `getSubscriptionInvoicesAll()`, `setSubscriptionInvoicesAll()`
   - `buildSubscriptionInvoicesKey()`, `buildSubscriptionInvoicesAllKey()`
   - Subscription invoice patterns in invalidation methods

6. **`billing.controller.ts`** - Replace `BillingOrchestrator` with direct `WhmcsPaymentService` + `WhmcsSsoService` injection

7. **`billing.module.ts`** - Remove `BillingOrchestrator` from providers/exports

### Portal Files to EDIT

8. **`InvoiceList.tsx`** - Remove dual-mode logic:
   - Remove `subscriptionId`, `showFilters` props
   - Remove `useSubscriptionInvoices` import
   - Remove `useInvoicesData()` helper, use `useInvoices()` directly
   - Remove `isSubscriptionMode` conditionals
   - Simplify `InvoicesFilterBar` (remove conditional spread)

9. **`SubscriptionDetail.tsx`** - Replace `<InvoicesList>` with billing link:
   - Remove `InvoicesList` and `InvoiceListSkeleton` imports
   - Replace billing history section with "View all invoices" link to `/account/billing`

10. **`app/account/subscriptions/[id]/loading.tsx`** - Remove `InvoiceListSkeleton`

11. **`useSubscriptions.ts`** - Remove `useSubscriptionInvoices()` hook

12. **`core/api/index.ts`** - Remove `subscriptions.invoices` query key

## Impact

- Eliminates 20+ WHMCS API calls per subscription detail view
- Removes ~300 lines of scanning/caching/batching code
- Simplifies InvoicesList to single-purpose component
- Removes unused service abstraction layer (BillingOrchestrator)
- No feature regression: invoice data still accessible via main billing page
