@unbox-plus/cli 0.20.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. package/LICENSE.md +46 -0
  2. package/README.md +175 -0
  3. package/bin/cli.js +439 -0
  4. package/package.json +43 -0
  5. package/src/colors.js +100 -0
  6. package/src/presets.js +241 -0
  7. package/src/theme.js +253 -0
  8. package/template/.claude/agents/assets-marca.md +40 -0
  9. package/template/.claude/agents/avaliador-visual.md +48 -0
  10. package/template/.claude/agents/branding-briefing.md +401 -0
  11. package/template/.claude/agents/conteudo-secao.md +46 -0
  12. package/template/.claude/agents/paginas-legais.md +44 -0
  13. package/template/.claude/settings.json +3 -0
  14. package/template/.claude/skills/frontend-design/ATTRIBUTION.md +3 -0
  15. package/template/.claude/skills/frontend-design/LICENSE.txt +177 -0
  16. package/template/.claude/skills/frontend-design/SKILL.md +55 -0
  17. package/template/.claude/skills/web-design-guidelines/ATTRIBUTION.md +3 -0
  18. package/template/.claude/skills/web-design-guidelines/SKILL.md +50 -0
  19. package/template/.claude/skills/web-design-guidelines/guidelines-snapshot.md +180 -0
  20. package/template/.env.example +158 -0
  21. package/template/.mcp.json.example +14 -0
  22. package/template/.nvmrc +1 -0
  23. package/template/CLAUDE.md +333 -0
  24. package/template/COVERAGE.md +80 -0
  25. package/template/DEPLOY.md +179 -0
  26. package/template/QA.md +108 -0
  27. package/template/README.md +152 -0
  28. package/template/agents/CONSTRUCAO.md +207 -0
  29. package/template/agents/MANAGER.md +192 -0
  30. package/template/agents/PADROES.md +255 -0
  31. package/template/agents/definitions/00-scaffold.md +56 -0
  32. package/template/agents/definitions/01-layout.md +47 -0
  33. package/template/agents/definitions/02-homepage.md +70 -0
  34. package/template/agents/definitions/03-catalog.md +86 -0
  35. package/template/agents/definitions/04-pdp.md +97 -0
  36. package/template/agents/definitions/05-cart.md +116 -0
  37. package/template/agents/definitions/06-checkout.md +146 -0
  38. package/template/agents/definitions/07-auth.md +130 -0
  39. package/template/agents/definitions/08-customer.md +55 -0
  40. package/template/agents/definitions/09-promotions.md +62 -0
  41. package/template/agents/definitions/10-feedback.md +128 -0
  42. package/template/agents/definitions/11-seo-infra.md +159 -0
  43. package/template/agents/definitions/12-deploy.md +173 -0
  44. package/template/agents/definitions/13-cro.md +275 -0
  45. package/template/agents/definitions/14-seo.md +388 -0
  46. package/template/agents/definitions/15-branding.md +26 -0
  47. package/template/agents/definitions/16-qa-visual.md +138 -0
  48. package/template/agents/definitions/17-aeo.md +257 -0
  49. package/template/app/(loja)/busca/page.tsx +72 -0
  50. package/template/app/(loja)/carrinho/oferta/page.tsx +57 -0
  51. package/template/app/(loja)/carrinho/page.tsx +160 -0
  52. package/template/app/(loja)/categoria/[tagSlug]/layout.tsx +31 -0
  53. package/template/app/(loja)/categoria/[tagSlug]/loading.tsx +17 -0
  54. package/template/app/(loja)/categoria/[tagSlug]/page.tsx +49 -0
  55. package/template/app/(loja)/checkout/page.tsx +80 -0
  56. package/template/app/(loja)/checkout/pix/[ref]/page.tsx +133 -0
  57. package/template/app/(loja)/conta/assinaturas/[referenceId]/page.tsx +112 -0
  58. package/template/app/(loja)/conta/assinaturas/page.tsx +51 -0
  59. package/template/app/(loja)/conta/enderecos/page.tsx +20 -0
  60. package/template/app/(loja)/conta/entrar/page.tsx +119 -0
  61. package/template/app/(loja)/conta/page.tsx +45 -0
  62. package/template/app/(loja)/conta/pedidos/[referenceId]/page.tsx +49 -0
  63. package/template/app/(loja)/conta/pedidos/page.tsx +104 -0
  64. package/template/app/(loja)/conta/preferencias/page.tsx +24 -0
  65. package/template/app/(loja)/devolucoes/page.tsx +36 -0
  66. package/template/app/(loja)/layout.tsx +22 -0
  67. package/template/app/(loja)/oferta/page.tsx +57 -0
  68. package/template/app/(loja)/page.tsx +86 -0
  69. package/template/app/(loja)/pedido/[referenceId]/page.tsx +78 -0
  70. package/template/app/(loja)/privacidade/page.tsx +113 -0
  71. package/template/app/(loja)/produto/[productSlug]/layout.tsx +23 -0
  72. package/template/app/(loja)/produto/[productSlug]/loading.tsx +20 -0
  73. package/template/app/(loja)/produto/[productSlug]/page.tsx +372 -0
  74. package/template/app/(loja)/produtos/loading.tsx +16 -0
  75. package/template/app/(loja)/produtos/page.tsx +33 -0
  76. package/template/app/(loja)/termos/page.tsx +104 -0
  77. package/template/app/acesso/page.tsx +129 -0
  78. package/template/app/api/account/addresses/route.ts +39 -0
  79. package/template/app/api/account/exists/route.ts +21 -0
  80. package/template/app/api/account/me/route.ts +25 -0
  81. package/template/app/api/account/otp/route.ts +26 -0
  82. package/template/app/api/account/preferences/route.ts +19 -0
  83. package/template/app/api/account/signin/route.ts +27 -0
  84. package/template/app/api/account/signout/route.ts +9 -0
  85. package/template/app/api/acesso/route.ts +171 -0
  86. package/template/app/api/capi/route.ts +34 -0
  87. package/template/app/api/cart/coupon/route.ts +49 -0
  88. package/template/app/api/cart/items/route.ts +45 -0
  89. package/template/app/api/cart/link/route.ts +69 -0
  90. package/template/app/api/cart/route.ts +113 -0
  91. package/template/app/api/cart/share/route.ts +21 -0
  92. package/template/app/api/cep/[code]/route.ts +18 -0
  93. package/template/app/api/checkout/address/route.ts +24 -0
  94. package/template/app/api/checkout/email/route.ts +41 -0
  95. package/template/app/api/checkout/installments/route.ts +16 -0
  96. package/template/app/api/checkout/route.ts +110 -0
  97. package/template/app/api/checkout/shipping/route.ts +65 -0
  98. package/template/app/api/checkout-destination/route.ts +31 -0
  99. package/template/app/api/order/[ref]/route.ts +17 -0
  100. package/template/app/api/payment-link/route.ts +28 -0
  101. package/template/app/api/revalidate/route.ts +52 -0
  102. package/template/app/api/shipping/quote/route.ts +29 -0
  103. package/template/app/api/subscriptions/[id]/route.ts +52 -0
  104. package/template/app/api/track/route.ts +28 -0
  105. package/template/app/api/unbox/catalogo/route.ts +136 -0
  106. package/template/app/api/unbox/paginas/route.ts +167 -0
  107. package/template/app/api/unbox/vitrine/route.ts +84 -0
  108. package/template/app/api/webhooks/unbox/route.ts +97 -0
  109. package/template/app/apple-icon.svg +5 -0
  110. package/template/app/error.tsx +15 -0
  111. package/template/app/globals.css +457 -0
  112. package/template/app/icon.svg +4 -0
  113. package/template/app/layout.tsx +90 -0
  114. package/template/app/llms.txt/route.ts +43 -0
  115. package/template/app/manifest.ts +21 -0
  116. package/template/app/not-found.tsx +18 -0
  117. package/template/app/opengraph-image.tsx +35 -0
  118. package/template/app/robots.ts +31 -0
  119. package/template/app/sitemap.ts +42 -0
  120. package/template/bootstrap.sh +87 -0
  121. package/template/components/account/account-shell.tsx +47 -0
  122. package/template/components/account/address-book.tsx +147 -0
  123. package/template/components/account/preferences-form.tsx +77 -0
  124. package/template/components/account/reorder-button.tsx +47 -0
  125. package/template/components/account/signout-button.tsx +20 -0
  126. package/template/components/account/subscription-actions.tsx +204 -0
  127. package/template/components/account-nav.tsx +41 -0
  128. package/template/components/address-fields.tsx +102 -0
  129. package/template/components/analytics/data-layer-ready.tsx +16 -0
  130. package/template/components/analytics/purchase-tracker.tsx +32 -0
  131. package/template/components/brand-search.tsx +34 -0
  132. package/template/components/cart/cart-provider.tsx +340 -0
  133. package/template/components/cart/mini-cart.tsx +228 -0
  134. package/template/components/cart-button.tsx +35 -0
  135. package/template/components/catalog/catalog-client.tsx +523 -0
  136. package/template/components/catalog/grid-skeleton.tsx +19 -0
  137. package/template/components/catalog/pager.tsx +66 -0
  138. package/template/components/catalog/product-grid-card.tsx +52 -0
  139. package/template/components/catalog/product-grid.tsx +27 -0
  140. package/template/components/checkout/checkout-client.tsx +1333 -0
  141. package/template/components/chrome/announce-bar.tsx +57 -0
  142. package/template/components/chrome/chrome-recipe.ts +13 -0
  143. package/template/components/chrome/footers/captura-botao.tsx +28 -0
  144. package/template/components/chrome/footers/colunas.tsx +110 -0
  145. package/template/components/chrome/footers/conversao.tsx +90 -0
  146. package/template/components/chrome/footers/editorial.tsx +98 -0
  147. package/template/components/chrome/footers/minimal.tsx +55 -0
  148. package/template/components/chrome/header-bar-mobile.tsx +64 -0
  149. package/template/components/chrome/headers/centralizado.tsx +71 -0
  150. package/template/components/chrome/headers/classico.tsx +64 -0
  151. package/template/components/chrome/headers/compacto.tsx +66 -0
  152. package/template/components/chrome/headers/equilibrado.tsx +73 -0
  153. package/template/components/chrome/headers/imersivo.tsx +62 -0
  154. package/template/components/chrome/registry.ts +70 -0
  155. package/template/components/chrome/solid-on-scroll.tsx +39 -0
  156. package/template/components/empty-state.tsx +22 -0
  157. package/template/components/home/combo-card-compact.tsx +67 -0
  158. package/template/components/home/combos-home.tsx +64 -0
  159. package/template/components/home/combos-section.tsx +177 -0
  160. package/template/components/home/home-recipe.ts +41 -0
  161. package/template/components/home/sections/attributes-marquee.tsx +178 -0
  162. package/template/components/home/sections/benefits.tsx +80 -0
  163. package/template/components/home/sections/bloco-html.tsx +47 -0
  164. package/template/components/home/sections/catalogo.ts +165 -0
  165. package/template/components/home/sections/category-pills.tsx +32 -0
  166. package/template/components/home/sections/combos-carousel.tsx +141 -0
  167. package/template/components/home/sections/comparison.tsx +73 -0
  168. package/template/components/home/sections/founder-story.tsx +40 -0
  169. package/template/components/home/sections/hero.tsx +187 -0
  170. package/template/components/home/sections/kits.tsx +11 -0
  171. package/template/components/home/sections/media-cards.tsx +70 -0
  172. package/template/components/home/sections/newsletter.tsx +62 -0
  173. package/template/components/home/sections/product-showcase.tsx +175 -0
  174. package/template/components/home/sections/purchase-hero.tsx +187 -0
  175. package/template/components/home/sections/quote-banner.tsx +50 -0
  176. package/template/components/home/sections/registry.ts +186 -0
  177. package/template/components/home/sections/reviews-carousel.tsx +66 -0
  178. package/template/components/home/sections/reviews.tsx +68 -0
  179. package/template/components/home/sections/ritual.tsx +96 -0
  180. package/template/components/home/sections/savings.tsx +47 -0
  181. package/template/components/home/sections/social-row.tsx +65 -0
  182. package/template/components/home/sections/spec-table.tsx +117 -0
  183. package/template/components/home/sections/stars.tsx +12 -0
  184. package/template/components/home/sections/stats-grid.tsx +54 -0
  185. package/template/components/home/sections/trust-bar.tsx +56 -0
  186. package/template/components/home/sections/trust-strip.tsx +40 -0
  187. package/template/components/home/sections/video-wall.tsx +59 -0
  188. package/template/components/landing/landing-recipe.ts +20 -0
  189. package/template/components/landing/oferta-sections.tsx +40 -0
  190. package/template/components/landing/product-picker.tsx +257 -0
  191. package/template/components/mobile-nav.tsx +71 -0
  192. package/template/components/order-status.tsx +163 -0
  193. package/template/components/powered-by-unbox.tsx +27 -0
  194. package/template/components/product/pdp/buy-box.tsx +604 -0
  195. package/template/components/product/pdp/catalog-grid.tsx +113 -0
  196. package/template/components/product/pdp/faq-modelo.ts +86 -0
  197. package/template/components/product/pdp/gallery.tsx +87 -0
  198. package/template/components/product/pdp/interactive.tsx +200 -0
  199. package/template/components/product/pdp/newsletter.tsx +64 -0
  200. package/template/components/product/pdp/payment-chips.tsx +22 -0
  201. package/template/components/product/pdp/pdp-view.tsx +227 -0
  202. package/template/components/product/pdp/recommendations.tsx +144 -0
  203. package/template/components/product/pdp/sections.tsx +173 -0
  204. package/template/components/quantity-stepper.tsx +36 -0
  205. package/template/components/search-box.tsx +37 -0
  206. package/template/components/site-footer.tsx +59 -0
  207. package/template/components/site-header.tsx +64 -0
  208. package/template/components/ui/accordion.tsx +72 -0
  209. package/template/components/ui/alert-dialog.tsx +187 -0
  210. package/template/components/ui/alert.tsx +76 -0
  211. package/template/components/ui/aspect-ratio.tsx +22 -0
  212. package/template/components/ui/avatar.tsx +109 -0
  213. package/template/components/ui/badge.tsx +52 -0
  214. package/template/components/ui/breadcrumb.tsx +125 -0
  215. package/template/components/ui/button.tsx +58 -0
  216. package/template/components/ui/card.tsx +103 -0
  217. package/template/components/ui/carousel.tsx +242 -0
  218. package/template/components/ui/command.tsx +196 -0
  219. package/template/components/ui/dialog.tsx +160 -0
  220. package/template/components/ui/dropdown-menu.tsx +268 -0
  221. package/template/components/ui/foto.tsx +54 -0
  222. package/template/components/ui/input-group.tsx +158 -0
  223. package/template/components/ui/input-otp.tsx +87 -0
  224. package/template/components/ui/input.tsx +20 -0
  225. package/template/components/ui/label.tsx +20 -0
  226. package/template/components/ui/navigation-menu.tsx +168 -0
  227. package/template/components/ui/pagination.tsx +132 -0
  228. package/template/components/ui/popover.tsx +90 -0
  229. package/template/components/ui/progress.tsx +83 -0
  230. package/template/components/ui/radio-group.tsx +38 -0
  231. package/template/components/ui/scroll-area.tsx +55 -0
  232. package/template/components/ui/select.tsx +201 -0
  233. package/template/components/ui/separator.tsx +25 -0
  234. package/template/components/ui/sheet.tsx +138 -0
  235. package/template/components/ui/skeleton.tsx +13 -0
  236. package/template/components/ui/sonner.tsx +44 -0
  237. package/template/components/ui/switch.tsx +32 -0
  238. package/template/components/ui/table.tsx +116 -0
  239. package/template/components/ui/tabs.tsx +82 -0
  240. package/template/components/ui/textarea.tsx +18 -0
  241. package/template/components/ui/toggle-group.tsx +89 -0
  242. package/template/components/ui/toggle.tsx +45 -0
  243. package/template/components/ui/tooltip.tsx +66 -0
  244. package/template/components.json +25 -0
  245. package/template/eslint.config.mjs +36 -0
  246. package/template/gitignore +21 -0
  247. package/template/lib/analytics.ts +369 -0
  248. package/template/lib/api.ts +60 -0
  249. package/template/lib/capi.ts +87 -0
  250. package/template/lib/cart-link.ts +51 -0
  251. package/template/lib/cart-normalize.ts +142 -0
  252. package/template/lib/cart-recovery.ts +23 -0
  253. package/template/lib/cart-response.ts +48 -0
  254. package/template/lib/catalog-map.ts +54 -0
  255. package/template/lib/catalog.ts +3 -0
  256. package/template/lib/checkout-lock.ts +21 -0
  257. package/template/lib/checkout-nav.ts +22 -0
  258. package/template/lib/config.ts +51 -0
  259. package/template/lib/crm.ts +40 -0
  260. package/template/lib/customer-session.ts +21 -0
  261. package/template/lib/dataloader.ts +23 -0
  262. package/template/lib/editable/config.ts +11 -0
  263. package/template/lib/editable/document.ts +1762 -0
  264. package/template/lib/editable/index.ts +3 -0
  265. package/template/lib/editable/primitives.tsx +821 -0
  266. package/template/lib/editable/provider.tsx +861 -0
  267. package/template/lib/editable/rastreio-navegacao.tsx +65 -0
  268. package/template/lib/editable/rastreio.tsx +168 -0
  269. package/template/lib/editable/server.ts +189 -0
  270. package/template/lib/editable/tokens.ts +22 -0
  271. package/template/lib/editable/verify.ts +24 -0
  272. package/template/lib/enrichment/combos.ts +184 -0
  273. package/template/lib/enrichment/index.ts +188 -0
  274. package/template/lib/enrichment/products.json +1 -0
  275. package/template/lib/env-check.ts +47 -0
  276. package/template/lib/format.ts +130 -0
  277. package/template/lib/icons.ts +67 -0
  278. package/template/lib/json-ld.ts +9 -0
  279. package/template/lib/llms-txt.ts +75 -0
  280. package/template/lib/mockup.ts +24 -0
  281. package/template/lib/newsletter.ts +12 -0
  282. package/template/lib/orders.ts +160 -0
  283. package/template/lib/queries.ts +66 -0
  284. package/template/lib/ratelimit.ts +47 -0
  285. package/template/lib/rotas-editaveis.ts +192 -0
  286. package/template/lib/sanitize.ts +36 -0
  287. package/template/lib/schemas.ts +78 -0
  288. package/template/lib/session.ts +98 -0
  289. package/template/lib/store-config.ts +67 -0
  290. package/template/lib/unbox/client.ts +829 -0
  291. package/template/lib/unbox/customer.ts +224 -0
  292. package/template/lib/unbox/errors.ts +97 -0
  293. package/template/lib/unbox/index.ts +10 -0
  294. package/template/lib/unbox/store.ts +113 -0
  295. package/template/lib/unbox/types.ts +195 -0
  296. package/template/lib/unbox/webhooks.ts +66 -0
  297. package/template/lib/utils.ts +6 -0
  298. package/template/lib/vitrine.ts +242 -0
  299. package/template/lib/webhook-store.ts +22 -0
  300. package/template/middleware.ts +178 -0
  301. package/template/next.config.ts +63 -0
  302. package/template/package.json +62 -0
  303. package/template/postcss.config.mjs +5 -0
  304. package/template/public/brand/coll/default.png +0 -0
  305. package/template/public/brand/hero-desktop.svg +12 -0
  306. package/template/public/brand/hero-mobile.svg +12 -0
  307. package/template/public/brand/heros/boutique-desktop.svg +11 -0
  308. package/template/public/brand/heros/boutique-mobile.svg +11 -0
  309. package/template/public/brand/heros/editorial-desktop.svg +11 -0
  310. package/template/public/brand/heros/editorial-mobile.svg +11 -0
  311. package/template/public/brand/heros/essencial-desktop.svg +12 -0
  312. package/template/public/brand/heros/essencial-mobile.svg +12 -0
  313. package/template/public/brand/heros/promocional-desktop.svg +12 -0
  314. package/template/public/brand/heros/promocional-mobile.svg +12 -0
  315. package/template/public/brand/logo-chrome.svg +6 -0
  316. package/template/public/brand/logo-white.svg +6 -0
  317. package/template/public/brand/logo.svg +7 -0
  318. package/template/public/brand/pay-amex.webp +0 -0
  319. package/template/public/brand/pay-elo.webp +0 -0
  320. package/template/public/brand/pay-mastercard.webp +0 -0
  321. package/template/public/brand/pay-pix.webp +0 -0
  322. package/template/public/brand/pay-visa.webp +0 -0
  323. package/template/public/brand/ph/avatar-a.svg +5 -0
  324. package/template/public/brand/ph/avatar-b.svg +5 -0
  325. package/template/public/brand/ph/avatar-c.svg +5 -0
  326. package/template/public/brand/ph/avatar-d.svg +5 -0
  327. package/template/public/brand/ph/photo-a.svg +7 -0
  328. package/template/public/brand/ph/photo-b.svg +6 -0
  329. package/template/public/brand/ph/photo-c.svg +6 -0
  330. package/template/public/brand/ph/poster-a.svg +6 -0
  331. package/template/public/brand/ph/poster-b.svg +6 -0
  332. package/template/public/brand/ph/poster-c.svg +6 -0
  333. package/template/public/unbox/powered-by-fundo-preto.png +0 -0
  334. package/template/public/unbox/powered-by-transparente.png +0 -0
  335. package/template/public/unbox/powered-by.png +0 -0
  336. package/template/scripts/abandoned-cart.ts +82 -0
  337. package/template/scripts/check-editable.mjs +467 -0
  338. package/template/scripts/check-honestidade.mjs +111 -0
  339. package/template/scripts/check-placeholder.mjs +200 -0
  340. package/template/scripts/check-recipe.mjs +76 -0
  341. package/template/scripts/check-unbox-brand.mjs +298 -0
  342. package/template/scripts/contraste.js +177 -0
  343. package/template/scripts/dump-catalog.ts +95 -0
  344. package/template/scripts/load-env.ts +13 -0
  345. package/template/scripts/medir-sistema.mjs +56 -0
  346. package/template/scripts/place-order-pix.ts +61 -0
  347. package/template/scripts/qa-screenshots.mjs +150 -0
  348. package/template/scripts/sistema.py +231 -0
  349. package/template/scripts/subscribe-webhook.ts +36 -0
  350. package/template/scripts/test-live.ts +186 -0
  351. package/template/scripts/vocabulario.py +264 -0
  352. package/template/tsconfig.json +27 -0
  353. package/tools/LEIA-ME.md +39 -0
  354. package/tools/check-template-neutro.mjs +111 -0
  355. package/tools/notion-doc.mjs +191 -0
  356. package/tools/tokenize-neutrals.mjs +0 -0
  357. package/tools/tokenize-radius.mjs +52 -0
  358. package/tools/workflow-storefront.legado.js +1207 -0
@@ -0,0 +1,159 @@
1
+ # Agente 11 — SEO + Infraestrutura
2
+
3
+ > ⚠️ **Doc de plano (histórico).** A implementação entregue pela foundation difere em nomes e
4
+ > caminhos de arquivo citados abaixo. O mapa REAL de arquivos por área é a tabela "Agentes
5
+ > 00-11" do `agents/MANAGER.md` — em conflito, valem o MANAGER e o código.
6
+
7
+ ## Escopo
8
+ SEO técnico: sitemap dinâmico, robots.txt, metadados estruturados, JSON-LD e helpers de metadata.
9
+
10
+ ## Dependências
11
+ - Agente 00 (Scaffold) — `lib/metadata.ts` base
12
+
13
+ ## Arquivos proprietários
14
+
15
+ | Arquivo | Descrição |
16
+ |---------|-----------|
17
+ | `app/sitemap.ts` | Sitemap dinâmico com produtos + categorias |
18
+ | `app/robots.ts` | robots.txt com bloqueio de /conta e /api |
19
+ | `lib/metadata.ts` | Helpers buildMetadata, buildCategoryMetadata, buildProductJsonLd |
20
+ | `app/(loja)/pedido/[referenceId]/page.tsx` | Confirmação de pedido (noindex) |
21
+
22
+ ## lib/metadata.ts (completo)
23
+
24
+ ```ts
25
+ import type { Metadata } from "next"
26
+
27
+ const SITE = process.env.NEXT_PUBLIC_SITE_NAME ?? "Loja"
28
+ const URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://seudominio.com.br"
29
+
30
+ export function buildMetadata(
31
+ product: { title: string; pageTitle?: string; metaDescription?: string; description?: string; imageUrls?: string[]; slug: string },
32
+ canonical?: string,
33
+ ): Metadata {
34
+ const title = product.pageTitle ?? product.title
35
+ const description = product.metaDescription ?? product.description?.replace(/<[^>]+>/g, "").slice(0, 160)
36
+ const image = product.imageUrls?.[0]
37
+ const url = canonical ?? `${URL}/p/${product.slug}`
38
+ return {
39
+ title: `${title} | ${SITE}`,
40
+ description,
41
+ alternates: { canonical: url },
42
+ openGraph: {
43
+ title, description, url, type: "website",
44
+ images: image ? [{ url: image, alt: title, width: 800, height: 800 }] : [],
45
+ },
46
+ twitter: {
47
+ card: "summary_large_image", title, description,
48
+ images: image ? [image] : [],
49
+ },
50
+ robots: { index: true, follow: true },
51
+ }
52
+ }
53
+
54
+ export function buildCategoryMetadata(tag: {
55
+ name: string; displayTitle?: string; description?: string; slug: string
56
+ }): Metadata {
57
+ const title = tag.displayTitle ?? tag.name
58
+ return {
59
+ title: `${title} | ${SITE}`,
60
+ description: tag.description,
61
+ alternates: { canonical: `${URL}/c/${tag.slug}` },
62
+ }
63
+ }
64
+
65
+ export function buildProductJsonLd(product: {
66
+ title: string; description?: string; imageUrls?: string[];
67
+ variants?: Array<{ sku?: string | null }>
68
+ isSoldOut: boolean; pricing?: Array<{ price: number | null }>
69
+ }) {
70
+ return {
71
+ "@context": "https://schema.org",
72
+ "@type": "Product",
73
+ name: product.title,
74
+ description: product.description?.replace(/<[^>]+>/g, ""),
75
+ image: product.imageUrls ?? [],
76
+ sku: product.variants?.[0]?.sku,
77
+ offers: {
78
+ "@type": "Offer",
79
+ availability: product.isSoldOut
80
+ ? "https://schema.org/OutOfStock"
81
+ : "https://schema.org/InStock",
82
+ price: product.pricing?.[0]?.price ?? 0,
83
+ priceCurrency: "BRL",
84
+ },
85
+ }
86
+ }
87
+ ```
88
+
89
+ ## app/sitemap.ts — paginação correta
90
+
91
+ ```ts
92
+ // Iterar catálogo completo com paginação (não buscar tudo com first grande)
93
+ let offset = 0
94
+ for (;;) {
95
+ const page = await client.getCatalog({ first: 100, offset })
96
+ // processar page.nodes
97
+ if (!page.pageInfo?.hasNextPage) break
98
+ offset += 100
99
+ }
100
+ ```
101
+
102
+ ## app/robots.ts
103
+
104
+ ```ts
105
+ import type { MetadataRoute } from "next"
106
+ export default function robots(): MetadataRoute.Robots {
107
+ return {
108
+ rules: [
109
+ {
110
+ userAgent: "*",
111
+ allow: "/",
112
+ disallow: ["/conta/", "/checkout", "/pedido/", "/api/", "/busca?"],
113
+ },
114
+ ],
115
+ sitemap: `${process.env.NEXT_PUBLIC_SITE_URL}/sitemap.xml`,
116
+ }
117
+ }
118
+ ```
119
+
120
+ ## Variáveis NEXT_PUBLIC seguras
121
+
122
+ ```ts
123
+ // PERMITIDOS como NEXT_PUBLIC (não são credenciais):
124
+ NEXT_PUBLIC_SITE_NAME=Minha Loja
125
+ NEXT_PUBLIC_SITE_URL=https://seudominio.com.br
126
+
127
+ // PROIBIDOS como NEXT_PUBLIC:
128
+ // NEXT_PUBLIC_UNBOX_API_KEY ← NUNCA
129
+ // NEXT_PUBLIC_UNBOX_SHOP_ID ← evitar (não é credencial mas não precisa ser público)
130
+ ```
131
+
132
+ ## Página de confirmação de pedido
133
+
134
+ ```tsx
135
+ // app/(loja)/pedido/[referenceId]/page.tsx
136
+ export const metadata: Metadata = {
137
+ robots: { index: false, follow: false } // noindex — evitar indexar URLs de pedido
138
+ }
139
+
140
+ async function getOrder(referenceId: string) {
141
+ const client = await getUnboxClient()
142
+ // buscar por referenceId — ver SDK
143
+ return client.getOrderByReferenceId(referenceId)
144
+ }
145
+
146
+ // Status: orderStatusLabel(order.status) — NUNCA displayStatus(language)
147
+ // Rastreio: tracking.trackingCode (não trackingUrl no contexto cliente)
148
+ ```
149
+
150
+ ## Performance — checklist
151
+
152
+ ```
153
+ - getCatalog para homepage: unstable_cache({ revalidate: 300 })
154
+ - getProductBySlug (PDP): export const revalidate = 3600
155
+ - getTags: unstable_cache({ revalidate: 3600 })
156
+ - getShop/shopSales: unstable_cache({ revalidate: 300 })
157
+ - Sitemap: sem cache explícito (Next.js revalida conforme revalidate da rota)
158
+ - Imagens: next/image com sizes corretos para evitar oversized downloads
159
+ ```
@@ -0,0 +1,173 @@
1
+ # Agente 12 — Deploy (Vercel)
2
+
3
+ ## Escopo
4
+ Preparar e executar o primeiro deploy da loja no Vercel: Node version, env vars nos três
5
+ ambientes (Production / Preview / Development) e configuração do projeto.
6
+
7
+ **REGRA DE OURO DO PRIMEIRO DEPLOY: sem git, sem GitHub.** O `vercel` sobe a pasta local
8
+ direto, e a conta Vercel pode ser criada com email (na tela de login, ignorar o "Continue
9
+ with GitHub"). NUNCA peça pro lojista criar conta GitHub ou inicializar git pra ver a loja
10
+ no ar — isso é atrito desnecessário. Git/GitHub é um opcional de CI/CD pra DEPOIS da loja
11
+ publicada, e só se o cliente quiser.
12
+
13
+ ## Dependências
14
+ - Todos os outros agentes concluídos
15
+ - `.env.local` preenchido com as credenciais reais da loja
16
+ - Conta Vercel (login por email serve)
17
+
18
+ ## O que este agente faz
19
+
20
+ 1. Garante Node 22 LTS (`nvm use 22`)
21
+ 2. Remove lock file global que conflita com npm
22
+ 3. Valida conexão com a API Unbox antes de subir
23
+ 4. Cria projeto no Vercel e sobe as env vars
24
+ 5. Configura Framework Preset como **Next.js**
25
+ 6. Executa o primeiro deploy de produção (upload direto, sem repositório)
26
+ 7. (Opcional, se o cliente pedir) conecta GitHub pra redeploy automático
27
+
28
+ ---
29
+
30
+ ## Passo a passo
31
+
32
+ ### 1. Ambiente local
33
+
34
+ ```bash
35
+ nvm install 22 && nvm use 22 # Node 22 LTS obrigatório (v26 causa startup lento)
36
+ rm -f ~/package-lock.json # evita conflito com npm install
37
+ npm install
38
+ npm run unbox:test # valida credenciais antes de qualquer coisa
39
+ ```
40
+
41
+ ### 2. Vercel — entrar e linkar o projeto
42
+
43
+ ```bash
44
+ npx vercel login # abre o browser; login por email funciona (não precisa GitHub)
45
+ npx vercel link # cria novo projeto na conta (ou linka um existente)
46
+ ```
47
+
48
+ Durante o `vercel link`, responder:
49
+ - **Set up and deploy?** → No (vamos configurar antes)
50
+ - **Link to existing project?** → depende (Yes se já existe, No para criar)
51
+
52
+ ### 3. Env vars — CRÍTICO
53
+
54
+ Adicionar **todas** as variáveis **nos 3 ambientes** (Production + Preview + Development) antes do
55
+ primeiro build. Sem elas o build falha com `UnboxError: signin HTTP 403`.
56
+
57
+ #### Via CLI (recomendado — selecionar todos os 3 ambientes no prompt):
58
+
59
+ ```bash
60
+ npx vercel env add UNBOX_PARTNER_API_KEY # modelo recomendado (ou UNBOX_API_KEY, por loja)
61
+ npx vercel env add UNBOX_CAPTCHA_BYPASS # obrigatório com a key de parceiro (placeOrder/OTP)
62
+ npx vercel env add UNBOX_USER
63
+ npx vercel env add UNBOX_PASS
64
+ npx vercel env add SESSION_SECRET
65
+ npx vercel env add NEXT_PUBLIC_SITE_URL
66
+ npx vercel env add NEXT_PUBLIC_SITE_NAME
67
+ # opcionais mas recomendados:
68
+ npx vercel env add UNBOX_WEBHOOK_SECRET
69
+ npx vercel env add REVALIDATE_SECRET
70
+ ```
71
+
72
+ > Quando o CLI perguntar "Which environments?", escolher **Production, Preview, Development** (todos).
73
+
74
+ #### Ou via dashboard:
75
+
76
+ > Settings → Environment Variables → Add
77
+
78
+ Para cada variável, marcar os checkboxes: **Production ✅ Preview ✅ Development ✅**
79
+
80
+ | Variável | Obrigatório | Descrição |
81
+ |---|---|---|
82
+ | `UNBOX_PARTNER_API_KEY` | ✅ (recomendado) | Key única do parceiro; dispensa `UNBOX_API_KEY` |
83
+ | `UNBOX_CAPTCHA_BYPASS` | ✅ com key de parceiro | Segredo do header x-captcha-verification (sem ele: CAPTCHA_MALFORMED_ERROR no pagamento) |
84
+ | `UNBOX_API_KEY` | ✅ se não houver key de parceiro | Chave de API da loja (modelo antigo) |
85
+ | `UNBOX_USER` | ✅ | Usuário de API |
86
+ | `UNBOX_PASS` | ✅ | Senha de API |
87
+ | `SESSION_SECRET` | ✅ | String aleatória forte (≥ 32 chars) |
88
+ | `NEXT_PUBLIC_SITE_URL` | ✅ | URL pública (`https://minhaloja.com.br`) |
89
+ | `NEXT_PUBLIC_SITE_NAME` | ✅ | Nome da loja (título, OG, manifest, JSON-LD) |
90
+ | `UNBOX_SHOP_ID` | — | Extraído do JWT se vazio |
91
+ | `UNBOX_SHOP_SLUG` | — | Extraído do JWT se vazio |
92
+ | `UNBOX_WEBHOOK_SECRET` | — | Secret dos webhooks |
93
+ | `REVALIDATE_SECRET` | — | Protege `/api/revalidate` |
94
+ | `NEXT_PUBLIC_GA_ID` | — | GA4 measurement ID |
95
+ | `NEXT_PUBLIC_META_PIXEL_ID` | — | Meta Pixel ID |
96
+ | `META_CAPI_TOKEN` | — | Meta Conversions API token |
97
+
98
+ ### 4. Framework Preset — CRÍTICO
99
+
100
+ > Settings → Build & Development Settings → Framework Preset → **Next.js**
101
+
102
+ **Nunca deixar como "Other"** — o Vercel não configura o build command correto e o deploy falha.
103
+
104
+ ### 5. Primeiro deploy
105
+
106
+ ```bash
107
+ npx vercel --prod
108
+ ```
109
+
110
+ Upload direto da pasta local; a URL de produção sai no final. Sem repositório envolvido.
111
+
112
+ ### 6. Opcional (só se o cliente pedir): redeploy automático via GitHub
113
+
114
+ Com a loja já no ar, quem quiser que todo push em `main` redeploye sozinho:
115
+
116
+ ```bash
117
+ # .gitignore já está correto no template — não alterar
118
+ git init
119
+ git add .
120
+ git commit -m "chore: initial storefront"
121
+ git remote add origin <repo-url>
122
+ git push -u origin main
123
+ ```
124
+
125
+ E no dashboard: Settings → Git → conectar o repositório.
126
+
127
+ > `git add -A` pode travar em repos grandes. O `.gitignore` já exclui `node_modules/` e `.next/`.
128
+
129
+ ---
130
+
131
+ ## Erros comuns
132
+
133
+ | Erro | Causa | Solução |
134
+ |---|---|---|
135
+ | `UnboxError: signin HTTP 403` | Env vars ausentes | Adicionar em todos os 3 ambientes e fazer Redeploy |
136
+ | Build falha silenciosamente | Framework Preset "Other" | Settings → Build → alterar para **Next.js** |
137
+ | `npm ERR!` no install | `~/package-lock.json` global | `rm -f ~/package-lock.json` |
138
+ | Startup lento (> 5 min) em dev | Node.js v26 | `nvm use 22` |
139
+ | `Project already exists` | Nome duplicado na conta | Usar nome diferente (ex: `minhaloja-app`) |
140
+ | Prerender error na home | API inacessível durante build | Checar credenciais + `npm run unbox:test` |
141
+
142
+ ---
143
+
144
+ ## Redeploy após mudar env vars
145
+
146
+ Após alterar variáveis no dashboard:
147
+
148
+ 1. Deployments → último deploy → **Redeploy**
149
+
150
+ Ou pela CLI:
151
+
152
+ ```bash
153
+ npx vercel --prod
154
+ ```
155
+
156
+ (Quem conectou GitHub também pode só dar `git push origin main`.)
157
+
158
+ ---
159
+
160
+ ## QA pré-go-live
161
+
162
+ Após o deploy, rodar o checklist em `QA.md` **com credenciais reais**.
163
+
164
+ > Sem `.env.local` preenchido e `npm run unbox:test` passando, os fluxos de carrinho,
165
+ > checkout e login não funcionam — o QA só vale com a API conectada.
166
+
167
+ ## Saída esperada
168
+
169
+ - Projeto no Vercel configurado e com todas as env vars
170
+ - Framework Preset = Next.js
171
+ - Primeira URL de produção retornada pelo `npx vercel --prod` (sem git/GitHub envolvidos)
172
+ - Confirmação de que a home carrega sem erros (prerender passou)
173
+ - QA.md executado e sem itens pendentes
@@ -0,0 +1,275 @@
1
+ # Agente 13 — Unbox AI CRO Package
2
+
3
+ ## Objetivo
4
+
5
+ Ativar os módulos de otimização de conversão (CRO) escolhidos pelo usuário. Cada módulo é independente — ative apenas os que fazem sentido para a loja atual.
6
+
7
+ ---
8
+
9
+ ## Apresentação ao usuário
10
+
11
+ Ao iniciar este agente, exiba o menu abaixo e pergunte quais módulos ativar:
12
+
13
+ ```
14
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15
+ Unbox AI CRO Package — Módulos disponíveis
16
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+
18
+ [1] Prova Social no PDP
19
+ Avaliações reais em destaque (badge "X compraram hoje" só com contador do backend)
20
+ ⚙️ Requer: reviews reais em lib/enrichment/products.json. NÃO existe valor mockup:
21
+ sem dado, o módulo fica bloqueado (regra do CLAUDE.md e gate unbox:honestidade)
22
+
23
+ [2] Urgência de Estoque
24
+ "Restam X unidades" quando stock ≤ threshold configurável
25
+ ⚙️ Requer: campo de estoque na API Unbox (productStock)
26
+
27
+ [3] Countdown Flash Sale
28
+ Banner com temporizador regressivo para ofertas com prazo
29
+ ⚙️ Requer: definir data/hora de fim da promoção
30
+
31
+ [4] Barra de Frete Grátis
32
+ Progress bar no carrinho: "Faltam R$X para frete grátis"
33
+ ⚙️ Requer: definir threshold de frete grátis (ex: R$149)
34
+
35
+ [5] Upsell Pós-Checkout
36
+ Seção "Você também vai gostar" na página de pedido confirmado
37
+ ⚙️ Requer: lógica de recomendação (por categoria ou manual)
38
+
39
+ [6] Recently Viewed
40
+ Histórico de produtos vistos (localStorage, sem backend)
41
+ ⚙️ Sem dependências — funciona sem credenciais
42
+
43
+ [7] Sticky CTA Mobile
44
+ Botão "Adicionar ao carrinho" fixo no scroll do PDP (mobile)
45
+ ⚙️ Sem dependências
46
+
47
+ [8] Trust Strip Customizável
48
+ Ícones de confiança editáveis: entrega, troca, pagamento seguro
49
+ ⚙️ Sem dependências — apenas editar os textos
50
+
51
+ [9] Kits & Combos com Cross-sell
52
+ Seção de kits na home com produtos complementares
53
+ ⚙️ Requer: definir os combos em lib/enrichment/combos.ts
54
+
55
+ [10] Brindes (Gift with Purchase)
56
+ Exibe brinde desbloqueado quando carrinho atinge valor mínimo
57
+ ⚠️ Requer configuração no back-end Unbox ANTES do lançamento
58
+ ⚙️ Requer: regra de brinde ativa no painel + SKU do brinde
59
+
60
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
61
+ ⚠️ Módulos 4 e 10 dependem de configuração no back-end
62
+ antes de ir ao ar. Veja a seção "Pré-requisitos de back-end".
63
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
64
+ Opções: "all", números separados por vírgula (ex: 1,4,7), ou "none"
65
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
66
+ ```
67
+
68
+ Aguarde a resposta antes de qualquer implementação.
69
+
70
+ ---
71
+
72
+ ## Módulos — especificação técnica
73
+
74
+ ### [1] Prova Social no PDP
75
+
76
+ **Arquivo:** `components/product/pdp/social-proof.tsx`
77
+
78
+ **Contador de compras ("X pessoas compraram hoje"): BLOQUEADO.** A API pública da loja não
79
+ expõe volume de vendas por SKU e o enrichment não tem campo pra isso (`lib/enrichment/index.ts`).
80
+ Um número "configurável" ou "hardcoded por SKU" é fabricação, e o `unbox:honestidade` derruba o
81
+ build (`\d+ pessoas compraram`, `compraram nas últimas 24h`). Só implemente se o lojista fornecer
82
+ um contador REAL (integração própria), e registre a fonte no `marca/DESIGN-<MARCA>.md`.
83
+
84
+ O que este módulo faz HOJE: destacar as avaliações reais do produto (`reviews` do enrichment)
85
+ logo abaixo do preço no `buy-box.tsx`: nota média + 1 depoimento curto + link pra seção completa.
86
+ Sem reviews, o bloco não existe.
87
+
88
+ ---
89
+
90
+ ### [2] Urgência de Estoque
91
+
92
+ **Arquivo:** `components/product/pdp/stock-urgency.tsx`
93
+
94
+ ```tsx
95
+ // Exibe "Restam 8 unidades" quando o estoque REAL <= THRESHOLD
96
+ const THRESHOLD = 15; // configurável
97
+ ```
98
+
99
+ Inserir no `buy-box.tsx`, abaixo do seletor de quantidade.
100
+
101
+ **Dependência API:** o catálogo público NÃO expõe quantidade (`productStock` não existe; só
102
+ `isSoldOut`). Quantidade real vem de `simpleInventory` na API de parceiros (`agents/COVERAGE.md`),
103
+ via `withStoreClient` no servidor. Sem esse dado, o módulo fica BLOQUEADO: contador que "desce
104
+ sozinho" ou threshold sem estoque real é fabricação.
105
+
106
+ ---
107
+
108
+ ### [3] Countdown Flash Sale
109
+
110
+ **Arquivo:** `components/home/flash-sale-banner.tsx`
111
+
112
+ ```tsx
113
+ // Banner full-width com countdown regressivo
114
+ // Configurar: SALE_END_DATE (ISO string) e mensagem da oferta
115
+ const SALE_END_DATE = "2025-12-31T23:59:59-03:00"; // TODO: atualizar
116
+ ```
117
+
118
+ Inserir na home, entre o hero e os combos. Condicionado: se `Date.now() < SALE_END_DATE`, exibe; caso contrário, não renderiza (null).
119
+
120
+ ---
121
+
122
+ ### [4] Barra de Frete Grátis
123
+
124
+ ⚠️ **A foundation JÁ tem isso** — régua de frete grátis no mini-cart, checkout, buy-box e
125
+ header, todos lendo `FREE_SHIPPING_THRESHOLD` de `lib/store-config.ts` (que nasce `null` =
126
+ nada renderiza até existir regra real; ver `npm run unbox:dump`). Este módulo NÃO cria
127
+ componente novo nem segundo limiar: se a régua não aparece, o motivo é o threshold `null` —
128
+ preencha a store-config com a regra REAL. Só crie UI adicional (ex.: barra no topo da página
129
+ de carrinho) consumindo o MESMO `FREE_SHIPPING_THRESHOLD`, nunca um número hardcoded.
130
+
131
+ ---
132
+
133
+ ### [5] Upsell Pós-Checkout
134
+
135
+ **Arquivo:** `components/order/upsell-section.tsx`
136
+
137
+ ```tsx
138
+ // Recomendações na página de pedido confirmado
139
+ // Fonte: últimos produtos vistos (localStorage) ou lista manual
140
+ ```
141
+
142
+ Inserir em `app/(loja)/pedido/[referenceId]/page.tsx` (confirmação de pedido).
143
+
144
+ ---
145
+
146
+ ### [6] Recently Viewed
147
+
148
+ **Arquivo:** `lib/recently-viewed.ts` + `components/product/recently-viewed.tsx`
149
+
150
+ ```ts
151
+ // localStorage: salva array de slugs visitados (max 8)
152
+ // Hook: useRecentlyViewed()
153
+ ```
154
+
155
+ - Salvar no `useEffect` do PDP (client component).
156
+ - Exibir no carrinho e na home como seção "Vistos recentemente".
157
+ - **Sem dependências externas** — funciona com qualquer storeToken.
158
+
159
+ ---
160
+
161
+ ### [7] Sticky CTA Mobile
162
+
163
+ **Arquivo:** `components/product/pdp/sticky-cta.tsx`
164
+
165
+ ```tsx
166
+ // Visível apenas em mobile (md:hidden)
167
+ // Aparece após scroll passar o botão principal (IntersectionObserver)
168
+ // Posição: fixed bottom-0, acima da nav bar (bottom-[84px])
169
+ ```
170
+
171
+ Inserir no layout do PDP (`app/(loja)/produto/[productSlug]/page.tsx`).
172
+
173
+ ---
174
+
175
+ ### [8] Trust Strip Customizável
176
+
177
+ ⚠️ **A foundation JÁ tem trust strips** — `components/home/sections/trust-strip.tsx` (escura)
178
+ e `trust-bar.tsx` (clara), registradas no `registry.ts` e documentadas no `agents/PADROES.md`.
179
+ Este módulo customiza os ITENS das existentes via receita: `props.items: [{ icon?, text }]`
180
+ (ícones em `TRUST_ICONS`, `trust-bar.tsx`). Sem `items`, as duas seções NÃO renderizam: os
181
+ selos são promessas do lojista ("entrega em 24h", "garantia de 1 ano"), não da foundation.
182
+
183
+ **Arquivo (só se precisar de variante nova):** `components/home/sections/` + registro no registry
184
+
185
+ ```tsx
186
+ // Array configurável de itens: { icon, label, sub }
187
+ const TRUST_ITEMS = [
188
+ { icon: "Truck", label: "Entrega rápida", sub: "Prazo conforme CEP" },
189
+ { icon: "RotateCcw", label: "Troca sem burocracia", sub: "Até 7 dias após recebimento" },
190
+ { icon: "Shield", label: "Pagamento seguro", sub: "SSL + antifraude" },
191
+ { icon: "Award", label: "Produto original", sub: "Nota fiscal inclusa" },
192
+ ];
193
+ ```
194
+
195
+ Reutilizável: inserir no PDP, na home e/ou no checkout.
196
+
197
+ ---
198
+
199
+ ### [9] Kits & Combos com Cross-sell
200
+
201
+ **Arquivo:** `lib/enrichment/combos.ts` (já existe, vazio por padrão)
202
+
203
+ ```ts
204
+ // Preencher com os combos da loja:
205
+ export const COMBOS: ComboDef[] = [
206
+ {
207
+ id: "kit-essencial",
208
+ name: "Kit Essencial",
209
+ description: "Os mais vendidos juntos",
210
+ items: [{ family: "FAMILIA_A" }, { family: "FAMILIA_B" }],
211
+ },
212
+ ];
213
+ ```
214
+
215
+ Os dados vivem em `lib/enrichment/combos.ts` (`COMBOS` + `resolveCombos`, chamado em `app/(loja)/page.tsx`; a seção da home é `kits`)
216
+
217
+ ---
218
+
219
+ ### [10] Brindes (Gift with Purchase)
220
+
221
+ **Arquivo:** `components/cart/gift-indicator.tsx`
222
+
223
+ ```tsx
224
+ // Exibe brinde desbloqueado quando carrinho atinge valor mínimo.
225
+ // A lógica de elegibilidade e o SKU do brinde vêm da API Unbox
226
+ // (campo `gifts` retornado no payload do carrinho).
227
+ //
228
+ // ⚠️ PRÉ-REQUISITO DE BACK-END — configurar no painel Unbox:
229
+ // 1. Criar regra de brinde (mínimo de valor, SKU do produto brinde)
230
+ // 2. Garantir que o SKU do brinde está com estoque ativo
231
+ // Sem isso, o componente renderiza vazio — nunca exibe brinde falso.
232
+ ```
233
+
234
+ **Comportamento:**
235
+ - Carrinho abaixo do mínimo: `"Adicione mais R$X e ganhe [nome do brinde]"` com progress bar
236
+ - Carrinho acima do mínimo: `"🎁 Brinde desbloqueado: [nome do brinde]!"` em destaque
237
+ - Sem regra configurada no back: componente não renderiza (null)
238
+
239
+ Inserir no `app/(loja)/carrinho/page.tsx`, abaixo da barra de frete grátis (módulo 4) se ativo, senão no topo do sumário.
240
+
241
+ **Dependência API:** `cart.gifts[]` — array de brindes elegíveis retornado pela Unbox API.
242
+
243
+ ---
244
+
245
+ ## Pré-requisitos de back-end
246
+
247
+ > Estes módulos exibem dados que vêm do painel Unbox. **Configurar antes do lançamento da loja.**
248
+
249
+ | Módulo | O que configurar no painel Unbox |
250
+ |--------|----------------------------------|
251
+ | **[4] Barra de Frete Grátis** | Regra de frete grátis: valor mínimo do pedido, CEPs/regiões elegíveis |
252
+ | **[10] Brindes** | Regra de brinde: valor mínimo, SKU do produto brinde, estoque ativo |
253
+
254
+ Sem essas configurações, os componentes renderizam vazios (não inventam dados). Isso é intencional — nunca exibir promoção que não existe.
255
+
256
+ ---
257
+
258
+ ## Fluxo do agente
259
+
260
+ 1. **Apresentar menu** e aguardar escolha.
261
+ 2. **Confirmar escopo:** listar módulos selecionados e suas dependências.
262
+ 3. **Perguntar configurações** específicas de cada módulo (ex: threshold de frete, data do flash sale).
263
+ 4. **Implementar** um módulo por vez, em ordem numérica.
264
+ 5. **Para cada módulo:** criar/editar arquivo → inserir no componente pai → confirmar sem erros de TypeScript.
265
+ 6. **Ao final:** listar TODOs de configuração que ainda precisam de dados reais (ex: `SALE_END_DATE`, combos, reviews).
266
+
267
+ ---
268
+
269
+ ## Regras
270
+
271
+ - **Nunca ativar módulo sem perguntar.** O template base é intencionalmente simples.
272
+ - **Módulos são opcionais e independentes** — remover um não quebra os outros.
273
+ - Usar os **brand tokens** (`--store-primary`, `--store-cta`) para cores, nunca hardcodar hex.
274
+ - Módulos sem dependência de API (6, 7, 8) podem ser ativados mesmo em modo mockup.
275
+ - Módulos com dependência (1, 2, 3, 4, 5, 9) devem exibir aviso se `.env.local` não estiver configurado.