LEO CDP — UAT Testing Plan: Email Marketing Workflows

Local UAT Testing Technical Specification

Document type: Technical UAT Guide
System: LEO CDP — Customer Data Platform
Module: Marketing Campaign & Workflow Engine
Environment: Local development / Docker
Email testing: Mailpit
Status: Local Mailpit integration implemented; UAT execution pending

1. Purpose

Define the local User Acceptance Testing (UAT) procedure for the LEO CDP Marketing Workflow, covering audience selection, workflow design, approvals, campaign execution, email capture, terminal states, and asynchronous child-run observability.

Mailpit acts as a local SMTP capture server. It allows outgoing emails to be inspected without delivery to real recipients or reliance on an external SMTP provider.

1.1 Scope

  • Customer segment selection and profile loading.
  • Workflow persistence, version pinning, and atomic saves.
  • Human approval of workflow versions and campaigns.
  • Campaign activation and execution.
  • Per-profile workflow evaluation and reachable action-node execution.
  • Email action validation using Mailpit.
  • Campaign completion and failure states.
  • Asynchronous audience-sync child runs.
  • Logs, troubleshooting, and acceptance criteria.

1.2 Reference documentation


2. Architecture

Marketing UI
    |
    v
Campaign & Workflow API
    |
    +---- Campaign Storage
    |
    +---- Workflow Storage
    |
    v
Campaign Approval & Activation
    |
    v
campaign_workflow_job
    |
    v
Load Selected Profiles
    |
    v
Evaluate Workflow Per Profile
    |
    v
Execute Reachable Action Nodes
    |
    v
Email Action Handler
    |
    v
Mailpit SMTP :1025
    |
    v
Mailpit Web UI :8025

Campaign Execution
    |
    +---- Completed / Failed
    |
    +---- Asynchronous Audience-Sync Child Runs

The diagram describes the logical integration. Actual API boundaries, persistence mechanisms, and job execution depend on the current LEO CDP implementation.


3. Prerequisites

Before UAT begins, ensure that:

  • Docker Engine and Docker Compose v2 are available.
  • LEO CDP and its required dependencies are running.
  • A designated test tenant is available.
  • At least one segment contains synthetic test profiles.
  • The marketing workflow module is enabled.
  • A user with appropriate permissions can create and approve campaigns.
  • The email action handler supports configurable SMTP settings.
  • Testers can inspect campaign execution logs and run identifiers.

3.1 Prerequisites Traceability Matrix

The following matrix establishes a traceable relationship between each prerequisite, its validation method, the evidence required, and the UAT cases that depend on it.

Status definitions: Pending = not checked; Pass = verified; Fail = prerequisite is not satisfied; Blocked = validation cannot proceed.

IDPrerequisiteValidation methodExpected evidence / acceptance conditionDependent testsStatus
PR-01Docker EngineRun docker --version and docker infoDocker daemon responds successfullyUAT-01, UAT-02Pending
PR-02Docker Compose v2Run docker compose versionCompose v2 is availableUAT-01, UAT-18Pending
PR-03LEO CDP applicationCheck service health and application accessRequired application endpoints respondUAT-03–UAT-17Pending
PR-04Required persistence servicesVerify database connectivity and migrationsRequired tables and schema are accessibleUAT-04–UAT-06, UAT-15–UAT-17Pending
PR-05Test tenantOpen or query the designated tenantTest tenant exists and is isolatedUAT-03–UAT-20Pending
PR-06Customer segmentQuery or open the selected segmentSegment contains the expected synthetic profilesUAT-03, UAT-10–UAT-14Pending
PR-07Profile test dataInspect profile IDs and required attributesEligible, ineligible, and invalid-recipient cases are representedUAT-10–UAT-14Pending
PR-08Workflow engineCreate and validate a test workflowConditions and action nodes can be configuredUAT-04, UAT-06, UAT-11–UAT-14Pending
PR-09Campaign persistenceInspect campaign and workflow recordsBoth configurations can be saved and retrievedUAT-04, UAT-05Pending
PR-10Atomic-save behaviorInject a controlled persistence failureNo inconsistent partial state remainsUAT-05Pending
PR-11Workflow version pinningInspect workflow version referencesCampaign references the approved versionUAT-06Pending
PR-12Human approval controlsTest workflow and campaign approval permissionsRequired review cannot be bypassedUAT-06–UAT-08Pending
PR-13Campaign lifecycleVerify allowed state transitionsReview, approval, activation, running, and terminal states follow policyUAT-07–UAT-09, UAT-15–UAT-16Pending
PR-14Campaign job runnerExecute a controlled test jobcampaign_workflow_job starts and produces an inspectable runUAT-10–UAT-17Pending
PR-15SMTP configurationInspect the effective email configurationSMTP host, port, TLS, and authentication match the test environmentUAT-02, UAT-11–UAT-14Pending
PR-16Mailpit availabilityCheck container health and open the Web UIMailpit is running; UI is accessible on port 8025UAT-01, UAT-02Pending
PR-17SMTP connectivitySend a standalone SMTP smoke-test emailSMTP accepts the message and Mailpit displays itUAT-02Pending
PR-18Email templateRender a sample template using a test profileExpected personalization fields resolve correctlyUAT-13Pending
PR-19Execution logsTrigger a controlled run and inspect logsCampaign, job, profile, and action outcomes can be correlatedUAT-10–UAT-17, UAT-19Pending
PR-20Asynchronous child-run supportTrigger an audience-sync action if implementedChild run can be identified and inspected independentlyUAT-17Pending
PR-21Retry and idempotency policyInspect implementation and execute a controlled retryDuplicate-side-effect behavior is documented and testedUAT-19Pending
PR-22Local delivery isolationVerify SMTP configuration and inspect captured messagesNo external SMTP relay or real-recipient delivery is enabledUAT-02, UAT-20Pending
PR-23Evidence collectionPrepare test records and screenshot/log storageTest results can be traced to campaign and run IDsAll UAT casesPending

3.2 Prerequisite exit criteria

UAT execution may begin when all mandatory prerequisites are marked Pass.

  • A failed prerequisite must be resolved before dependent tests proceed.
  • A blocked prerequisite must be documented with its reason and impact.
  • A prerequisite that depends on an unimplemented feature must not be reported as passed.
  • Evidence should identify the build or Git commit used for testing.

The matrix is a living test artifact. Update its status and evidence references during test execution.


4. Start and verify Mailpit

Mailpit is included in both development Compose variants: dev-docker-compose.yml (SSO) and dev-no-sso-docker-compose.yml. Do not create a separate Mailpit Compose project; using the integrated service keeps the host port mapping, health status, and persistent inbox consistent with dev-c360.sh.

From the repository root, run the normal startup:

bash ./dev-c360.sh

dev-c360.sh chooses the Compose variant from SSO_LOGIN, starts Mailpit, and waits for its /mailpit readyz healthcheck before it starts/restarts the host API and backend. Startup fails with container logs if Mailpit does not become healthy.

Access:

Check the service directly:

docker compose -f dev-docker-compose.yml ps mailpit
docker compose -f dev-docker-compose.yml logs --tail=100 mailpit

When SSO_LOGIN=false, replace dev-docker-compose.yml with dev-no-sso-docker-compose.yml. The same service/container name and ports are used by both variants, so do not run the two Compose files simultaneously.

Mailpit binds to loopback by default. Captured messages persist in the named customer360-mailpitdata volume across container restarts. dev-c360.sh reset uses down -v and deletes this volume along with the local development data.

5. Configure LEO CDP SMTP

The repository-supported settings are:

EMAIL_DISPATCH_ADAPTER=smtp
SMTP_HOST=127.0.0.1
SMTP_PORT=1025
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_USE_TLS=false
EMAIL_FROM_ADDRESS=no-reply@leocdp.local
EMAIL_FROM_NAME=LEOCDP

These settings are present in the root .env.example. dev-c360.sh creates .env from that example if absent and adds missing keys without overwriting existing local values. For an existing .env, set the Mailpit values there; the values in .env.example do not replace customized values automatically. Do not put production SMTP credentials in this local configuration.

5.1 Which email path uses these settings?

  • EMAIL_DISPATCH_ADAPTER and the SMTP_* variables are the environment fallback for both customer360-backend/email_engine and campaign workflow email actions. An active tenant crm_connector_config EMAIL row takes precedence.
  • With no active tenant connector, EMAIL_DISPATCH_ADAPTER=smtp routes through the Mailpit settings above. If neither a tenant connector nor an explicit environment adapter is configured, campaign workflow email actions are recorded as skipped.

For either email path, verify the effective provider is Mailpit before running UAT. If the tenant has an active EMAIL connector, set that connector to SMTP host 127.0.0.1, port 1025, TLS disabled, and empty credentials, or remove the row from the local test tenant. A database connector always takes precedence over .env.

Mailpit’s local SMTP listener is plaintext by default. SMTP_USE_TLS=false and empty username/password are intentional for this loopback-only development setup. Do not expose Mailpit ports beyond loopback or use these settings for a production relay.


6. SMTP Smoke Test

Before campaign execution, verify that Mailpit captures a standalone message.

curl --url smtp://127.0.0.1:1025 \
  --mail-from noreply@leo-cdp.local \
  --mail-rcpt uat-recipient@example.test \
  --upload-file - <<'EOF'
From: LEO CDP UAT <noreply@leo-cdp.local>
To: UAT Recipient <uat-recipient@example.test>
Subject: LEO CDP SMTP Smoke Test
Content-Type: text/plain; charset=UTF-8

This is a local SMTP capture test for LEO CDP.
No external email delivery is expected.
EOF

Acceptance criteria:

  1. The SMTP client completes successfully.
  2. The message appears in Mailpit.
  3. Sender, recipient, subject, and body are correct.
  4. The message is not delivered to an external mailbox.

If the smoke test fails, resolve the problem before running campaign UAT.


7. Workflow Under Test

Phase 1 — Plan and design

  1. Select a segment.
  2. Design a workflow containing conditions and actions.
  3. Save the campaign and workflow atomically.

Expected behavior: The campaign and workflow are persisted consistently. A failed atomic save must not leave an inconsistent partial configuration.

Phase 2 — Governance and approval

  1. Approve the pinned workflow version.
  2. Submit the campaign for review.
  3. Approve the campaign.
  4. Activate the campaign.

Expected behavior: Execution uses the approved pinned workflow version. Agent-proposed changes require the specified human review before approval.

Phase 3 — Execution

  1. Mark the campaign Running.
  2. Execute campaign_workflow_job.
  3. Load the selected profiles.
  4. Evaluate workflow logic per profile.
  5. Execute reachable action nodes.

Expected behavior: Only actions reachable under the evaluated workflow path execute. Email actions submit messages to Mailpit.

Phase 4 — Completion and observability

  1. Mark the campaign Completed or Failed according to the execution policy.
  2. Inspect asynchronous audience-sync child runs separately.

Expected behavior: Campaign terminal states follow the implemented execution policy. Child runs remain independently observable and must not be assumed to share the parent campaign’s status.


8. UAT Test Data

Use synthetic profiles in an isolated tenant.

ProfileEmailPurpose
P001uat-p001@example.testEligible; email action reachable
P002uat-p002@example.testIneligible; email action skipped
P003uat-p003@example.testEligible; validate personalization
P004uat-p004@example.testMissing or invalid email; validate error handling

Example workflow:

Start
  |
  v
Check profile eligibility
  |
  +-- Not eligible --> End
  |
  +-- Eligible
        |
        v
     Send Email
        |
        v
       End

Example email content:

Subject: LEO CDP UAT — Hello {{ first_name }}

Hello {{ first_name }},

This is a local UAT message for profile {{ profile_id }}.

Campaign: {{ campaign_name }}

The template syntax is illustrative. Use the actual syntax supported by the LEO CDP template engine.


9. UAT Test Cases

IDScenarioExpected result
UAT-01Start MailpitContainer runs; UI is accessible
UAT-02SMTP smoke testMessage appears in Mailpit
UAT-03Select segmentCorrect segment is associated with the campaign
UAT-04Save workflowCampaign and workflow persist consistently
UAT-05Atomic-save failureNo inconsistent partial state remains
UAT-06Approve pinned versionCampaign references the approved workflow version
UAT-07Submit campaignCampaign enters the expected review state
UAT-08Activate before approvalActivation is rejected or blocked according to policy
UAT-09Approve and activateCampaign becomes eligible for execution
UAT-10Execute campaign jobJob starts and loads intended profiles
UAT-11Eligible profilesReachable email actions execute
UAT-12Ineligible profileEmail action is skipped
UAT-13PersonalizationProfile-specific values render correctly
UAT-14Invalid recipientError or skip behavior follows the defined policy
UAT-15Successful terminal stateCampaign becomes Completed under the defined success criteria
UAT-16Execution failureCampaign becomes Failed under the defined failure criteria
UAT-17Async child runAudience-sync child run is independently inspectable
UAT-18Restart MailpitPersisted messages remain available
UAT-19Retry failed jobDuplicate-side-effect behavior is verified
UAT-20Delivery isolationNo test message reaches an external recipient

Additional assertions

Atomic persistence: Inject a controlled persistence failure and verify rollback or equivalent consistency behavior.

Pinned version: Modify a workflow after approving an earlier version. Confirm the campaign still references its approved version unless a new version is explicitly reviewed and approved.

Human approval: Confirm that agent-proposed changes cannot bypass mandatory human review.

Reachable actions: Test branching conditions and verify that only reachable action nodes execute.

Idempotency: Retry a controlled job and verify duplicate behavior against the documented guarantee. If exactly-once execution is not implemented, record the limitation.

Asynchronous child runs: Trigger an audience-sync action if supported. Inspect the child run’s status, timestamps, and logs independently of the parent campaign.


10. Test Execution Procedure

  1. Start the required LEO CDP services.
  2. Start Mailpit and clear old messages if required.
  3. Verify SMTP connectivity.
  4. Create a campaign with a unique UAT identifier.
  5. Select the test segment and design the workflow.
  6. Save the campaign and workflow.
  7. Approve the pinned workflow version.
  8. Submit the campaign for review.
  9. Approve and activate the campaign.
  10. Trigger campaign_workflow_job.
  11. Inspect job logs and profile-level outcomes.
  12. Inspect the Mailpit inbox.
  13. Compare captured messages against expected recipients, content, and action counts.
  14. Verify the terminal campaign status.
  15. Inspect asynchronous child runs separately.
  16. Record evidence and assign pass/fail results.

10.1 Evidence to collect

  • Test ID and execution timestamp.
  • Build or Git commit.
  • Tenant, campaign, segment, and workflow identifiers.
  • Pinned workflow version.
  • Approval and activation state.
  • Campaign job or run identifier.
  • Expected and actual profile counts.
  • Expected and actual email submissions.
  • Mailpit message details or screenshots.
  • Errors, logs, and child-run identifiers.
  • Pass/fail result and defect reference.

Use synthetic data in local UAT evidence.


11. Troubleshooting

SymptomLikely causeDiagnostic action
UI does not openContainer stopped or port conflictCheck docker compose ps and logs
SMTP connection refusedWrong host/port or service unavailableCheck container and network reachability
mailpit hostname unresolvedServices do not share a Docker networkAttach both services to a common network
No email after campaign executionAction unreachable, disabled, or misconfiguredInspect workflow and SMTP logs
Incorrect message countBranching, retries, or duplicate executionCorrelate job, profile, and action records
Empty personalizationTemplate or profile mapping mismatchInspect resolved template inputs
Campaign remains RunningStalled job or failed status updateInspect worker health and run logs
Campaign fails but messages existPartial execution before an errorCompare action outcomes with terminal-state policy
Child run remains pendingStill processing or failed independentlyInspect child-run status and logs
Messages disappear after restartPersistence misconfiguredVerify MP_DATABASE and the mounted volume

Diagnostic commands:

docker compose ps
docker compose logs --tail=200 mailpit
docker inspect leo-cdp-mailpit
curl -I http://localhost:8025
nc -vz 127.0.0.1 1025

12. Cleanup

Stop Mailpit:

docker compose down

Clear captured messages using the supported Mailpit interface or API. Stop Mailpit before manually resetting its database.

Reset campaign and test-profile data separately using the supported LEO CDP test-data procedure.


13. Acceptance Criteria

  • All mandatory prerequisites are marked Pass.
  • Mailpit starts reliably and captures SMTP messages.
  • Campaign and workflow persistence maintains required consistency.
  • Approved workflow versions remain pinned.
  • Agent-proposed changes cannot bypass required human review.
  • Campaign approval and activation transitions behave correctly.
  • The campaign job loads the intended profiles.
  • Profile conditions determine which action nodes execute.
  • Email actions generate the expected messages in Mailpit.
  • Personalization values render correctly.
  • Error handling and terminal states follow the defined policy.
  • Retry and duplicate-side-effect behavior is tested.
  • Asynchronous audience-sync child runs can be inspected independently.
  • Logs and evidence support failure diagnosis.
  • No test email is delivered to an external recipient.

A test case must be marked Blocked if the feature is unavailable or cannot be exercised. Untested behavior must not be marked Pass.


14. UAT Completion Report

FieldValue
Build / Git commitTo be recorded
EnvironmentLocal Docker
Test tenantTo be recorded
Campaign IDTo be recorded
Workflow ID / versionTo be recorded
Prerequisites passedTo be recorded
Test cases passedTo be recorded
Test cases failedTo be recorded
Test cases blockedTo be recorded
DefectsTo be recorded
UAT decisionPending

PASS: All mandatory acceptance criteria are satisfied.

FAIL: One or more mandatory acceptance criteria fail.

BLOCKED: Critical prerequisites or implementation capabilities prevent valid testing.


15. Implementation Notes

This document defines the UAT process and expected behavior; it does not claim that every capability is already implemented in the LEO CDP repository.

Before using this guide as a release gate, verify the actual SMTP configuration keys, campaign lifecycle states, job runner interfaces, workflow version model, retry/idempotency policy, and child-run observability against the current source code.

The central validation chain is:

Approved campaign → pinned workflow → profile evaluation → reachable action → captured email → observable execution outcome.

Add explicit test case proceduresSeparate implemented from illustrative behavior