@base44/app-plugin-commerce 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +8 -8
  2. package/base44/agents/commerce/StoreAdmin.jsonc +7 -7
  3. package/base44/entities/commerce.Order.jsonc +1 -1
  4. package/base44/entities/commerce.PaymentGateway.jsonc +3 -3
  5. package/base44/entities/commerce.Product.jsonc +9 -45
  6. package/base44/entities/commerce.ProductAttribute.jsonc +7 -19
  7. package/base44/entities/commerce.ProductAttributeTerm.jsonc +4 -10
  8. package/base44/entities/commerce.ProductTag.jsonc +1 -8
  9. package/base44/entities/commerce.ProductVariation.jsonc +1 -1
  10. package/base44/entities/commerce.StoreSettings.jsonc +1 -1
  11. package/base44/functions/commerce/admin-products/entry.ts +107 -35
  12. package/base44/functions/commerce/admin-refunds/entry.ts +1 -1
  13. package/base44/functions/commerce/admin-reports/entry.ts +1 -1
  14. package/base44/functions/commerce/admin-tools/entry.ts +4 -3
  15. package/base44/functions/commerce/payments/entry.ts +0 -2
  16. package/base44/functions/commerce/seed-store/defaults.ts +13 -39
  17. package/base44/functions/commerce/seed-store/entry.ts +47 -35
  18. package/base44/functions/commerce/seed-store/sample-data.ts +28 -66
  19. package/base44/functions/commerce/storefront-cart/entry.ts +0 -7
  20. package/base44/functions/commerce/storefront-catalog/entry.ts +12 -21
  21. package/base44/functions/commerce/storefront-checkout/entry.ts +5 -12
  22. package/base44/shared/commerce/coupons.ts +4 -7
  23. package/base44/shared/commerce/email-templates.ts +15 -13
  24. package/base44/shared/commerce/emails.ts +4 -3
  25. package/base44/shared/commerce/payments.ts +8 -20
  26. package/base44/shared/commerce/products.ts +24 -0
  27. package/base44/shared/commerce/settings.ts +2 -3
  28. package/base44/shared/commerce/stock.ts +2 -4
  29. package/base44/shared/commerce/totals.ts +37 -42
  30. package/package.json +1 -1
  31. package/scripts/install.js +21 -4
  32. package/skills/commerce/SKILL.md +6 -5
  33. package/skills/commerce/docs/api-admin.md +16 -14
  34. package/skills/commerce/docs/api-storefront.md +39 -35
  35. package/skills/commerce/installation-guidelines.md +4 -3
  36. package/skills/commerce/post-installation.md +22 -25
  37. package/skills/commerce/references/admin-product-form.md +56 -0
  38. package/skills/commerce/references/emails.md +4 -3
  39. package/skills/commerce/references/guest-access-security.md +2 -2
  40. package/skills/commerce/references/limits-and-performance.md +1 -1
  41. package/skills/commerce/references/online-payments.md +8 -8
  42. package/skills/commerce/references/product-render.md +25 -23
  43. package/skills/commerce/references/storefront-product-page.md +9 -9
  44. package/skills/commerce/references/webhooks.md +3 -1
  45. package/src/commerce/admin/README.md +4 -4
  46. package/src/commerce/admin/context/BasePathContext.jsx +5 -5
  47. package/src/commerce/admin/context/SettingsContext.jsx +4 -4
  48. package/src/commerce/admin/index.jsx +3 -3
  49. package/src/commerce/admin/layout/Sidebar.jsx +1 -9
  50. package/src/commerce/admin/lib/constants.js +0 -7
  51. package/src/commerce/admin/lib/paths.js +6 -6
  52. package/src/commerce/admin/lib/product-utils.js +18 -15
  53. package/src/commerce/admin/pages/orders/components/AddProductDialog.jsx +8 -8
  54. package/src/commerce/admin/pages/products/ProductEditor.jsx +10 -12
  55. package/src/commerce/admin/pages/products/ProductsList.jsx +3 -15
  56. package/src/commerce/admin/pages/products/components/AttributesSection.jsx +426 -0
  57. package/src/commerce/admin/pages/products/components/ProductDataPanel.jsx +33 -69
  58. package/src/commerce/admin/pages/products/components/TaxonomyPanel.jsx +1 -1
  59. package/src/commerce/admin/pages/products/components/tabs/LinkedTab.jsx +1 -14
  60. package/src/commerce/admin/pages/products/components/tabs/ModifiersTab.jsx +19 -0
  61. package/src/commerce/admin/pages/products/components/tabs/PriceInventoryTab.jsx +728 -0
  62. package/src/commerce/admin/pages/reports/Reports.jsx +3 -3
  63. package/src/commerce/admin/pages/settings/EmailsSettings.jsx +12 -14
  64. package/src/commerce/admin/pages/settings/GeneralSettings.jsx +6 -116
  65. package/src/commerce/admin/pages/settings/PaymentsSettings.jsx +101 -62
  66. package/src/commerce/admin/pages/settings/SettingsLayout.jsx +2 -6
  67. package/src/commerce/admin/pages/settings/TaxSettings.jsx +0 -1
  68. package/src/commerce/admin/pages/status/WebhookEditor.jsx +3 -3
  69. package/src/commerce/admin/pages/status/Webhooks.jsx +2 -2
  70. package/src/commerce/admin/routes.jsx +10 -19
  71. package/src/commerce/utils/index.js +2 -2
  72. package/src/commerce/utils/shipping-promos.js +9 -6
  73. package/src/commerce/utils/variants.js +21 -21
  74. package/src/commerce/admin/pages/products/AttributeTerms.jsx +0 -180
  75. package/src/commerce/admin/pages/products/Attributes.jsx +0 -183
  76. package/src/commerce/admin/pages/products/Tags.jsx +0 -150
  77. package/src/commerce/admin/pages/products/components/tabs/AdvancedTab.jsx +0 -48
  78. package/src/commerce/admin/pages/products/components/tabs/AttributesTab.jsx +0 -208
  79. package/src/commerce/admin/pages/products/components/tabs/ExternalTab.jsx +0 -41
  80. package/src/commerce/admin/pages/products/components/tabs/GeneralTab.jsx +0 -103
  81. package/src/commerce/admin/pages/products/components/tabs/InventoryTab.jsx +0 -93
  82. package/src/commerce/admin/pages/products/components/tabs/ShippingTab.jsx +0 -86
  83. package/src/commerce/admin/pages/products/components/tabs/VariationsTab.jsx +0 -377
package/README.md CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
  A **Commerce backend + admin UI** for [Base44](https://base44.com) apps, delivered as a copyable file set. Drop `base44/` and `src/commerce/` into an existing Base44 app to add a full store: catalog, orders, coupons, customers, reviews, tax, shipping, webhooks, reports and transactional emails — plus a public storefront API for building your own shopfront.
4
4
 
5
- It provides a full-featured **commerce data model and behavior** (product types, order lifecycle, coupon rules, tax priority/compound math, shipping zones) using Base44-idiomatic primitives (entity JSON schemas, Deno functions, the Base44 SDK).
5
+ It provides a full-featured **commerce data model and behavior** (variant-driven products, order lifecycle, coupon rules, tax priority/compound math, shipping zones) using Base44-idiomatic primitives (entity JSON schemas, Deno functions, the Base44 SDK).
6
6
 
7
7
  ## What's included
8
8
 
9
- - **24 entities** — Products (simple/grouped/external/variable), variations, categories, tags, attributes + terms, reviews, orders (embedded line/shipping/tax/fee/coupon lines), order notes, refunds, coupons, customers, tax classes/rates, shipping zones/methods, payment gateways, store settings, webhooks + deliveries, carts, download permissions, email log.
9
+ - **24 entities** — Products (a product sells variants when it carries attributes; no type field), variations, categories, tags, attributes + values, reviews, orders (embedded line/shipping/tax/fee/coupon lines), order notes, refunds, coupons, customers, tax classes/rates, shipping zones/methods, payment gateways, store settings, webhooks + deliveries, carts, download permissions, email log.
10
10
  - **16 backend functions** — 9 admin (`commerce/admin-products`, `commerce/admin-orders`, `commerce/admin-refunds`, `commerce/admin-coupons`, `commerce/admin-customers`, `commerce/admin-reviews`, `commerce/admin-webhooks`, `commerce/admin-reports`, `commerce/admin-tools`), 4 storefront (`commerce/storefront-catalog`, `commerce/storefront-cart`, `commerce/storefront-checkout`, `commerce/storefront-account`), 2 payment (`commerce/payments`, `commerce/payment-webhook`), and an idempotent `commerce/seed-store`.
11
11
  - **Online card payments, implemented** — hosted payment page, payment links for unpaid orders, two idempotent confirmation paths (customer return + signed webhook) and refunds through the provider. Wired to **Stripe** out of the box behind a provider-neutral payment utility, so the store takes cards as soon as the connector is connected — no charge flow to write — and moving to another provider means implementing one adapter. See [`skills/commerce/references/online-payments.md`](./skills/commerce/references/online-payments.md).
12
12
  - **Shared commerce engine** (`base44/shared/commerce/`) — totals, tax, shipping, coupons, stock, order lifecycle, webhook dispatch (HMAC-signed), emails, payments utility + Stripe adapter, plus static country/currency/continent data.
13
- - **Admin UI** (`src/commerce/admin/`) — a React/Tailwind/shadcn admin with a familiar store back-office information architecture: dashboard, orders, products, coupons, customers, reports, full settings, webhooks. Admin-role gated.
14
- - **Storefront helpers** (`src/commerce/utils/`) — framework-free, dependency-free functions for the shopfront you build: `variants.js` maps an attribute selection (Size, Color) onto a `ProductVariation` and back, plus per-option availability and variable-product price ranges; `shipping-promos.js` reads the store's real free-shipping configuration so "Free shipping over €150" copy states a configured rule rather than an invented number. See [`skills/commerce/references/storefront-product-page.md`](./skills/commerce/references/storefront-product-page.md).
13
+ - **Admin UI** (`src/commerce/admin/`) — a React/Tailwind/shadcn admin with a familiar store back-office information architecture: dashboard, orders, products, coupons, customers, reports, and full settings including webhooks. Admin-role gated.
14
+ - **Storefront helpers** (`src/commerce/utils/`) — framework-free, dependency-free functions for the shopfront you build: `variants.js` maps an attribute selection (Size, Color) onto a `ProductVariation` and back, plus per-option availability and variant price ranges; `shipping-promos.js` reads the store's real free-shipping configuration so "Free shipping over €150" copy states a configured rule rather than an invented number. See [`skills/commerce/references/storefront-product-page.md`](./skills/commerce/references/storefront-product-page.md).
15
15
  - **StoreAdmin agent + bot** — an AI copilot (`base44/agents/commerce/StoreAdmin.jsonc`, registered as `commerce/StoreAdmin`) with the `commerce/*` functions attached directly as tools (calls run as the chatting user → `requireAdmin()` still applies), variant-aware order editing, plus a chat panel in the admin sidebar with GFM markdown-table rendering.
16
16
  - **Docs** — this README plus the commerce skill folder [`skills/commerce/`](./skills/commerce/), which holds [`SKILL.md`](./skills/commerce/SKILL.md) (the short map agents start from), [`installation-guidelines.md`](./skills/commerce/installation-guidelines.md), [`post-installation.md`](./skills/commerce/post-installation.md), per-topic guides in [`references/`](./skills/commerce/references/) and the API references in [`docs/`](./skills/commerce/docs/) — the whole folder is installed into the app so agents pick it up natively.
17
17
 
@@ -83,10 +83,10 @@ From your existing Base44 app:
83
83
  ```jsx
84
84
  import AdminApp from "@/commerce/admin";
85
85
  // inside your <Routes>:
86
- <Route path="/admin/*" element={<AdminApp />} />
86
+ <Route path="/store-admin/*" element={<AdminApp />} />
87
87
  ```
88
88
  6. **Grant yourself the `admin` role** (Base44 dashboard → users, or `users.inviteUser(email, "admin")`). The admin UI refuses non-admins.
89
- 7. **Seed the store.** Either open `/admin` and click **Initialize store defaults** on the first-run setup screen, or call `commerce/seed-store` directly — it creates the settings groups, gateways, tax classes and a fallback shipping zone, plus a sample catalog when `with_sample_data: true` and the store is empty. Once the `general` settings group exists the store counts as ready and the first-run screen stops appearing. If an agent is installing this, it should **ask which data the user wants** first — a generated catalog for their actual business, the generic demo data, or nothing: see [`skills/commerce/post-installation.md`](./skills/commerce/post-installation.md) §2.
89
+ 7. **Seed the store.** Either open `/store-admin` and click **Initialize store defaults** on the first-run setup screen, or call `commerce/seed-store` directly — it creates the settings groups, gateways, tax classes and a fallback shipping zone, plus a sample catalog when `with_sample_data: true` and the store is empty. Either way pass `store_name` (the app's name) — it is required on a first seed and becomes both the email subject prefix and the sender name. Once the `general` settings group exists the store counts as ready and the first-run screen stops appearing. If an agent is installing this, it should **ask which data the user wants** first — a generated catalog for their actual business, the generic demo data, or nothing: see [`skills/commerce/post-installation.md`](./skills/commerce/post-installation.md) §2.
90
90
 
91
91
  ## Quick start (Base44 MCP / hosted apps)
92
92
 
@@ -98,8 +98,8 @@ If you build on Base44's hosted platform, use the Base44 agent/MCP to write the
98
98
 
99
99
  ## What's NOT included
100
100
 
101
- - **No visitor/storefront UI.** The storefront **API** is complete (`commerce/storefront-*` functions); building the shopfront is up to you — see [`skills/commerce/docs/api-storefront.md`](./skills/commerce/docs/api-storefront.md). What *does* ship for the storefront is **helper logic**: [`src/commerce/utils/`](./src/commerce/utils/) — framework-free variant-selection functions (map a Size/Color selection to a `ProductVariation` and back, per-option availability, variable-product price ranges) — plus [`skills/commerce/references/product-render.md`](./skills/commerce/references/product-render.md) (what to render in a grid vs. a product page, and which fields each call returns) and [`skills/commerce/references/storefront-product-page.md`](./skills/commerce/references/storefront-product-page.md), the variant rules that go with the helpers.
102
- - **No payment credentials** — the card integration itself *is* included (see above), but a store can only charge once someone connects a payment provider's connector for the app. Until then the card option stays hidden from customers and the manual gateways (bank transfer / cheque / COD) carry checkout.
101
+ - **No visitor/storefront UI.** The storefront **API** is complete (`commerce/storefront-*` functions); building the shopfront is up to you — see [`skills/commerce/docs/api-storefront.md`](./skills/commerce/docs/api-storefront.md). What *does* ship for the storefront is **helper logic**: [`src/commerce/utils/`](./src/commerce/utils/) — framework-free variant-selection functions (map a Size/Color selection to a `ProductVariation` and back, per-option availability, variant price ranges) — plus [`skills/commerce/references/product-render.md`](./skills/commerce/references/product-render.md) (what to render in a grid vs. a product page, and which fields each call returns) and [`skills/commerce/references/storefront-product-page.md`](./skills/commerce/references/storefront-product-page.md), the variant rules that go with the helpers.
102
+ - **No payment credentials** — the card integration itself *is* included (see above), but a store can only charge once someone connects a payment provider's connector for the app. Until then the card option stays hidden from customers and the offline gateway (bank transfer, cash on delivery) carries checkout.
103
103
  - **No scheduled workflows shipped.** Base44 *does* have a scheduler, but this template ships no workflow files — time-based jobs (stock-hold release, cart expiry, webhook-log pruning) run **opportunistically** where possible, and for the rest you (or the Base44 agent) create scheduled workflows that call `commerce/admin-tools`/`commerce/admin-orders` actions — see *Scheduled work* in [`skills/commerce/SKILL.md`](./skills/commerce/SKILL.md).
104
104
 
105
105
  ## Next steps
@@ -10,15 +10,15 @@
10
10
  {
11
11
  "name": "StoreAdmin",
12
12
  "description": "Store administration copilot for the commerce template: manage products, orders, refunds, coupons, customers, reviews, reports and maintenance.",
13
- "instructions": "You are StoreAdmin, the store administration copilot for this shop's back office. You help store operators inspect and manage the store: products, orders, refunds, coupons, customers, reviews, webhooks, reports, and maintenance.\n\n## How you access the store\nEvery tool takes a JSON body of the form {\"action\": \"<action>\", ...payload} (exception: commerce/seed-store takes {with_sample_data?} with no action key) and responds {success, data} or {success:false, error, code}. Search/list actions return {rows, has_next} using limit+skip pagination (there are no total counts). Use search actions for free-text lookups (product name, customer email, coupon code, order number).\n\nStore configuration (settings, tax rates, shipping zones, payment gateways, webhook definitions) is not editable through your tools — see \"Sending the operator to a screen\" below.\n\n## Sending the operator to a screen\nSome configuration is only editable in the admin UI. When one of those is asked for, say plainly that you cannot change it from chat, name the screen, and give a link the operator can click — never just \"do it manually\", and never imply you tried and failed. Do not blame permissions or a security error: the reason is simply that the UI is the only place that configuration is edited.\n\nLinks use the `admin:` scheme with a path from the table below — `[Settings → Tax](admin:settings/tax)`. The chat resolves that to wherever the admin is mounted, so never write `/admin/...` yourself.\n\n| Ask | Screen | Link |\n|---|---|---|\n| Currency, store name/address, coupon & tax toggles | Settings → General | admin:settings/general |\n| Catalog defaults, review settings | Settings → Products | admin:settings/products |\n| Stock thresholds, hold minutes, inventory recipient | Settings → Inventory | admin:settings/inventory |\n| Tax classes, tax rates, price display | Settings → Tax | admin:settings/tax |\n| Shipping zones, methods, shipping classes | Settings → Shipping | admin:settings/shipping |\n| Enabling a gateway, bank/BACS details | Settings → Payments | admin:settings/payments |\n| From-name, admin notification recipients, per-email overrides | Settings → Emails | admin:settings/emails |\n| Creating or deleting a webhook (you CAN test and redeliver) | Webhooks | admin:webhooks |\n\nExample: \"Tax rates aren't something I can change from here — they live in the store's tax settings. Open [Settings → Tax](admin:settings/tax) to add the rate, then tell me and I'll re-check the order's totals.\"\n\nCatalog taxonomy is the opposite: you CAN create categories, tags, attributes and attribute terms yourself with commerce/admin-products save-term. Never send the operator to a screen to create one — only link to admin:products/categories, admin:products/tags or admin:products/attributes if they want to review or reorder them by hand.\n\n## Product variants — be careful\nProducts of type \"variable\" are sold as variations, and every variation can differ in attributes (e.g. size/color), SKU, price and stock.\n- NEVER pick a variation automatically. When an order line, stock change, or download grant involves a variable product, first fetch its variations with commerce/storefront-catalog {\"action\":\"get-product\",\"id\":...} (returns {product, variations}), present them in a table (attributes, SKU, price, stock status), and ask the operator which variation to use — then include that variation_id in the item spec.\n- If the operator already named an exact variation (by SKU or full attribute combination), match it against the fetched variations and confirm the match in your reply; if the description is partial or matches more than one variation, ask.\n- Order item specs for commerce/admin-orders create/update are {product_id, variation_id?, quantity, price_override?} — variation_id is REQUIRED for variable products; the backend rejects a bare product_id for them.\n- The same applies to commerce/admin-products set-stock (pass variation_id to change a variation's stock, not the parent's).\n\n## Behavior\n- Be concise and operational. Confirm before destructive or irreversible operations (delete, refund, bulk-status, prune, clear-abandoned-carts) by restating what will happen and asking the user to confirm — unless the user's message already explicitly confirms it.\n- When showing lists or reports, format them as GitHub-flavored markdown tables (| col | col | with a |---| separator row). Keep tables ≤ 8 columns; prefer the most decision-relevant fields (name/number, status, total, date). Format money with the store currency.\n- After a mutation, report exactly what changed (ids, statuses, totals) and surface any error/code verbatim.\n- If a request is ambiguous (which order? which product?), search first and present the candidates in a table, then ask.\n- For store health questions, start with commerce/admin-tools {\"action\":\"status\"} and commerce/admin-reports {\"action\":\"summary\"}.\n- Payments: for an unpaid order paid online, commerce/payments create-link {order_id} gives a payment page link to send the customer, and verify {order_id} re-checks whether the money arrived. If no payment provider is connected, say \"no payment provider is connected\" and that connecting one enables card payments — don't name or troubleshoot a specific provider. Never invent a payment link or claim an order is paid without verifying.\n- You act with store-operator privileges; do not attempt to weaken or bypass access controls, and never expose secrets (webhook secrets, tokens).",
13
+ "instructions": "You are StoreAdmin, the store administration copilot for this shop's back office. You help store operators inspect and manage the store: products, orders, refunds, coupons, customers, reviews, webhooks, reports, and maintenance.\n\n## How you access the store\nEvery tool takes a JSON body of the form {\"action\": \"<action>\", ...payload} (exception: commerce/seed-store takes {store_name, with_sample_data?} with no action key — store_name is REQUIRED on a first seed) and responds {success, data} or {success:false, error, code}. Search/list actions return {rows, has_next} using limit+skip pagination (there are no total counts). Use search actions for free-text lookups (product name, customer email, coupon code, order number).\n\nStore configuration (settings, tax rates, shipping zones, payment gateways, webhook definitions) is not editable through your tools — see \"Sending the operator to a screen\" below.\n\n## Sending the operator to a screen\nSome configuration is only editable in the admin UI. When one of those is asked for, say plainly that you cannot change it from chat, name the screen, and give a link the operator can click — never just \"do it manually\", and never imply you tried and failed. Do not blame permissions or a security error: the reason is simply that the UI is the only place that configuration is edited.\n\nLinks use the `admin:` scheme with a path from the table below — `[Settings → Tax](admin:settings/tax)`. The chat resolves that to wherever the admin is mounted, so never write `/store-admin/...` yourself.\n\n| Ask | Screen | Link |\n|---|---|---|\n| Currency and price formatting, payment return path | Settings → General | admin:settings/general |\n| Catalog defaults, review settings | Settings → Products | admin:settings/products |\n| Stock thresholds, hold minutes, inventory recipient | Settings → Inventory | admin:settings/inventory |\n| Tax classes, tax rates, price display | Settings → Tax | admin:settings/tax |\n| Shipping zones, methods, shipping classes | Settings → Shipping | admin:settings/shipping |\n| Enabling a gateway, offline bank details | Settings → Payments | admin:settings/payments |\n| Store name (subjects + sender), admin notification recipients, per-email overrides | Settings → Emails | admin:settings/emails |\n| Creating or deleting a webhook (you CAN test and redeliver) | Settings → Webhooks | admin:settings/webhooks |\n\nExample: \"Tax rates aren't something I can change from here — they live in the store's tax settings. Open [Settings → Tax](admin:settings/tax) to add the rate, then tell me and I'll re-check the order's totals.\"\n\nCatalog taxonomy is the opposite: you CAN create categories, tags, attributes and attribute values yourself with commerce/admin-products save-term. Never send the operator to a screen to create one — link to admin:products/categories if they want to review or reorder categories by hand. Tags and attributes have no screen of their own: attributes are edited in the Attributes section of a product's Price & Inventory tab, tags in the Tags card of the product sidebar — so link to the product (admin:products) instead.\n\n## Product variants — be careful\nA product that carries attributes is sold through its variants (there is no product type), and every variant can differ in attributes (e.g. size/color), SKU, price and stock.\n- NEVER pick a variation automatically. When an order line, stock change, or download grant involves a product that carries attributes, first fetch its variations with commerce/storefront-catalog {\"action\":\"get-product\",\"id\":...} (returns {product, variations}), present them in a table (attributes, SKU, price, stock status), and ask the operator which variation to use — then include that variation_id in the item spec.\n- If the operator already named an exact variation (by SKU or full attribute combination), match it against the fetched variations and confirm the match in your reply; if the description is partial or matches more than one variation, ask.\n- Order item specs for commerce/admin-orders create/update are {product_id, variation_id?, quantity, price_override?} — variation_id is REQUIRED for a product with attributes.\n- The same applies to commerce/admin-products set-stock (pass variation_id to change a variation's stock, not the parent's).\n\n## Behavior\n- Be concise and operational. Confirm before destructive or irreversible operations (delete, refund, bulk-status, prune, clear-abandoned-carts) by restating what will happen and asking the user to confirm — unless the user's message already explicitly confirms it.\n- When showing lists or reports, format them as GitHub-flavored markdown tables (| col | col | with a |---| separator row). Keep tables ≤ 8 columns; prefer the most decision-relevant fields (name/number, status, total, date). Format money with the store currency.\n- After a mutation, report exactly what changed (ids, statuses, totals) and surface any error/code verbatim.\n- If a request is ambiguous (which order? which product?), search first and present the candidates in a table, then ask.\n- For store health questions, start with commerce/admin-tools {\"action\":\"status\"} and commerce/admin-reports {\"action\":\"summary\"}.\n- Payments: for an unpaid order paid online, commerce/payments create-link {order_id} gives a payment page link to send the customer, and verify {order_id} re-checks whether the money arrived. If no payment provider is connected, say \"no payment provider is connected\" and that connecting one enables card payments — don't name or troubleshoot a specific provider. Never invent a payment link or claim an order is paid without verifying.\n- You act with store-operator privileges; do not attempt to weaken or bypass access controls, and never expose secrets (webhook secrets, tokens).",
14
14
  "tool_configs": [
15
15
  {
16
16
  "function_name": "commerce/admin-products",
17
- "description": "Product & variation management, plus category/tag terms. Actions: save {product, variations?} (upsert + derived price/stock, SKU/slug uniqueness), delete {id}, batch {create?,update?,delete?}, duplicate {id}, set-stock {id, variation_id?, quantity}, search {q?, category_id?, type?, stock_status?, status?, sort?, limit?, skip?} → {rows, has_next}, list-terms {taxonomy, q?, attribute_id?, limit?, skip?} → {rows, has_next}, save-term {taxonomy, term: {...}} (upsert; slug auto-derived and made unique), delete-term {taxonomy, id, detach?}. taxonomy is \"category\" | \"tag\" | \"attribute\" | \"attribute-term\"; term fields per taxonomy: category {id?, name, slug?, description?, parent_id?, image?, menu_order?}, tag {id?, name, slug?, description?}, attribute {id?, name, slug?, type?, order_by?, has_archives?}, attribute-term {id?, attribute_id (required), name, slug?, description?, menu_order?}. Create these yourself with save-term — do NOT tell the operator to create them by hand. list-terms first and reuse a match before creating a duplicate. Deleting an attribute deletes its terms. A variable product needs a ProductAttribute (+ its terms) to exist before product.attributes[].options can reference it, so create the attribute and terms first, then save the product."
17
+ "description": "Product & variant management, plus category/tag/attribute records. Actions: save {product, variations?} (upsert + derived price/stock, SKU/slug uniqueness), delete {id}, batch {create?,update?,delete?}, duplicate {id}, set-stock {id, variation_id?, quantity}, search {q?, category_id?, stock_status?, status?, sort?, limit?, skip?} → {rows, has_next}, list-terms {taxonomy, q?, attribute_id?, limit?, skip?} → {rows, has_next}, save-term {taxonomy, term: {...}} (upsert), delete-term {taxonomy, id, detach?}. taxonomy is \"category\" | \"tag\" | \"attribute\" | \"attribute-term\"; term fields per taxonomy: category {id?, name, slug?, description?, parent_id?, image?, menu_order?}, tag {id?, name}, attribute {id?, name, code?, order?}, attribute-term {id?, attribute_id (required), name, order?}. Only categories have a slug. Creating a tag is get-or-create by name. Renaming an attribute value rewrites every product that uses it. Create these yourself with save-term — do NOT tell the operator to create them by hand. list-terms first and reuse a match before creating a duplicate. Deleting an attribute deletes its values. A product sells variants because it carries attributes — there is no type field — so the ProductAttribute (+ its values) must exist before product.attributes[].options can reference it: create the attribute and values first, then save the product with attributes[] and variations[]. For a product with attributes do NOT set the parent's regular_price/sale_price: the parent's regular_price, price and on_sale are rolled up from the cheapest published variation on every save, so anything you set there is overwritten."
18
18
  },
19
19
  {
20
20
  "function_name": "commerce/admin-orders",
21
- "description": "Order lifecycle. Actions: create-draft, create {items, ...}, update {order_id, patch}, update-status {order_id, status, note?}, bulk-status {ids, status}, status-counts, search {q?, status?, date_min?, date_max?, sort?, limit?, skip?}, recalculate {order_id}, apply-coupon/remove-coupon {order_id, code}, add-note {order_id, note, is_customer_note?}, delete-note {note_id}, send-email {order_id, type}, grant-download {order_id, product_id}, revoke-download {permission_id}, delete {order_id}, release-expired-holds. Item specs: {product_id, variation_id?, quantity, price_override?} — variation_id REQUIRED for variable products (ask the operator which variation; never auto-pick). Statuses: pending, processing, on-hold, completed, cancelled, refunded, failed."
21
+ "description": "Order lifecycle. Actions: create-draft, create {items, ...}, preview {items, ...} (price without saving), update {order_id, patch}, update-status {order_id, status, note?}, bulk-status {ids, status}, status-counts, search {q?, status?, date_min?, date_max?, sort?, limit?, skip?}, recalculate {order_id}, apply-coupon/remove-coupon {order_id, code}, add-note {order_id, note, is_customer_note?}, delete-note {note_id}, send-email {order_id, type}, grant-download {order_id, product_id}, revoke-download {permission_id}, delete {order_id}, release-expired-holds. Item specs: {product_id, variation_id?, quantity, price_override?} — variation_id REQUIRED for a product that carries attributes (ask the operator which variation; never auto-pick). Statuses: pending, processing, on-hold, completed, cancelled, refunded, failed."
22
22
  },
23
23
  {
24
24
  "function_name": "commerce/admin-refunds",
@@ -46,19 +46,19 @@
46
46
  },
47
47
  {
48
48
  "function_name": "commerce/admin-tools",
49
- "description": "System status & maintenance. Actions: status (template_version, seeded, entity counts, health checks), recount-terms, recount-coupon-usage, recalculate-customer-stats-all, prune-webhook-deliveries {keep_days}, clear-abandoned-carts {older_than_days}, regenerate-download-permissions {order_id}."
49
+ "description": "System status & maintenance. Actions: status (template_version, seeded, entity counts, health checks), payment-connector-status, admin-email-recipients, recount-terms, recount-coupon-usage, recalculate-customer-stats-all, prune-webhook-deliveries {keep_days}, clear-abandoned-carts {older_than_days}, regenerate-download-permissions {order_id}."
50
50
  },
51
51
  {
52
52
  "function_name": "commerce/seed-store",
53
- "description": "Initialize store defaults (idempotent; canary schema check first). Body: {with_sample_data?: boolean} — no action key. Sample catalog only created when the store has zero products."
53
+ "description": "Initialize store defaults (idempotent; canary schema check first). Body: {store_name: string, with_sample_data?: boolean} — no action key. store_name is REQUIRED on a first seed (else 400 store_name_required): pass the app's name as the platform shows it, since a function's env cannot read it. It becomes the email subject prefix and the sender name. Sample catalog only created when the store has zero products."
54
54
  },
55
55
  {
56
56
  "function_name": "commerce/payments",
57
- "description": "Online payment for an order. Actions: status {} → {provider, connected, gateway_slug} (is a payment provider connected?), create-link {order_id} → {url} (provider-hosted payment page for an UNPAID online order — the link to send a customer; 409 already_paid, 400 not_an_online_payment, 503 payment_provider_unavailable), verify {order_id} → {paid, status} (re-ask the provider and move the order on if paid; idempotent)."
57
+ "description": "Online payment for an order. Actions: status {} → {provider, connected, gateway_slug} (is a payment provider connected?), create-link {order_id} → {url} (provider-hosted payment page for an UNPAID online order — the link to send a customer; 409 already_paid, 400 not_an_online_payment, 503 payment_provider_unavailable), verify {order_id} → {paid, status} (re-ask the provider and move the order on if paid; idempotent), complete-return {order_id, order_key, payment?} (what the storefront's return page calls: confirms, advances the order and hands back {state, order, payment_link})."
58
58
  },
59
59
  {
60
60
  "function_name": "commerce/storefront-catalog",
61
- "description": "Read-only public catalog browsing — use get-product BEFORE putting a variable product on an order, to list its variations and ask the operator which one. Actions: get-store-info, list-products {q?, category_id?, tag_id?, featured?, on_sale?, min_price?, max_price?, sort?, page?, per_page?}, get-product {id | slug} → {product, variations, ...}, list-categories, list-tags, list-reviews {product_id, page?, per_page?}."
61
+ "description": "Read-only public catalog browsing — use get-product BEFORE putting a product that carries attributes on an order, to list its variations and ask the operator which one. Actions: get-store-info, list-products {q?, category_id?, tag_id?, attribute_id?, attribute_term?, featured?, on_sale?, in_stock_only?, min_price?, max_price?, sort? (default \"-created_date\"), page?, per_page?}, get-product {id | slug} → {product, variations, ...}, list-categories, list-tags, list-attributes. There is no list-reviews — a product's reviews come back inside get-product, and moderation is commerce/admin-reviews."
62
62
  }
63
63
  ]
64
64
  }
@@ -84,7 +84,7 @@
84
84
  },
85
85
  "payment_method": {
86
86
  "type": "string",
87
- "description": "PaymentGateway slug (e.g. bacs|cheque|cod|stripe)"
87
+ "description": "PaymentGateway slug (e.g. offline|stripe)"
88
88
  },
89
89
  "payment_method_title": {
90
90
  "type": "string",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "commerce.PaymentGateway",
3
3
  "type": "object",
4
- "description": "Payment gateway configuration (data model only — no processing). Seeded: bacs, cheque, cod, stripe (placeholder). Secrets are never stored here; use Base44 secrets.",
4
+ "description": "Payment gateway configuration. Seeded: offline (settled outside the store) and stripe (processed by commerce/payments + commerce/payment-webhook). Secrets are never stored here; use Base44 secrets.",
5
5
  "properties": {
6
6
  "slug": {
7
7
  "type": "string",
8
8
  "minLength": 1,
9
- "description": "Unique gateway id, e.g. bacs | cheque | cod | stripe"
9
+ "description": "Unique gateway id, e.g. offline | stripe"
10
10
  },
11
11
  "title": {
12
12
  "type": "string",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "settings": {
37
37
  "type": "object",
38
- "description": "Per-gateway settings. bacs: {account_details: [{account_name, account_number, bank_name, sort_code, iban, bic}]}; cod: {enable_for_methods, enable_for_virtual}; stripe: {connector: \"stripe\"} placeholder — see skills/commerce/references/online-payments.md"
38
+ "description": "Per-gateway settings. offline: {account_details: [{account_name, account_number, bank_name, sort_code, iban, bic}]}; stripe: {connector: \"stripe\"} — see skills/commerce/references/online-payments.md"
39
39
  }
40
40
  },
41
41
  "required": ["slug"],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "commerce.Product",
3
3
  "type": "object",
4
- "description": "A store product (simple, grouped, external, or variable). Full-featured product model.",
4
+ "description": "A store product. It sells variants when it carries attributes \u2014 there is no type field. Descriptive properties live in meta_data (the admin calls them modifiers).",
5
5
  "properties": {
6
6
  "name": {
7
7
  "type": "string",
@@ -12,12 +12,6 @@
12
12
  "type": "string",
13
13
  "description": "URL slug, unique (enforced in commerce/admin-products)"
14
14
  },
15
- "type": {
16
- "type": "string",
17
- "enum": ["simple", "grouped", "external", "variable"],
18
- "default": "simple",
19
- "description": "Product type"
20
- },
21
15
  "status": {
22
16
  "type": "string",
23
17
  "enum": ["draft", "pending", "private", "publish"],
@@ -51,7 +45,7 @@
51
45
  "regular_price": {
52
46
  "type": "number",
53
47
  "minimum": 0,
54
- "description": "Regular price"
48
+ "description": "Regular price. For a product with attributes this is rolled up from the cheapest published variation."
55
49
  },
56
50
  "sale_price": {
57
51
  "type": "number",
@@ -70,12 +64,12 @@
70
64
  },
71
65
  "price": {
72
66
  "type": "number",
73
- "description": "Derived: sale_price when sale is active, else regular_price. Maintained by commerce/admin-products."
67
+ "description": "Derived: sale_price when sale is active, else regular_price — or, for a product with attributes, the cheapest published variation's price. Maintained by commerce/admin-products."
74
68
  },
75
69
  "on_sale": {
76
70
  "type": "boolean",
77
71
  "default": false,
78
- "description": "Derived: whether the sale window is currently active. Maintained by commerce/admin-products."
72
+ "description": "Derived: whether the sale window is currently active — or, for a product with attributes, whether any published variation is on sale. Maintained by commerce/admin-products."
79
73
  },
80
74
  "virtual": {
81
75
  "type": "boolean",
@@ -108,15 +102,6 @@
108
102
  "default": -1,
109
103
  "description": "Days until download access expires, -1 = never"
110
104
  },
111
- "external_url": {
112
- "type": "string",
113
- "format": "uri",
114
- "description": "Target URL for external/affiliate products"
115
- },
116
- "button_text": {
117
- "type": "string",
118
- "description": "Buy-button text for external products"
119
- },
120
105
  "tax_status": {
121
106
  "type": "string",
122
107
  "enum": ["taxable", "shipping", "none"],
@@ -175,11 +160,6 @@
175
160
  "type": "string",
176
161
  "description": "ShippingClass id"
177
162
  },
178
- "reviews_allowed": {
179
- "type": "boolean",
180
- "default": true,
181
- "description": "Allow customer reviews"
182
- },
183
163
  "average_rating": {
184
164
  "type": "number",
185
165
  "default": 0,
@@ -200,15 +180,6 @@
200
180
  "items": { "type": "string" },
201
181
  "description": "Cross-sell Product ids"
202
182
  },
203
- "grouped_products": {
204
- "type": "array",
205
- "items": { "type": "string" },
206
- "description": "Child Product ids for type=grouped"
207
- },
208
- "purchase_note": {
209
- "type": "string",
210
- "description": "Note shown to the customer after purchase"
211
- },
212
183
  "category_ids": {
213
184
  "type": "array",
214
185
  "items": { "type": "string" },
@@ -234,22 +205,20 @@
234
205
  },
235
206
  "attributes": {
236
207
  "type": "array",
237
- "description": "Assigned attributes (global via attribute_id, or custom/local when attribute_id is empty)",
208
+ "description": "Variant axes. Every entry is one axis: attaching an attribute is what makes the product sell variants. Descriptive properties belong in meta_data instead.",
238
209
  "items": {
239
210
  "type": "object",
240
211
  "properties": {
241
- "attribute_id": { "type": "string", "description": "ProductAttribute id; empty for custom/local attribute" },
212
+ "attribute_id": { "type": "string", "description": "ProductAttribute id" },
242
213
  "name": { "type": "string" },
243
- "position": { "type": "integer" },
244
- "visible": { "type": "boolean", "description": "Visible on the product page" },
245
- "variation": { "type": "boolean", "description": "Used for variations" },
246
- "options": { "type": "array", "items": { "type": "string" } }
214
+ "position": { "type": "integer", "description": "Order the axes are presented in" },
215
+ "options": { "type": "array", "items": { "type": "string" }, "description": "Values this product comes in, by ProductAttributeTerm name" }
247
216
  }
248
217
  }
249
218
  },
250
219
  "default_attributes": {
251
220
  "type": "array",
252
- "description": "Pre-selected variation attributes for variable products",
221
+ "description": "Pre-selected variant combination",
253
222
  "items": {
254
223
  "type": "object",
255
224
  "properties": {
@@ -259,11 +228,6 @@
259
228
  }
260
229
  }
261
230
  },
262
- "menu_order": {
263
- "type": "integer",
264
- "default": 0,
265
- "description": "Custom sort position"
266
- },
267
231
  "total_sales": {
268
232
  "type": "integer",
269
233
  "default": 0,
@@ -1,32 +1,20 @@
1
1
  {
2
2
  "name": "commerce.ProductAttribute",
3
3
  "type": "object",
4
- "description": "Global product attribute (e.g. Color, Size). Terms live in ProductAttributeTerm.",
4
+ "description": "A variant axis shared between products (e.g. Color, Size). Its values live in ProductAttributeTerm. Edited in the Attributes section of a product's Price & Inventory tab, or via commerce/admin-products save-term.",
5
5
  "properties": {
6
6
  "name": {
7
7
  "type": "string",
8
8
  "minLength": 1
9
9
  },
10
- "slug": {
10
+ "code": {
11
11
  "type": "string",
12
- "description": "Unique slug (enforced in admin UI / functions)"
12
+ "description": "Stable machine key, unique (enforced in commerce/admin-products save-term). Derived from the name; what a storefront filter URL should carry."
13
13
  },
14
- "type": {
15
- "type": "string",
16
- "enum": ["select"],
17
- "default": "select",
18
- "description": "Attribute type"
19
- },
20
- "order_by": {
21
- "type": "string",
22
- "enum": ["menu_order", "name", "name_num", "id"],
23
- "default": "menu_order",
24
- "description": "Default term sort order"
25
- },
26
- "has_archives": {
27
- "type": "boolean",
28
- "default": false,
29
- "description": "Enable attribute archives"
14
+ "order": {
15
+ "type": "integer",
16
+ "default": 0,
17
+ "description": "Sort position among attributes"
30
18
  }
31
19
  },
32
20
  "required": ["name"],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "commerce.ProductAttributeTerm",
3
3
  "type": "object",
4
- "description": "A term (option value) of a global ProductAttribute.",
4
+ "description": "One value of a ProductAttribute (e.g. Size \u2192 M). Products reference it by name in attributes[].options, so renaming one rewrites those references (commerce/admin-products save-term).",
5
5
  "properties": {
6
6
  "attribute_id": {
7
7
  "type": "string",
@@ -11,16 +11,10 @@
11
11
  "type": "string",
12
12
  "minLength": 1
13
13
  },
14
- "slug": {
15
- "type": "string",
16
- "description": "Unique within the attribute (enforced in admin UI / functions)"
17
- },
18
- "description": {
19
- "type": "string"
20
- },
21
- "menu_order": {
14
+ "order": {
22
15
  "type": "integer",
23
- "default": 0
16
+ "default": 0,
17
+ "description": "Sort position within the attribute"
24
18
  },
25
19
  "count": {
26
20
  "type": "integer",
@@ -1,19 +1,12 @@
1
1
  {
2
2
  "name": "commerce.ProductTag",
3
3
  "type": "object",
4
- "description": "Product tag.",
4
+ "description": "Product tag. Created and picked from the product form; storefronts filter by id (list-products tag_id).",
5
5
  "properties": {
6
6
  "name": {
7
7
  "type": "string",
8
8
  "minLength": 1
9
9
  },
10
- "slug": {
11
- "type": "string",
12
- "description": "URL slug, unique (enforced in admin UI / functions)"
13
- },
14
- "description": {
15
- "type": "string"
16
- },
17
10
  "count": {
18
11
  "type": "integer",
19
12
  "default": 0,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "commerce.ProductVariation",
3
3
  "type": "object",
4
- "description": "A variation of a variable Product, identified by its attribute combination.",
4
+ "description": "A variation of a Product that carries attributes, identified by its attribute combination.",
5
5
  "properties": {
6
6
  "product_id": {
7
7
  "type": "string",
@@ -5,7 +5,7 @@
5
5
  "properties": {
6
6
  "group_id": {
7
7
  "type": "string",
8
- "enum": ["general", "products", "inventory", "downloadable", "tax", "shipping", "emails"],
8
+ "enum": ["general", "products", "inventory", "tax", "shipping", "emails"],
9
9
  "description": "Settings group; unique (one record per group, enforced by seed/admin UI)"
10
10
  },
11
11
  "values": {