# Portal Integration Overview — Salesforce + WHMCS

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.

## System Overview

- Components
  - Frontend: Next.js portal (`apps/portal`)
  - Backend (BFF): NestJS (`apps/bff`), orchestrates Salesforce + WHMCS
  - Billing: WHMCS (invoices, payment methods, subscriptions)
  - CRM/Control Plane: Salesforce (catalog via Product2, Orders, provisioning trigger)
  - Infra: PostgreSQL (mappings), Redis (cache), BullMQ (queues)

- Sources of truth
  - Salesforce: Product catalog, Pricebook pricing, Orders, provisioning status and tracking
  - WHMCS: Customer profile, payment methods, subscriptions, invoices
  - 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:
  - `Product2.StockKeepingUnit` (SKU), portal visibility flags, `Item_Class__c`, billing cycle, and WHMCS product id/name.
- 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.

## Invoices & Payments

- Endpoints: `GET /invoices`, `GET /invoices/:id`, `GET /invoices/:id/subscriptions`, `POST /invoices/:id/sso-link`, `POST /invoices/:id/payment-link` (apps/bff/src/invoices/invoices.controller.ts:1).
- Service flow: resolve mapping → fetch from WHMCS via `WhmcsService` → transform/cache → return (apps/bff/src/invoices/invoices.service.ts:24).
  - List/paginate via WHMCS GetInvoices; details enriched with line items and `serviceId` links (apps/bff/src/vendors/whmcs/services/whmcs-invoice.service.ts:1).
  - Subscriptions listed via WHMCS GetClientsProducts; transformed and cached (apps/bff/src/vendors/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/vendors/whmcs/services/whmcs-payment.service.ts:1).
- SSO links: invoice view/download/pay and payment-page with preselected method/gateway (apps/bff/src/vendors/whmcs/services/whmcs-payment.service.ts:168).

## Orders — Creation (Portal ➝ Salesforce)

- Entry point: `OrderOrchestrator.createOrder()` (apps/bff/src/orders/services/order-orchestrator.service.ts:36).
- Steps
  1. Validate request, user mapping, and business rules via `OrderValidator.validateCompleteOrder()` (apps/bff/src/orders/services/order-validator.service.ts:296):
     - Format: `orderType`, non‑empty `skus[]` (apps/bff/src/orders/services/order-validator.service.ts:24)
     - Mapping present: user ↔ WHMCS client ↔ SF Account (apps/bff/src/orders/services/order-validator.service.ts:79)
     - Payment method exists in WHMCS (gating) (apps/bff/src/orders/services/order-validator.service.ts:96)
     - SKU existence in portal pricebook (apps/bff/src/orders/services/order-validator.service.ts:197)
     - Business rules by type (SIM, VPN, Internet) e.g. SIM requires activation fee (apps/bff/src/orders/services/order-validator.service.ts:225)
     - Internet duplication guard: one active Internet service per account (apps/bff/src/orders/services/order-validator.service.ts:166)
  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).
- Processor guardrails (apps/bff/src/orders/queue/provisioning.processor.ts:26):
  - Only process when Order `Activation_Status__c` is `Activating` (apps/bff/src/orders/queue/provisioning.processor.ts:35)
  - Skip if last error is `PAYMENT_METHOD_MISSING` to avoid thrash (apps/bff/src/orders/queue/provisioning.processor.ts:52)
  - Commit Salesforce Pub/Sub replay IDs for exactly‑once handling (apps/bff/src/orders/queue/provisioning.processor.ts:73)
- Orchestration steps (apps/bff/src/orders/services/order-fulfillment-orchestrator.service.ts:57):
  - 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/vendors/whmcs/services/whmcs-order.service.ts:20)
  - Accept/provision order (AcceptOrder), capture service IDs and invoice ID returned (apps/bff/src/vendors/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).

## Subscriptions (Shown in Portal)

- Data comes from WHMCS products/services via `GetClientsProducts` and is transformed into a standard Subscription list (apps/bff/src/vendors/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/vendors/whmcs/transformers/whmcs-data.transformer.ts:35).

## Payments & SSO

- Payment methods summary drives UI gating and provisioning validation (apps/bff/src/vendors/whmcs/services/whmcs-payment.service.ts:44).
- SSO flows
  - General WHMCS SSO (dashboard/settings) via `CreateSsoToken`
  - Invoice view/download/pay SSO (apps/bff/src/vendors/whmcs/services/whmcs-payment.service.ts:168)
  - Payment link with pre‑selected saved method or gateway (apps/bff/src/vendors/whmcs/services/whmcs-payment.service.ts:168)

## Caching & Performance

- 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).
- Key paths used in flows
  - Order activation: type/scheduledAt/status
  - WHMCS IDs: `Order.WHMCS_Order_ID__c`, `OrderItem.WHMCS_Service_ID__c`
  - Address snapshot: BillingStreet/City/State/Postal/Country + `Address_Changed__c`

## Environment & Health

- Env validation schema lists required/optional vars and sensible defaults (apps/bff/src/common/config/env.validation.ts:1). Sample file provides production-ready defaults (env/portal-backend.env.sample:1).
- Health endpoints expose DB/queue/feature flags and Salesforce events status (apps/bff/src/health/health.controller.ts:1).

## End‑to‑End Flow Summary

1. User links account at signup; mapping stored. Adds payment method in WHMCS via SSO.
2. Portal shows catalog from Salesforce Product2 + Pricebook. User selects options; frontend builds explicit SKUs.
3. `POST /orders` triggers validation (mapping, payment method exists, SKUs exist, business rules) → creates SF Order + OrderItems with address snapshot.
4. Operator approves in Salesforce; Platform Event published.
5. BFF subscriber enqueues provisioning; worker validates, maps items to WHMCS, creates/accepts WHMCS order, and updates Salesforce with status/IDs.
6. Portal pages show subscriptions and invoices from WHMCS with SSO links for payment.

## Key Checks & Guards

- Payment method required before order creation and before provisioning.
- SKU validity in pricebook; missing UnitPrice is a hard error.
- Business rules per order type (SIM requires activation fee, etc.).
- Internet duplication guard to prevent multiple active Internet services.
- Idempotency: If `WHMCS_Order_ID__c` is set, fulfillment short‑circuits as already provisioned.
- Queue processor only acts in `Activating` state; skips when awaiting user‑actionable errors.

## Where to Look in Code

- Order creation orchestration: apps/bff/src/orders/services/order-orchestrator.service.ts:36
- Validation (format/mapping/PM/SKUs/rules): apps/bff/src/orders/services/order-validator.service.ts:24
- Order header + address snapshot: apps/bff/src/orders/services/order-builder.service.ts:22
- OrderItems from SKUs: apps/bff/src/orders/services/order-item-builder.service.ts:20
- Fulfillment orchestration: apps/bff/src/orders/services/order-fulfillment-orchestrator.service.ts:57
- Salesforce events subscriber: apps/bff/src/vendors/salesforce/events/pubsub.subscriber.ts:58
- Provisioning queue processor: apps/bff/src/orders/queue/provisioning.processor.ts:26
- Invoices service: apps/bff/src/invoices/invoices.service.ts:24
- Subscriptions service: apps/bff/src/vendors/whmcs/services/whmcs-subscription.service.ts:1
- Payment/SSO service: apps/bff/src/vendors/whmcs/services/whmcs-payment.service.ts:1

---

For deeper details, see:

- docs/PORTAL-ORDERING-PROVISIONING.md
- docs/ORDER-FULFILLMENT-COMPLETE-GUIDE.md
- docs/PRODUCT-CATALOG-ARCHITECTURE.md
- docs/ADDRESS_SYSTEM.md
