---
apiVersion: data-spec/v1
id: campaign-default-member-statuses-flow-20260421
description: "Register a runtime flow that seeds Sent and Responded CampaignMemberStatus rows on Campaign create"
issue: "#1519"
created: 2026-04-21
scope: production-only
status: pending
tables: [FlowDefinition, Flow]
depends_on: []
---

# Campaign Default Member Statuses Flow

## Summary

Registers a runtime `RecordAfterSave` flow on `Campaign` that creates the two
Salesforce-default `CampaignMemberStatus` rows for every newly-created Campaign:
`Sent` and `Responded`.

The flow metadata source of truth lives at
`backend/internal/features/automation/testdata/campaign_member_status_flows/Campaign_Default_Member_Statuses.flow.json`.

## Changes

### 1. Upsert the `Campaign_Default_Member_Statuses` flow definition and active version

```sql
SET @flow_definition_insert_id := 'flowdef-campaign-default-member-statuses-20260421';
SET @flow_version_insert_id := 'flowver-campaign-default-member-statuses-v1-20260421';

INSERT INTO FlowDefinition (
  Id,
  DeveloperName,
  MasterLabel,
  Description,
  ProcessType,
  TriggerType,
  TriggerObjectOrEvent,
  ActiveVersionId,
  LatestVersionId,
  IsDeleted
) VALUES (
  @flow_definition_insert_id,
  'Campaign_Default_Member_Statuses',
  'Campaign Default Member Statuses',
  'Auto-provision the standard Sent and Responded CampaignMemberStatus rows when a Campaign is created.',
  'AutoLaunchedFlow',
  'RecordAfterSave',
  'Campaign',
  NULL,
  NULL,
  0
)
ON DUPLICATE KEY UPDATE
  MasterLabel = VALUES(MasterLabel),
  Description = VALUES(Description),
  ProcessType = VALUES(ProcessType),
  TriggerType = VALUES(TriggerType),
  TriggerObjectOrEvent = VALUES(TriggerObjectOrEvent),
  IsDeleted = 0,
  LastModifiedDate = CURRENT_TIMESTAMP;

SET @flow_definition_id := (
  SELECT Id
  FROM FlowDefinition
  WHERE DeveloperName = 'Campaign_Default_Member_Statuses'
  LIMIT 1
);

INSERT INTO Flow (
  Id,
  DefinitionId,
  MasterLabel,
  VersionNumber,
  Status,
  Description,
  ProcessType,
  Metadata,
  IsDeleted
) VALUES (
  @flow_version_insert_id,
  @flow_definition_id,
  'Campaign Default Member Statuses',
  1,
  'Active',
  'Auto-provision the standard Sent and Responded CampaignMemberStatus rows when a Campaign is created.',
  'AutoLaunchedFlow',
  CONVERT(FROM_BASE64('eyJhcGlWZXJzaW9uIjo2Mywic3RhdHVzIjoiQWN0aXZlIiwibGFiZWwiOiJDYW1wYWlnbiBEZWZhdWx0IE1lbWJlciBTdGF0dXNlcyIsImRlc2NyaXB0aW9uIjoiQXV0by1wcm92aXNpb24gdGhlIHN0YW5kYXJkIFNlbnQgYW5kIFJlc3BvbmRlZCBDYW1wYWlnbk1lbWJlclN0YXR1cyByb3dzIHdoZW4gYSBDYW1wYWlnbiBpcyBjcmVhdGVkLiIsInN0YXJ0Ijp7ImxvY2F0aW9uWCI6NDAsImxvY2F0aW9uWSI6MCwiY29ubmVjdG9yIjp7InRhcmdldFJlZmVyZW5jZSI6IkNyZWF0ZVNlbnRTdGF0dXMifSwib2JqZWN0IjoiQ2FtcGFpZ24iLCJ0cmlnZ2VyVHlwZSI6IlJlY29yZEFmdGVyU2F2ZSIsInJlY29yZFRyaWdnZXJUeXBlIjoiQ3JlYXRlIn0sInZhcmlhYmxlcyI6W3sibmFtZSI6IiRSZWNvcmQiLCJkYXRhVHlwZSI6IlNPYmplY3QiLCJpc0lucHV0Ijp0cnVlLCJpc091dHB1dCI6dHJ1ZSwib2JqZWN0VHlwZSI6IkNhbXBhaWduIn1dLCJyZWNvcmRDcmVhdGVzIjpbeyJuYW1lIjoiQ3JlYXRlU2VudFN0YXR1cyIsImxhYmVsIjoiQ3JlYXRlIFNlbnQgc3RhdHVzIiwibG9jYXRpb25YIjo0MCwibG9jYXRpb25ZIjoxMjAsIm9iamVjdCI6IkNhbXBhaWduTWVtYmVyU3RhdHVzIiwiaW5wdXRBc3NpZ25tZW50cyI6W3siZmllbGQiOiJDYW1wYWlnbklkIiwidmFsdWUiOnsiZWxlbWVudFJlZmVyZW5jZSI6IiRSZWNvcmQuSWQifX0seyJmaWVsZCI6IkxhYmVsIiwidmFsdWUiOiJTZW50In0seyJmaWVsZCI6IklzRGVmYXVsdCIsInZhbHVlIjp0cnVlfSx7ImZpZWxkIjoiSGFzUmVzcG9uZGVkIiwidmFsdWUiOmZhbHNlfSx7ImZpZWxkIjoiU29ydE9yZGVyIiwidmFsdWUiOjF9XSwiY29ubmVjdG9yIjp7InRhcmdldFJlZmVyZW5jZSI6IkNyZWF0ZVJlc3BvbmRlZFN0YXR1cyJ9fSx7Im5hbWUiOiJDcmVhdGVSZXNwb25kZWRTdGF0dXMiLCJsYWJlbCI6IkNyZWF0ZSBSZXNwb25kZWQgc3RhdHVzIiwibG9jYXRpb25YIjoyNjAsImxvY2F0aW9uWSI6MTIwLCJvYmplY3QiOiJDYW1wYWlnbk1lbWJlclN0YXR1cyIsImlucHV0QXNzaWdubWVudHMiOlt7ImZpZWxkIjoiQ2FtcGFpZ25JZCIsInZhbHVlIjp7ImVsZW1lbnRSZWZlcmVuY2UiOiIkUmVjb3JkLklkIn19LHsiZmllbGQiOiJMYWJlbCIsInZhbHVlIjoiUmVzcG9uZGVkIn0seyJmaWVsZCI6IklzRGVmYXVsdCIsInZhbHVlIjpmYWxzZX0seyJmaWVsZCI6Ikhhc1Jlc3BvbmRlZCIsInZhbHVlIjp0cnVlfSx7ImZpZWxkIjoiU29ydE9yZGVyIiwidmFsdWUiOjJ9XX1dfQo=') USING utf8mb4),
  0
)
ON DUPLICATE KEY UPDATE
  MasterLabel = VALUES(MasterLabel),
  Status = VALUES(Status),
  Description = VALUES(Description),
  ProcessType = VALUES(ProcessType),
  Metadata = VALUES(Metadata),
  IsDeleted = 0,
  LastModifiedDate = CURRENT_TIMESTAMP;

SET @flow_version_id := (
  SELECT Id
  FROM Flow
  WHERE DefinitionId = @flow_definition_id
    AND VersionNumber = 1
  LIMIT 1
);

UPDATE FlowDefinition
SET
  ProcessType = 'AutoLaunchedFlow',
  TriggerType = 'RecordAfterSave',
  TriggerObjectOrEvent = 'Campaign',
  ActiveVersionId = @flow_version_id,
  LatestVersionId = @flow_version_id,
  IsDeleted = 0,
  LastModifiedDate = CURRENT_TIMESTAMP
WHERE Id = @flow_definition_id;
```

**Idempotency**: The flow definition is keyed by unique `DeveloperName`, and the
flow version is keyed by `(DefinitionId, VersionNumber)`. Re-running the spec
updates the same logical flow metadata and re-points `ActiveVersionId` /
`LatestVersionId` to the current version row.

## Rollback

```sql
DELETE f
FROM Flow f
JOIN FlowDefinition fd ON fd.Id = f.DefinitionId
WHERE fd.DeveloperName = 'Campaign_Default_Member_Statuses';

DELETE FROM FlowDefinition
WHERE DeveloperName = 'Campaign_Default_Member_Statuses';
```
