B2B
The B2B surfaces this baseline actually ships — account, CSR, quotes, reordering, kits, subscriptions — and which of them are inert without identities.
What the baseline guarantees
Layers: surface-swift 1.5.1 + feature-reordering + feature-subscription-orders + feature-bom-configurator + feature-b2b-comms. Account surfaces (surface-swift, replace/_content/Swift 2/Customer center/Account/): Addresses, Carts, Favorites, Orders, Quotes, Users plus Subscriptions (feature-subscription-orders) CSR surfaces (Customer center/CSR/): Accounts, Carts, Orders, Users Personal surfaces (Customer center/Customer center/): Change password, My addresses, My carts, My favorites, My orders, My profile > Edit profile, My quotes, My returns, My wallet Overview (Customer center/Overview) — the dashboard shell. From Swift 2.4 this is a per-role tile dashboard on ONE shared page; the separate CSR tile dashboard was retired. Quote flow: base ships EcomOrderFlow "Default Quote flow" and the order states "Price given", "Approved", "Rejected". Shopping cart/Cart/Quote checkout user is the quote checkout page. Reordering (feature-reordering 1.0.2, data-only, zero customCode): <site-root>/quick-order — the pad; the form carries cartcmd=addmulti <site-root>/express-buy — id="ExpressBuySearchForm" Both bind ProductsFrontend/Products.query (1.0.2 fixed this; it previously named a `Products` repository no install provisions, so every SKU read "Unknown SKU"). Known cycle limitation: the 2-page Quick Order fragment does not fully re-bind after a deactivate/reactivate cycle (the page 404s). First activation is unaffected; a full re-deserialize restores it. Kits (feature-bom-configurator 1.1.1): <site-root>/kit-configurator and its Detail page; PACK-BOM-0001 is ProductType 2 with two BOM slots. Subscriptions (feature-subscription-orders 1.1.1): <site-root>/subscribe, <site-root>/account/subscriptions, PACK-SUB-PROD1, PAY2 (Invoice, resolves to DefaultCheckoutHandler, IRecurring), SHIP9 (Home delivery), and a ScheduledTask row "Place recurring orders" bound to the DW-native RecurringOrdersScheduledTask, ** TaskEnabled = false ** — the demo enables it to show renewals. Dealer comms (feature-b2b-comms 1.0.2): 5 emails under /Newsletter Emails/Dealer Emails/ (Cart reminder, Dealer welcome, How to order, Product compliance notice, Seasonal promotion) + EmailMarketingFlow 100500 with 3 steps. NOT present by design: zero users. Every one of these pages renders its signed-out state until you author identities. feature-rma's seeded return and feature-pricing's contract price both key off customer number 98745621, which no user on this site holds.
Which skill covers it
dw-commerce-b2b (dynamo: true) — references/account-shape.md (the customer number as the account key), references/dc-scoping.md (DC-as-user-group). dw-demo-swift (dynamo: false) — references/customer-center.md (529 lines) for the customer-center playbook, sign-in profiles, impersonation and checkout order fields.
Which MCP tools brand it
save_user_groups -> create_users -> assign_users_to_group / assign_groups_to_user -> save_user_addresses -> save_assortments -> assign_groups_to_assortment -> assign_products_to_assortment -> assign_shops_to_assortment -> assign_permissions_to_assortment -> flag_assortments_for_rebuild -> build_assortments -> check_assortment_product_access (the read-back) Two ceilings to say out loud rather than work around: - Impersonation (a CSR acting on behalf of an account) has NO MCP tool at all. Name the admin screen (Edit user > Impersonation tab) and stop. - create_order_field errors on every call on this platform line: its MERGE into EcomOrderField passes an OrderFieldTypeID not present in EcomFieldType. A custom checkout field is an admin-screen operation.
Verify
MCP: get_user_groups returns the three base groups (Customers 1325, Account Admin 1270, CSR 1292) and get_users_by_group_id on each returns 0 rows on a clean baseline. After authoring: get_users_by_customer_number on your contract customer number returns exactly one user, and every contact in an account returns the SAME customerNumber — a per-contact suffix silently disables account-wide favourites, CSR account listing and contract pricing, because all four features compare the string exactly (dw-commerce-b2b/references/account-shape.md: 42-45). Storefront, BOTH auth states: GET <site-root>/customer-center signed out renders the anonymous state; signed in as a Customers member it renders the account tiles. Assert both — the signed-in assert alone cannot show the anonymous deny works. Assortment: build_assortments first, then assert the item count is non-zero BEFORE switching Active on. Activating a zero-item assortment does not add nothing; it takes the whole catalogue away from everyone who holds it (dw-commerce-b2b/SKILL.md:117-119). check_assortment_product_access must report no access for an out-of-scope user.