- Control plane: Salesforce (review/approval, provisioning trigger)
- Logging: centralized logger "dino" – do not introduce alternate loggers
We require a Customer Number (SF Number) at signup and gate checkout on the presence of a WHMCS payment method. Orchestration runs in the BFF; Salesforce reviews and triggers provisioning.
## 0) Architecture at a Glance
- Source of truth
- Salesforce: Catalog (Product2 + PricebookEntry with portal fields), eligibility, order review/trigger, reporting
- User provides: Email, Confirm Email, Password, Confirm Password, First/Last Name, optional Company/Phone, and Customer Number (SF Number).
- Portal validates and links to the existing Salesforce Account using the SF Number; if email differs, proceed and auto-create a Salesforce Case for CS (details in data model doc).
- WHMCS client is always created on signup (no pre-existing clients expected). WHMCS custom field for Customer Number must be set to the SF Number.
- Mapping is stored: `portalUserId ↔ whmcsClientId ↔ sfAccountId`.
- BFF subscribes to the event and enqueues a provisioning job. Worker validates payment method, (for eSIM) calls activation API, then `AddOrder` and `AcceptOrder` in WHMCS, updates Salesforce Order fields/status.
- Legacy (webhook): previously called `POST /orders/{sfOrderId}/fulfill`. This path has been removed.
- Reuse centralized logger; no sensitive data in logs.
- Add a lightweight `EmailService` abstraction in BFF using existing modules style; queue via BullMQ jobs for reliability (Jobs module already present). Transport to be configured (SMTP/SendGrid) via env.
- Templates stored server-side; configurable CC list via env.
- Validate request; check portal user exists by email; if exists → error (prompt login/reset).
- Salesforce: find Account by Customer Number (SF Number). If not found → error.
- WHMCS: create client unconditionally for this flow. Set Customer Number custom field to SF Number.
- Create portal user and store mapping.
- Send Welcome email (to customer) with support on CC.
- If email mismatch is detected between inputs/systems (e.g., SF Account email vs signup email), automatically create a Salesforce Case to notify CS team and include both emails and Account reference.
- Security: sanitize errors; never log passwords; use centralized logger.
-`POST /auth/claim` (optional future): If we ever separate claim flow from signup.
- Salesforce: Catalog (Product2/PricebookEntry) and process control (Order approvals/status), account eligibility fields. Read-only from portal at runtime except Order creations/updates.
- WHMCS: Customer details, payment methods, invoices, subscriptions, provisioning outcomes. Source of truth for customer contact/billing data.
- Portal (BFF): Orchestration state and ID mappings only.
- Mapping Records (existing):
-`portalUserId ↔ whmcsClientId ↔ sfAccountId` stored in BFF mappings service.
- Customer Number (SF Number) is provided once at signup to create the mapping; we do not ask again.
- Portal User → Salesforce Account (lookup only)
- Authoritative lookup key: Customer Number on Account (provided via SF Number at signup).
- We do not sync profile/address changes from portal to Salesforce.
- Portal User → WHMCS Client (authoritative for customer profile)
- Email → `email`
- First/Last Name → `firstname`, `lastname`
- Company → `companyname` (optional)
- Phone → `phonenumber`
- Address: `address1`, `address2`, `city`, `state`, `postcode`, `country` (ISO 2-letter)
- Custom Field (Customer Number) → set to SF Number (id/name TBD; currently used in mapping)
- Notes (optional) → include correlation IDs / SF refs
- Discrepancy handling
- If SF Account email differs from signup email, proceed and auto-create a Salesforce Case for CS with both emails and Account reference (for review). No sync/write to SF.
- Used to open WHMCS payment methods and invoice/pay pages.
### 2.5 Catalog (Salesforce Product2 as Source of Truth)
We will not expose WHMCS catalog directly. Instead, Salesforce `Product2` (with `PricebookEntry`) will be the catalog, augmented with a small set of custom fields used by the portal and BFF.
Custom fields on `Product2` (proposal; confirm API names):
-`GET /catalog` (exists): return public offerings from `Product2` where `Portal_Catalog__c = true` and within validity dates; price via `PricebookEntry` for the portal pricebook.
- Query `Product2` filtered by `Portal_Catalog__c` and validity, then apply eligibility filters using Account fields (e.g., dwelling/tier). eSIM/VPN are always included.
- Use the Account’s serviceability/plan eligibility field(s) to decide which Internet product variants to show.
- Examples (to confirm API names and values):
-`Dwelling_Type__c`: `Home` | `Apartment`
-`Internet_Tier__c`: `1G` | `100Mb`
- The BFF personalization endpoint maps these to curated catalog SKUs.
- Customer Number (SF Number) is authoritative. Signup requires it. We find Account by that number.
- Mirror SF Number to WHMCS client custom field.
- If a discrepancy is found (e.g., Account has a different email than signup), create a Salesforce Case automatically with context so CS can triage; proceed with signup (no hard block), but flag the portal user for review.
- Optional overrides in `ConfigOptions_JSON__c` (e.g., size, add-ons) based on user selection
- Provisioning (triggered from Salesforce)
- BFF receives `sfOrderId`, loads `Order` and its lines.
- For each line, dereference Product2 to fetch `WHMCS_Product_Id__c` and default config options, then merge with any line-level overrides in `ConfigOptions_JSON__c`.
- Build `AddOrder` payload using the mapping above; place `sfOrderId` in WHMCS `notes`.
- The authoritative subscription record lives in WHMCS.
This keeps the mapping clean and centralized in Product2 portal fields, while Orders/OrderItems act as a snapshot of the customer’s selection and price at time of checkout.
## 3.5 Flow Sanity Check
1. Catalog comes from Salesforce Product2 (filtered/personalized by Account eligibility).
2. Customer signs up with SF Number; portal creates WHMCS client and mapping; address/profile managed in WHMCS.
3. Checkout creates an SF `Order` and child lines (no provisioning yet).
4. Operator approves in SF; Flow publishes Platform Event.
5. BFF subscriber enqueues job and provisions: recheck payment method (WHMCS), handle eSIM activation if needed, then `AddOrder` + `AcceptOrder` in WHMCS using mappings from Product2 portal fields referenced by the OrderItems.
- Actions available on an active eSIM subscription:
- Reissue eSIM: triggers BFF endpoint to call activation provider for a new profile, updates WHMCS notes/custom fields, sends email to customer.
- Top-up: triggers BFF to call provider top-up API; invoice/charges handled via WHMCS (AddOrder for add-on or gateway charge depending on implementation), sends email confirmation.
- UI: buttons gated by subscription status; confirmations and progress states.
## 5) Security, Idempotency, Observability
- Secrets in env/KMS, HTTPS-only, strict timeouts and retries with backoff in BFF external calls.
- Signed Salesforce → BFF requests with short TTL; IP allowlisting of Salesforce egress ranges.
- Idempotency keys for order creation and provisioning; include `sfOrderId` marker in WHMCS order notes.
- Logging: use centralized logger "dino" only; redact sensitive values; no payment data.
- Metrics: activation latency, WHMCS API error rates, provisioning success/failure, retries; alerts on anomalies.
9. eSIM Actions: implement `POST /subscriptions/:id/reissue-esim` and `POST /subscriptions/:id/topup` endpoints with BFF provider calls and WHMCS updates.
10. Future: Cancellations form → Salesforce Cancellations object submission (no immediate service cancel by customer).
## 8) Acceptance Criteria
- Signup requires Customer Number (SF Number) and links to the correct Salesforce Account and WHMCS client.
- Portal blocks checkout until a WHMCS payment method exists; SSO to WHMCS to add card.
- Orders are created in Salesforce and provisioned via BFF after operator trigger; idempotent and retriable.
- Customer sees clear order status and resulting subscriptions/invoices; sensitive details are not exposed.
## 9) WHMCS Field Mapping (Order Creation)
-`AddOrder` parameters to use:
-`clientid`: from user mapping
-`pid[]`: array of WHMCS product IDs (map from our catalog selection)
-`billingcycle`: `monthly` | `quarterly` | `semiannually` | `annually` | etc.
-`configoptions`: key/value for configurable options (from product detail form)
-`customfields`: include Customer Number (SF Number) and any order-specific data
-`paymentmethod`: WHMCS gateway system name (optional if default)
-`promocode`: if provided
-`notes`: include `sfOrderId=<Salesforce Order Id>` for idempotency tracing
-`noinvoice` / `noemail`: set to 0 to allow normal invoice + emails unless we handle emails ourselves
- After creation, call `AcceptOrder` to provision services and generate invoice/subscription as per WHMCS settings.
### 9.1 WHMCS Updates for eSIM Actions
- On Reissue:
- Update service custom fields (store masked new ICCID/EID if applicable), append to service notes with correlation ID and SF Order/Case references if any.
- Optionally create a zero-priced order for traceability or a billable add-on as business rules dictate.
- On Top-up:
- Create an add-on order or billable item/invoice through WHMCS; capture payment via existing payment method.