← All scenarios

Worked example — Supplier and product data

Supplier files that never match your catalogue

Every supplier sends their catalogue in their own shape, the same product arrives twice under two spellings, and downstream systems each read it differently.

The situation

Products have variable attributes, nested option groups, bundles and customer-specific fields, and the catalogue never stops changing. Suppliers send spreadsheets in their own layouts. A relational schema creates constant migrations; a loose document column gives up validation and governance. Meanwhile the storefront, the search index and the reporting warehouse each integrate against something slightly different.

These are illustrative scenarios showing how the products are used, not customer case studies.

Build-versus-buy lens

What this helps you decide

Use the example to find where product configuration ends and custom code begins — and whether the boundary leaves your team with less infrastructure to own.

Model fit
Can the record shape evolve without coordinating a migration, API and UI release?
Workflow fit
Can approvals, exceptions and deadlines move out of application code without losing control?
Integration fit
Can your existing APIs become reusable steps with retries, throttling and visible run history?
Control fit
Can your team reconstruct model changes, workflow runs and human decisions later?

What gets modeled

The structure as it would actually be defined — sections that repeat are marked.

  • Productrecord type
    • Identitysection

      Code, name, supplier reference

    • Categorychoice

      Options read live from Categories

    • Attributesrepeating section

      Varies by category — the reason a fixed column set never held

      • Nametext
      • Valuetext
      • Unitchoice
    • Option groupsrepeating section
      • Group nametext
      • Choicesrepeating section

        Nested inside the group

  • Categoriesrecord type
  • Suppliersrecord type

How it gets built

In the order somebody would actually do it. Each step names the capability it rests on, so it can be checked against the product pages.

  1. Model the variability instead of fighting it

    Attributes and option groups are repeating sections, and choices nest inside their group. The structure of a real product survives contact with the system rather than being flattened into columns nobody can name in advance.

    What it uses: Sections that nest and repeat to any depth

  2. Send suppliers the shape you expect

    Every published version can be imported and exported as CSV or JSON, and a sample file shows the expected shape. The supplier gets the format from the model rather than from a document somebody wrote once.

    What it uses: Import and export per published version, with a downloadable sample

  3. Let the model reject the bad rows

    Required, unique, typed and validated are properties of the field, so they apply on import exactly as they apply to the API. The import cannot introduce something the product would otherwise refuse.

    What it uses: Per-field rules enforced on every path in

  4. Catch the same product arriving twice

    What counts as a duplicate is defined on the schema, with a similarity threshold for the likely ones — the same item under a slightly different spelling. The rules are versioned with the schema rather than living in an import script.

    What it uses: Duplicate detection with a similarity threshold, versioned with the schema

  5. Make it findable

    Full-text search across the record type, weighted so that a name matters more than a description, with language-aware stemming. Where a contains-match is enough, that is available too.

    What it uses: Full-text search with per-field weighting

  6. Give every consumer the same contract

    The catalogue is published with its own REST URL space and an API description generated from the model, plus a schema description per version. The storefront, the search indexer and the warehouse read the same thing rather than three interpretations of it.

    What it uses: Its own API on publish, described by a generated API description

  7. Open the public part, and only the public part

    Where the catalogue is meant to be public, anonymous read is opted into for that schema alone — reads only, with anonymous writes refused outright, and available only for schemas that publish on save. Everything else stays behind keys scoped to particular record types.

    What it uses: Opt-in anonymous read per schema, and API keys scoped per record type

  8. Push the changes rather than being polled

    Downstream systems subscribe to product events and receive them signed, with retries, a delivery log and dead-lettering that can be redriven in bulk. A price change reaches the storefront because it was sent, not because something asked.

    What it uses: Signed event delivery with retries, dead-lettering and bulk redrive

Numbers used above, and where they come from

Every figure on this site is counted from the product itself. Nothing here is a performance or customer claim, because there is no measurement to cite for one.

field types
9field typesCounted from egav/backend/app/api/v1/egav/schemas/entity_type_attribute.py — DataType
places a choice list can come from
5places a choice list can come fromCounted from egav/backend/app/api/v1/egav/schemas/entity_type_attribute.py — OptionSourceType (file is reserved and not counted)
destinations for an event
4destinations for an eventCounted from egav/backend/app/api/v1/egav/lib/webhook/transports — http, sqs, sns, kafka

What changes

Onboarding a supplier stops being a script per supplier, the catalogue changes shape without a migration, and every downstream system reads one contract that is generated from the model rather than described in a document.

Written for Teams with data that keeps changing shape.

Evaluate it with your real model

Bring the awkward record, the exception-heavy workflow and the integration you do not want to own. We will make the configuration-versus-code boundary explicit.