---
id: CAP-COM-CAT-006
title: Prepare and publish product presentations
feature: FEAT-COM-CAT-02
product_area: commerce
module: catalog
revision: 1
status: draft
product_intent: proposed
implementation_evidence: observed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-commerce:docs/milestones/COMM-M1-set-up-what-you-sell.md#D8'
  - 'services-commerce:docs/milestones/COMM-M1-set-up-what-you-sell.md#D11'
  - >-
    services-commerce:docs/milestones/COMM-M1b-promotions-and-codes.md#Decisions
    (R6)
  - >-
    services-commerce:docs/milestones/walkthroughs/COMM-M1-handoff.md#What
    changed after your review (6)
purpose: >-
  Staff maintain the storefront information that lets buyers recognize and
  access catalog products.
outcomes:
  - A product appears to shoppers exclusively when customer staff publish it.
  - 'Pictures and files are retained once, safely, and cleaned up when replaced.'
concepts:
  - CON-COM-CAT-003
actors:
  - ACT-COM-001
  - ACT-COM-004
surfaces:
  - console
  - api
permissions:
  - key: commerce.product-listings.read
    where_checked: api
    scope: tenant
  - key: commerce.product-listings.create
    where_checked: api
    scope: tenant
  - key: commerce.product-listings.update
    where_checked: api
    scope: tenant
  - key: commerce.product-listings.delete
    where_checked: api
    scope: tenant
  - key: commerce.product-listings.bulk
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-COM-CAT-006-01
    proved_by: [ATS-COM-CAT-006-01, TST-COM-CAT-015, TST-COM-CAT-021]
    statement: >-
      Each product has at most one listing, with a workspace-unique web slug
      composed of lowercase words separated by hyphens.
    kind: validation
    enforced_at:
      - api
      - service
      - database
      - console
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/e2e/product-listings.e2e.spec.js#answers
      400 to a second listing of the same product
    origin: none
  - id: BR-CAP-COM-CAT-006-02
    proved_by: [ATS-COM-CAT-005-09, ATS-COM-CAT-006-02, ATS-COM-CAT-006-12, ATS-COM-CAT-006-13, ATS-COM-CAT-006-17, ATS-COM-CAT-006-18, TST-COM-CAT-027]
    statement: >-
      Draft listings remain unavailable to the public, published listings appear
      in store lists, and unlisted listings are accessible through their
      individual pages.
    kind: lifecycle
    enforced_at:
      - api
      - database
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/unit/storefront/storefront-visibility.spec.js#removes
      a draft everywhere, an unlisted listing from the list only, and a
      published one nowhere
    origin: COMM-M1 D8 (docs/milestones/COMM-M1-set-up-what-you-sell.md)
  - id: BR-CAP-COM-CAT-006-03
    proved_by: [ATS-COM-CAT-006-03, ATS-COM-CAT-006-15, TST-COM-CAT-057]
    statement: >-
      A direct link to an unlisted product permits public quoting and
      purchasing.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/pricing/tests/e2e/price-quote-public-sale.e2e.spec.js#prices
      an unlisted product, which the product page opens by its link
    origin: none
    note: >-
      D-REC-7 retains this pending Andrew; the checkout side has no test at the
      pinned commit.
  - id: BR-CAP-COM-CAT-006-04
    proved_by: [ATS-COM-CAT-006-04, ATS-COM-CAT-006-14, ATS-COM-CAT-009-04, TST-COM-CAT-015, TST-COM-CAT-025]
    statement: >-
      Only digitally delivered merchandise may carry downloadable files,
      retained privately with ordered labels.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/e2e/product-listings.e2e.spec.js#answers
      400 to files on a product that is not digital merchandise
    origin: none
  - id: BR-CAP-COM-CAT-006-05
    proved_by: [ATS-COM-CAT-006-04, ATS-COM-CAT-006-14, TST-COM-CAT-015, TST-COM-CAT-025]
    statement: >-
      Download settings reject zero limits and values exceeding the grant’s
      maximum use count or ten-year duration.
    kind: validation
    enforced_at:
      - api
      - database
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/unit/api/product-listing-download-rules.spec.js#refuses
      a window of 4000 days, naming the field and the bound
    origin: none
  - id: BR-CAP-COM-CAT-006-06
    proved_by: [ATS-COM-CAT-006-05, TST-COM-CAT-009, TST-COM-CAT-021]
    statement: >-
      Listing galleries and related-product lists each allow eight entries, and
      related products cannot include the product itself.
    kind: validation
    enforced_at:
      - service
      - console
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/integration/services/persistence/product-listings.integration.spec.js#refuses
      files on a product that is not digital merchandise (none, or physical),
      and a product that goes with itself (400)
    origin: none
  - id: BR-CAP-COM-CAT-006-07
    proved_by: [ATS-COM-CAT-006-05, TST-COM-CAT-009, TST-COM-CAT-021]
    statement: >-
      Featured dates must be ordered; the Featured label applies within its
      interval and New applies through its configured day.
    kind: validation
    enforced_at:
      - database
      - console
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/integration/db/catalog-tables.table.integration.spec.js#refuses
      a Featured window that ends before it starts
    origin: none
  - id: BR-CAP-COM-CAT-006-08
    proved_by: [ATS-COM-CAT-003-17, ATS-COM-CAT-005-13, ATS-COM-CAT-006-06, ATS-COM-CAT-006-17, ATS-COM-CAT-006-18, ATS-COM-CAT-006-19, TST-COM-CAT-021]
    statement: >-
      Listing saves prepare every image and file through the shared asset
      pipeline, retain unchanged image identities without recopying, detach
      replaced assets and reject unprepared references.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/integration/services/persistence/product-listings.integration.spec.js#refuses
      a gallery picture written past the pipeline (a reference the save never
      prepared)
    origin: COMM-M1 D11 (docs/milestones/COMM-M1-set-up-what-you-sell.md)
  - id: BR-CAP-COM-CAT-006-09
    proved_by: []
    statement: >-
      Staff may supply listing images by web address or upload, with the console
      exposing web addresses while the shared upload control remains pending.
    kind: policy
    enforced_at:
      - service
      - console
    must_prove: false
    provenance: documented
    source: 'services-commerce:docs/milestones/COMM-M1-set-up-what-you-sell.md#D11'
    origin: COMM-M1 D11 (docs/milestones/COMM-M1-set-up-what-you-sell.md)
  - id: BR-CAP-COM-CAT-006-10
    proved_by: [ATS-COM-CAT-006-16, ATS-COM-CAT-007-10]
    statement: >-
      New merchandise defaults to selling in the store, and omitted
      customer-facing listing text uses the product name.
    kind: policy
    enforced_at:
      - console
    must_prove: false
    provenance: documented
    source: 'services-commerce:docs/milestones/COMM-M1b-promotions-and-codes.md#R6'
    origin: COMM-M1b R6 (docs/milestones/COMM-M1b-promotions-and-codes.md)
  - id: BR-CAP-COM-CAT-006-11
    proved_by: [ATS-COM-CAT-006-07, ATS-COM-CAT-006-17, ATS-COM-CAT-006-18, TST-COM-CAT-004]
    statement: >-
      The initial listing save requires create permission; changes and
      publication of an existing listing require update permission.
    kind: permission
    enforced_at:
      - api
      - console
    must_prove: true
    provenance: test
    source: >-
      react-console:components/commerce/__tests__/permission-gating.test.tsx#asks
      a product not on the shelf yet for the create key, since its first save is
      a create
    origin: none
  - id: BR-CAP-COM-CAT-006-12
    proved_by: [ATS-COM-CAT-006-08, ATS-COM-CAT-006-17, ATS-COM-CAT-006-18, TST-COM-CAT-015]
    statement: >-
      Listing replacement requires the complete record at its read version and
      rejects a payload referring to another product.
    kind: invariant
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/e2e/product-listings.e2e.spec.js#replaces
      at the version read, a gallery picture kept with its id and one replaced;
      the stale version is 409; a mismatched product_id 400
    origin: none
  - id: BR-CAP-COM-CAT-006-13
    proved_by: [ATS-COM-CAT-006-10, ATS-COM-CAT-006-17, ATS-COM-CAT-006-18]
    statement: >-
      A full lock prevents replacing a listing, and either full or deletion-only
      locking prevents removing it.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-commerce:modules/catalog/services/persistence/product-listings.ts'
    origin: none
  - id: BR-CAP-COM-CAT-006-14
    proved_by: [ATS-COM-CAT-003-17, ATS-COM-CAT-005-13, ATS-COM-CAT-006-11, ATS-COM-CAT-006-17, ATS-COM-CAT-006-18, ATS-COM-CAT-006-19]
    statement: >-
      Scheduled cleanup queues due assets without deleting them; the consumer
      rechecks references, retires detached files or deletes never-committed
      files, and retries failures before retaining a terminal failure reason.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: inferred
    source: >-
      services-commerce:modules/catalog/services/assets/clean-up-one-catalog-asset.ts:1
    origin: none
    note: >-
      Local wrappers delegate cleanup to the shared record-asset composition.
      The pinned integration examples demonstrate queuing detached pictures,
      retiring them and retaining referenced pictures; retry exhaustion and
      never-committed deletion rely on the wrapper’s stated composition contract
      and require additional proof.
scenarios:
  - id: SC-CAP-COM-CAT-006-01
    given: The merchandise t-shirt uses physical delivery
    when: 'Save its headline, gallery and category selections'
    then: >-
      The first listing version retains prepared permanent assets and the
      selected shelves
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/e2e/product-listings.e2e.spec.js#answers
      200 with the listing as sent, every file a permanent reference, its
      shelves, at version 1
  - id: SC-CAP-COM-CAT-006-02
    given: The merchandise e-book uses digital delivery
    when: Attach labeled files
    then: >-
      The response retains ordered private files and the digital delivery
      information
    provenance: test
    source: >-
      services-commerce:modules/catalog/tests/e2e/product-listings.e2e.spec.js#carries
      its files, private, with their labels, and the merchandise extension’s
      delivery
depends_on:
  - CAP-COM-CAT-005
  - CAP-COM-CAT-007
related:
  - CAP-COM-CAT-008
  - CAP-COM-CAT-009
  - CAP-COM-CAT-013
journeys:
  - JNY-COM-CAT-001
  - JNY-COM-CAT-003
open_questions:
  - OQ-COM-CAT-003
evidence:
  - >-
    Pinned service inputs: modules/catalog/aws/api/product-listings.routes.ts
    and .schemas.ts; services/persistence/product-listings.ts;
    services/assets/**; db/product-listings.table.ts,
    product-listing-images.table.ts, product-listing-files.table.ts,
    managed-assets.table.ts; tests (listings e2e, persistence, queries, table,
    assets, download rules)
  - >-
    Pinned console inputs: components/commerce/catalog/** (the storefront
    section of the merchandise editor), lib/commerce/catalog/** and tests,
    components/commerce/__tests__/permission-gating.test.tsx
controls: [TC-IAM-006, 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-CRY-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-LOG-004, TC-LOG-005, TC-AVL-004, TC-MON-001, TC-MON-002, TC-MON-004, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-VEN-001, TC-VEN-002, TC-VEN-003, TC-PRV-001, TC-PRV-002]
exercised_by: [FAS-COM-CAT-02-01, FAS-COM-CAT-02-02, FAS-COM-CAT-02-03, FAS-COM-CAT-02-04, FAS-COM-CAT-02-05]
suites: [TST-COM-CAT-004, TST-COM-CAT-009, TST-COM-CAT-015, TST-COM-CAT-021, TST-COM-CAT-025, TST-COM-CAT-027, TST-COM-CAT-057]
---

# Prepare and publish product presentations

## Purpose

Staff maintain the storefront information that lets buyers recognize and access catalog products.

## How It Works

Staff edit the Storefront section beside the merchandise record. They supply descriptive text, images, shelves and publication choices before reviewing the saved presentation. Digital merchandise can also carry privately delivered files. Asset preparation connects each retained picture or file with the record that uses it. An invalid asset, excessive collection or inconsistent publication input prevents the save. Initial preparation and later edits have distinct permission requirements. The product should confirm the treatment of direct-link unlisted products and complete shared upload adoption.

## Relationships

The organize product shelves capability supplies related configuration or assessment used in this work.

The manage merchandise selections and sale availability capability supplies related configuration or assessment used in this work.

The present the store’s available products capability supplies related configuration or assessment used in this work.

The retrieve purchased digital files capability supplies related configuration or assessment used in this work.

The calculate and explain a buyer’s item price capability supplies related configuration or assessment used in this work.
