@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,255 @@
1
+ # PADRÕES: biblioteca de layout da foundation
2
+
3
+ Repertório pro agente de Branding (15) decidir **estrutura visual** com critério, sem
4
+ reinventar código. A regra de ouro: **layout muda pela RECEITA**
5
+ (`components/home/home-recipe.ts`), pelas **fontes** (bloco `UNBOX-FONTS` de
6
+ `app/layout.tsx`) e pelos **tokens** (`app/globals.css`), nunca reescrevendo o JSX de uma
7
+ seção pra ela "virar outra coisa". Variante nova = arquivo novo em
8
+ `components/home/sections/` + registro no `registry.ts` + entrada aqui.
9
+
10
+ O mesmo vale pro **chrome** (header e rodapé): muda pela receita
11
+ `components/chrome/chrome-recipe.ts`, nunca reescrevendo `site-header.tsx`/`site-footer.tsx`
12
+ (esses são só a casca: fetch, wrapper e o selo obrigatório). Ver seção 2c.
13
+
14
+ Complementos gerais (skills em `.claude/skills/`): `frontend-design` (direção estética na
15
+ hora de construir, use pra fugir de escolha "de template") e `web-design-guidelines`
16
+ (auditoria de UI/acessibilidade, rode antes de declarar pronto).
17
+
18
+ ## Composição da home: impacto, não comprimento
19
+
20
+ Não existe teto de seções, e o medidor (`npm run unbox:medir`) reporta o número sem reprovar. O
21
+ que existe é uma pergunta por seção: **o que esta seção faz que a anterior não fez?** Seção que
22
+ repete a promessa da anterior com outras palavras alonga a página sem acrescentar motivo de
23
+ compra, e é assim que uma home vira rolagem.
24
+
25
+ A receita default tem 16 seções porque é uma biblioteca, não uma recomendação: o briefing escolhe.
26
+ Sinais de que sobrou seção: duas seções seguidas com o mesmo tipo de argumento, um bloco que só
27
+ existe para ocupar espaço entre dois que importam, e qualquer seção que o cliente não saberia
28
+ descrever depois de ver a página uma vez.
29
+
30
+ ## O header segue o estilo da marca
31
+
32
+ A biblioteca tem 5 headers e a escolha é do briefing, não do preset. O preset dá o ponto de
33
+ partida; a marca decide. Um roteiro curto para escolher, em vez de aceitar o que veio:
34
+
35
+ | a marca é | header que costuma servir |
36
+ |---|---|
37
+ | fotográfica, com hero de imagem forte | `imersivo` (transparente sobre o hero, sólido ao rolar) |
38
+ | catálogo grande, busca é o começo da visita | `classico` (busca visível) |
39
+ | poucos produtos, identidade no logo | `centralizado` ou `equilibrado` |
40
+ | conteúdo denso, o header não é protagonista | `compacto` |
41
+
42
+ Trocar é uma linha em `components/chrome/chrome-recipe.ts`. O que não vale é deixar o default
43
+ porque ninguém olhou: o header aparece em toda página, e é a primeira coisa que faz uma loja
44
+ parecer com outra.
45
+
46
+ ## 1. Os 4 estilos (presets do CLI)
47
+
48
+ O scaffold já aplicou um (campo `estilo` do `marca/briefing.json`). Seu papel no briefing é
49
+ VALIDAR contra as referências reais do cliente e ajustar, trocar o estilo inteiro é raro;
50
+ ajustar receita/fontes/variantes é comum.
51
+
52
+ | Estilo | Quando usar | Quando NÃO usar | Chrome | Radius | Display |
53
+ |---|---|---|---|---|---|
54
+ | **essencial** | qualquer segmento, cliente sem opinião forte de design | marca com identidade visual forte já definida | brand-dark | 0.875rem | Poppins |
55
+ | **promocional** | ticket médio, kits/combos, oferta agressiva, food/consumo recorrente | marca premium (fica "feirão") | brand-dark | 1.25rem (pill) | Barlow Condensed |
56
+ | **editorial** | assinatura/clube, curadoria, marca com história pra contar | catálogo grande de conveniência | ink-dark | 0.5rem | Fraunces (serif) |
57
+ | **boutique** | premium, minimal, autoral, poucos SKUs | loja de volume com muitas categorias | ink-dark | 0.25rem | Playfair Display (serif) |
58
+
59
+ Receitas default de cada um: ver o `components/home/home-recipe.ts` gerado neste projeto
60
+ (a fonte delas vive no CLI `create-unbox-store`, fora deste repo).
61
+
62
+ ## 1b. Eixos de composição (a linguagem visual além de cor/fonte)
63
+
64
+ Tokens no bloco CONFIGURE de `globals.css`, mudam o "jeito" da loja inteira sem tocar em
65
+ componente. Cada estilo já vem com uma combinação; ajuste por marca livremente:
66
+
67
+ | Eixo | Token | O que muda | Valores dos estilos |
68
+ |---|---|---|---|
69
+ | Ritmo vertical | `--section-gap` | respiro entre seções (denso ↔ arejado) | essencial 52px · promocional 44px · editorial 72px · boutique 88px |
70
+ | Largura | `--container-max` | largura do conteúdo das seções | 1240px · 1240px · 1080px · 1000px |
71
+ | Chrome dos cards | `--card-bg`/`--card-border`/`--card-shadow` (classe `.store-card`) | bordado clássico · sombra flutuante · preenchido flat · hairline | essencial bordado · promocional sombra · editorial preenchido · boutique hairline |
72
+
73
+ Combinar eixos + fontes + neutros + radius = linguagens genuinamente diferentes com as MESMAS
74
+ seções. Se ainda assim a referência da marca pedir outra cara pra uma seção específica, o
75
+ caminho é **variante nova** (nível 2 abaixo), nunca editar a existente.
76
+
77
+ ## 1c. Dials do briefing (variância · motion · densidade)
78
+
79
+ `marca/briefing.json` traz `dials` (1-10) com o default do estilo. Eles são a *temperatura*
80
+ da loja, e você revalida cada um no briefing contra as referências da marca:
81
+
82
+ | Dial | O que governa | Onde mexer |
83
+ |---|---|---|
84
+ | `variancia` | quão ousada é a composição: variantes menos óbvias, chrome mais autoral | receita da home e `chrome-recipe.ts` |
85
+ | `motion` | quanta animação (0 desliga tudo) | token `--motion` em `globals.css` |
86
+ | `densidade` | quanto conteúdo por tela | `--section-gap`, `--container-max`, nº de seções da receita |
87
+
88
+ **A paleta neutra é canvas provisória, não escolha estética.** A loja nasce em cinza + tinta
89
+ porque é a tela mais neutra pra qualquer marca cair bem em cima, aplicar as cores REAIS é o
90
+ primeiro ato do briefing, antes de qualquer seção. O `npm run build` avisa enquanto a paleta
91
+ default estiver no ar.
92
+
93
+ ## 2. Catálogo de seções e variantes
94
+
95
+ | Seção | O que faz | Variantes | Critério |
96
+ |---|---|---|---|
97
+ | `hero` | primeira dobra | `imagem-full` (banner clicável), `carousel` (banners com setas), `split-editorial` (texto+CTA / imagem), `minimal-texto` (tipográfico, sem imagem), `imagem-imersiva` (foto sangrando até o topo, por baixo do header, par do header `imersivo`) | **full-bleed é o default** (`imagem-imersiva`): banner em card arredondado é o tell nº 1 de "site de template". História/proposta clara → split; sem foto decente AINDA → minimal-texto (nunca deixe hero com foto ruim); `imagem-full` só quando a marca QUISER o banner contido |
98
+ | `trust-bar` | selos de confiança claros (`items` via receita; some sem itens) | única | logo abaixo do hero em lojas novas (dá segurança); em boutique costuma sair |
99
+ | `category-pills` | chips de categorias | única | só faz sentido com 3+ categorias reais |
100
+ | `combos-carousel` | produtos em destaque com add-to-cart (âncora `#destaques`) | única | quase sempre presente; é o coração comercial |
101
+ | `savings` | comparativo de economia | única (some sozinha sem desconto real) | lojas de kit/combo; NUNCA force com desconto fake |
102
+ | `reviews` | depoimentos | `grid` (3 cards), `faixa` (linha discreta) | grid quando reviews são um ativo; faixa em estilos minimais; SEMPRE conteúdo real ou remova |
103
+ | `kits` | kits temáticos curados (`lib/enrichment/combos.ts`) | única (some com `COMBOS` vazio) | popular os combos reais primeiro |
104
+ | `trust-strip` | faixa escura de diferenciais | única | reforço no fim da página; redundante se trust-bar já diz o mesmo |
105
+ | `newsletter` | captura de e-mail (`title` + `action` obrigatórios; some sem eles) | `bloco` (CTA forte), `inline` (linha fina) | bloco em lojas promocionais; inline em editorial/boutique; form ainda é TODO de integração |
106
+
107
+ **Biblioteca de conversão** (portada de uma loja Unbox real em produção, genericizadas, todas aceitam
108
+ conteúdo via `props` com defaults neutros):
109
+
110
+ | Seção | O que faz | Regra de conteúdo |
111
+ |---|---|---|
112
+ | `attributes-marquee` | marquee infinito de atributos do produto (vegano, artesanal...) | atributos VERDADEIROS do produto; ícones por nome (leaf, drop, heart, shield...) |
113
+ | `benefits` | grid 2+foto+2 de benefícios | sem promessa de resultado inventada |
114
+ | `stats-grid` | 4 cards de destaque (com números OU qualitativos) | número SÓ com pesquisa/dado real (passe `source`); default é qualitativo de propósito |
115
+ | `quote-banner` | faixa foto + citação grande | citação da própria marca/fundador, nunca depoimento inventado |
116
+ | `media-cards` | carrossel de cards de imagem com legenda (ingredientes, materiais, bastidores) | fotos reais assim que existirem |
117
+ | `spec-table` | ficha técnica com modal (nutricional, composição, medidas) | dados REAIS do produto |
118
+ | `ritual` | crossfade de fotos + checklist "como usar" |, |
119
+ | `founder-story` | card de história com foto de fundo + assinatura (âncora #nossa-historia) | história real |
120
+ | `video-wall` | grade 9:16 de vídeo-depoimentos com play inline | SÓ vídeo real; sem vídeo, remova da receita |
121
+ | `social-row` | cards de comunidade/creators com @handle | gente real com autorização; seguidores só se verdadeiros |
122
+ | `reviews-carousel` | carrossel de reviews em card bordado com pílulas de tema | reviews reais |
123
+ | `comparison` | tabela "aqui vs por aí" estrutural | compare atributos, sem citar concorrente nem inventar |
124
+ | `product-showcase` | vitrine de cards com fundo colorido, produtos e preços do CATÁLOGO | `ctaHref: "#comprar"` pra mandar pro hero de compra |
125
+ | `purchase-hero` | **o bloco de conversão principal**: galeria + tiers de quantidade + vantagens + garantia (âncora `#comprar`) | produto/preço do catálogo (data.featured); tiers de `QUANTITY_TIERS`; CTA → passo 2 |
126
+
127
+ ## 2c. Catálogo de header e rodapé (o chrome)
128
+
129
+ O chrome aparece em TODAS as páginas, é ele que mais pesa na sensação de "loja igual às
130
+ outras". Troque em `components/chrome/chrome-recipe.ts` (1 linha cada). `npm run typecheck`
131
+ acusa nome inexistente.
132
+
133
+ | Header | O que é | Quando usar | Quando NÃO usar |
134
+ |---|---|---|---|
135
+ | `classico` | logo esq · busca · ações · faixa de categorias abaixo | catálogo grande, busca é o caminho principal | marca que quer respiro |
136
+ | `compacto` | uma barra fina, categorias inline, busca em ícone | promocional/campanha: menos altura, mais tela pra oferta | catálogo com muitas categorias (não cabem) |
137
+ | `centralizado` | logo grande no centro, ações nas pontas, nav centralizada abaixo | editorial, assinatura, wordmark bonito | loja de volume onde busca manda |
138
+ | `equilibrado` | UMA linha: categorias à esquerda, logo ao centro, busca/conta/carrinho em ícone à direita | logo no centro sem gastar duas faixas; catálogo de 2 a 6 categorias | muitas categorias (empurram o logo do centro) |
139
+ | `imersivo` | barra mínima, menu em drawer (inclusive desktop), **transparente sobre hero de imagem** e sólido ao rolar | marca com fotografia boa, catálogo curto, premium | catálogo grande, ou loja sem foto real |
140
+
141
+ | Rodapé | O que é | Quando usar |
142
+ |---|---|---|
143
+ | `colunas` | trust strip + 4 colunas + pagamento | loja completa, navegação secundária importa |
144
+ | `conversao` | captura de e-mail em destaque + links enxutos | promocional: rodapé como última conversão |
145
+ | `editorial` | manifesto da marca + colunas discretas + redes | marca com história, tom de revista |
146
+ | `minimal` | logo, uma linha de links, pagamento discreto | catálogo curto, estética premium/minimal |
147
+
148
+ **Regras do chrome:**
149
+ - Variante muda composição e hierarquia, **nunca capacidade**: busca, conta, carrinho,
150
+ categorias e links legais existem em todas. Trocar o chrome não pode tirar função da loja.
151
+ - O `imersivo` só fica transparente com o hero `imagem-imersiva` na receita da home (é a
152
+ única variante que emite `.hero-imersivo`). Em qualquer outra página, e em qualquer home
153
+ sem esse hero, ele é sólido. Sem foto boa da marca, use outro hero: o header se ajusta
154
+ sozinho, e foto ruim em tela cheia é pior que header sólido.
155
+ - A barra inferior do rodapé (© + selo Powered by Unbox) é da CASCA, não da variante: é
156
+ contrato da plataforma e o build falha sem ela.
157
+
158
+ ## 2b. O funil de compra (purchase-hero → picker → checkout)
159
+
160
+ O padrão das lojas Unbox de produção: o **hero de compra é uma SEÇÃO da home** (ou topo da
161
+ PDP/landing), não uma página escondida. Fluxo:
162
+
163
+ 1. **`purchase-hero`** (seção, âncora `#comprar`): quantidade via `QUANTITY_TIERS`
164
+ (`lib/store-config.ts`) com preço real por unidade. CTAs de outras seções apontam pra cá
165
+ (`href`/`ctaHref: "#comprar"`).
166
+ 2. **`/carrinho/oferta`** (picker, tela split sem chrome): escolha de produtos/variantes com
167
+ stepper + **frequência de envio**, assinatura com o desconto REAL da política da loja
168
+ (`recurringOrdersPolicy`) vs compra única. Só aparece se a política existe e há produto
169
+ com `recurrenceAllowed`.
170
+ 3. `/checkout`.
171
+
172
+ `/oferta` existe como deep-link de campanha (mesma seção + pilha de convencimento de
173
+ `components/landing/landing-recipe.ts`). Regras: preços SEMPRE do catálogo; `offPct`/
174
+ `perks`/`badge` dos tiers só quando a promoção equivalente EXISTE no painel Unbox (senão o
175
+ total diverge no checkout, defaults saem zerados por isso).
176
+
177
+ ## 3. Receitas por objetivo
178
+
179
+ - **Subir ticket médio:** promocional; `combos-carousel` + `savings` logo após o hero;
180
+ `kits` populado; newsletter `bloco` prometendo oferta (só se a oferta existir).
181
+ - **Assinatura/clube:** editorial; hero `split-editorial` contando a proposta; reviews
182
+ `faixa`; newsletter `inline` como "entrar pra lista"; assinatura destacada na PDP (a
183
+ PDP já suporta; não mexa na estrutura dela nesta versão).
184
+ - **Marca premium/minimal:** boutique; 5 a 6 seções NO MÁXIMO; hero `minimal-texto` até
185
+ existir fotografia à altura; sem `savings`, sem `trust-strip`.
186
+ - **Cliente não sabe / loja generalista:** essencial completo; corte o que não tiver
187
+ conteúdo real (reviews fake NÃO, ou dado real, ou remove).
188
+
189
+ ## 4. Como aplicar mudanças
190
+
191
+ 1. **Ordem/presença/variante de seção:** editar `components/home/home-recipe.ts`.
192
+ 2. **Copy do hero (split/minimal):** `props` da entrada `hero` na receita
193
+ (`title`, `subtitle`, `ctaLabel`, `ctaHref`).
194
+ 3. **Imagens do hero:** troque os arquivos em `public/brand/` e os paths nos `props`
195
+ (`.webp` otimizado; os `.svg` gerados são placeholder até existir imagem real).
196
+ 4. **Tipografia:** bloco `UNBOX-FONTS` em `app/layout.tsx` (só Google Fonts com pesos
197
+ 500-800; corpo legível + display com personalidade).
198
+ 5. **Neutros/radius/chrome:** tokens em `app/globals.css` (bloco CONFIGURE). Cor SEMPRE
199
+ via `var(--store-*)`, nunca hex solto.
200
+ 6. **Composição (ritmo/largura/cards):** eixos `--section-gap`, `--container-max` e
201
+ `--card-*` no mesmo bloco CONFIGURE (ver seção 1b).
202
+ 7. **Variante nova de seção:** criar o componente em `components/home/sections/`,
203
+ registrar no `registry.ts`, documentar aqui. Antes de desenhar, carregue o skill
204
+ `frontend-design` e faça uma escolha estética própria da marca, variante nova que
205
+ parece a original com outra cor não justifica existir. `npm run typecheck` valida a
206
+ receita.
207
+ 8. **Chrome (header/rodapé):** trocar a variante = editar `components/chrome/chrome-recipe.ts`
208
+ (ver seção 2c). Variante NOVA = arquivo em `components/chrome/headers/` ou `footers/` +
209
+ entrada no `components/chrome/registry.ts` (e no `HEADER_SHELL`, se for header) +
210
+ linha na tabela daqui. A variante desenha só o MIOLO: o `<header>`/`<footer>` com
211
+ `store-layout site-chrome` e o selo Powered by são da casca, e é assim que a loja garante
212
+ que o chrome some no checkout e que o contrato não cai.
213
+
214
+ ## 4b. O que NÃO importamos de frameworks externos de "taste"
215
+
216
+ Avaliamos a `taste-skill` (anti-slop) e extraímos o que serve: os dials (1c), o "design read"
217
+ do agente 15, os anti-tells de copy (5) e a medição de composição (`npm run unbox:receita`).
218
+ **Recusamos de propósito**, não "conserte" isto depois:
219
+
220
+ - **Ban de serifa** (Fraunces/Playfair): são o display de dois estilos nossos, escolha decidida.
221
+ - **Ban de paleta**: a crítica ao bege premium procede e já foi resolvida trocando os neutros;
222
+ quem decide a cor da marca é o briefing, não um doc externo.
223
+ - **Stack de motion com dependência nova** (GSAP/motion): nosso motion é CSS puro, sem JS.
224
+ - **Imagens de Picsum**: foto aleatória numa loja real é pior que placeholder declarado.
225
+ - **Design systems oficiais** (Material/Fluent/Carbon): a loja é shadcn/Base UI + tokens `--store-*`.
226
+
227
+ ## 5. Anti-padrões
228
+
229
+ - 9 seções numa loja minimal (boutique com receita do essencial).
230
+ - **Toda loja com a mesma composição.** Se as referências da marca pedem outra linguagem
231
+ e você entregou o default da biblioteca, o briefing falhou, use os eixos (1b) e
232
+ variantes novas.
233
+ - Remover toda âncora de confiança de loja nova (algum trust fica).
234
+ - Prova social inventada em QUALQUER estilo, dado real, estado honesto, ou decisão
235
+ EXPLÍCITA do lojista registrada (`marca/honestidade-permitido.txt`). Nunca por omissão.
236
+ - Hex solto no JSX; fonte fora do bloco UNBOX-FONTS; receita reescrita como JSX.
237
+ - Editar destrutivamente variante existente da biblioteca (crie uma nova).
238
+ - Mexer no motor (`lib/unbox`, `app/api`, checkout) por causa de layout.
239
+ - **Copy que denuncia texto de IA** (some com ela; se a marca quiser algo assim, tem que ser
240
+ decisão declarada dela): verbos de enchimento ("Elevate", "Seamless", "Unleash",
241
+ "Revolucione"), eyebrows numeradas ("001 · Recursos"), rótulos de etapa por número
242
+ (Etapa 1/2/3, use o verbo direto: Instale, Configure), "role para explorar"/scroll cues,
243
+ rótulos de versão (v1.4.2, BETA) fora de contexto, nomes genéricos em depoimento
244
+ (João Silva, Maria S.), legendas decorativas de foto ("Estudo de campo nº 12").
245
+ - Travessão na copy voltada ao cliente final. **Fios/traços decorativos contam**: o
246
+ risquinho antes de eyebrow/kicker lê como "cara de AI" pro cliente, mesma proibição.
247
+ - Classe de marca apontando pra variável de fonte que só existe no `@theme inline` do
248
+ Tailwind (ex.: `var(--font-mono)`): funciona por acaso dentro de `.store-layout` e cai
249
+ em serifa fora dele. Classes de fonte apontam pra variável do **next/font** com stack
250
+ completa de fallback.
251
+ - **`text-white` (ou cor cravada) sobre fundo de cor de marca.** A cor da marca muda por
252
+ loja: na loja de referência o CTA era escuro e funcionou; numa bifurcação virou
253
+ verde-limão e o texto caiu pra 1,39:1 de contraste. Sobre `--store-cta` use SEMPRE
254
+ `--store-cta-fg`; sobre `--store-chrome-bg` use `--store-chrome-text`. Branco fixo só
255
+ sobre `--store-primary` (o CLI garante primary escuro o bastante).
@@ -0,0 +1,56 @@
1
+ # Agente 00 — Scaffold
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
+ Criar a estrutura completa do projeto Next.js 15: arquivos de configuração, fundação compartilhada
9
+ (`lib/`), shell de `app/layout.tsx` e todas as rotas como placeholders para os outros agentes preencherem.
10
+
11
+ ## Dependências
12
+ Nenhuma — este agente roda primeiro.
13
+
14
+ ## Arquivos a criar
15
+
16
+ | Arquivo | Descrição |
17
+ |---------|-----------|
18
+ | `package.json` | Next.js 15 + Base UI + shadcn + Tailwind v4 |
19
+ | `tsconfig.json` | Padrão Next.js com paths `@/*` |
20
+ | `next.config.ts` | Minimal, domains de imagem em branco |
21
+ | `app/globals.css` | `@import "tailwindcss"` + variáveis CSS de tema |
22
+ | `app/layout.tsx` | RootLayout shell (providers placeholder) |
23
+ | `lib/unbox.ts` | UnboxClient singleton server-only |
24
+ | `lib/auth.ts` | getCustomerToken/setCustomerToken/clearCustomerToken |
25
+ | `lib/feedback.ts` | Re-export friendlyError, cartEventLabel do SDK |
26
+ | `lib/metadata.ts` | buildMetadata(product) → Metadata do Next.js |
27
+ | `.env.local.example` | Template de variáveis de ambiente |
28
+ | `middleware.ts` | Proteção das rotas /conta/* |
29
+ | Todas as rotas | Placeholders com comentário `// TODO: agente X` |
30
+
31
+ ## SDK
32
+ ```ts
33
+ import "server-only"
34
+ import { UnboxClient } from "@payflows/unbox-sdk"
35
+
36
+ let _client: UnboxClient | null = null
37
+
38
+ export async function getUnboxClient(): Promise<UnboxClient> {
39
+ if (_client) return _client
40
+ _client = new UnboxClient({
41
+ apiKey: process.env.UNBOX_API_KEY!,
42
+ shopId: process.env.UNBOX_SHOP_ID!,
43
+ })
44
+ await _client.signIn(process.env.UNBOX_USER!, process.env.UNBOX_PASS!)
45
+ return _client
46
+ }
47
+ ```
48
+
49
+ ## Regras
50
+ - `UNBOX_API_KEY` nunca com prefixo `NEXT_PUBLIC_`
51
+ - `lib/unbox.ts` deve ter `import "server-only"` na primeira linha
52
+ - Token de cliente é separado — `lib/auth.ts` usa cookies httpOnly
53
+ - Tailwind v4: `app/globals.css` deve ter `@import "tailwindcss"`
54
+
55
+ ## Saída esperada
56
+ Lista de todos os arquivos criados com conteúdo completo.
@@ -0,0 +1,47 @@
1
+ # Agente 01 — Layout
2
+
3
+ ## Escopo
4
+ Chrome global da loja: header (barra de anúncio + nav + busca + carrinho), footer (trust strip +
5
+ colunas de links + pagamento) e navegação mobile. Usado em toda página via `app/layout.tsx`.
6
+
7
+ ## Dependências
8
+ - Agente 00 (Scaffold) — `lib/config.ts`, `lib/unbox/*`, tokens de cor em `app/globals.css`
9
+
10
+ ## Arquivos proprietários
11
+
12
+ | Arquivo | Descrição |
13
+ |---------|-----------|
14
+ | `app/layout.tsx` | RootLayout — monta `<SiteHeader>`, `{children}`, `<SiteFooter>`, providers (`CartProvider`, `Toaster`) |
15
+ | `components/site-header.tsx` | Barra de anúncio + header sticky (logo, busca, conta, carrinho) + nav de categorias |
16
+ | `components/site-footer.tsx` | Trust strip, colunas de links, `PaymentChips`, logo em fundo escuro |
17
+ | `components/mobile-nav.tsx` | Drawer mobile com categorias (`NavCategory[]`) |
18
+ | `components/account-nav.tsx` | Ícone/menu de conta no header desktop |
19
+
20
+ ## Regra de ouro — degradação sem credenciais
21
+ Header e footer **sempre** buscam dados da loja (`getShopData`, `getTopTags`) com `.catch()` e
22
+ fallback, nunca deixam o erro subir — é o que permite o "modo mockup" (sem `.env.local`
23
+ preenchido) funcionar sem crashar a página inteira:
24
+
25
+ ```tsx
26
+ const [shop, tags] = await Promise.all([
27
+ getShopData().catch(() => null),
28
+ getTopTags().catch(() => []),
29
+ ]);
30
+ const shopName = shop?.name ?? "Minha Loja";
31
+ ```
32
+
33
+ Qualquer novo dado buscado no chrome global (header/footer) precisa seguir esse padrão — uma
34
+ página de dados (catálogo, PDP, checkout) pode mostrar erro, mas o chrome nunca pode derrubar o
35
+ layout inteiro.
36
+
37
+ ## Categorias (nav)
38
+ `NavCategory[]` vem de `getTopTags()` — **sem** filtro `isTopLevel` (ver doc 05-cart/lib/unbox/client.ts:
39
+ forçar `isTopLevel: true` esconde categorias reais marcadas `false` no admin). Filtra por
40
+ `isVisible !== false` e ordena por `position`. Reusado pelo header desktop e pelo `mobile-nav.tsx`.
41
+
42
+ ## Tokens de marca
43
+ Logo: `public/brand/logo.svg` (fundo claro, header) e `logo-white.svg` (fundo escuro, footer).
44
+ Cores via CSS vars `--store-primary`, `--store-cta`, `--store-chrome-bg`/`--store-chrome-text`
45
+ (bloco "CONFIGURE AQUI" em `app/globals.css`) — **nunca hardcode hex** nos componentes de layout;
46
+ sempre `bg-[var(--store-X,#fallback)]` para que a customização do CLI (`create-unbox-store`)
47
+ realmente se propague.
@@ -0,0 +1,70 @@
1
+ # Agente 02 — Homepage
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
+ Página inicial: hero banner, promoções da loja (shopSales), produtos em destaque e grade de categorias.
9
+
10
+ ## Dependências
11
+ - Agente 00 (Scaffold)
12
+ - Agente 03 (Catalog) — reutiliza `ProductCard`
13
+ - Agente 09 (Promotions) — reutiliza `ShopSalesBanner`
14
+
15
+ ## Arquivos proprietários
16
+
17
+ | Arquivo | Descrição |
18
+ |---------|-----------|
19
+ | `app/(loja)/page.tsx` | Server Component com Suspense por seção |
20
+ | `components/home/HeroBanner.tsx` | Banner principal com CTA |
21
+ | `components/home/FeaturedProducts.tsx` | Grade de 8 produtos em destaque |
22
+ | `components/home/CategoryGrid.tsx` | Grade visual de categorias |
23
+ | `app/loading.tsx` | Skeleton da homepage |
24
+
25
+ ## Dados da API
26
+
27
+ ```ts
28
+ import { getUnboxClient } from "@/lib/unbox"
29
+ import { unstable_cache } from "next/cache"
30
+
31
+ const getHomeData = unstable_cache(async () => {
32
+ const client = await getUnboxClient()
33
+ const [shop, catalog, tags] = await Promise.all([
34
+ client.getShop(), // shopSales
35
+ client.getCatalog({ first: 8, sortBy: "updatedAt", sortOrder: "desc" }),
36
+ client.getTags(true), // categorias
37
+ ])
38
+ return {
39
+ shopSales: shop.shopSales ?? [],
40
+ products: catalog.nodes.map(n => n.product),
41
+ categories: tags.filter(t => t.isVisible),
42
+ }
43
+ }, ["home-data"], { revalidate: 300 })
44
+ ```
45
+
46
+ ## Estrutura de app/(loja)/page.tsx
47
+
48
+ ```tsx
49
+ export default async function HomePage() {
50
+ const { shopSales, products, categories } = await getHomeData()
51
+ return (
52
+ <main id="main-content">
53
+ <ShopSalesBanner sales={shopSales} />
54
+ <HeroBanner />
55
+ <Suspense fallback={<ProductGridSkeleton count={8} />}>
56
+ <FeaturedProducts products={products} />
57
+ </Suspense>
58
+ <CategoryGrid categories={categories} />
59
+ </main>
60
+ )
61
+ }
62
+ ```
63
+
64
+ ## SEO
65
+ ```ts
66
+ export const metadata: Metadata = {
67
+ title: "Nome da Loja — Compre Online",
68
+ description: "...",
69
+ }
70
+ ```
@@ -0,0 +1,86 @@
1
+ # Agente 03 — Catalog (Listagem de Produtos)
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
+ Páginas de catálogo geral, categoria/tag e busca. O `ProductCard` gerado aqui é reutilizado por
9
+ Homepage e outros agentes.
10
+
11
+ ## Dependências
12
+ - Agente 00 (Scaffold)
13
+
14
+ ## Arquivos proprietários
15
+
16
+ | Arquivo | Descrição |
17
+ |---------|-----------|
18
+ | `app/(loja)/produtos/page.tsx` | Catálogo completo, paginado por offset (searchParams) |
19
+ | `app/(loja)/categoria/[tagSlug]/page.tsx` | Produtos de uma categoria |
20
+ | `app/(loja)/busca/page.tsx` | Resultados de busca (?q=) |
21
+ | `app/(loja)/produtos/loading.tsx` | Skeleton do grid |
22
+ | `components/catalog/ProductCard.tsx` | **Componente central — reutilizado em todo o storefront** |
23
+ | `components/catalog/ProductGrid.tsx` | Grid responsivo (1→2→3→4 colunas) |
24
+ | `components/catalog/Pagination.tsx` | Links de paginação via URL (?page=) |
25
+ | `components/catalog/FilterBar.tsx` | Filtros de categoria e ordenação |
26
+ | `components/catalog/SearchBar.tsx` | Campo de busca client (redireciona para /busca) |
27
+
28
+ ## Dados da API
29
+
30
+ ```ts
31
+ // Catálogo geral
32
+ const result = await client.getCatalog({
33
+ first: 24,
34
+ offset: (page - 1) * 24, // page vem de searchParams.page
35
+ sortBy: "updatedAt",
36
+ sortOrder: "desc",
37
+ })
38
+
39
+ // Categoria
40
+ const tags = await client.getTags(true)
41
+ const tag = tags.find(t => t.slug === tagSlug)
42
+ const result = await client.getCatalog({ first: 24, offset: 0, tagIds: [tag._id] })
43
+
44
+ // Busca
45
+ const result = await client.getCatalog({ first: 24, searchText: q })
46
+ ```
47
+
48
+ ## ProductCard — campos obrigatórios
49
+
50
+ ```tsx
51
+ interface ProductCardProps {
52
+ product: {
53
+ _id: string
54
+ title: string
55
+ slug: string
56
+ imageUrls?: string[]
57
+ pricing?: Array<{ displayPrice: string; price: number | null }>
58
+ variants?: Array<{ pricing?: Array<{ compareAtPrice?: { displayAmount: string } | null }> }>
59
+ isSoldOut: boolean
60
+ isBackorder?: boolean
61
+ isLowQuantity?: boolean
62
+ recurrenceAllowed?: boolean
63
+ }
64
+ }
65
+
66
+ // Link: /p/[product.slug]
67
+ // Imagem: product.imageUrls?.[0] (Next.js <Image>)
68
+ // Preço: product.pricing?.[0]?.displayPrice
69
+ // Preço de: product.variants?.[0]?.pricing?.[0]?.compareAtPrice?.displayAmount
70
+ // Badges: "Esgotado" | "Pré-venda" | "Últimas unidades" | "Assine e Poupe"
71
+ ```
72
+
73
+ ## generateStaticParams (categoria)
74
+
75
+ ```ts
76
+ export async function generateStaticParams() {
77
+ const client = await getUnboxClient()
78
+ const tags = await client.getTags(true)
79
+ return tags.filter(t => t.isVisible).map(t => ({ tagSlug: t.slug }))
80
+ }
81
+ ```
82
+
83
+ ## Paginação
84
+ - URL-based: `?page=2` via Link (não state de cliente — SSR-friendly)
85
+ - Mostrar total de resultados (`result.totalCount`)
86
+ - Desabilitar "anterior" na página 1, "próxima" se `!result.pageInfo?.hasNextPage`
@@ -0,0 +1,97 @@
1
+ # Agente 04 — PDP (Product Detail Page)
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
+ Página de detalhe de produto: galeria de imagens, seleção de variante, toggle assinatura,
9
+ botão de adicionar ao carrinho.
10
+
11
+ ## Dependências
12
+ - Agente 00 (Scaffold)
13
+ - Agente 05 (Cart) — AddToCartForm chama /api/cart
14
+
15
+ ## Arquivos proprietários
16
+
17
+ | Arquivo | Descrição |
18
+ |---------|-----------|
19
+ | `app/(loja)/produto/[productSlug]/page.tsx` | Server Component com SSG + ISR (revalidate: 3600) |
20
+ | `app/(loja)/produto/[productSlug]/loading.tsx` | Skeleton de PDP |
21
+ | `components/pdp/ProductImages.tsx` | Galeria: imagem principal + miniaturas |
22
+ | `components/pdp/ProductInfo.tsx` | Título, preço, badges, short description |
23
+ | `components/pdp/VariantSelector.tsx` | Botões de seleção de variante (client) |
24
+ | `components/pdp/SubscriptionToggle.tsx` | Toggle Avulso/Assine, seleção de frequência (client) |
25
+ | `components/pdp/AddToCartForm.tsx` | Quantidade + botão Adicionar (client) |
26
+ | `components/pdp/ProductDescription.tsx` | Descrição longa + Informações Adicionais (accordion) |
27
+
28
+ ## Dados da API
29
+
30
+ ```ts
31
+ export const revalidate = 3600 // ISR: revalidar a cada 1h
32
+
33
+ const item = await client.getProductBySlug(params.productSlug)
34
+ // item.product.variants[] — variantes para seleção
35
+ // item.product.recurrenceAllowed — exibir SubscriptionToggle
36
+ // item.product.pricing[].displayPrice — preço base
37
+ // item.shortDescription — texto acima do fold
38
+ // item.product.description — descrição longa (HTML)
39
+ // item.product.additionalInformation — accordion extra
40
+
41
+ // Frequências de assinatura (se recurrenceAllowed):
42
+ const shop = await client.getShop()
43
+ const frequencies = shop.recurringOrdersPolicy?.frequencyOptions ?? []
44
+ ```
45
+
46
+ ## generateStaticParams
47
+
48
+ ```ts
49
+ export async function generateStaticParams() {
50
+ const client = await getUnboxClient()
51
+ const catalog = await client.getCatalog({ first: 200 })
52
+ return catalog.nodes.map(n => ({ productSlug: n.product.slug }))
53
+ }
54
+ ```
55
+
56
+ ## SubscriptionToggle — lógica crítica
57
+
58
+ ```
59
+ - Só exibir se product.recurrenceAllowed === true
60
+ - "Avulso" (default) → isRecurring: false
61
+ - "Assinar" → isRecurring: true + selecionar frequência
62
+ - A FREQUÊNCIA vai no placeOrder (orderRecurrence), NÃO no cartItem
63
+ - No cartItem: apenas isRecurring: true (sem frequencyId — campo não existe no live)
64
+ ```
65
+
66
+ ## AddToCartForm
67
+
68
+ ```tsx
69
+ // Client component
70
+ async function handleAddToCart() {
71
+ const res = await fetch("/api/cart", {
72
+ method: "POST",
73
+ body: JSON.stringify({
74
+ action: "add",
75
+ productId: product._id,
76
+ productVariantId: selectedVariantId,
77
+ price: selectedVariant.pricing?.[0]?.price ?? 0,
78
+ quantity,
79
+ isRecurring,
80
+ }),
81
+ })
82
+ if (!res.ok) toast.error(friendlyError(await res.json()))
83
+ else { openCart(); toast.success("Produto adicionado!") }
84
+ }
85
+ ```
86
+
87
+ ## SEO
88
+
89
+ ```ts
90
+ export async function generateMetadata({ params }) {
91
+ const item = await client.getProductBySlug(params.productSlug)
92
+ return buildMetadata(item.product, `${SITE_URL}/p/${params.productSlug}`)
93
+ }
94
+ ```
95
+
96
+ ## JSON-LD
97
+ Incluir `<script type="application/ld+json">` com Product schema na página.