Kestrel Fastening Systems KESTREL FASTENING SYSTEMS

PIM

This is the emptiest area of the baseline and the one most customers care about. The page says exactly what PIM structure exists (almost none), what the base contract guarantees, and the canonical order in which an agent builds a real model.

What the baseline guarantees

Layer: base 3.2.1 only. base.contract.json `idRules.baseCatalog: "empty"`.
Present:
- One shop: SHOP1 "B2B Commerce Store", ShopType 1, ShopAutoBuildIndex true,
  ShopImageFolder /Images/Products, ShopOrderFlowId 1, ShopDefault FALSE.
- Three shop languages (EcomShopLanguageRelation): ENU en-US (IsDefault true), ESM es-MX,
  FRC fr-CA. EcomLanguages carries 20 rows; only these three are attached to SHOP1.
- One hidden template category: `reference_category` (EcomProductCategory, CategoryType 2)
  plus its LANG1 translation. This row is load-bearing: every completeness rule and every
  category field is plumbed through it, and a missing one is the #1 cause of
  "rule defined and assigned but no panel renders".
- Five product groups and eight products, all from feature layers, all PACK-* keyed:
    PACK-RPP-GRP1  -> PACK-RPP-PROD1, PACK-RPP-PROD2      (feature-pricing)
    PACK-SUB-GRP1  -> PACK-SUB-PROD1                      (feature-subscription-orders)
    PACK-BOM-GRP1  -> PACK-BOM-0001 (ProductType 2, kit)  (feature-bom-configurator)
    PACK-BOM-FORKS -> PACK-BOM-FORK-1, PACK-BOM-FORK-2
    PACK-BOM-RACKS -> PACK-BOM-RACK-1, PACK-BOM-RACK-2
  Each group carries an EcomShopGroupRelation row to SHOP1.
- Two EcomProductItems rows (PACK-BOM3-0002, PACK-BOM3-0003) — the BOM slots on
  PACK-BOM-0001.
NOT present by design:
- Zero Data Models (no EcomGroups GroupType 2), zero DataModelFolders, zero DataStructure
  shop (ShopType 4).
- Zero category fields beyond whatever `reference_category` holds.
- Zero completeness rules, zero workflows, zero Dynamic Workspaces, zero dashboards.
- Zero variant groups, options or combinations.
- Zero manufacturers, zero units.
ID rules you MUST honour when you add rows (base.contract.json idRules): nvarchar PKs on
base-owned tables get a `PACK-<NAME>-` prefix; int-identity PKs (including
ItemType_<systemName> item ids) start at 100000. `FIXT*`, `FIXTGRP*`, `FIXT-PRICE-*` are
reserved by sample-data — do not use them even though sample-data is not activated here.
There is deliberately NO per-itemType numeric range table; the contract is prefix-based.

Which skill covers it

dw-demo-pim (dynamo: false) — references/canonical-setup-order.md is the spine. Pick
Variant A (Storefront-first, §1, lines 61-90): this site HAS a Swift storefront.
dw-pim-modelling (dynamo: true) — references/structural-model.md (505 lines) for shop types
(§2.1), group types (§2.2), the 3-table variant shape (§2.5), BOM (§2.6), and the
reference_category four-row mechanic (§2.8).
dw-pim-completeness (dynamo: true) — references/rules-and-dashboards.md.
dw-pim-workflow (dynamo: true) — references/workflow-engine.md,
references/completeness-and-workflows.md.
dw-pim-localization (dynamo: true) — references/translation-mechanics.md.

Which MCP tools brand it

The order in dw-demo-pim/references/canonical-setup-order.md:63-90 (Variant A), reduced to
the MCP-expressible steps:
  1  save_currencies, save_countries, save_languages
  2  save_shops                       (WHOLE-ENTITY REPLACE — snapshot SHOP1 first, :64)
  4  save_units, save_manufacturers
  7  create_data_model_structure  (or create_categories -> create_category_fields ->
                                   save_groups -> assign_categories_to_data_models)
  8  save_groups                      (pass shopId on SUBGROUPS too, :70)
  9  save_variant_groups, save_variant_options
 10  create_products                  (ignores languageId — lands on master, :72)
 11  assign_data_model_to_products
 12  patch_products_safe
 13  get_product_asset_categories -> import_product_images_from_urls
 14  create_variant_combinations
 17  create_or_update_product_queries
 21  create_or_update_completeness_rules -> assign_completion_rules_to_groups
 22  create_users, save_user_groups, save_assortments, assign_permissions_to_assortment
 23  create_dashboards -> add_widgets_to_dashboards
 24  build_product_index -> wait_for_product_index
The variant sub-flow is its own ordered recipe (dw-pim-modelling/SKILL.md:177-183):
  save_variant_groups -> save_variant_options -> assign_variant_groups_to_product
  -> create_variant_combinations -> get_variant_combinations
  Assign ALL groups at once; each combination's option ids must contain exactly one option
  per assigned group, no more and no fewer. create_variant_combinations leaves ProductActive
  and ProductPrice NULL on the combination rows, and a NULL-active NULL-price variant is
  invisible storefront-wide — fix both before declaring variants done.
The dashboard sub-flow is its own ordered recipe
(dw-pim-completeness/references/rules-and-dashboards.md:224):
  get_dashboard_areas -> get_dashboards -> create_dashboards (capture the Id)
  -> get_available_widgets (exact SystemName, never guess) -> get_widget_parameters
  -> add_widgets_to_dashboards        (counts first, the grid last, :300)
ID discipline for every create/save above (canonical-setup-order.md:12): the PIM catalogue
tools AUTO-ASSIGN entity ids and IGNORE ids you pass in. Capture items[].id from every
response and key all subsequent steps off the captured ids. A blind re-run after a partial
failure stacks duplicate, mis-IDed entities.

Verify

MCP: get_shops returns exactly one row, ShopId SHOP1. get_products returns 8 rows, every
ProductId prefixed PACK-. get_groups returns 5, every GroupId prefixed PACK-. Any FIXT* row
means the sample-data layer was activated and this guide is out of date.
After building a model: get_product_index_status must report the PRIMARY instance
LifecycleState Completed with the expected document count. An index-level State=Warning whose
only cause is an unbuilt secondary balancer instance is a false alarm
(canonical-setup-order.md:53).
Group plumbing: assert one EcomShopGroupRelation row per group before moving on
(canonical-setup-order.md:70) — a group with a parent row but no shop row renders in
navigation and returns 200 while ProductsByGroupId returns 0.