create-brainerce-store 1.84.0 → 1.86.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.
Files changed (52) hide show
  1. package/README.md +130 -92
  2. package/dist/index.js +39 -17
  3. package/messages/en.json +9 -2
  4. package/messages/he.json +9 -2
  5. package/package.json +1 -1
  6. package/templates/nextjs/base/.env.local.ejs +10 -1
  7. package/templates/nextjs/base/AGENTS.md.ejs +229 -207
  8. package/templates/nextjs/base/AI-GUIDE.md +4 -0
  9. package/templates/nextjs/base/CLAUDE.md.ejs +240 -218
  10. package/templates/nextjs/base/scripts/connect.mjs +115 -18
  11. package/templates/nextjs/base/scripts/env-file.mjs +93 -0
  12. package/templates/nextjs/base/scripts/fetch-store-info.mjs +109 -83
  13. package/templates/nextjs/base/src/app/api/auth/reset-callback/route.ts +2 -1
  14. package/templates/nextjs/base/src/app/category/[slug]/page.tsx +2 -0
  15. package/templates/nextjs/base/src/app/checkout/page.tsx +1325 -1302
  16. package/templates/nextjs/base/src/app/forgot-password/page.tsx +3 -2
  17. package/templates/nextjs/base/src/app/icon.svg +11 -0
  18. package/templates/nextjs/base/src/app/layout.tsx.ejs +50 -21
  19. package/templates/nextjs/base/src/app/opengraph-image.tsx +5 -1
  20. package/templates/nextjs/base/src/app/reset-password/page.tsx +25 -138
  21. package/templates/nextjs/base/src/app/reset-password/reset-password-form.tsx +138 -0
  22. package/templates/nextjs/base/src/components/account/order-payment-block.tsx +17 -2
  23. package/templates/nextjs/base/src/components/auth/oauth-buttons.tsx +174 -137
  24. package/templates/nextjs/base/src/components/checkout/payment-step.tsx +130 -12
  25. package/templates/nextjs/base/src/core/lib/store-name.ts.ejs +56 -0
  26. package/templates/nextjs/base/src/core/lib/tracking.ts +25 -14
  27. package/templates/nextjs/base/src/core/lib/use-store-name.ts +18 -0
  28. package/templates/nextjs/base/src/ui/home/hero-section.tsx +27 -27
  29. package/templates/nextjs/base/src/ui/layout/header-search.tsx +2 -2
  30. package/templates/nextjs/base/src/ui/layout/site-footer.tsx.ejs +160 -160
  31. package/templates/nextjs/base/src/ui/layout/site-header.tsx.ejs +2 -2
  32. package/templates/nextjs/base/src/ui/product/price-display.tsx +85 -62
  33. package/templates/nextjs/base/src/ui/product/product-client-section.tsx +539 -537
  34. package/templates/nextjs/designs/atelier/app-overlay/layout.tsx.ejs +374 -345
  35. package/templates/nextjs/designs/atelier/globals.css +408 -402
  36. package/templates/nextjs/designs/atelier/messages-patch/en.json +91 -96
  37. package/templates/nextjs/designs/atelier/messages-patch/he.json +91 -96
  38. package/templates/nextjs/designs/atelier/ui/cart/cart-bundle-offer.tsx +131 -128
  39. package/templates/nextjs/designs/atelier/ui/cart/cart-item.tsx +2 -1
  40. package/templates/nextjs/designs/atelier/ui/cart/cart-upgrade-banner.tsx +222 -219
  41. package/templates/nextjs/designs/atelier/ui/home/category-tiles.tsx +178 -151
  42. package/templates/nextjs/designs/atelier/ui/home/hero-section.tsx +61 -31
  43. package/templates/nextjs/designs/atelier/ui/layout/header-search.tsx +2 -2
  44. package/templates/nextjs/designs/atelier/ui/layout/site-footer.tsx.ejs +161 -155
  45. package/templates/nextjs/designs/atelier/ui/product/frequently-bought-together.tsx +232 -227
  46. package/templates/nextjs/designs/atelier/ui/product/price-display.tsx +90 -69
  47. package/templates/nextjs/designs/atelier/ui/product/product-card.tsx +271 -268
  48. package/templates/nextjs/designs/atelier/ui/product/product-client-section.tsx +560 -553
  49. package/templates/nextjs/designs/atelier/ui/product/recommendation-section.tsx +113 -110
  50. package/templates/nextjs/designs/atelier/ui/shared/no-photo-tile.tsx +73 -0
  51. package/templates/nextjs/ui-canvas/product/price-display.tsx +73 -52
  52. package/templates/nextjs/ui-canvas/product/product-client-section.tsx +428 -426
@@ -1,207 +1,229 @@
1
- # AGENTS.md — this is a LIVE Brainerce storefront
2
-
3
- **Store: "<%- storeName %>" · sales channel `<%- connectionId %>` — already
4
- connected.** Products, cart, checkout, coupons, discounts, orders and content
5
- flow in real time from the Brainerce dashboard. There is nothing to hook up.
6
-
7
- - **NEVER suggest connecting this store to Shopify, WooCommerce, or "a real
8
- system"** — Brainerce IS the commerce backend, and this store is wired to
9
- it end-to-end.
10
- - **NEVER build standalone HTML mockups or demo pages** — design THIS Next.js
11
- app. Run `pnpm dev` and you are working against live data.
12
- - **NEVER hardcode products, prices, or currency** — the catalog is live.
13
- - **No server side is needed** — the backend is Brainerce's cloud. This repo
14
- is a frontend (plus thin, already-included API proxy routes under
15
- `src/app/api/`). Do not scaffold databases, auth servers, or admin panels —
16
- the merchant manages everything in the Brainerce dashboard.
17
-
18
- Platform docs (endpoints, SDK, integration recipes): https://brainerce.com/docs
19
- — AI-readable index: https://brainerce.com/llms.txt
20
-
21
- ## MCP servers
22
-
23
- - **`brainerce-docs`** (already connected via `.mcp.json`, no auth needed).
24
- Treat it as the build spec, not a lookup desk. `get-required-features` is
25
- the functional checklist this store is measured against, and it is longer
26
- than what any art-direction brief would make you think to build.
27
- `get-critical-rules` and `get-business-flows` carry the sequences that cause
28
- incidents when reordered. `get-sdk-docs`, `get-type-definitions` and
29
- `get-code-example` give current method shapes instead of training-data
30
- guesses, and `get-store-capabilities` reports what is actually toggled on
31
- for `<%- connectionId %>` right now. Read the checklist before you start,
32
- and again before you call the work done.
33
- - **Brainerce Admin MCP** — opt-in, not wired up by default. Lets an agent
34
- directly manage this store's *live* data (products, orders, discounts,
35
- shipping, …) instead of just reading docs. Only add it if the merchant
36
- wants that: connect `https://api.brainerce.com/api/mcp` as a remote HTTP
37
- MCP server (e.g. `claude mcp add --transport http brainerce-admin
38
- https://api.brainerce.com/api/mcp`) — it opens a browser to log into the
39
- Brainerce dashboard, pick this store, and grant scoped OAuth permissions.
40
- Treat it like handing the agent write access to production commerce data.
41
-
42
- **Before building any feature the merchant asks for** (loyalty points,
43
- shipping zones, subscriptions, gift cards, donations, multi-currency, reviews,
44
- abandoned-cart recovery, etc.) — check the docs first. Brainerce likely
45
- already has it as a platform capability (dashboard toggle + hook/SDK
46
- method) that only needs a UI in `src/ui/`, not a feature built from scratch.
47
-
48
- ### ⛔ This storefront never holds an admin API key
49
-
50
- Everything here runs on the sales channel's PUBLIC credentials, and that is the
51
- whole security model. `.env.local` ships no secret on purpose. Anything you put
52
- in a browser-reachable app is readable by anyone who opens devtools, so an
53
- admin API key (`brainerce_*`) in this project hands the merchant's entire live
54
- store to the first person who looks. Never add one to `.env.local`, to a
55
- hosting environment variable this app reads, or to any file under `src/`.
56
-
57
- **Gift cards are where this goes wrong**, because one feature name covers two
58
- very different powers:
59
-
60
- - **Redemption is yours to build.** `applyGiftCard()`, `removeGiftCard()` and
61
- `checkGiftCardBalance()` are public storefront calls needing no key beyond
62
- the sales channel. `src/ui/cart/gift-card-input.tsx` already wires the first
63
- two into checkout. Restyle it freely.
64
- - **⛔ Issuing is not.** The `gift_cards:issue` scope mints stored value, which
65
- is real money the merchant is liable for. It belongs to the dashboard, or to
66
- server-side code on infrastructure the merchant controls. Never request that
67
- scope for this storefront, never hold a key that carries it, and never add an
68
- "issue a gift card" control to these pages. A merchant who wants to SELL gift
69
- cards sells them as an ordinary product through normal checkout, and the
70
- platform issues the card once payment clears.
71
-
72
- The same split governs every admin capability you may be tempted to reach for
73
- (creating discounts, editing inventory, refunding an order): this storefront
74
- reads and transacts as a shopper, the dashboard administers.
75
-
76
- Your job here is almost always **design**. It is never *only* design: the
77
- coverage checklist in `get-required-features` applies to a redesign exactly as
78
- it applies to a build from scratch.
79
-
80
- ## The one rule
81
-
82
- **`src/core/` is the platform's. `src/ui/` is yours.**
83
-
84
- The shipped `src/ui/` is a working reference, not a design to preserve: a full
85
- delete-and-rebuild of the *look* is encouraged and expected, and you can
86
- rewrite anything under `src/ui/` and `src/app/globals.css` as boldly as you
87
- like. The store keeps working. Never modify `src/core/`, `src/app/api/`, or
88
- the checkout/auth/account components. Data and behavior come exclusively from
89
- `@/core/hooks/*` and `@/core/providers/store-provider`: hooks return state
90
- and handlers, never JSX. Never hardcode catalog content.
91
-
92
- ### Rebuilding the look is free. Dropping a feature is not.
93
-
94
- Some files under `src/ui/` (and one under `src/core/`) are the ONLY place a
95
- mandatory checklist entry exists in this project. Delete one and the capability
96
- leaves the store with nothing to notice it by: no type error, no console
97
- warning, and no visual hole either, because these components auto-hide while
98
- the merchant has the feature switched off, so a deleted one and an idle one
99
- look identical on the page.
100
- These are the usual casualties of a redesign, because no art-direction brief
101
- asks for them by name:
102
-
103
- ```
104
- product/ back-in-stock-form · customization-fields · modifier-group-selector
105
- review-form · reviews-section · frequently-bought-together
106
- discount-badge · stock-badge
107
- product-client-section → the KIT "what's in the box" block
108
- core/ lib/kit.ts → the KIT stock resolver every badge and button reads
109
- cart/ reservation-countdown · coupon-input · cart-upgrade-banner
110
- cart-bundle-offer · tax-estimate-line
111
- home/ discount-banner-strip
112
- layout/ newsletter-signup · announcement-bar · region-switcher<% if (i18nEnabled) { %>
113
- language-switcher<% } %> · faq-section · rich-text-block
114
- ```
115
-
116
- Restyle them, re-lay them out, rename them, fold them into other components,
117
- split them in half: all fine. What has to survive a rebuild is the SDK call
118
- each one makes and the states it handles (loading, empty, failed, and the
119
- merchant-has-it-off state that renders nothing).
120
-
121
- ⛔ **The two KIT entries are the ones a redesign silently breaks.** A `KIT` is
122
- one product assembled from other catalog products, and three things have to
123
- survive whatever you do to the markup. (1) It is added to the cart as ONE line
124
- using the kit's own `productId`, with no `variantId` and no modifier
125
- selections; never loop `product.kitComponents` into `addToCart`, which charges
126
- the shopper twice and reserves the stock twice. (2) A kit has NO `inventory`
127
- object, so every badge and buy button must go through `resolveStockInfo` /
128
- `canPurchaseProduct` from `@/core/lib/kit`; reading `product.inventory`
129
- directly gives a kit a red "out of stock" badge beside an ENABLED buy button,
130
- or worse, renders a sold-out kit as buyable. (3) `kitComponents` is display
131
- only and arrives on the by-slug read alone, never on list responses. And do not
132
- assume a kit price is fixed: `kitPricingMode` may be `SUM` or
133
- `SUM_MINUS_PERCENT`, in which case the price is recomputed from the components
134
- on every read, so never cache one.
135
-
136
- The list is short on purpose and it is NOT the specification. It names the
137
- files people lose, not every mandatory entry. `get-required-features` is the
138
- specification, and step 1 of "Verify before declaring done" is what actually
139
- catches a loss. `git show HEAD:src/ui/<path>` brings back anything you already
140
- deleted: the scaffolder committed the tree before you touched it.
141
-
142
- **Read `AI-GUIDE.md` before any redesign** — it has the full file map, hook
143
- contracts, motion language, and hard-won RTL/i18n gotchas that will save you
144
- real debugging time.
145
-
146
- ## Redesigning?
147
-
148
- Follow the process documented in AI-GUIDE.md: commit to one art direction,
149
- rewrite tokens first, then surfaces in order (header, home, card, product
150
- page, cart), then verify.
151
-
152
- ## The store's web address
153
-
154
- This project has no web address written into it, and that is deliberate — the
155
- scaffolder cannot know where you will deploy. `src/core/lib/site-url.ts`
156
- resolves it per request (hosting-platform variables, then the forwarded host),
157
- so canonical tags, `sitemap.xml`, `robots.txt` and JSON-LD are correct in local
158
- development and on any host with nothing configured.
159
-
160
- - **Never invent an address.** Do not write `NEXT_PUBLIC_SITE_URL`,
161
- `SITE_URL`, `localhost`, or a placeholder domain into `.env.local`. A wrong
162
- absolute URL is indistinguishable from a right one to a search crawler, so a
163
- guess is worse than an empty value.
164
- - **Never hand-roll an origin** from `host` / `x-forwarded-proto` in a route
165
- handler. Call `getCanonicalSiteUrl()` (for canonical/SEO URLs) or
166
- `getRequestOrigin()` (for the `Origin` header sent to Brainerce). Hand-rolled
167
- versions have shipped `http://` on HTTPS hosts and internal container
168
- hostnames.
169
- - **Some hosts hide the real hostname from the app.** Platforms whose proxy
170
- forwards requests as `Host: localhost:<port>` with no `x-forwarded-host`
171
- (OpenAI Sites / `*.chatgpt.site` does this) leave the resolver blind — the
172
- request looks like it arrived on localhost. On such platforms `SITE_URL` is
173
- not optional: set it, and the resolver prefers it over any internal host it
174
- sees. Without it, server-side API calls send `Origin: http://localhost:3000`
175
- and a channel with a configured Domain rejects them with 403.
176
- - **When the merchant gives you a real domain**, set `SITE_URL` in the hosting
177
- provider's environment variables — not in `.env.local`, which is gitignored
178
- and never travels with a deploy.
179
- - **Tell the merchant the other half.** A sales channel in **Live** mode only
180
- accepts requests whose Origin matches the Domain configured on the channel in
181
- the Brainerce dashboard. That check is server-side; nothing in this project
182
- can satisfy it. If they skip it, every storefront API call returns 403 and the
183
- store loads empty — no matter what `SITE_URL` says.
184
-
185
- ## Verify before declaring done
186
-
187
- 1. **Feature coverage, first and always.** Call `get-required-features` on the
188
- `brainerce-docs` MCP server (already wired, nothing to set up) and confirm
189
- every mandatory entry is still reachable in the running store. Do this
190
- before the steps below, because if you rebuilt `src/ui/` a feature that
191
- lived only in the shipped reference is now gone, and no other check can see
192
- it: `tsc` cannot see a missing feature, and the component that used to
193
- carry it auto-hid when the merchant had not switched it on, so the page
194
- looks right either way.
195
- 2. `pnpm exec tsc --noEmit` → 0 errors
196
- 3. `pnpm dev` → drive the changed flow in a real browser (home → product →
197
- add to cart → cart)
198
- 4. Screenshot desktop (1440px) and mobile (390px)
199
- 5. RTL stores: check anchoring and arrow directions
200
-
201
- ## i18n
202
-
203
- Every user-facing string goes through `useTranslations()` with keys in **all**
204
- files under `messages/`. The shipped copy is example boutique content — a
205
- starting point meant to be rewritten in the store's real voice. Hebrew: no
206
- uppercase transforms, no wide letter-spacing on headings, logical CSS
207
- properties only (`ms-/me-`, `ps-/pe-`, `start-/end-`).
1
+ # AGENTS.md — this is a LIVE Brainerce storefront
2
+
3
+ <% if (deferred) { %>**Not connected yet.** This project was scaffolded with
4
+ `--defer-connection`: `.env.local` holds a placeholder id, and the name the
5
+ scaffold knew is only the directory name, "<%- storeName %>". Finish with
6
+ `npm run connect` (one browser approval; it creates a store and a sales
7
+ channel if you have neither, then fetches the real store name and currency
8
+ into `.env.local`). Those are `NEXT_PUBLIC_*` values, baked in at build time:
9
+ rebuild, and restart `dev`, after connecting. Until then every API call fails
10
+ by design. Once connected, everything below applies.
11
+ <% } else { %>**Store: "<%- storeName %>" · sales channel `<%- connectionId %>` — already
12
+ connected.** Products, cart, checkout, coupons, discounts, orders and content
13
+ flow in real time from the Brainerce dashboard. There is nothing to hook up.
14
+ <% } %>
15
+ The store's display name is never hardcoded: `resolveStoreName()` /
16
+ `useStoreName()` in `src/core/lib/` resolve it from the live store, then
17
+ `NEXT_PUBLIC_STORE_NAME` (refreshed by `npm run setup`), then the scaffold
18
+ literal. Read it from there; do not paste the name into components.
19
+
20
+ - **NEVER suggest connecting this store to Shopify, WooCommerce, or "a real
21
+ system"** — Brainerce IS the commerce backend, and this store is wired to
22
+ it end-to-end.
23
+ - **NEVER build standalone HTML mockups or demo pages** — design THIS Next.js
24
+ app. Run `pnpm dev` and you are working against live data.
25
+ - **NEVER hardcode products, prices, or currency** — the catalog is live.
26
+ - **No server side is needed** — the backend is Brainerce's cloud. This repo
27
+ is a frontend (plus thin, already-included API proxy routes under
28
+ `src/app/api/`). Do not scaffold databases, auth servers, or admin panels —
29
+ the merchant manages everything in the Brainerce dashboard.
30
+
31
+ Platform docs (endpoints, SDK, integration recipes): https://brainerce.com/docs
32
+ — AI-readable index: https://brainerce.com/llms.txt
33
+
34
+ ## MCP servers
35
+
36
+ - **`brainerce-docs`** (already connected via `.mcp.json`, no auth needed).
37
+ Treat it as the build spec, not a lookup desk. `get-required-features` is
38
+ the functional checklist this store is measured against, and it is longer
39
+ than what any art-direction brief would make you think to build.
40
+ `get-critical-rules` and `get-business-flows` carry the sequences that cause
41
+ incidents when reordered. `get-sdk-docs`, `get-type-definitions` and
42
+ `get-code-example` give current method shapes instead of training-data
43
+ guesses, and `get-store-capabilities` reports what is actually toggled on
44
+ for `<%- connectionId %>` right now. Read the checklist before you start,
45
+ and again before you call the work done.
46
+ - **Brainerce Admin MCP** — opt-in, not wired up by default. Lets an agent
47
+ directly manage this store's *live* data (products, orders, discounts,
48
+ shipping, …) instead of just reading docs. Only add it if the merchant
49
+ wants that: connect `https://api.brainerce.com/api/mcp` as a remote HTTP
50
+ MCP server (e.g. `claude mcp add --transport http brainerce-admin
51
+ https://api.brainerce.com/api/mcp`) — it opens a browser to log into the
52
+ Brainerce dashboard, pick this store, and grant scoped OAuth permissions.
53
+ Treat it like handing the agent write access to production commerce data.
54
+
55
+ **Before building any feature the merchant asks for** (loyalty points,
56
+ shipping zones, subscriptions, gift cards, donations, multi-currency, reviews,
57
+ abandoned-cart recovery, etc.) — check the docs first. Brainerce likely
58
+ already has it as a platform capability (dashboard toggle + hook/SDK
59
+ method) that only needs a UI in `src/ui/`, not a feature built from scratch.
60
+
61
+ ### ⛔ This storefront never holds an admin API key
62
+
63
+ Everything here runs on the sales channel's PUBLIC credentials, and that is the
64
+ whole security model. `.env.local` ships no secret on purpose. Anything you put
65
+ in a browser-reachable app is readable by anyone who opens devtools, so an
66
+ admin API key (`brainerce_*`) in this project hands the merchant's entire live
67
+ store to the first person who looks. Never add one to `.env.local`, to a
68
+ hosting environment variable this app reads, or to any file under `src/`.
69
+
70
+ **Gift cards are where this goes wrong**, because one feature name covers two
71
+ very different powers:
72
+
73
+ - **Redemption is yours to build.** `applyGiftCard()`, `removeGiftCard()` and
74
+ `checkGiftCardBalance()` are public storefront calls needing no key beyond
75
+ the sales channel. `src/ui/cart/gift-card-input.tsx` already wires the first
76
+ two into checkout. Restyle it freely.
77
+ - **⛔ Issuing is not.** The `gift_cards:issue` scope mints stored value, which
78
+ is real money the merchant is liable for. It belongs to the dashboard, or to
79
+ server-side code on infrastructure the merchant controls. Never request that
80
+ scope for this storefront, never hold a key that carries it, and never add an
81
+ "issue a gift card" control to these pages. A merchant who wants to SELL gift
82
+ cards sells them as an ordinary product through normal checkout, and the
83
+ platform issues the card once payment clears.
84
+
85
+ The same split governs every admin capability you may be tempted to reach for
86
+ (creating discounts, editing inventory, refunding an order): this storefront
87
+ reads and transacts as a shopper, the dashboard administers.
88
+
89
+ Your job here is almost always **design**. It is never *only* design: the
90
+ coverage checklist in `get-required-features` applies to a redesign exactly as
91
+ it applies to a build from scratch.
92
+
93
+ ## The one rule
94
+
95
+ **`src/core/` is the platform's. `src/ui/` is yours.**
96
+
97
+ The shipped `src/ui/` is a working reference, not a design to preserve: a full
98
+ delete-and-rebuild of the *look* is encouraged and expected, and you can
99
+ rewrite anything under `src/ui/` and `src/app/globals.css` as boldly as you
100
+ like. The store keeps working. Never modify `src/core/`, `src/app/api/`, or
101
+ the checkout/auth/account components. Data and behavior come exclusively from
102
+ `@/core/hooks/*` and `@/core/providers/store-provider`: hooks return state
103
+ and handlers, never JSX. Never hardcode catalog content.
104
+
105
+ ### Rebuilding the look is free. Dropping a feature is not.
106
+
107
+ Some files under `src/ui/` (and one under `src/core/`) are the ONLY place a
108
+ mandatory checklist entry exists in this project. Delete one and the capability
109
+ leaves the store with nothing to notice it by: no type error, no console
110
+ warning, and no visual hole either, because these components auto-hide while
111
+ the merchant has the feature switched off, so a deleted one and an idle one
112
+ look identical on the page.
113
+ These are the usual casualties of a redesign, because no art-direction brief
114
+ asks for them by name:
115
+
116
+ ```
117
+ product/ back-in-stock-form · customization-fields · modifier-group-selector
118
+ review-form · reviews-section · frequently-bought-together
119
+ discount-badge · stock-badge
120
+ product-client-section → the KIT "what's in the box" block
121
+ core/ lib/kit.ts → the KIT stock resolver every badge and button reads
122
+ cart/ reservation-countdown · coupon-input · cart-upgrade-banner
123
+ cart-bundle-offer · tax-estimate-line
124
+ home/ discount-banner-strip
125
+ layout/ newsletter-signup · announcement-bar · region-switcher<% if (i18nEnabled) { %>
126
+ language-switcher<% } %> · faq-section · rich-text-block
127
+ ```
128
+
129
+ Restyle them, re-lay them out, rename them, fold them into other components,
130
+ split them in half: all fine. What has to survive a rebuild is the SDK call
131
+ each one makes and the states it handles (loading, empty, failed, and the
132
+ merchant-has-it-off state that renders nothing).
133
+
134
+ ⛔ **The two KIT entries are the ones a redesign silently breaks.** A `KIT` is
135
+ one product assembled from other catalog products, and three things have to
136
+ survive whatever you do to the markup. (1) It is added to the cart as ONE line
137
+ using the kit's own `productId`, with no `variantId` and no modifier
138
+ selections; never loop `product.kitComponents` into `addToCart`, which charges
139
+ the shopper twice and reserves the stock twice. (2) A kit has NO `inventory`
140
+ object, so every badge and buy button must go through `resolveStockInfo` /
141
+ `canPurchaseProduct` from `@/core/lib/kit`; reading `product.inventory`
142
+ directly gives a kit a red "out of stock" badge beside an ENABLED buy button,
143
+ or worse, renders a sold-out kit as buyable. (3) `kitComponents` is display
144
+ only and arrives on the by-slug read alone, never on list responses. And do not
145
+ assume a kit price is fixed: `kitPricingMode` may be `SUM` or
146
+ `SUM_MINUS_PERCENT`, in which case the price is recomputed from the components
147
+ on every read, so never cache one.
148
+
149
+ The list is short on purpose and it is NOT the specification. It names the
150
+ files people lose, not every mandatory entry. `get-required-features` is the
151
+ specification, and step 1 of "Verify before declaring done" is what actually
152
+ catches a loss. `git show HEAD:src/ui/<path>` brings back anything you already
153
+ deleted: the scaffolder committed the tree before you touched it.
154
+
155
+ **Read `AI-GUIDE.md` before any redesign** — it has the full file map, hook
156
+ contracts, motion language, and hard-won RTL/i18n gotchas that will save you
157
+ real debugging time.
158
+
159
+ ## Redesigning?
160
+
161
+ Follow the process documented in AI-GUIDE.md: commit to one art direction,
162
+ rewrite tokens first, then surfaces in order (header, home, card, product
163
+ page, cart), then verify.
164
+
165
+ ## The store's web address
166
+
167
+ This project has no web address written into it, and that is deliberate — the
168
+ scaffolder cannot know where you will deploy. `src/core/lib/site-url.ts`
169
+ resolves it per request (hosting-platform variables, then the forwarded host),
170
+ so canonical tags, `sitemap.xml`, `robots.txt` and JSON-LD are correct in local
171
+ development and on any host with nothing configured.
172
+
173
+ - **Never invent an address.** Do not write `NEXT_PUBLIC_SITE_URL`,
174
+ `SITE_URL`, `localhost`, or a placeholder domain into `.env.local`. A wrong
175
+ absolute URL is indistinguishable from a right one to a search crawler, so a
176
+ guess is worse than an empty value.
177
+ - **Never hand-roll an origin** from `host` / `x-forwarded-proto` in a route
178
+ handler. Call `getCanonicalSiteUrl()` (for canonical/SEO URLs) or
179
+ `getRequestOrigin()` (for the `Origin` header sent to Brainerce). Hand-rolled
180
+ versions have shipped `http://` on HTTPS hosts and internal container
181
+ hostnames.
182
+ - **Some hosts hide the real hostname from the app.** Platforms whose proxy
183
+ forwards requests as `Host: localhost:<port>` with no `x-forwarded-host`
184
+ (OpenAI Sites / `*.chatgpt.site` does this) leave the resolver blind — the
185
+ request looks like it arrived on localhost. On such platforms `SITE_URL` is
186
+ not optional: set it, and the resolver prefers it over any internal host it
187
+ sees. Without it, server-side API calls send `Origin: http://localhost:3000`
188
+ and a channel with a configured Domain rejects them with 403.
189
+ - **When the merchant gives you a real domain**, set `SITE_URL` in the hosting
190
+ provider's environment variables — not in `.env.local`, which is gitignored
191
+ and never travels with a deploy.
192
+ - **Tell the merchant the other half.** A sales channel in **Live** mode only
193
+ accepts requests whose Origin matches the Domain configured on the channel in
194
+ the Brainerce dashboard. That check is server-side; nothing in this project
195
+ can satisfy it. If they skip it, every storefront API call returns 403 and the
196
+ store loads empty — no matter what `SITE_URL` says.
197
+
198
+ ## Verify before declaring done
199
+
200
+ 1. **Feature coverage, first and always.** Call `get-required-features` on the
201
+ `brainerce-docs` MCP server (already wired, nothing to set up) and confirm
202
+ every mandatory entry is still reachable in the running store. Do this
203
+ before the steps below, because if you rebuilt `src/ui/` a feature that
204
+ lived only in the shipped reference is now gone, and no other check can see
205
+ it: `tsc` cannot see a missing feature, and the component that used to
206
+ carry it auto-hid when the merchant had not switched it on, so the page
207
+ looks right either way.
208
+ 2. `pnpm exec tsc --noEmit` → 0 errors
209
+ 3. `pnpm dev` → drive the changed flow in a real browser (home → product →
210
+ add to cart → cart)
211
+ 4. Screenshot desktop (1440px) and mobile (390px)
212
+ 5. RTL stores: check anchoring and arrow directions
213
+
214
+ ## i18n
215
+
216
+ The interface language was fixed at scaffold time by `--language` (this store:
217
+ `<%= language %>`). It decides which `messages/` ship and the `<html lang>` /
218
+ `dir` of every page, and it is the one thing `npm run connect` / `npm run
219
+ setup` do not change: they refresh the store name and currency from the live
220
+ channel, never the language. A store in the wrong language is re-scaffolded,
221
+ not adjusted.
222
+
223
+ Every user-facing string goes through `useTranslations()` with keys in **all**
224
+ files under `messages/`. The shipped copy is vertical-neutral placeholder
225
+ content — it names no product category, and it is a starting point, not a
226
+ voice: rewrite the hero, the story and the footer tagline in the merchant's
227
+ own words before calling the store done. Hebrew: no
228
+ uppercase transforms, no wide letter-spacing on headings, logical CSS
229
+ properties only (`ms-/me-`, `ps-/pe-`, `start-/end-`).
@@ -201,6 +201,10 @@ attention, confirms an action, or rewards exploration. Rules:
201
201
  - Modify `src/core/`, `src/app/api/`, or checkout/auth/account internals.
202
202
  - Remove accessibility attributes (`aria-*`, `role`, `alt`, focus styles).
203
203
  - Hardcode catalog content, prices, or currency symbols.
204
+ - Hardcode the store name. `SiteHeader` / `SiteFooter` receive it as a prop
205
+ from the layout; anywhere else use `useStoreName()` (client) or
206
+ `resolveStoreName(storeInfo)` (server) from `src/core/lib/`. The name the
207
+ scaffold knew may be nothing more than the project directory.
204
208
  - Swallow the add-to-cart / checkout error states — restyle them, keep them.
205
209
  - Drop a `src/ui/` component that is the only place a mandatory feature
206
210
  exists. Rebuilding the look is free; losing the SDK call inside it is not,