Skip to content

Demo Scenario

The demo is the product acceptance test.

It should prove that Wayscribe can reconstruct a complete entity journey and reveal where a data defect first appeared.

Simulates Salesforce sending an account webhook.

Receives the webhook, transforms the account, writes PostgreSQL, and publishes a message.

Consumes the message and sends the customer to the target API.

This may initially run in the same application repository but should be a distinct process.

Simulates HubSpot and rejects customers without a phone number.

  • API
  • web
  • PostgreSQL
{
"Id": "0018Z00002ABC",
"Name": "Jorge Polanco",
"Phone": "+1 919 555 1234",
"Status__c": "Active"
}

Expected internal customer:

{
"externalId": "0018Z00002ABC",
"name": "Jorge Polanco",
"phone": "+1 919 555 1234",
"status": "active"
}

The transformation incorrectly reads:

phone: account.Phone__c ?? null

The incoming payload uses Phone, so output becomes:

{
"phone": null
}

Primary entity:

customer:0018Z00002ABC

Aliases added later:

salesforceAccountId = 0018Z00002ABC
internalCustomerId = 18492
targetContactId = absent because creation failed
10:31:02 receive-salesforce-webhook
10:31:04 transform-salesforce-account
10:31:05 persist-customer
10:31:06 publish-customer-updated
10:31:07 consume-customer-updated
10:31:09 deliver-customer-to-target failed
10:31:39 retry-customer-delivery failed
10:32:39 retry-customer-delivery failed
10:34:38 move-message-to-dead-letter

The transformation maps a Salesforce account onto an internal customer, and every field is renamed in the process. The diff therefore shows the Salesforce fields leaving and the internal fields arriving:

Field Before After
Id "0018Z00002ABC" (absent)
Name "Jorge Polanco" (absent)
Phone "+1 919 555 1234" (absent)
Status__c "Active" (absent)
externalId (absent) "0018Z00002ABC"
name (absent) "Jorge Polanco"
phone (absent) null
status (absent) "active"

The defect is visible in the pair of rows for the phone number: Phone went in carrying a value, and phone came out null. Every other field arrives with its value intact, which is what makes that pair stand out.

This replaced an earlier version of this section that showed phone changing from "+1 919 555 1234" to null with name unchanged, as though input and output shared field names. That diff is not producible from this step: section 3 defines the input as the Salesforce shape and the output as the internal shape, so an input-versus-output comparison can only ever report removals and additions.

What the earlier version depicted was expected output versus actual output: the correct internal customer against the defective one. That is the replay comparison in REPLAY_SPEC.md section 11, not the transformation diff. See ADR-030.

{
"error": {
"code": "phone_required",
"message": "A phone number is required."
}
}

HTTP status:

422

The journey should be found using:

  • 0018Z00002ABC
  • 18492
  • journey ID
  • queue message ID
  • trace ID where present

After correcting the transformation to:

phone: account.Phone ?? null

The user replays the original source payload to a development replay endpoint.

Expected replay output:

{
"externalId": "0018Z00002ABC",
"name": "Jorge Polanco",
"phone": "+1 919 555 1234",
"status": "active"
}

The comparison shows that the phone number is preserved.

The test should:

  1. start the full Compose stack
  2. wait for readiness
  3. trigger the source webhook
  4. poll for journey completion or failure
  5. search by Salesforce ID
  6. verify the event count and order
  7. verify the phone diff
  8. verify target rejection
  9. verify retry events
  10. invoke replay against corrected endpoint
  11. verify replay result
  12. verify replay audit event

The final developer experience should approach:

Terminal window
docker compose -f infrastructure/compose.yaml \
-f infrastructure/compose.demo.yaml up --build
pnpm demo:trigger

Then open the web UI and search:

0018Z00002ABC