Assist_Design/docs/CDC_ONLY_ORDER_IMPLEMENTATION.md
barsa d943d04754 Refactor environment configuration and enhance order processing logic
- 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.
2025-11-17 10:31:33 +09:00

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:

  1. Order Provisioning (NEW)

    • Detects when Salesforce sets Activation_Status__c to "Activating"
    • Validates order is not already provisioning/provisioned
    • Enqueues provisioning job
  2. 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

  1. Enable CDC on Order object (required)

    Setup → Integrations → Change Data Capture
    Select: Order, OrderItem
    Save
    
  2. 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:

  1. Re-enable Salesforce Flow

    • Flow that publishes Order_Fulfilment_Requested__e
  2. Remove provisioning from OrderCdcSubscriber

    • Comment out the handleActivationStatusChange() call
    • Keep cache invalidation logic
  3. 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:

  1. OrderCdcSubscriber triggers provisioning when Salesforce sets Activation_Status__c = "Activating"
  2. Multiple guards prevent duplicate provisioning
  3. Cache invalidation still works with smart filtering
  4. Simpler Salesforce setup - just enable CDC
  5. No Platform Event needed for order provisioning

Next Steps:

  1. Enable CDC on Order object in Salesforce
  2. Restart your application
  3. Test by approving an order (confirm Flow sets Activation_Status__c = "Activating")
  4. Monitor logs for successful provisioning

Your CDC-only implementation is complete and production-ready! 🚀