This document explains how the portal integrates Salesforce (catalog, orders, provisioning control) and WHMCS (billing, invoices, subscriptions, payments). It covers the main flows end‑to‑end, what checks occur, and where the logic lives in code.
- BFF: Orchestration + ID mappings only; no customer data authority
- Key environment flags (validation schema)
-`SF_EVENTS_ENABLED`, `SF_PROVISION_EVENT_CHANNEL`, `SF_*` for Salesforce; `WHMCS_*` for WHMCS; `PORTAL_PRICEBOOK_ID/PORTAL_PRICEBOOK_NAME` for catalog/pricing. See env sample for full list (env/portal-backend.env.sample:1).
## Identity & Mapping
- Purpose: link a portal user to a WHMCS client and Salesforce Account.
- Persistence: `idMapping` table via `MappingsService` (apps/bff/src/mappings/mappings.service.ts:1).
- Lookups
- By user → WHMCS client ID (apps/bff/src/mappings/mappings.service.ts:148)
- By Salesforce Account → WHMCS client ID (apps/bff/src/mappings/mappings.service.ts:63)
- Usage: Most flows start by resolving mapping to enforce access and route calls correctly (e.g., invoices, orders).
## Catalog (Shown in Portal)
- Source of truth: Salesforce Product2 + PricebookEntry.
- Field mapping is configurable via env (apps/bff/src/common/config/field-map.ts:1). Important fields include:
- Base query helper uses a “Portal” pricebook (ID or name) and builds SOQL with visible/accessible filters (apps/bff/src/catalog/services/base-catalog.service.ts:1).
- SIM catalog example: returns plans, activation fees, add‑ons; optionally personalizes based on existing WHMCS services (apps/bff/src/catalog/services/sim-catalog.service.ts:1).
- Principle: Frontend selects explicit SKUs; backend validates SKUs exist in the portal pricebook and creates Salesforce OrderItems accordingly. See docs/PRODUCT-CATALOG-ARCHITECTURE.md:1.
- List/paginate via WHMCS GetInvoices; details enriched with line items and `serviceId` links (apps/bff/src/integrations/whmcs/services/whmcs-invoice.service.ts:1).
- Subscriptions listed via WHMCS GetClientsProducts; transformed and cached (apps/bff/src/integrations/whmcs/services/whmcs-subscription.service.ts:1).
- Payment methods/gateways via WHMCS; cached in Redis; also used for gating order creation/provisioning (apps/bff/src/integrations/whmcs/services/whmcs-payment.service.ts:1).
- SSO links: invoice view/download/pay and payment-page with preselected method/gateway (apps/bff/src/integrations/whmcs/services/whmcs-payment.service.ts:168).
1. Validate request, user mapping, and business rules via `OrderValidator.validateCompleteOrder()` (apps/bff/src/orders/services/order-validator.service.ts:296):
2. Build Order header fields including activation fields and address snapshot (apps/bff/src/orders/services/order-builder.service.ts:22)
- Address snapshot always sets BillTo\* fields; sets `Address_Changed__c` if user supplied a different address at checkout (apps/bff/src/orders/services/order-builder.service.ts:88)
3. Create Salesforce Order and then OrderItems by SKU using the pricebook entry and unit price (apps/bff/src/orders/services/order-item-builder.service.ts:20)
- Result: Returns `sfOrderId` with status Created for operator review/approval in Salesforce.
## Orders — Provisioning (Salesforce ➝ WHMCS)
- Trigger: Salesforce publishes a Platform Event (record‑triggered flow) on approval. The BFF subscriber listens when `SF_EVENTS_ENABLED=true` and enqueues provisioning (apps/bff/src/vendors/salesforce/events/pubsub.subscriber.ts:58).
- Queue: BullMQ `provisioning` queue with idempotent job IDs (apps/bff/src/orders/queue/provisioning.queue.ts:1).
- Validate request: not already provisioned (checks `WHMCS_Order_ID__c`), ensure client has payment method; resolve mapping (apps/bff/src/orders/services/order-fulfillment-validator.service.ts:23)
- Set SF activation status to `Activating` (apps/bff/src/orders/services/order-fulfillment-orchestrator.service.ts:98)
- Load SF Order details + OrderItems, map each to WHMCS items using the Product2 mapping (`WH_Product_ID__c`) and billing cycle (apps/bff/src/orders/services/order-whmcs-mapper.service.ts:1)
- Create WHMCS order (AddOrder) with Stripe as payment method; optional promo code and tracking notes (apps/bff/src/integrations/whmcs/services/whmcs-order.service.ts:20)
- Accept/provision order (AcceptOrder), capture service IDs and invoice ID returned (apps/bff/src/integrations/whmcs/services/whmcs-order.service.ts:60)
- Update SF: `Status=Completed`, `Activation_Status__c=Activated`, and write back `WHMCS_Order_ID__c` (apps/bff/src/orders/services/order-fulfillment-orchestrator.service.ts:117)
- Error handling: On failure, set `Status=Pending Review`, `Activation_Status__c=Failed`, and write concise error code/message for operator triage (apps/bff/src/orders/services/order-fulfillment-orchestrator.service.ts:146).
- Data comes from WHMCS products/services via `GetClientsProducts` and is transformed into a standard Subscription list (apps/bff/src/integrations/whmcs/services/whmcs-subscription.service.ts:1).
- Cached per user; supports status filtering; invoice items link to `serviceId` to show related subscriptions (apps/bff/src/integrations/whmcs/transformers/whmcs-data.transformer.ts:35).
- Redis cache is used for: invoices (lists and by ID), subscriptions, payment methods, payment gateways, user mappings (apps/bff/src/common/cache/cache.service.ts:1).
- Cache invalidation helpers exist per domain (e.g., `invalidatePaymentMethodsCache`, `invalidateInvoiceCache`).
- HTTP pagination/limits enforced in controller input validation for invoices (apps/bff/src/invoices/invoices.controller.ts:1).
## Field Map (Configurable)
- All SF field API names are env‑driven and wrapped by `getSalesforceFieldMap()` (apps/bff/src/common/config/field-map.ts:1).