---
id: WF-COM-CAT-022
title: Save a Promotion With Its First Code
trigger: >-
  The promotion form creates or edits a campaign and may also create its entered first claim code. These
  requests commit independently, and failed code creation after a new draft triggers a compensating rename and
  archive attempt.
product_area: commerce
module: catalog
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-COM-CAT-014
  - CAP-COM-CAT-015
crosses:
  - SVC-COM-CAT-promotions
inference: []
idempotency: >-
  A repeat has no composite replay key. Unique campaign names and normalized codes can refuse another creation
  after an earlier request committed.
concurrency: >-
  Every request uses its own record and version rules. No transaction spans campaign creation, code creation,
  renaming and archiving.
hops:
  - 'n': 1
    actor_or_service: Console promotion adapter
    action: Create a draft campaign or PATCH the existing campaign before attempting the entered claim code.
    anchor: 'react-console:lib/commerce/promotions/live.ts:createLivePromotionsAdapter'
    seam: sync
    on_failure: Return campaign-write errors and stop before code creation.
    left_inconsistent: A failed campaign write retains no newly requested code.
    observer: The form displays returned errors and staff can reload saved records.
    provenance: observed
    source: 'react-console:lib/commerce/promotions/live.ts:createLivePromotionsAdapter'
  - 'n': 2
    actor_or_service: Console promotion adapter
    action: 'Create the entered code when required; on edits, first check the campaign’s existing code collection.'
    anchor: 'react-console:lib/commerce/promotions/live.ts:createLivePromotionsAdapter'
    seam: sync
    on_failure: >-
      Return code failure. After a new draft, attempt withdrawal; after an edit, retain the already saved
      campaign change.
    left_inconsistent: A campaign can be saved without its intended code.
    observer: The form displays returned errors and staff can reload saved records.
    provenance: observed
    source: 'react-console:lib/commerce/promotions/live.ts:createLivePromotionsAdapter'
  - 'n': 3
    actor_or_service: Console promotion adapter
    action: >-
      For failed new-code creation, rename the created draft to free its original name, then archive it in a
      separate request.
    anchor: 'react-console:lib/commerce/promotions/live.ts:createLivePromotionsAdapter'
    seam: sync
    on_failure: >-
      If withdrawal fails, report that the draft was saved and its code was not added. Successful withdrawal
      still returns the original code error.
    left_inconsistent: >-
      A renamed draft can remain if archive fails; successful withdrawal retains an archived record rather
      than deleting it.
    observer: The form displays returned errors and staff can reload saved records.
    provenance: observed
    source: 'react-console:lib/commerce/promotions/live.ts:createLivePromotionsAdapter'
evidence:
  - 'react-console:lib/commerce/promotions/live.ts:createLivePromotionsAdapter'
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-CRY-001, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-005, TC-PRV-001, TC-PRV-002]
---

# Save a Promotion With Its First Code

## What It Does

The promotion form creates or edits a campaign and may also create its entered first claim code. These requests commit independently, and failed code creation after a new draft triggers a compensating rename and archive attempt.

## The Flow

```mermaid
sequenceDiagram
  participant Console
  participant Promotions
  Console->>Promotions: Save campaign
  Console->>Promotions: Create entered code
  alt Code creation fails after new draft
    Console->>Promotions: Rename draft
    Console->>Promotions: Archive draft
    Console-->>Console: Return code error and withdrawal result
  end
```

## When Something Fails

Return campaign-write errors and stop before code creation. A failed campaign write retains no newly requested code. Return code failure. After a new draft, attempt withdrawal; after an edit, retain the already saved campaign change. A campaign can be saved without its intended code. If withdrawal fails, report that the draft was saved and its code was not added. Successful withdrawal still returns the original code error. A renamed draft can remain if archive fails; successful withdrawal retains an archived record rather than deleting it.

## Open Design Questions

Product should decide whether the composite save needs a single transaction. Until then, staff need to recognize that withdrawal keeps an archived record and that editing followed by code failure does not undo the campaign edit.
