@wix/agent-skills 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/package.json +29 -0
- package/skills/wix-app/SKILL.md +344 -0
- package/skills/wix-app/references/APP_IDENTIFIERS.md +35 -0
- package/skills/wix-app/references/APP_MARKET_REVIEW.md +311 -0
- package/skills/wix-app/references/APP_VALIDATION.md +171 -0
- package/skills/wix-app/references/BACKEND_API.md +233 -0
- package/skills/wix-app/references/BACKEND_EVENT.md +116 -0
- package/skills/wix-app/references/CODE_QUALITY.md +33 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +587 -0
- package/skills/wix-app/references/DASHBOARD_MENU_PLUGIN.md +157 -0
- package/skills/wix-app/references/DASHBOARD_MODAL.md +283 -0
- package/skills/wix-app/references/DASHBOARD_PAGE.md +403 -0
- package/skills/wix-app/references/DASHBOARD_PLUGIN.md +205 -0
- package/skills/wix-app/references/DATA_COLLECTION.md +451 -0
- package/skills/wix-app/references/DOCUMENTATION.md +42 -0
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +65 -0
- package/skills/wix-app/references/EMBEDDED_SCRIPT.md +468 -0
- package/skills/wix-app/references/EXTENSION_REGISTRATION.md +96 -0
- package/skills/wix-app/references/SERVICE_PLUGIN.md +235 -0
- package/skills/wix-app/references/SITE_PLUGIN.md +436 -0
- package/skills/wix-app/references/STORES_VERSIONING.md +334 -0
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +84 -0
- package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +345 -0
- package/skills/wix-app/references/dashboard-menu-plugin/blog-slots.md +71 -0
- package/skills/wix-app/references/dashboard-menu-plugin/bookings-slots.md +58 -0
- package/skills/wix-app/references/dashboard-menu-plugin/crm-slots.md +8 -0
- package/skills/wix-app/references/dashboard-menu-plugin/ecommerce-slots.md +17 -0
- package/skills/wix-app/references/dashboard-menu-plugin/events-slots.md +29 -0
- package/skills/wix-app/references/dashboard-menu-plugin/restaurants-slots.md +27 -0
- package/skills/wix-app/references/dashboard-menu-plugin/stores-slots.md +35 -0
- package/skills/wix-app/references/dashboard-page/API_SPEC.md +138 -0
- package/skills/wix-app/references/dashboard-page/DASHBOARD_API.md +573 -0
- package/skills/wix-app/references/dashboard-page/DYNAMIC_PARAMETERS.md +269 -0
- package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +164 -0
- package/skills/wix-app/references/dashboard-plugin/SLOTS.md +294 -0
- package/skills/wix-app/references/data-collection/WIX_DATA.md +270 -0
- package/skills/wix-app/references/data-collection/extension-template.ts +107 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +138 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +454 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +165 -0
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +576 -0
- package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +170 -0
- package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +6 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +25 -0
- package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +203 -0
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +167 -0
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +137 -0
- package/skills/wix-app/references/service-plugin/ADDITIONAL-FEES.md +112 -0
- package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +118 -0
- package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +87 -0
- package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +86 -0
- package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +135 -0
- package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +79 -0
- package/skills/wix-app/references/service-plugin/VALIDATIONS.md +68 -0
- package/skills/wix-app/references/site-plugin/EXAMPLES.md +311 -0
- package/skills/wix-app/references/site-plugin/SLOTS.md +263 -0
- package/skills/wix-design-system/SKILL.md +129 -0
- package/skills/wix-design-system/references/file-structure.md +56 -0
- package/skills/wix-design-system/scripts/wds.cjs +531 -0
- package/skills/wix-headless/SKILL.md +418 -0
- package/skills/wix-headless/references/DISCOVERY.md +332 -0
- package/skills/wix-headless/references/ORCHESTRATION.md +269 -0
- package/skills/wix-headless/references/SETUP.md +154 -0
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +152 -0
- package/skills/wix-headless/references/blog/BLOG_PAGES.md +299 -0
- package/skills/wix-headless/references/blog/BLOG_SETUP.md +218 -0
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +32 -0
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +373 -0
- package/skills/wix-headless/references/cms/FAQ_KNOWLEDGE_BASE.md +229 -0
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +40 -0
- package/skills/wix-headless/references/cms/PORTFOLIO.md +454 -0
- package/skills/wix-headless/references/cms/RESOURCE_LIBRARY.md +356 -0
- package/skills/wix-headless/references/cms/TEAM_DIRECTORY.md +299 -0
- package/skills/wix-headless/references/commands/install-app.md +42 -0
- package/skills/wix-headless/references/commands/known-apps.json +5 -0
- package/skills/wix-headless/references/commands/mcp-bootstrap.md +28 -0
- package/skills/wix-headless/references/designer/INSTRUCTIONS.md +828 -0
- package/skills/wix-headless/references/ecom/CART_PAGES.md +120 -0
- package/skills/wix-headless/references/ecom/CART_WIRING.md +103 -0
- package/skills/wix-headless/references/ecom/COMPONENTS_CSS.md +132 -0
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +59 -0
- package/skills/wix-headless/references/forms/CONTACT_FORM.md +477 -0
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +43 -0
- package/skills/wix-headless/references/gift-cards/COMPONENTS.md +119 -0
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +51 -0
- package/skills/wix-headless/references/gift-cards/PAGES.md +129 -0
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +359 -0
- package/skills/wix-headless/references/shared/BUILD_NOISE.md +8 -0
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +185 -0
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +155 -0
- package/skills/wix-headless/references/shared/MCP_PREFIX.md +105 -0
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +97 -0
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +423 -0
- package/skills/wix-headless/references/shared/STYLING.md +117 -0
- package/skills/wix-headless/references/stores/BACK_IN_STOCK.md +178 -0
- package/skills/wix-headless/references/stores/CATEGORY_PAGES.md +86 -0
- package/skills/wix-headless/references/stores/COMPONENTS_CSS.md +129 -0
- package/skills/wix-headless/references/stores/HOME_AND_NAV.md +227 -0
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +96 -0
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +249 -0
- package/skills/wix-headless/references/stores/PRODUCT_PAGES.md +213 -0
- package/skills/wix-headless/references/stores/SHARED_WIRING.md +164 -0
- package/skills/wix-headless/references/verticals/_schema.json +160 -0
- package/skills/wix-headless/references/verticals/_schema.md +185 -0
- package/skills/wix-headless/references/verticals/blog.md +125 -0
- package/skills/wix-headless/references/verticals/cms.md +121 -0
- package/skills/wix-headless/references/verticals/ecom.md +96 -0
- package/skills/wix-headless/references/verticals/forms.md +106 -0
- package/skills/wix-headless/references/verticals/gift-cards.md +121 -0
- package/skills/wix-headless/references/verticals/stores.md +167 -0
- package/skills/wix-headless/scripts/check-manifest.mjs +198 -0
- package/skills/wix-headless/scripts/copy-utility-templates.mjs +153 -0
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +77 -0
- package/skills/wix-headless/scripts/finalize-run-json.mjs +141 -0
- package/skills/wix-headless/scripts/init-site-json.mjs +63 -0
- package/skills/wix-headless/scripts/patch-decorative-slots.mjs +124 -0
- package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +190 -0
- package/skills/wix-headless/scripts/preview.sh +45 -0
- package/skills/wix-headless/scripts/release.sh +73 -0
- package/skills/wix-headless/scripts/scaffold.sh +53 -0
- package/skills/wix-headless/scripts/seed-utilities.sh +55 -0
- package/skills/wix-headless/shared-utilities/analytics.ts +40 -0
- package/skills/wix-headless/shared-utilities/ricos.ts +179 -0
- package/skills/wix-headless/shared-utilities/wix-image.ts +72 -0
- package/skills/wix-headless/templates/ecom/CartBadge.tsx +84 -0
- package/skills/wix-headless/templates/ecom/CartView.tsx +543 -0
- package/skills/wix-headless/templates/ecom/cart.astro +13 -0
- package/skills/wix-headless/templates/ecom/components-ecom.css +215 -0
- package/skills/wix-headless/templates/ecom/discounts.ts +71 -0
- package/skills/wix-headless/templates/ecom/thank-you.astro +24 -0
- package/skills/wix-headless/templates/gift-cards/GiftCardPurchase.tsx +172 -0
- package/skills/wix-headless/templates/gift-cards/_home-teaser-snippet.astro +42 -0
- package/skills/wix-headless/templates/gift-cards/_nav-snippet.astro +11 -0
- package/skills/wix-headless/templates/gift-cards/components-gift-cards.css +219 -0
- package/skills/wix-headless/templates/gift-cards/gift-cards.astro +51 -0
- package/skills/wix-headless/templates/gift-cards/gift-cards.ts +75 -0
- package/skills/wix-headless/templates/stores/AddToCartButton.tsx +77 -0
- package/skills/wix-headless/templates/stores/BackInStockForm.tsx +176 -0
- package/skills/wix-headless/templates/stores/CategoryRail.astro +69 -0
- package/skills/wix-headless/templates/stores/ProductCard.astro +79 -0
- package/skills/wix-headless/templates/stores/ProductPurchase.tsx +397 -0
- package/skills/wix-headless/templates/stores/SeoTags.astro +21 -0
- package/skills/wix-headless/templates/stores/back-in-stock.ts +67 -0
- package/skills/wix-headless/templates/stores/categories.ts +155 -0
- package/skills/wix-headless/templates/stores/category/[slug].astro +130 -0
- package/skills/wix-headless/templates/stores/components-stores.css +295 -0
- package/skills/wix-headless/templates/stores/products/[slug].astro +128 -0
- package/skills/wix-headless/templates/stores/products/index.astro +101 -0
- package/skills/wix-manage/SKILL.md +280 -0
- package/skills/wix-manage/references/app-installation/install-wix-apps.md +155 -0
- package/skills/wix-manage/references/app-installation/list-installed-apps.md +124 -0
- package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +226 -0
- package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +95 -0
- package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +416 -0
- package/skills/wix-manage/references/bookings/bookings-staff-setup.md +255 -0
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +462 -0
- package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +278 -0
- package/skills/wix-manage/references/bookings/external-calendar-integration.md +258 -0
- package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +231 -0
- package/skills/wix-manage/references/calendar/configure-default-business-hours.md +226 -0
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +422 -0
- package/skills/wix-manage/references/cms/cms-data-operations-extended.md +263 -0
- package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +136 -0
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +160 -0
- package/skills/wix-manage/references/cms/cms-schema-management.md +143 -0
- package/skills/wix-manage/references/contacts/bulk-delete-contacts.md +73 -0
- package/skills/wix-manage/references/contacts/bulk-label-and-unlabel-contacts.md +67 -0
- package/skills/wix-manage/references/domains/domain-search-and-purchase.md +434 -0
- package/skills/wix-manage/references/ecommerce/api-recommendation-tracking.md +420 -0
- package/skills/wix-manage/references/ecommerce/flow-add-free-shipping.md +267 -0
- package/skills/wix-manage/references/ecommerce/flow-bundle-and-save.md +290 -0
- package/skills/wix-manage/references/ecommerce/flow-fix-coverage-gaps.md +300 -0
- package/skills/wix-manage/references/ecommerce/flow-optimize-shipping-rates.md +364 -0
- package/skills/wix-manage/references/ecommerce/flow-seasonal-promotion.md +315 -0
- package/skills/wix-manage/references/ecommerce/flow-stock-mover.md +308 -0
- package/skills/wix-manage/references/ecommerce/flow-upsell-boost.md +271 -0
- package/skills/wix-manage/references/ecommerce/goal-clear-inventory.md +118 -0
- package/skills/wix-manage/references/ecommerce/goal-drive-cross-sells.md +122 -0
- package/skills/wix-manage/references/ecommerce/goal-increase-aov.md +132 -0
- package/skills/wix-manage/references/ecommerce/goal-reduce-cart-abandonment.md +148 -0
- package/skills/wix-manage/references/ecommerce/goal-seasonal-revenue.md +146 -0
- package/skills/wix-manage/references/ecommerce/guardrail-discount-conflicts.md +118 -0
- package/skills/wix-manage/references/ecommerce/guardrail-margin-protection.md +88 -0
- package/skills/wix-manage/references/ecommerce/guardrail-rate-pricing-sanity.md +108 -0
- package/skills/wix-manage/references/ecommerce/guardrail-shipping-health.md +124 -0
- package/skills/wix-manage/references/ecommerce/recipe-apply-shipping-recommendations.md +299 -0
- package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +582 -0
- package/skills/wix-manage/references/ecommerce/setup-coupons.md +338 -0
- package/skills/wix-manage/references/ecommerce/setup-discount-rules.md +444 -0
- package/skills/wix-manage/references/ecommerce/setup-shipping-rates.md +86 -0
- package/skills/wix-manage/references/ecommerce/setup-shipping-regions.md +56 -0
- package/skills/wix-manage/references/ecommerce/setup-store-pickup-location.md +209 -0
- package/skills/wix-manage/references/ecommerce/skill-graph.md +139 -0
- package/skills/wix-manage/references/ecommerce/troubleshoot-checkout-delivery-dropoff.md +124 -0
- package/skills/wix-manage/references/ecommerce/troubleshoot-discount-not-applying.md +95 -0
- package/skills/wix-manage/references/events/list-events.md +203 -0
- package/skills/wix-manage/references/forms/create-form.md +260 -0
- package/skills/wix-manage/references/get-paid/create-payment-links.md +212 -0
- package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +57 -0
- package/skills/wix-manage/references/get-paid/payment-links-for-bookings.md +101 -0
- package/skills/wix-manage/references/media/upload-media-to-wix.md +216 -0
- package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +77 -0
- package/skills/wix-manage/references/pricing-plans/pricing-plans-bookings-integration.md +166 -0
- package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +336 -0
- package/skills/wix-manage/references/rich-content/ricos-converter-service.md +295 -0
- package/skills/wix-manage/references/site-properties/change-payment-currency-site-properties.md +59 -0
- package/skills/wix-manage/references/sites/create-site-from-template.md +183 -0
- package/skills/wix-manage/references/sites/query-sites.md +125 -0
- package/skills/wix-manage/references/stores/add-store-pages-to-site.md +57 -0
- package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +1041 -0
- package/skills/wix-manage/references/stores/create-product-catalog-v1.md +125 -0
- package/skills/wix-manage/references/stores/create-product-from-image.md +824 -0
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +566 -0
- package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +194 -0
- package/skills/wix-manage/references/stores/query-products-catalog-v1.md +80 -0
- package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +99 -0
- package/skills/wix-manage/references/stores/update-product-pre-order.md +213 -0
- package/skills/wix-manage/references/stores/update-product-with-options.md +318 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stores-implementer
|
|
3
|
+
description: "Implements Wix Stores vertical — product catalog, categories, add-to-cart, product pages. Scopes: seed, components, components-css, pages-products, pages-categories, pages-home-and-nav. Extends references/shared/IMPLEMENTER.md."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Stores Implementer
|
|
7
|
+
|
|
8
|
+
Extends `references/shared/IMPLEMENTER.md`. Read that file first for phase routing, MCP prefix, site.json read pattern, return contract, style conventions, and common failure modes.
|
|
9
|
+
|
|
10
|
+
## Scope routing
|
|
11
|
+
|
|
12
|
+
| Scope | Phase | Reference |
|
|
13
|
+
|-------|-------|-----------|
|
|
14
|
+
| `seed` | Seed (MCP catalog setup — products only; categories are merchant-driven, not seeded) | `./PRODUCT_CATALOG_DATA.md` |
|
|
15
|
+
| `components` | Components (React islands + SeoTags + back-in-stock util — TSX/Astro only, **no CSS**) | `./SHARED_WIRING.md` |
|
|
16
|
+
| `components-css` | Components (scoped CSS — `components-stores.css` only; runs concurrently with `components`) | `./COMPONENTS_CSS.md` |
|
|
17
|
+
| `pages-categories` | Pages (`/category/[slug]` listing + shared CategoryRail + `utils/categories.ts`) | `./CATEGORY_PAGES.md` |
|
|
18
|
+
| `pages-products` | Pages (products listing + detail + ProductCard; mounts the rail written by `pages-categories`) | `./PRODUCT_PAGES.md` |
|
|
19
|
+
| `pages-home-and-nav` | Pages (home-page contribution + Shop submenu in Navigation) | `./HOME_AND_NAV.md` |
|
|
20
|
+
|
|
21
|
+
> **Why `components` is split.** A single agent writing five .tsx/.astro files plus the scoped CSS dominated Phase 3 wall time (228 s on a 3-product run, 320 s on an 8-product run). The CSS file has no runtime coupling to the TSX components — it's referenced only by class name at build time — so it splits cleanly into a sibling agent that runs in the same dispatch batch. Each scope gets a smaller reading set and a smaller write list. See `./COMPONENTS_CSS.md` § "What this scope owns".
|
|
22
|
+
|
|
23
|
+
## Files this vertical creates / contributes
|
|
24
|
+
|
|
25
|
+
See `<SKILL_ROOT>/references/verticals/stores.md` frontmatter (`creates:` and `contributes:` blocks).
|
|
26
|
+
|
|
27
|
+
## Pre-return file-existence assertion (all page scopes)
|
|
28
|
+
|
|
29
|
+
Before returning `status: "complete"` from any `pages-*` scope, verify every file listed in your scope's `files:` block (see verticals/stores.md) exists on disk. Silently dropping a file (e.g. `[slug].astro` from `pages-products`) reports `complete` to the orchestrator, but every product link 404s at runtime.
|
|
30
|
+
|
|
31
|
+
If a declared file is missing, return `status: "partial"` with `errors: [{ code: "PHASE4_FILE_MISSING", path: "<expected path>" }]` rather than claiming success. The orchestrator's Step 8.0.5 manifest check will also catch this, but an agent-side assertion gives a faster and more precise failure.
|
|
32
|
+
|
|
33
|
+
## Templates
|
|
34
|
+
|
|
35
|
+
Canonical templates live at `<SKILL_ROOT>/templates/stores/`. Your `components` and `pages-*` scopes read these and adapt them — don't invent markup or logic.
|
|
36
|
+
|
|
37
|
+
Components (`components` scope — TSX/Astro only):
|
|
38
|
+
- `<SKILL_ROOT>/templates/stores/AddToCartButton.tsx`
|
|
39
|
+
- `<SKILL_ROOT>/templates/stores/ProductPurchase.tsx`
|
|
40
|
+
- `<SKILL_ROOT>/templates/stores/BackInStockForm.tsx`
|
|
41
|
+
- `<SKILL_ROOT>/templates/stores/SeoTags.astro`
|
|
42
|
+
|
|
43
|
+
Components CSS (`components-css` scope — scoped CSS only):
|
|
44
|
+
- `<SKILL_ROOT>/templates/stores/components-stores.css`
|
|
45
|
+
|
|
46
|
+
Pages (`pages-products` scope):
|
|
47
|
+
- `<SKILL_ROOT>/templates/stores/ProductCard.astro`
|
|
48
|
+
- `<SKILL_ROOT>/templates/stores/products/index.astro`
|
|
49
|
+
- `<SKILL_ROOT>/templates/stores/products/[slug].astro`
|
|
50
|
+
|
|
51
|
+
Pages (`pages-categories` scope):
|
|
52
|
+
- `<SKILL_ROOT>/templates/stores/CategoryRail.astro`
|
|
53
|
+
- `<SKILL_ROOT>/templates/stores/category/[slug].astro`
|
|
54
|
+
|
|
55
|
+
### Pre-copied by the orchestrator (do NOT write these yourself)
|
|
56
|
+
|
|
57
|
+
The following utility files are deterministically copied by the orchestrator BEFORE your phase dispatches (`components` for the first, `pages` for the second). They are mechanical SDK wrappers with no brand-specific content; reading or rewriting them as part of your scope wastes tokens and risks drift. Just import the helpers at the listed paths:
|
|
58
|
+
|
|
59
|
+
- `src/utils/back-in-stock.ts` — pre-copied from `<SKILL_ROOT>/templates/stores/back-in-stock.ts` before `components` dispatches.
|
|
60
|
+
- `src/utils/categories.ts` — pre-copied from `<SKILL_ROOT>/templates/stores/categories.ts` before `pages` dispatches.
|
|
61
|
+
|
|
62
|
+
If you find one of these missing at runtime, that's an orchestrator-side bug — return `status: "partial"` with `errors: [{code: "UTILITY_TEMPLATE_NOT_PRECOPIED", path: "<missing>"}]` and continue. Do NOT write your own version; the post-phase manifest check will recover by template-copy and the right helper lands on disk.
|
|
63
|
+
|
|
64
|
+
## CSS ownership — stores pack
|
|
65
|
+
|
|
66
|
+
Stores-specific component CSS lives in `src/styles/components-stores.css` (written by the `components-css` scope — see `./COMPONENTS_CSS.md`), NOT in the designer's `global.css`. The classes the pack owns:
|
|
67
|
+
|
|
68
|
+
- `.product-card`, `.product-card-media`, `.product-card-ribbon`, `.product-card-index` — the product card itself, including the `overflow: hidden` + `border-radius` clipping context. Whoever writes the `border-radius` here also writes any inner padding required to keep child content inside the rounded edges. Without inner padding, a price `<p>` sits flush against the rounded bottom corner and descenders get clipped. Add `padding-bottom: var(--spacing-md)` on the card plus horizontal padding on each text block when you set the radius. See `references/shared/STYLING.md` § "Component-specific CSS is owned by the component, not the designer".
|
|
69
|
+
- `.product-grid` — the layout that lists product cards. Both `/products` (pages-products scope) and `/category/[slug]` (pages-categories scope) consume it from one place. Include `display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--spacing-xl);` plus the View-Transitions opacity fade for in-flight navigations.
|
|
70
|
+
- `.offer-callout` family (`.offer-callout`, `-item`, `-badge`, `-name`, `-detail`, `-foot`) — discount panel rendered above `<ProductPurchase>` on `/products/[slug]`.
|
|
71
|
+
|
|
72
|
+
The designer's `global.css` declares only tokens, the `.btn` family, decorative slots, the editorial-rule, and the site-shell shells. If `global.css` ships with a partial rule for any class above, that's a designer bug — flag it in your return JSON's `errors` array (`{code: "GLOBAL_CSS_LEAK", class: "<name>"}`) and override with the complete rule in `components-stores.css`.
|
|
73
|
+
|
|
74
|
+
## Back-in-stock subscribe — components + pages wiring split
|
|
75
|
+
|
|
76
|
+
Back-in-stock is a dashboard-toggleable feature: it ships in every stores build but only lights up when the merchant clicks "Start Collecting Requests" in the Back in Stock dashboard. The implementation is split across the two scopes the same way every other stores feature is:
|
|
77
|
+
|
|
78
|
+
- **`components` scope** writes the SSR probe (`src/utils/back-in-stock.ts`) and the React form island (`src/components/BackInStockForm.tsx`). See `./BACK_IN_STOCK.md` for the full rules — especially the two app ids (use `1380b703-…` for back-in-stock, NOT the Stores install id `215238eb-…`) and the bare-fields rule (no `itemUrl`, no `image` on the SDK call).
|
|
79
|
+
- **`components-css` scope** appends the back-in-stock form rules to `src/styles/components-stores.css` as part of writing that file. See `./BACK_IN_STOCK.md` § 3 for the CSS append.
|
|
80
|
+
- **`pages-products` scope** imports `getBackInStockEnabled` in `[slug].astro`, awaits the probe, and passes `backInStockEnabled` + `priceAmount` to `<ProductPurchase>`. ProductPurchase renders the form in its three OOS branches when the prop is true.
|
|
81
|
+
|
|
82
|
+
If the merchant hasn't enabled "Start Collecting Requests", the probe returns `false`, the prop stays `false`, and the form never mounts — no rebuild needed when the merchant flips the toggle in the dashboard.
|
|
83
|
+
|
|
84
|
+
## Stores-specific failure modes
|
|
85
|
+
|
|
86
|
+
| Wrong | Right |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `import { products }` | `import { productsV3 }` — V1 silently returns 0 on V3 catalogs |
|
|
89
|
+
| Skip `variantId` on cart add | Always include — single-variant products have one |
|
|
90
|
+
| Omit `wixMetadata` on `/products/[slug]` | Required for Wix sitemap/SEO/deep-link routing |
|
|
91
|
+
| Mount CartBadge on a page component | Mount via ecom's `contributes:` marker in `Navigation.astro` so it appears on all pages |
|
|
92
|
+
| Hit `/stores/v3/categories/...` for category endpoints | Categories live under `/categories/v1/` — `POST /categories/v1/categories`, `POST /categories/v1/bulk/categories/{id}/add-items`, `POST /categories/v1/categories/query` |
|
|
93
|
+
| Use the back-in-stock app id `1380b703-…` when adding items to a category | Use the **Stores install id** `215238eb-22a5-4c36-9e7b-e7c08025e04e` for `appId` on `bulkAddItemsToCategory` items — it's the same id Wix Stores writes to its products |
|
|
94
|
+
| Call `categories.queryCategories(...).limit(N).find()` with no filter | The SDK builder rejects empty filter expressions with `INVALID_FILTER`. Always chain at least `.eq("visible", true)` before `.find()` |
|
|
95
|
+
| Call `categories.listCategoriesForItems(items, ...)` from the SDK | The SDK function ships items via GET querystring and breaks on arrays. Use `POST /categories/v1/categories/list-categories-for-items` directly, or fan out per-category via `listItemsInCategory` |
|
|
96
|
+
| Ship a client-side filter (`data-category-ids` + JS hide) on the product grid | Filter server-side via `/category/[slug]` routes; client-side filtering doesn't scale past ~100 products and breaks SEO. The `<CategoryRail/>` swaps cards via `<ClientRouter />`, not by hiding them |
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Recipe: Product Catalog Data Setup (Phase 1)
|
|
2
|
+
|
|
3
|
+
Replace the default sample products Wix Stores installs with on-brand products via MCP. This file covers the `seed-seed` scope — data seeding only. Frontend wiring lives in the Phase 2 scope references (`SHARED_WIRING.md`, `PRODUCT_PAGES.md`, `CART_CHECKOUT.md`, `HOME_AND_NAV.md`) and should not be read by `seed-seed`.
|
|
4
|
+
|
|
5
|
+
> **Critical Rules — Read Before Starting**
|
|
6
|
+
> 1. **V3 only** — all endpoints under `/stores/v3/...` for products.
|
|
7
|
+
> 2. **No improvised endpoints** — if an MCP call returns 404, stop and report. Do not guess alternative URLs. Do not loop on `SearchWixRESTDocumentation` more than twice on the same topic.
|
|
8
|
+
> 3. **Do not seed categories.** Categories are merchant-driven — created in the Wix dashboard, not by this scope. The storefront's rail, Shop submenu, and `/category/[slug]` route are still wired (Phase 4) and light up automatically once the merchant adds at least one visible category with items (≤ 5 min after creation, the helper's TTL).
|
|
9
|
+
|
|
10
|
+
> **V3 Catalog:** New Wix sites use Catalog V3. All endpoints below live under `/stores/v3/...`. The V1 product endpoints should not be used — they silently return 0 results on V3 catalogs.
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
- Wix Stores app must be installed on the site (via MCP after scaffolding, or installed via MCP if missing — see Step 0)
|
|
15
|
+
|
|
16
|
+
## Setup: Replace Default Products via MCP
|
|
17
|
+
|
|
18
|
+
> **Conditional:** This section only applies when ALL of these are true:
|
|
19
|
+
> - The Stores app was just installed (default sample products exist)
|
|
20
|
+
> - Wix MCP tools are available (`mcp__wix-mcp-remote__CallWixSiteAPI` exists)
|
|
21
|
+
> - Discovery context is available in your prompt (business type, brand name, style)
|
|
22
|
+
>
|
|
23
|
+
> **If MCP tools are not available, skip this entire section.** The 12 default products remain and can be customized later in the Wix dashboard.
|
|
24
|
+
|
|
25
|
+
> **API error guard:** If any MCP call in Phase 1 returns a 404 or an unexpected error, do **not** retry the same call with a guessed alternative URL or namespace. Report the failing endpoint, request body, and error verbatim to the user, then stop. Improvised endpoints have caused multi-minute silent stalls in past runs.
|
|
26
|
+
|
|
27
|
+
> **Stores appDefId** for install and `catalogReference.appId`: `215238eb-22a5-4c36-9e7b-e7c08025e04e`. (A different defId — `1380b703-ce81-ff05-f115-39571d94dfcd` — is used for `wixMetadata.appDefId` in Phase 2. Do not swap them.)
|
|
28
|
+
|
|
29
|
+
### Step 0: Ensure Stores App Is Installed
|
|
30
|
+
|
|
31
|
+
Before querying products, verify the Stores app is installed:
|
|
32
|
+
|
|
33
|
+
1. **Probe** — `CallWixSiteAPI: POST /stores/v3/products/query` with body `{ "query": { "paging": { "limit": 1 } } }`
|
|
34
|
+
2. **If the API returns a "REQUIRED_APP_NOT_INSTALLED" error** → install the Wix Stores app:
|
|
35
|
+
```
|
|
36
|
+
CallWixSiteAPI: POST https://www.wixapis.com/apps-installer-service/v1/app-instance/install
|
|
37
|
+
body: {
|
|
38
|
+
"tenant": { "tenantType": "SITE", "id": "<siteId>" },
|
|
39
|
+
"appInstance": { "appDefId": "215238eb-22a5-4c36-9e7b-e7c08025e04e", "enabled": true }
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
> Translate this prose-HTTP form into the full `CallWixSiteAPI` tool-call shape — include `siteId`, `reason`, `sourceDocUrl` wrapper fields and pass `body` as a real object (NOT a stringified JSON). See `../../shared/MCP_PREFIX.md` § "CallWixSiteAPI call conventions".
|
|
43
|
+
|
|
44
|
+
Then retry the probe query to confirm installation succeeded.
|
|
45
|
+
3. **If the probe succeeds** → proceed to Step 1.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
Replace the 12 generic sample products with 3 on-brand products that match the user's business before building any code.
|
|
50
|
+
|
|
51
|
+
### Step 1: Query Default Products
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
CallWixSiteAPI: POST /stores/v3/products/query
|
|
55
|
+
body: {
|
|
56
|
+
"query": {
|
|
57
|
+
"paging": { "limit": 50 }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Collect all product IDs from the response.
|
|
63
|
+
|
|
64
|
+
### Step 2: Bulk Delete Defaults
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
CallWixSiteAPI: POST /stores/v3/bulk/products/delete
|
|
68
|
+
body: {
|
|
69
|
+
"productIds": ["<id1>", "<id2>", ..., "<id12>"]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Step 3: Design 3 On-Brand Products
|
|
74
|
+
|
|
75
|
+
No API call — use discovery context (business type, brand name, style, industry) to plan 3 products:
|
|
76
|
+
|
|
77
|
+
- Product names, descriptions, and pricing appropriate for the business
|
|
78
|
+
- Product type: `PHYSICAL`
|
|
79
|
+
- Options (size, color, etc.) if appropriate for the business type
|
|
80
|
+
|
|
81
|
+
**Product design guidelines by business type:**
|
|
82
|
+
|
|
83
|
+
| Business Type | Product 1 | Product 2 | Product 3 |
|
|
84
|
+
|--------------|-----------|-----------|-----------|
|
|
85
|
+
| Skincare / beauty | Signature serum or moisturizer | Cleansing product | Gift set or bundle |
|
|
86
|
+
| Clothing / fashion | Signature top or dress | Accessory item | Seasonal piece |
|
|
87
|
+
| Food / bakery | Signature item (cake, bread) | Sampler or variety pack | Gift box |
|
|
88
|
+
| Home / decor | Statement piece | Functional item | Set or collection |
|
|
89
|
+
| Fitness / wellness | Core product (mat, equipment) | Accessory | Starter kit |
|
|
90
|
+
| General retail | Best-seller item | Complementary item | Value bundle |
|
|
91
|
+
|
|
92
|
+
Adapt names, descriptions, and pricing to match the brand's tone and style. Use the brand name in product descriptions where natural.
|
|
93
|
+
|
|
94
|
+
### Step 4: Bulk Create Products
|
|
95
|
+
|
|
96
|
+
> **V3 bulk create body format:** Each item in the `products` array is a flat product object — do NOT wrap in a `"product"` key. Only include `options` and `variantsInfo` when the product has meaningful variants (multiple sizes, colors, etc.). Simple products with no real variants should omit these fields — the API creates a default variant automatically using the product-level price.
|
|
97
|
+
|
|
98
|
+
**Product with variants** (e.g., skincare with 30ml/50ml sizes):
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
CallWixSiteAPI: POST /stores/v3/bulk/products-with-inventory/create
|
|
102
|
+
body: {
|
|
103
|
+
"products": [
|
|
104
|
+
{
|
|
105
|
+
"name": "<Product Name>",
|
|
106
|
+
"productType": "PHYSICAL",
|
|
107
|
+
"description": {
|
|
108
|
+
"nodes": [
|
|
109
|
+
{
|
|
110
|
+
"type": "PARAGRAPH",
|
|
111
|
+
"id": "<unique-id>",
|
|
112
|
+
"nodes": [
|
|
113
|
+
{ "type": "TEXT", "textData": { "text": "<Product description>" } }
|
|
114
|
+
],
|
|
115
|
+
"paragraphData": { "textStyle": { "textAlignment": "AUTO" } }
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"metadata": { "version": 1, "id": "<unique-id>" }
|
|
119
|
+
},
|
|
120
|
+
"visible": true,
|
|
121
|
+
"visibleInPos": true,
|
|
122
|
+
"physicalProperties": {},
|
|
123
|
+
"options": [
|
|
124
|
+
{
|
|
125
|
+
"name": "Size",
|
|
126
|
+
"optionRenderType": "TEXT_CHOICES",
|
|
127
|
+
"choicesSettings": {
|
|
128
|
+
"choices": [
|
|
129
|
+
{ "choiceType": "CHOICE_TEXT", "name": "30ml" },
|
|
130
|
+
{ "choiceType": "CHOICE_TEXT", "name": "50ml" }
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"variantsInfo": {
|
|
136
|
+
"variants": [
|
|
137
|
+
{
|
|
138
|
+
"choices": [
|
|
139
|
+
{
|
|
140
|
+
"optionChoiceNames": {
|
|
141
|
+
"optionName": "Size",
|
|
142
|
+
"choiceName": "30ml",
|
|
143
|
+
"renderType": "TEXT_CHOICES"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"price": { "actualPrice": { "amount": "48.00" } },
|
|
148
|
+
"visible": true,
|
|
149
|
+
"inventoryItem": { "quantity": 50, "preorderInfo": { "enabled": false } },
|
|
150
|
+
"physicalProperties": {}
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
"returnEntity": true
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Add one more variant object per size in the `variants` array (one per choice combination). Use the Ricos format for descriptions (PARAGRAPH > TEXT > textData).
|
|
161
|
+
|
|
162
|
+
**Simple product without real variants** (e.g., a gift set with one price and no size/color choices):
|
|
163
|
+
|
|
164
|
+
Omit `options` and `variantsInfo` entirely. Set the price at the product level. The API creates a default variant automatically:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"name": "Complete Gift Set",
|
|
169
|
+
"productType": "PHYSICAL",
|
|
170
|
+
"visible": true,
|
|
171
|
+
"visibleInPos": true,
|
|
172
|
+
"physicalProperties": {},
|
|
173
|
+
"priceData": { "price": 89.00 },
|
|
174
|
+
"manageVariants": false,
|
|
175
|
+
"inventoryItem": { "trackQuantity": true, "quantity": 30 }
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
> **Do NOT create dummy options** (e.g., "Type: Standard") for simple products. Only add `options` and `variantsInfo` when the product genuinely has multiple variants. Phase 2's `ProductPurchase` component detects products without meaningful options and renders just the "Add to Cart" button — no unnecessary selection step for the buyer.
|
|
180
|
+
|
|
181
|
+
Include all products in the same `products` array. Do not include `media` — product images are handled separately by the image agent after product creation.
|
|
182
|
+
|
|
183
|
+
### Step 5: Verify
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
CallWixSiteAPI: POST /stores/v3/products/query
|
|
187
|
+
body: {
|
|
188
|
+
"query": { "paging": { "limit": 50 } }
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Confirm exactly 3 products exist. Report the product names and prices to the user.
|
|
193
|
+
|
|
194
|
+
### Step 6: Categories are NOT seeded
|
|
195
|
+
|
|
196
|
+
This scope does **not** create categories. The default Wix Stores install ships one auto-managed category (`online_stores_all_products`) — leave it; the frontend filters it out by handle.
|
|
197
|
+
|
|
198
|
+
If the merchant later creates visible categories in the Wix dashboard and assigns products to them, the storefront wires up automatically:
|
|
199
|
+
|
|
200
|
+
- `<CategoryRail/>` renders pills above `/products` and `/category/[slug]`.
|
|
201
|
+
- The `Navigation` Shop submenu lists the categories.
|
|
202
|
+
- `/category/<slug>` becomes a reachable, server-side-filtered listing.
|
|
203
|
+
|
|
204
|
+
This works because the frontend (`src/utils/categories.ts`, written by the `pages-categories` scope in Phase 4) live-queries the Wix API at SSR time with a 5-min cache — no redeploy or regen is needed.
|
|
205
|
+
|
|
206
|
+
### Step 7: Return Results
|
|
207
|
+
|
|
208
|
+
Emit a structured JSON block at the end of your completion message per `../../shared/RETURN_CONTRACT.md`. Do NOT write a sidecar file.
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"status": "complete",
|
|
213
|
+
"phase": "stores-seed",
|
|
214
|
+
"scope": "seed-seed",
|
|
215
|
+
"summary": "Deleted {N} default products; created {N} on-brand products with variants",
|
|
216
|
+
"data": {
|
|
217
|
+
"products": [
|
|
218
|
+
{
|
|
219
|
+
"id": "<uuid>",
|
|
220
|
+
"name": "<name>",
|
|
221
|
+
"slug": "<slug>",
|
|
222
|
+
"variantId": "<uuid>",
|
|
223
|
+
"price": 0,
|
|
224
|
+
"inventory": 0,
|
|
225
|
+
"sku": "<sku>"
|
|
226
|
+
}
|
|
227
|
+
],
|
|
228
|
+
"categories": [],
|
|
229
|
+
"deletedCount": 0,
|
|
230
|
+
"createdCount": 0
|
|
231
|
+
},
|
|
232
|
+
"files": [],
|
|
233
|
+
"errors": []
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`data.categories` is always `[]` — this scope does not seed categories. The field is retained for shape stability so downstream consumers don't need a new schema.
|
|
238
|
+
|
|
239
|
+
The JSON block MUST be the last content in your message. Parent skill consumes `data.products[*].slug` and `data.products[*].variantId` for the Phase 4 Pages scopes.
|
|
240
|
+
|
|
241
|
+
### Phase 1 Boundary — Do Not Touch Other Site Data
|
|
242
|
+
|
|
243
|
+
Phase 1 is complete after Step 7. Do **not** attempt any of the following, even if they seem like reasonable polish:
|
|
244
|
+
|
|
245
|
+
- Cleaning up "orphan customizations", "All Products" containers, brand records, or any other catalog metadata you didn't create.
|
|
246
|
+
- Creating, renaming, or deleting any category — categories are merchant-driven (see Step 6). The auto-managed "All Products" category (handle `online_stores_all_products`) stays in place; the frontend filters it out by handle.
|
|
247
|
+
- Verifying your work via additional `query` calls beyond the Step 5 verification already performed.
|
|
248
|
+
|
|
249
|
+
Phase 2+ (frontend wiring) is covered in the scope-specific references (`SHARED_WIRING.md`, `PRODUCT_PAGES.md`, `CATEGORY_PAGES.md`, `CART_CHECKOUT.md`, `HOME_AND_NAV.md`) — do not read them during `seed-seed`.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Phase 4 Product Pages — Stores
|
|
2
|
+
|
|
3
|
+
Scope: `product-pages`. Launched in **Step 7** after designer page scopes have written placeholder `.astro` files. This scope rewrites the product listing, product detail, and ProductCard component with live `productsV3` queries.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
Files this agent OWNS (rewrites from designer output):
|
|
8
|
+
|
|
9
|
+
- `src/pages/products/index.astro` — product listing
|
|
10
|
+
- `src/pages/products/[slug].astro` — product detail with `wixMetadata` + SEO tags
|
|
11
|
+
- `src/components/ProductCard.astro` — reusable card used by listing + home
|
|
12
|
+
|
|
13
|
+
Files this agent MUST NOT touch:
|
|
14
|
+
- `src/components/ProductPurchase.tsx`, `src/components/AddToCartButton.tsx` — owned by `components`
|
|
15
|
+
- `src/pages/cart.astro`, `src/pages/thank-you.astro` — owned by `pages-cart-checkout`
|
|
16
|
+
- `src/pages/index.astro`, `src/components/Navigation.astro` — owned by `pages-home-and-nav`
|
|
17
|
+
- `global.css`, any other `.astro` page, any other component — owned by designers
|
|
18
|
+
|
|
19
|
+
## Inputs (from parent prompt)
|
|
20
|
+
|
|
21
|
+
- **Phase 1 return data** — `products: [{id, name, slug, variantId, price, inventory, sku}]` — use slugs when needed (rarely; `queryProducts` returns them already).
|
|
22
|
+
- **Design tokens** — read `.wix/site.json.designTokens` for the published color/spacing/typography vocabulary; compose Tailwind utilities derived from those tokens (`class="py-4xl flex flex-col gap-md font-display"`) at the call site rather than inventing semantic classes for layout/spacing/typography. Retained global semantic classes are limited to compound patterns (`offer-callout`, `cart-summary`), interactive primitives (`btn-primary`, `product-card`), and JS targets — see `references/shared/STYLING.md`.
|
|
23
|
+
- **Designer output summary** — paths of existing `products/index.astro`, `products/[slug].astro`, `ProductCard.astro` with placeholder data.
|
|
24
|
+
|
|
25
|
+
## Critical rules (all must be honored)
|
|
26
|
+
|
|
27
|
+
1. **Use `productsV3`, not `products`** — V1 silently returns 0 on V3 catalogs.
|
|
28
|
+
2. **Product detail MUST use `getProductBySlug()`**, not `queryProducts()`. `queryProducts` omits variant data (`options`, `variantsInfo`), making add-to-cart silently fail.
|
|
29
|
+
3. **Product detail MUST export `wixMetadata`** — required for Wix sitemap, SEO editor, and dashboard deep links. Without it, the sitemap has zero product entries.
|
|
30
|
+
4. **Mount `SeoTags` on the detail page** — pipe `product.seoData.tags` through `Layout`'s `head` slot so merchant SEO edits in the Wix dashboard reach the live site. `seoData` is returned by default — no `fields` flag needed.
|
|
31
|
+
5. **Mount `ProductPurchase` with `client:load` and a single `product` prop, plus the back-in-stock probe + price props.** `<ProductPurchase client:load product={product} inventoryByVariant={inventoryByVariant} backInStockEnabled={backInStockEnabled} priceAmount={priceAmount} />`. The component destructures internally; passing flat props (`productId={product._id}`, `options={product.options}`, …) silently renders nothing because the new contract expects `product`. The `backInStockEnabled` boolean comes from `await getBackInStockEnabled()` (template imports it from `../../utils/back-in-stock`); `priceAmount` is the numeric price already computed in the frontmatter. See `BACK_IN_STOCK.md` for why both are needed.
|
|
32
|
+
6. **SSR only — do NOT add `export const prerender = true` or `getStaticPaths()`.** The productsV3 SDK depends on request-context auth (tenant resolution, site headers). At prerender time there is no request, and `.queryProducts().limit()` short-circuits to `"is not a function"`. Keep `[slug].astro` server-rendered with `Astro.params.slug`.
|
|
33
|
+
7. **No HTML comments in `.astro` frontmatter.** Build fails with "Legacy HTML single-line comments are not allowed".
|
|
34
|
+
8. **Default to tokens-as-utilities for layout/spacing/typography.** When you need a section padding, a flex column, a typographic treatment — write Tailwind utilities derived from `@theme` tokens (`<section class="py-4xl flex flex-col gap-md">`, `<h1 class="font-display text-4xl">`). Do NOT invent semantic classes like `.featured-section`, `.page-header`, `.products-header-image` — Tailwind v4 silently drops undeclared classes. Use a global semantic class only when one is published in designer `INSTRUCTIONS.md`'s always-required list (`product-card`, `product-card-ribbon`, `offer-callout` family). For one-off page decoration, write a co-located `<style>` block at the bottom of the same `.astro` file using `var(--color-foo)` token references.
|
|
35
|
+
9. **Preserve designer classes.** When the designer used a published global semantic class on existing markup, keep it; don't rename. Add Tailwind utilities alongside if you need additional layout adjustment.
|
|
36
|
+
|
|
37
|
+
## Wix Site Structure — `wixMetadata` + `@wix/astro-pages`
|
|
38
|
+
|
|
39
|
+
`@wix/astro-pages` is already wired into the blank scaffold's `astro.config.mjs` as `wixPages()`. It injects a `/_wix/pages.json` endpoint enumerating every page and reading each page's `wixMetadata` export. Wix platform services use this JSON to:
|
|
40
|
+
|
|
41
|
+
- Generate server-side sitemap entries for dynamic product URLs (via `@wix/auto_sdk_seo_seo-sitemap-entries`)
|
|
42
|
+
- Power the dashboard SEO editor ("Edit SEO for Product pages")
|
|
43
|
+
- Resolve deep links from dashboard / email / analytics surfaces back to the right headless URL
|
|
44
|
+
|
|
45
|
+
> **Two different Stores appDefIds — do not confuse:**
|
|
46
|
+
> - `215238eb-22a5-4c36-9e7b-e7c08025e04e` — for `catalogReference.appId` in cart operations (same value used for app install in Phase 1).
|
|
47
|
+
> - `1380b703-ce81-ff05-f115-39571d94dfcd` — for **`wixMetadata.appDefId`** on Stores sub-pages (product, category).
|
|
48
|
+
>
|
|
49
|
+
> Both are correct. They identify different entities.
|
|
50
|
+
|
|
51
|
+
## Template files
|
|
52
|
+
|
|
53
|
+
This scope uses **template files** instead of inline code. For each file below:
|
|
54
|
+
|
|
55
|
+
1. Read the template from `<Agent location>/templates/<path>`
|
|
56
|
+
2. Write it to the project at the target path
|
|
57
|
+
3. Adapt class names only if the styling contract maps them differently than the defaults
|
|
58
|
+
|
|
59
|
+
Do NOT modify logic, imports, SDK calls, `wixMetadata` export, or prop-passing. The templates encode non-negotiable Wix platform integrations (sitemap registration, inventoryItemsV3 OOS truth, SSR-only constraint, analytics payloads).
|
|
60
|
+
|
|
61
|
+
## Implementation
|
|
62
|
+
|
|
63
|
+
> Every Wix SDK `await` in the templates is already wrapped in try/catch — keep those guards when adapting. See `references/shared/IMPLEMENTER.md` § "SSR error guards" for the underlying rule and rationale.
|
|
64
|
+
|
|
65
|
+
### 1. `src/pages/products/index.astro` — product listing
|
|
66
|
+
|
|
67
|
+
Use template `templates/products/index.astro`.
|
|
68
|
+
|
|
69
|
+
Preserves the designer's page structure (class names, layout) and replaces the placeholder products array with a guarded, **cursor-paginated** `productsV3.queryProducts({ fields: ["CURRENCY"] }).limit(24).skipTo(cursor).find()` (cursor read from `?cursor=` on the URL; Prev/Next anchors built from `result.cursors.next` / `.prev`). Mounts the shared `<CategoryRail/>` (written by `pages-categories`) above the grid, passing `activeSlug={null}` and the prev/next hrefs. Emits the `AddProductImpression` analytics event from a client-side script that reads a JSON payload serialized at SSR.
|
|
70
|
+
|
|
71
|
+
> **Imports written by `pages-categories`.** Both `<CategoryRail/>` and `listStoreCategories` come from files this scope must NOT write — they're owned by the `pages-categories` scope. Import paths: `../../components/CategoryRail.astro` and `../../utils/categories`. If either import fails to resolve, return `status: "partial"` with `errors: [{ code: "MISSING_PAGES_CATEGORIES_OUTPUT", path: "<missing path>" }]` — that means the orchestrator dispatched scopes out of order.
|
|
72
|
+
|
|
73
|
+
> **Page size 24** — multiple of the 2/3/4-column grid, well under Wix's per-request cap of 100. Do not change without updating `CATEGORY_PAGES.md` to match.
|
|
74
|
+
|
|
75
|
+
> **No client-side filter.** The previous "ship every product, hide non-matching cards via JS" pattern is gone — it doesn't scale and breaks SEO. Do not reintroduce `data-category-ids` on `<ProductCard>` or any DOM-hide script. Filtering is done by navigating to `/category/<slug>` (a real route), and `<ClientRouter />` from the designer's Layout handles the swap.
|
|
76
|
+
|
|
77
|
+
> **Why the double-script pattern:** Listing page is server-rendered but `AddProductImpression` must fire in the browser. The server-computed payload is serialized into an inert JSON `<script>` (`is:inline`) and read by a separate processed `<script>` (bundled by Astro — has ES `import`). `define:vars` + inline-script combinations cannot do ES imports.
|
|
78
|
+
|
|
79
|
+
> **Gift-card mirror filter (do not remove).** The template applies `productList = productList.filter(p => p.ribbon?.name !== "Gift Card")` after building the result list. When the dashboard's Wix Gift Card app is enabled, it auto-creates 5 mirror Stores products (one per denomination, `productType: "DIGITAL"`, ribbon name `"Gift Card"`). Buying a mirror yields a dud DIGITAL line item that does NOT trigger gift-card issuance — the customer-facing surface for gift cards is `/gift-cards` (gift-cards pack), not `/products`. The filter holds whether or not the gift-cards pack is loaded for this site, so a future site that drops gift-cards but still has the dashboard app stays clean.
|
|
80
|
+
|
|
81
|
+
### 2. `src/components/ProductCard.astro` — reusable card
|
|
82
|
+
|
|
83
|
+
Use template `templates/ProductCard.astro`.
|
|
84
|
+
|
|
85
|
+
The template:
|
|
86
|
+
- Accepts a single `{ product }` prop — the full Wix product object from `productsV3`
|
|
87
|
+
- Resolves product images via `resolveWixImageUrl` (imported from the seeded shared util at `../utils/wix-image`)
|
|
88
|
+
- Applies `product-card` contract class
|
|
89
|
+
- Includes delegated click analytics (`ClickProduct` event via data attributes)
|
|
90
|
+
|
|
91
|
+
Class from contract: `productCard` → `"product-card"`. If the designer already added the class, don't duplicate.
|
|
92
|
+
|
|
93
|
+
### 3. `src/pages/products/[slug].astro` — product detail
|
|
94
|
+
|
|
95
|
+
Use template `templates/products/[slug].astro`.
|
|
96
|
+
|
|
97
|
+
The template:
|
|
98
|
+
- Exports `wixMetadata` with the Stores sub-page appDefId (`1380b703-…`) and `STORES.PRODUCT.SLUG` token for platform expansion
|
|
99
|
+
- Uses `getProductBySlug()` (NOT `queryProducts()` — it omits variant data)
|
|
100
|
+
- Queries `inventoryItemsV3.queryInventoryItems({ filter: { productId } })` and builds a `variantId → { quantity, trackQuantity, preorderEnabled }` map. This is the AUTHORITATIVE OOS signal; `variantsInfo[].inventoryStatus.inStock` is a stale cached flag.
|
|
101
|
+
- Pipes `product.seoData.tags` through Layout's `head` slot via `<SeoTags slot="head" tags={seoTags} />` (rendered only when any tag is visible)
|
|
102
|
+
- Calls `await getBackInStockEnabled()` from `../../utils/back-in-stock` to learn whether the dashboard's "Start Collecting Requests" toggle is on for Wix Stores; passes the boolean and `priceAmount` to `<ProductPurchase>`. The back-in-stock subscribe form renders inside ProductPurchase's three OOS branches when the prop is true. See `BACK_IN_STOCK.md` for the app-id discrepancy and the bare-fields rule.
|
|
103
|
+
- Mounts `<ProductPurchase client:load product={product} inventoryByVariant={inventoryByVariant} backInStockEnabled={backInStockEnabled} priceAmount={priceAmount} />` with the canonical `{ product }` contract
|
|
104
|
+
- Wraps both SDK awaits in try/catch so an SDK error produces a 404 redirect (product fetch) or an empty inventory map (inventory fetch), never a torn page (the back-in-stock probe is internally wrapped — it returns `false` on any failure, so it doesn't need an outer try/catch)
|
|
105
|
+
|
|
106
|
+
**Critical details on `wixMetadata`:**
|
|
107
|
+
|
|
108
|
+
- **Required for Wix platform indexing.** Without it, the product detail route is invisible to Wix's sitemap generator, SEO editor, and deep-link resolver.
|
|
109
|
+
- **`appDefId`: `1380b703-ce81-ff05-f115-39571d94dfcd`** is the Stores page-registration defId — do NOT confuse with the Stores install/catalog defId (`215238eb-...`) used in Phase 1 and `catalogReference.appId`.
|
|
110
|
+
- **`pageIdentifier`: `"wix.stores.sub_pages.product"`** is the canonical Wix identifier — constant.
|
|
111
|
+
- **`identifiers.slug`**: maps the Astro route param to Wix's identifier token. Route is `[slug].astro`, so key is `slug`. Value `"STORES.PRODUCT.SLUG"` tells Wix to expand with each product's slug.
|
|
112
|
+
|
|
113
|
+
**Layout `head` slot** — the `Layout.astro` written by the Design System phase must accept a `head` slot and a `hasSeoTags` prop. When `hasSeoTags` is true, the Layout omits its default `<title>`/`<meta description>` and instead renders the `head` slot contents into `<head>`. This lets `SeoTags` entirely replace the default metadata. If the Layout signature doesn't match, the Design System brief is missing it — flag this in the return's `errors` array and continue with a fallback (non-merchant-editable) title.
|
|
114
|
+
|
|
115
|
+
## Live offers (discount-rule indicators)
|
|
116
|
+
|
|
117
|
+
The promotion ribbon on each product card is **owned by `ProductCard.astro` itself** — the component imports `fetchLiveOffers` + `offersForProduct` from `src/utils/discounts.ts` (shipped by the ecom `components` scope) and renders its own ribbon. Pages that mount `ProductCard` do NOT pass an `offers` prop and do NOT fetch offers themselves. This concentrates the wiring in one place — page-level wiring forced every page that renders ProductCard to remember it, and category pages would silently ship without ribbons.
|
|
118
|
+
|
|
119
|
+
`fetchLiveOffers` is memoized per request via `auth.elevate`'s caching, so rendering N ProductCards in one page does NOT fan out N discount-rule queries.
|
|
120
|
+
|
|
121
|
+
**Listing (`products/index.astro`)** — just `<ProductCard product={product} index={idx} />`. No offers wiring required.
|
|
122
|
+
|
|
123
|
+
**Detail (`products/[slug].astro`)** — the detail page renders a richer offer callout above `<ProductPurchase>`. That callout still belongs to this scope (it's not part of the card). After the product is loaded:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { fetchLiveOffers, offersForProduct } from "../../utils/discounts";
|
|
127
|
+
const offers = await fetchLiveOffers();
|
|
128
|
+
const productOffers = offersForProduct(offers, product._id);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```astro
|
|
132
|
+
{productOffers.length > 0 && (
|
|
133
|
+
<div class="offer-callout">
|
|
134
|
+
{productOffers.map((o) => (
|
|
135
|
+
<div class="offer-callout-item">
|
|
136
|
+
<span class="offer-callout-badge">Offer</span>
|
|
137
|
+
<div>
|
|
138
|
+
<p class="offer-callout-name">{o.name}</p>
|
|
139
|
+
{o.offer && o.offer !== o.name && (
|
|
140
|
+
<p class="offer-callout-detail">{o.offer}</p>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
))}
|
|
145
|
+
<p class="offer-callout-foot">Applied automatically at checkout.</p>
|
|
146
|
+
</div>
|
|
147
|
+
)}
|
|
148
|
+
|
|
149
|
+
<ProductPurchase client:load product={product} inventoryByVariant={inventoryByVariant} />
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The `.offer-callout*` classes are owned by `src/styles/components-stores.css` (written by the stores Phase 3 components agent), NOT by the designer. Use `{o.offer}` for the body text — that's the dashboard-authored offer string (e.g. `"Buy 1 item\nAll products\n\nGet 1 item for free"`) which Wix formats with `\n` line breaks; the CSS includes `white-space: pre-line` so those render as line breaks.
|
|
153
|
+
|
|
154
|
+
**Do NOT** hit `discountRules.queryDiscountRules` directly from this scope — always go through `fetchLiveOffers()`. The helper wraps the call with `auth.elevate()` (the endpoint requires `ECOM.DISCOUNT_RULES_READ`, visitor clients return nothing silently) and normalizes the scope-id field (`_id` vs `id`) which trips up naive matching.
|
|
155
|
+
|
|
156
|
+
When the site has no active rules (first deploys, or the user hasn't created any in the dashboard yet), `offers` comes back as `[]`, `offersForProduct(...)` returns `[]`, the ribbon and callout both render nothing — no code path to guard for.
|
|
157
|
+
|
|
158
|
+
## Analytics fired from this scope
|
|
159
|
+
|
|
160
|
+
| Event | Fires from | When | Payload |
|
|
161
|
+
|-------|------------|------|---------|
|
|
162
|
+
| `AddProductImpression` | `products/index.astro` | Listing page load | `{ contents: [{id, name, price, currency, position}], origin: "Product Listing" }` |
|
|
163
|
+
| `ClickProduct` | `ProductCard.astro` | Delegated click on any card | `{ id, name, price, currency, origin: "Product Listing" }` |
|
|
164
|
+
| `ViewContent` | `products/[slug].astro` | Detail page load | `{ id, name, price, currency, origin: "Product Page" }` |
|
|
165
|
+
|
|
166
|
+
`AddToCart` fires from `AddToCartButton.tsx` (written by `components`) — not this scope.
|
|
167
|
+
|
|
168
|
+
## Return format
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"status": "complete",
|
|
173
|
+
"phase": "stores-pages-products",
|
|
174
|
+
"scope": "product-pages",
|
|
175
|
+
"summary": "Wired product listing + detail + ProductCard to productsV3; wixMetadata + SeoTags mounted",
|
|
176
|
+
"data": {
|
|
177
|
+
"pagesWired": 2,
|
|
178
|
+
"wixMetadataExported": true,
|
|
179
|
+
"seoTagsMounted": true,
|
|
180
|
+
"useGetProductBySlug": true,
|
|
181
|
+
"analyticsEvents": ["AddProductImpression", "ClickProduct", "ViewContent"]
|
|
182
|
+
},
|
|
183
|
+
"files": [
|
|
184
|
+
"src/pages/products/index.astro",
|
|
185
|
+
"src/pages/products/[slug].astro",
|
|
186
|
+
"src/components/ProductCard.astro"
|
|
187
|
+
],
|
|
188
|
+
"errors": []
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
If any of `wixMetadataExported`, `seoTagsMounted`, `useGetProductBySlug` ends up `false`, set `status: "partial"` and populate `errors` with the specific issue. These three are non-negotiable for a merchant-grade site.
|
|
193
|
+
|
|
194
|
+
## Anti-patterns
|
|
195
|
+
|
|
196
|
+
| WRONG | CORRECT |
|
|
197
|
+
|-------|---------|
|
|
198
|
+
| `import { products }` from `@wix/stores` | `productsV3` |
|
|
199
|
+
| Use `queryProducts()` on detail page | `getProductBySlug()` — `queryProducts` omits variant data |
|
|
200
|
+
| `export const prerender = true` + `getStaticPaths()` on `[slug].astro` | SSR only — productsV3 needs request-context auth; prerender short-circuits it |
|
|
201
|
+
| Pass flat props to `<ProductPurchase>` (`productId`, `options`, `variantsInfo`, …) | Pass the whole product: `<ProductPurchase client:load product={product} inventoryByVariant={inventoryByVariant} />` |
|
|
202
|
+
| Hardcode `<title>` from `product.name` | Pipe `product.seoData.tags` through `SeoTags` slot, fall back to `product.name` only when tags are empty/disabled |
|
|
203
|
+
| Omit `wixMetadata` export | Required — platform indexing breaks silently without it |
|
|
204
|
+
| Add `fields: ["SEO_DATA"]` | `seoData` is returned by default — no such enum value exists |
|
|
205
|
+
| Write `src/utils/wix-image.ts` inline | Import `resolveWixImageUrl` from `../utils/wix-image` — shared util already exposes it |
|
|
206
|
+
| `ls src/` to find designer output | Parent prompt lists every existing `src/` file — read directly |
|
|
207
|
+
| Rename designer class names | Keep them; use contract classes when ADDING new markup |
|
|
208
|
+
| HTML `<!-- comment -->` in `.astro` frontmatter | `//` or `/* */` — frontmatter is TypeScript |
|
|
209
|
+
| Mount React island without `client:load` | Options + cart state needs hydration |
|
|
210
|
+
| Pass `"INVENTORY"` in the `fields` array | No such enum value exists for `productsV3`. Valid values: `URL`, `CURRENCY`, `INFO_SECTION`, `MERCHANT_DATA`, `PLAIN_DESCRIPTION`, `INFO_SECTION_PLAIN_DESCRIPTION`, `SUBSCRIPTION_PRICES_INFO`, `BREADCRUMBS_INFO`, `WEIGHT_MEASUREMENT_UNIT_INFO`, `VARIANT_OPTION_CHOICE_NAMES`, `MEDIA_ITEMS_INFO`, `DESCRIPTION`, `DIRECT_CATEGORIES_INFO`, `ALL_CATEGORIES_INFO`, `INFO_SECTION_DESCRIPTION`, `THUMBNAIL`, `PRODUCT_CHOICES_MEDIA_REFERENCES`. Passing an invalid value makes the query throw. |
|
|
211
|
+
| Trust `variantsInfo[].inventoryStatus.inStock` as the OOS gate | It's a stale cached flag — a variant with real quantity 0 can still report `inStock: true`. Query `inventoryItemsV3.queryInventoryItems({ filter: { productId } })` at SSR and pass a `variantId → { quantity, trackQuantity, preorderEnabled }` map into `ProductPurchase`. The template already does this. |
|
|
212
|
+
| Skip the `backInStockEnabled` prop on `<ProductPurchase>` | Always pass it (template already imports `getBackInStockEnabled`). When the prop is missing, the OOS subscribe form never renders even if the merchant has enabled collecting requests. |
|
|
213
|
+
| Pass the formatted price string (`"$695"`) as `priceAmount` | Pass the numeric `priceAmount` already computed in frontmatter. The Wix back-in-stock service rejects formatted prices with `400 DECIMAL_GTE`. |
|