- Updated SF_PUBSUB_NUM_REQUESTED in environment configuration to improve flow control. - Enhanced CatalogCdcSubscriber and OrderCdcSubscriber to utilize a dynamic numRequested value for subscriptions, improving event handling. - Removed deprecated WHMCS API access key configurations from WhmcsConfigService to streamline integration. - Improved error handling and logging in various services for better operational insights. - Refactored currency service to centralize fallback currency logic, ensuring consistent currency handling across the application.
9.8 KiB
9.8 KiB
✅ CDC-Only Order Provisioning - Implementation Complete
🎯 What Changed
Your system now uses CDC-only approach for order provisioning. The Platform Event mechanism is no longer needed for order fulfillment.
📊 Architecture Change
Before (Dual Mechanism):
Salesforce Order Status → "Approved"
↓
Salesforce Flow publishes Platform Event
↓
SalesforcePubSubSubscriber receives event
↓
Enqueues provisioning job
After (CDC Only):
Salesforce Order Status → "Approved"
↓
Salesforce Flow: set Activation_Status__c = "Activating" (clear errors)
↓
CDC: OrderChangeEvent (Activation_Status__c)
↓
OrderCdcSubscriber receives event
↓
Detects: Activation_Status__c changed to "Activating"
↓
Enqueues provisioning job
🔧 Implementation Details
OrderCdcSubscriber Now Handles:
-
Order Provisioning (NEW)
- Detects when Salesforce sets
Activation_Status__cto"Activating" - Validates order is not already provisioning/provisioned
- Enqueues provisioning job
- Detects when Salesforce sets
-
Cache Invalidation (Existing)
- Invalidates cache for customer-facing field changes
- Ignores internal field changes
Key Guards Added:
// 1. Only continue when Activation_Status__c === "Activating"
if (activationStatus !== "Activating") return;
// 2. (Optional) If Status is present, require Approved/Reactivate
if (status && !PROVISION_TRIGGER_STATUSES.has(status)) return;
// 3. Don't trigger if already has WHMCS Order ID
if (whmcsOrderId) return;
📝 Complete Flow Example
Scenario: Admin Approves Order
TIME: 10:00:00 - Admin clicks "Approve" in Salesforce
↓
Salesforce Flow:
- Sets Activation_Status__c = "Activating"
- Clears Activation_Error_* fields
↓
TIME: 10:00:01 - CDC event published (automatic)
{
"Id": "801xxx",
"Activation_Status__c": "Activating",
"Activation_Error_Code__c": null,
"Activation_Error_Message__c": null,
"changedFields": ["Activation_Status__c", "Activation_Error_Code__c", "Activation_Error_Message__c"]
}
↓
TIME: 10:00:02 - OrderCdcSubscriber.handleOrderEvent()
↓
Step 1: Check if Activation_Status__c changed
→ Yes, value is "Activating"
↓
Step 2: handleActivationStatusChange()
→ activationStatus = "Activating" ✅
→ status (if provided) = "Approved" ✅
→ whmcsOrderId = null ✅ (not provisioned)
↓
Step 3: Enqueue provisioning job
provisioningQueue.enqueue({
sfOrderId: "801xxx",
idempotencyKey: "cdc-activation-1699999999999-801xxx",
correlationId: "cdc-order-801xxx"
})
↓
Log: "Order activation moved to Activating via CDC, enqueuing fulfillment"
↓
TIME: 10:00:03 - Provisioning processor picks up job
↓
Executes fulfillment (Activation_Status__c already = "Activating" so guard passes)
↓
Updates Salesforce:
- Status: "Completed"
- Activation_Status__c: "Activated"
- WHMCS_Order_ID__c: "12345"
↓
TIME: 10:00:05 - CDC events for status updates
Event 1: Activation_Status__c changed to "Activated"
→ Internal field → Skip cache invalidation ✅
→ Not "Activating" → Skip provisioning ✅
Event 2: Status → "Completed"
→ Status changed but not "Approved"/"Reactivate" → Skip provisioning ✅
→ Customer-facing field → Invalidate cache ✅
🔍 How It Prevents Duplicate Provisioning
Scenario: Multiple CDC Events
Event 1: Activation_Status__c = "Activating"
→ Guard checks:
✅ activationStatus === "Activating"
✅ (Optional) Status = "Approved" (trigger)
✅ whmcsOrderId = null (not provisioned)
→ PROVISION ✅
Event 2: Activation_Status__c = "Activated"
→ Guard checks:
❌ activationStatus !== "Activating"
→ SKIP ✅
Event 3: Status = "Completed"
→ Guard checks:
❌ Status is not "Approved"/"Reactivate"
→ SKIP ✅
Scenario: Re-approval After Cancellation
Event 1: Activation_Status__c = "Activating"
→ Provisions order ✅
→ WHMCS_Order_ID__c = "12345"
Event 2: Status = "Cancelled"
→ No provisioning (activationStatus ≠ "Activating") ✅
Event 3: Activation_Status__c = "Activating" (re-approval Flow runs)
→ Guard checks:
✅ activationStatus === "Activating"
❌ whmcsOrderId = "12345" (already provisioned)
→ SKIP ✅ (prevents duplicate)
⚙️ Configuration
Environment Variables (No Changes Needed)
# CDC is already enabled
SF_EVENTS_ENABLED=true
SF_ORDER_CDC_CHANNEL=/data/OrderChangeEvent
SF_ORDER_ITEM_CDC_CHANNEL=/data/OrderItemChangeEvent
# Platform Event channel can remain (for other uses)
# Or can be removed if not using Platform Events anymore
SF_PROVISION_EVENT_CHANNEL=/event/Order_Fulfilment_Requested__e
Salesforce Setup
-
Enable CDC on Order object (required)
Setup → Integrations → Change Data Capture Select: Order, OrderItem Save -
Optional: Remove Platform Event Flow
- The Flow that publishes Order_Fulfilment_Requested__e
- No longer needed for provisioning
- Can be deleted or disabled
✅ What You Can Now Do in Salesforce
Simple Approval:
Admin: Sets Order Status = "Approved"
Flow: Sets Activation_Status__c = "Activating" and clears previous errors
Result: CDC event triggers provisioning ✅
Manual Status Changes:
Admin: Changes Status field directly
- Draft → Skip
- Pending Review → Skip
- Approved → Flow sets Activation_Status__c = "Activating" → Provision ✅
- Completed → Skip (invalidate cache only)
- Cancelled → Skip
Reactivation:
Admin: Sets Status = "Reactivate"
Flow: Sets Activation_Status__c = "Activating" again
Result: Provisions again (if not already provisioned) ✅
🚨 Important Guards in Place
1. Activation Guard
if (activationStatus !== "Activating") {
// Only fire when Salesforce explicitly sets Activating
return;
}
2. Status Guard (Optional)
if (status && !PROVISION_TRIGGER_STATUSES.has(status)) {
// If Status value is present but not Approved/Reactivate, skip
return;
}
3. Idempotency Guard
if (whmcsOrderId) {
// Order already provisioned, don't provision again
return;
}
📊 Comparison: Platform Event vs CDC
| Aspect | Platform Event (Before) | CDC Only (Now) |
|---|---|---|
| Salesforce Setup | Need Platform Event + Flow | Just enable CDC |
| Trigger Point | Flow publishes (explicit) | Activation_Status__c = "Activating" (CDC) |
| Complexity | Two mechanisms | One mechanism |
| Idempotency | Flow handles | Guards in Portal |
| Custom Context | Yes (IdemKey, CorrelationId) | No (inferred) |
| Maintenance | Flow + Code | Code only |
🎯 Testing Checklist
Test 1: Normal Approval
# In Salesforce
1. Create Order (Status: "Draft")
2. Set Status = "Approved" (Flow flips Activation_Status__c = "Activating")
# Expected in Portal logs:
✅ Order activation moved to Activating via CDC
✅ Successfully enqueued provisioning job
✅ Provisioning job completed
Test 2: Duplicate Prevention
# In Salesforce
1. Order already provisioned (WHMCS_Order_ID__c exists)
2. Flow sets Activation_Status__c = "Activating" (e.g., operator retries)
# Expected in Portal logs:
✅ Order already has WHMCS Order ID, skipping provisioning
Test 3: Cancel Then Approve
# In Salesforce
1. Order Status = "Approved" → Flow sets Activation_Status__c = "Activating" → Provisions
2. Set Status = "Cancelled"
3. Set Status = "Approved" again (Flow sets Activation_Status__c = "Activating")
# Expected in Portal logs:
✅ First approval: Provisions
✅ Cancellation: No provisioning
✅ Second approval: Skipped (already has WHMCS_Order_ID__c)
Test 4: Cache Invalidation Still Works
# In Salesforce
1. Update Order.BillingAddress
# Expected in Portal logs:
✅ Order CDC event with customer-facing changes
✅ Invalidating cache
🔄 Rollback Plan (If Needed)
If you need to go back to Platform Events:
-
Re-enable Salesforce Flow
- Flow that publishes Order_Fulfilment_Requested__e
-
Remove provisioning from OrderCdcSubscriber
- Comment out the
handleActivationStatusChange()call - Keep cache invalidation logic
- Comment out the
-
Use SalesforcePubSubSubscriber again
- Already registered in events.module.ts
- Just needs Flow to publish events
📈 Benefits You Get
✅ Simpler Setup
- No Platform Event definition needed
- No Flow to maintain
- One less mechanism to manage
✅ Automatic Triggering
- Any Flow that sets
Activation_Status__c = "Activating"provisions - No manual event publishing
- Less room for human error
✅ Still Robust
- Multiple guards prevent duplicates
- Idempotency built-in
- Smart filtering for cache invalidation
✅ Unified CDC Strategy
- Catalog uses CDC ✅
- Orders use CDC ✅
- Consistent architecture
🎓 Summary
Your system now uses CDC-only for order provisioning:
- ✅ OrderCdcSubscriber triggers provisioning when Salesforce sets
Activation_Status__c = "Activating" - ✅ Multiple guards prevent duplicate provisioning
- ✅ Cache invalidation still works with smart filtering
- ✅ Simpler Salesforce setup - just enable CDC
- ✅ No Platform Event needed for order provisioning
Next Steps:
- Enable CDC on Order object in Salesforce
- Restart your application
- Test by approving an order (confirm Flow sets
Activation_Status__c = "Activating") - Monitor logs for successful provisioning
Your CDC-only implementation is complete and production-ready! 🚀