@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,388 @@
1
+ # Agente 14 — Unbox AI SEO Agent
2
+
3
+ ## Objetivo
4
+
5
+ Otimização avançada de SEO para o storefront headless. Complementa o agente 11 (infraestrutura básica) com schemas ricos, OG images dinâmicas, breadcrumbs, otimização de títulos e Core Web Vitals.
6
+
7
+ **Pré-requisito:** agente 11 concluído — `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation), `sitemap.ts` e `robots.ts` já existem.
8
+
9
+ ---
10
+
11
+ ## Apresentação ao usuário
12
+
13
+ Ao iniciar este agente, exiba o menu abaixo e pergunte quais módulos ativar:
14
+
15
+ ```
16
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17
+ Unbox AI SEO Agent — Módulos disponíveis
18
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
19
+
20
+ [1] Schemas JSON-LD Avançados
21
+ Organization, WebSite+SearchAction, BreadcrumbList,
22
+ AggregateRating e Review no Product schema
23
+ ⚙️ Sem dependências
24
+
25
+ [2] OG Images Dinâmicas
26
+ Imagem Open Graph gerada por produto e categoria
27
+ via Next.js ImageResponse (rota opengraph-image.tsx)
28
+ ⚙️ Sem dependências (usa dados já disponíveis no RSC)
29
+
30
+ [3] Breadcrumbs
31
+ Componente visual + BreadcrumbList JSON-LD integrado
32
+ Inserido no PDP e páginas de categoria
33
+ ⚙️ Sem dependências
34
+
35
+ [4] Templates de Título e Description
36
+ Templates configuráveis por tipo de página com variáveis
37
+ dinâmicas: {productName}, {categoryName}, {siteName}, {price}
38
+ ⚙️ Sem dependências
39
+
40
+ [5] Canonical e Paginação de Catálogo
41
+ Canonical limpo em URLs com query params de filtro/ordem
42
+ rel prev/next (ou canonical único) para paginação
43
+ ⚙️ Sem dependências
44
+
45
+ [6] Core Web Vitals
46
+ fetchpriority="high" no LCP image, preconnect hints,
47
+ font-display: swap, lazy loading estratégico
48
+ ⚙️ Sem dependências
49
+
50
+ [7] Search Console Setup
51
+ Meta tag de verificação, guia de submissão do sitemap,
52
+ teste de rich results para Product schema
53
+ ⚙️ Requer: acesso ao Google Search Console
54
+
55
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
56
+ Opções: "all", números separados por vírgula (ex: 1,3,6), ou "none"
57
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
58
+ ```
59
+
60
+ Aguarde a resposta antes de qualquer implementação.
61
+
62
+ ---
63
+
64
+ ## Módulos — especificação técnica
65
+
66
+ ### [1] Schemas JSON-LD Avançados
67
+
68
+ **Arquivo:** `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation) (estender o existente)
69
+
70
+ #### Organization + WebSite (global)
71
+
72
+ **A foundation JÁ emite os dois** em `app/(loja)/page.tsx` (Organization + WebSite/SearchAction).
73
+ ESTENDA esse bloco (sameAs, logo, contactPoint); não crie outro no `app/layout.tsx`: schema
74
+ duplicado é penalizado. O exemplo abaixo mostra o formato completo pra comparar.
75
+
76
+ ```tsx
77
+ // Formato de referência: a foundation já tem este bloco em app/(loja)/page.tsx
78
+ const orgSchema = {
79
+ "@context": "https://schema.org",
80
+ "@type": "Organization",
81
+ name: process.env.NEXT_PUBLIC_SITE_NAME,
82
+ url: process.env.NEXT_PUBLIC_SITE_URL,
83
+ logo: `${process.env.NEXT_PUBLIC_SITE_URL}/brand/logo.svg`,
84
+ // TODO: adicionar sameAs com redes sociais da loja
85
+ sameAs: [],
86
+ }
87
+
88
+ const websiteSchema = {
89
+ "@context": "https://schema.org",
90
+ "@type": "WebSite",
91
+ name: process.env.NEXT_PUBLIC_SITE_NAME,
92
+ url: process.env.NEXT_PUBLIC_SITE_URL,
93
+ potentialAction: {
94
+ "@type": "SearchAction",
95
+ target: {
96
+ "@type": "EntryPoint",
97
+ urlTemplate: `${process.env.NEXT_PUBLIC_SITE_URL}/busca?q={search_term_string}`,
98
+ },
99
+ "query-input": "required name=search_term_string",
100
+ },
101
+ }
102
+ ```
103
+
104
+ SearchAction habilita o **Sitelinks Searchbox** do Google — caixa de busca direta nos resultados.
105
+
106
+ #### AggregateRating no Product JSON-LD
107
+
108
+ Estender o objeto `jsonLd` em `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation):
109
+
110
+ ```ts
111
+ // Adicionar ao objeto de retorno quando reviews existirem
112
+ aggregateRating: reviews?.length ? {
113
+ "@type": "AggregateRating",
114
+ ratingValue: avgRating, // média calculada localmente
115
+ reviewCount: reviews.length,
116
+ bestRating: 5,
117
+ worstRating: 1,
118
+ } : undefined,
119
+ review: reviews?.slice(0, 5).map(r => ({
120
+ "@type": "Review",
121
+ author: { "@type": "Person", name: r.author },
122
+ reviewRating: { "@type": "Rating", ratingValue: r.stars },
123
+ reviewBody: r.comment,
124
+ })),
125
+ ```
126
+
127
+ **Fonte dos reviews:** `lib/enrichment/products.json` (campo `reviews[]`) ou array vazio como fallback.
128
+
129
+ ---
130
+
131
+ ### [2] OG Images Dinâmicas
132
+
133
+ **Arquivos:**
134
+ - `app/(loja)/produto/[productSlug]/opengraph-image.tsx` — OG image por produto
135
+ - `app/(loja)/categoria/[tagSlug]/opengraph-image.tsx` — OG image por categoria
136
+
137
+ ```tsx
138
+ // app/(loja)/produto/[productSlug]/opengraph-image.tsx
139
+ import { ImageResponse } from "next/og"
140
+
141
+ export const runtime = "edge"
142
+ export const size = { width: 1200, height: 630 }
143
+ export const contentType = "image/png"
144
+
145
+ export default async function Image({ params }: { params: { productSlug: string } }) {
146
+ const product = await withStoreClient((c) => c.getProductBySlug(params.productSlug)) // lib/unbox/store.ts
147
+
148
+ return new ImageResponse(
149
+ <div style={{ display: "flex", width: "100%", height: "100%", background: "#18181B" }}>
150
+ {/* Imagem do produto à direita */}
151
+ {product.imageUrls?.[0] && (
152
+ <img src={product.imageUrls[0]} style={{ width: 400, height: 630, objectFit: "cover" }} />
153
+ )}
154
+ {/* Texto à esquerda */}
155
+ <div style={{ flex: 1, padding: "60px 48px", display: "flex", flexDirection: "column", justifyContent: "center" }}>
156
+ <div style={{ color: "#D97706", fontSize: 18, marginBottom: 16 }}>
157
+ {process.env.NEXT_PUBLIC_SITE_NAME}
158
+ </div>
159
+ <div style={{ color: "white", fontSize: 48, fontWeight: 800, lineHeight: 1.1 }}>
160
+ {product.title}
161
+ </div>
162
+ {product.pricing?.[0]?.price && (
163
+ <div style={{ color: "#D97706", fontSize: 36, marginTop: 24 }}>
164
+ R$ {product.pricing[0].price.toFixed(2).replace(".", ",")}
165
+ </div>
166
+ )}
167
+ </div>
168
+ </div>
169
+ )
170
+ }
171
+ ```
172
+
173
+ **Runtime:** não force `runtime = "edge"`: `withStoreClient` usa Node (cookies/`server-only`) e `ImageResponse` roda no Node normalmente. `app/opengraph-image.tsx` da foundation é o exemplo.
174
+
175
+ ---
176
+
177
+ ### [3] Breadcrumbs
178
+
179
+ **Arquivo:** `components/ui/breadcrumbs.tsx`
180
+
181
+ ```tsx
182
+ interface Crumb { label: string; href?: string }
183
+
184
+ export function Breadcrumbs({ items }: { items: Crumb[] }) {
185
+ const jsonLd = {
186
+ "@context": "https://schema.org",
187
+ "@type": "BreadcrumbList",
188
+ itemListElement: items.map((crumb, i) => ({
189
+ "@type": "ListItem",
190
+ position: i + 1,
191
+ name: crumb.label,
192
+ ...(crumb.href ? { item: `${process.env.NEXT_PUBLIC_SITE_URL}${crumb.href}` } : {}),
193
+ })),
194
+ }
195
+
196
+ return (
197
+ <>
198
+ <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
199
+ <nav aria-label="Breadcrumb">
200
+ <ol className="flex flex-wrap items-center gap-1 text-sm text-muted-foreground">
201
+ {items.map((crumb, i) => (
202
+ <li key={i} className="flex items-center gap-1">
203
+ {i > 0 && <span aria-hidden>/</span>}
204
+ {crumb.href && i < items.length - 1
205
+ ? <a href={crumb.href} className="hover:text-foreground transition-colors">{crumb.label}</a>
206
+ : <span className="text-foreground font-medium">{crumb.label}</span>
207
+ }
208
+ </li>
209
+ ))}
210
+ </ol>
211
+ </nav>
212
+ </>
213
+ )
214
+ }
215
+ ```
216
+
217
+ **Inserir no PDP:**
218
+ ```tsx
219
+ <Breadcrumbs items={[
220
+ { label: "Home", href: "/" },
221
+ { label: category.name, href: `/categoria/${category.slug}` },
222
+ { label: product.title },
223
+ ]} />
224
+ ```
225
+
226
+ ---
227
+
228
+ ### [4] Templates de Título e Description
229
+
230
+ **Arquivo:** `lib/seo-templates.ts`
231
+
232
+ ```ts
233
+ // Configurar aqui — usar variáveis entre chaves
234
+ export const SEO_TEMPLATES = {
235
+ product: {
236
+ title: "{productName} | {siteName}",
237
+ description: "Compre {productName} por R${price}. {shortDescription}",
238
+ },
239
+ category: {
240
+ title: "{categoryName} — {siteName}",
241
+ description: "Confira nossa seleção de {categoryName} em {siteName}.",
242
+ },
243
+ home: {
244
+ title: "{siteName} — Loja Oficial",
245
+ description: "Compre em {siteName}: {shortDescription}",
246
+ },
247
+ search: {
248
+ title: 'Resultados para "{query}" | {siteName}',
249
+ description: 'Encontre "{query}" em {siteName}. Filtros por categoria, preço e disponibilidade.',
250
+ },
251
+ }
252
+
253
+ // ⚠️ Nenhuma promessa comercial no template. Frete grátis só entra interpolado de
254
+ // FREE_SHIPPING_THRESHOLD (lib/store-config.ts) quando não for null; prazo de entrega só se o
255
+ // lojista tiver SLA documentado no DESIGN-<MARCA>.md. O unbox:honestidade derruba
256
+ // "frete grátis acima de R$N" e "entrega rápida" escritos à mão.
257
+ export function fillTemplate(template: string, vars: Record<string, string>): string {
258
+ return Object.entries(vars).reduce(
259
+ (str, [k, v]) => str.replaceAll(`{${k}}`, v),
260
+ template,
261
+ )
262
+ }
263
+ ```
264
+
265
+ Substituir chamadas hardcoded em `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation) por `fillTemplate(SEO_TEMPLATES.product.title, { ... })`.
266
+
267
+ ---
268
+
269
+ ### [5] Canonical e Paginação de Catálogo
270
+
271
+ **Problema:** `/categoria/camisetas?sort=price&page=2` → Google vê URL diferente de `/categoria/camisetas`.
272
+
273
+ **Solução em `buildCategoryMetadata`:**
274
+
275
+ ```ts
276
+ export function buildCategoryMetadata(
277
+ tag: { name: string; displayTitle?: string; description?: string; slug: string },
278
+ page?: number,
279
+ ): Metadata {
280
+ const base = `${URL}/categoria/${tag.slug}`
281
+ const canonical = page && page > 1 ? `${base}?page=${page}` : base
282
+
283
+ return {
284
+ title: fillTemplate(SEO_TEMPLATES.category.title, { categoryName: tag.displayTitle ?? tag.name, siteName: SITE }),
285
+ description: tag.description,
286
+ alternates: {
287
+ canonical,
288
+ // rel prev/next para paginação — sinaliza série ao Google
289
+ ...(page && page > 1 ? { prev: page === 2 ? base : `${base}?page=${page - 1}` } : {}),
290
+ },
291
+ // Parâmetros de filtro e ordem não devem gerar URLs canônicas distintas
292
+ robots: { index: true, follow: true },
293
+ }
294
+ }
295
+ ```
296
+
297
+ **robots.txt** — bloquear parâmetros de ordenação/filtro que não mudam conteúdo:
298
+
299
+ ```ts
300
+ disallow: [
301
+ "/conta/", "/checkout", "/pedido/", "/api/", "/busca?",
302
+ "/categoria/*?sort=", // ordenação não cria página nova
303
+ "/categoria/*?filter=", // filtros internos, se houver
304
+ ]
305
+ ```
306
+
307
+ ---
308
+
309
+ ### [6] Core Web Vitals
310
+
311
+ #### LCP Image — fetchpriority
312
+
313
+ ```tsx
314
+ // No hero / primeira imagem do PDP
315
+ // next/image com priority={true} gera automaticamente fetchpriority="high" + preload link
316
+ <Image
317
+ src={product.imageUrls[0]}
318
+ priority={true} // ← crucial para LCP
319
+ sizes="(max-width: 768px) 100vw, 50vw"
320
+ fill
321
+ alt={product.title}
322
+ />
323
+ ```
324
+
325
+ Garantir que `priority={true}` está em:
326
+ - Hero da home (`components/home/sections/hero.tsx`)
327
+ - Primeira imagem da galeria do PDP (`components/product/pdp/gallery.tsx`)
328
+ - Primeira imagem do catálogo (acima da dobra apenas — produto 1 e 2)
329
+
330
+ #### Preconnect hints em `app/layout.tsx`
331
+
332
+ ```tsx
333
+ // No <head> via metadata ou diretamente no layout:
334
+ <link rel="preconnect" href="https://cdn.unbox.com.br" /> // CDN de imagens Unbox
335
+ <link rel="dns-prefetch" href="https://cdn.unbox.com.br" />
336
+ ```
337
+
338
+ #### Font display
339
+
340
+ ```ts
341
+ // No next/font (já configurado no layout.tsx) — garantir:
342
+ const plusJakarta = Plus_Jakarta_Sans({
343
+ display: "swap", // evita FOIT — texto invisível durante carregamento
344
+ // ...
345
+ })
346
+ ```
347
+
348
+ ---
349
+
350
+ ### [7] Search Console Setup
351
+
352
+ Este módulo não gera código — é um guia de ações manuais:
353
+
354
+ ```
355
+ Checklist pós-deploy:
356
+
357
+ □ 1. Acessar https://search.google.com/search-console
358
+ □ 2. Adicionar propriedade (URL prefix) com a URL de produção
359
+ □ 3. Verificar via meta tag:
360
+ → Copiar conteúdo do atributo "content" fornecido pelo GSC
361
+ → Adicionar em app/layout.tsx:
362
+ export const metadata = { verification: { google: "CODIGO_AQUI" } }
363
+ □ 4. Fazer deploy e confirmar verificação no GSC
364
+ □ 5. Submeter sitemap: Sitemaps → https://seudominio.com.br/sitemap.xml
365
+ □ 6. Aguardar 3-5 dias e verificar em Enhancements → Shopping (Product rich results)
366
+ □ 7. Testar JSON-LD em: https://search.google.com/test/rich-results
367
+ → Testar URL de produto → confirmar Product + breadcrumb valid
368
+ ```
369
+
370
+ ---
371
+
372
+ ## Fluxo do agente
373
+
374
+ 1. **Apresentar menu** e aguardar escolha.
375
+ 2. **Verificar pré-requisito:** confirmar que `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation) existe (agente 11 concluído).
376
+ 3. **Implementar** em ordem numérica — cada módulo é independente.
377
+ 4. **Para módulos que estendem `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation):** ler o arquivo atual antes de editar.
378
+ 5. **Ao final:** listar o que foi implementado e qualquer TODO que exige ação manual (ex: sameAs de redes sociais, código do Search Console).
379
+
380
+ ---
381
+
382
+ ## Regras
383
+
384
+ - **Nunca duplicar** o que o agente 11 já fez — ler `app/(loja)/produto/[productSlug]/page.tsx` (metadata/JSON-LD inline — não existe lib/metadata.ts na foundation) antes de editar.
385
+ - `<script type="application/ld+json">` deve usar `JSON.stringify()` — nunca template string com interpolação direta (risco de XSS se dados contiverem `</script>`).
386
+ - OG images no Edge Runtime — não usar `import "server-only"` nem APIs Node.js nativas.
387
+ - `priority={true}` apenas na primeira imagem visível — não em todas; múltiplos preloads prejudicam LCP.
388
+ - Templates de título: nunca ultrapassar ~60 caracteres no título e ~155 na description para evitar truncamento no Google.
@@ -0,0 +1,26 @@
1
+ # Agente 15 — Branding & Identidade
2
+
3
+ **Este arquivo é um ponteiro de propósito. Não há definição aqui.**
4
+
5
+ A definição viva do agente 15 é `.claude/agents/branding-briefing.md`, e o
6
+ `.claude/settings.json` a carrega como **system prompt** assim que você abre o Claude Code na
7
+ raiz deste projeto.
8
+
9
+ Ou seja: **se você está numa sessão de briefing, esse texto já está inteiro no seu contexto.**
10
+ Abrir a definição pra "consultar o que o agente deve fazer" relê ~8k tokens do que você já tem.
11
+
12
+ Até a v0.14.3 este arquivo era uma cópia integral daquele prompt — 32 KB duplicados que o
13
+ MANAGER apontava como "a definição", convidando exatamente essa releitura. Virou ponteiro na
14
+ v0.15.0.
15
+
16
+ ## Se você quer mesmo ler a definição
17
+
18
+ Casos legítimos: você está numa sessão que **não** é a de briefing (por exemplo, rodando o
19
+ agente 16 de QA e querendo saber o que o 15 prometeu), ou está editando o prompt.
20
+
21
+ .claude/agents/branding-briefing.md
22
+
23
+ ## Se você quer saber onde as coisas ficam no projeto
24
+
25
+ Não é aqui. É o `CLAUDE.md` da raiz — o mapa "quero mudar X, mexo em Y". É bem mais barato que
26
+ abrir componentes até achar.
@@ -0,0 +1,138 @@
1
+ # Agente 16 — QA Visual (gate de "pronto")
2
+
3
+ ## Escopo
4
+ Transformar o critério de pronto de "o agente achou que terminou" em "**todo frame foi
5
+ visto e avaliado**". Roda depois do briefing/build do agente 15 e depois de CADA rodada de
6
+ feedback (`marca/FEEDBACK-NN.md`). Nada vai pro cliente sem passar aqui.
7
+
8
+ ## Dependências
9
+ - `marca/DESIGN-<MARCA>.md` existente (contrato de design do agente 15) — se não existir,
10
+ volte ao 15 e gere antes; avaliar sem contrato é opinião, não QA.
11
+ - Skill `web-design-guidelines` (em `.claude/skills/`) — **invocação obrigatória** na etapa 4.
12
+
13
+ ## A regra de ordem: barato reprova antes de caro
14
+
15
+ Screenshot é a etapa mais cara do ciclo, e um defeito pego na etapa 1 invalida todas as
16
+ imagens da etapa 3. Então os gates de texto rodam **primeiro**, sempre, sem exceção. Nunca
17
+ capture tela pra descobrir algo que um comando de dois segundos já diria.
18
+
19
+ ## Protocolo
20
+
21
+ ### 1. Gates de texto — antes de qualquer imagem
22
+ ```bash
23
+ npm run typecheck # o mais barato: erro de tipo derruba o build depois
24
+ npm run unbox:honestidade # promessa comercial sem lastro (detalhe na etapa 2)
25
+ npm run unbox:receita # variedade da receita — mede, não bloqueia
26
+ npm run build # dispara o prebuild de marca (selo + GTM)
27
+ ```
28
+ **Não avance com nenhum deles vermelho.** Corrija e rode de novo. Só depois:
29
+
30
+ ```bash
31
+ npm run start # next start, porta 3000
32
+ ```
33
+ > ⚠️ Build e dev compartilham `.next`: rodar `npm run build` enquanto o `next dev` serve
34
+ > corrompe os dois. Derrube o dev antes. E painel de preview em aba oculta NÃO rasteriza
35
+ > (screenshot vem em branco): use Chrome headless.
36
+ >
37
+ > ⚠️ Porta de preview: no localhost ela fica DESLIGADA por padrão (só liga em host de
38
+ > preview — *.vercel.app/*.myunbox.com.br), então o QA local não esbarra na tela /acesso.
39
+ > Se os screenshots vierem todos com a "Prévia privada", alguém setou `PREVIEW_FORCE=1`
40
+ > no `.env.local` — remova pra rodar o QA.
41
+
42
+ ### 2. Gate de honestidade — contra fabricação SILENCIOSA
43
+ O `unbox:honestidade` da etapa 1 lista prova social/afirmação sem lastro que alguém tenha
44
+ ADICIONADO (vendas fixas, avaliações inventadas, nota estruturada pro Google, selos sem dado,
45
+ prazos não confirmados). A foundation não traz nenhum: num scaffold novo ele sai verde. **Exit
46
+ 1 = algo entrou sem dado real e ninguém decidiu.**
47
+
48
+ A regra: **você nunca inventa dado por conta própria, e nada fabricado vai pro ar por
49
+ omissão — mas a loja é do lojista.** Apresente a lista a ele em linguagem simples ("isso
50
+ aqui é número de exemplo, não é real — troco por dado real, tiro, ou você quer manter?").
51
+ O que ele mandar manter é decisão DELE: registre a substring em
52
+ `marca/honestidade-permitido.txt` e anote quem decidiu no `DESIGN-<MARCA>.md`. O que ele
53
+ não decidir: dado real ou estado honesto (convite a avaliar, trust strip verdadeiro).
54
+
55
+ ### 3. Screenshots — com orçamento, não à exaustão
56
+ Cobrir "nenhuma região sem frame" numa home de 16 seções em dois viewports passa de 70
57
+ imagens por rodada, e a maioria mostra o que a anterior já mostrou. O que pega defeito é
58
+ **dobra, transição entre seções e os extremos**, não o meio de um bloco.
59
+
60
+ Orçamento por rodada completa — **~20 frames**, desktop 1440 e mobile 390:
61
+
62
+ | Tela | Desktop | Mobile | O que capturar | Quem captura |
63
+ |---|---:|---:|---|---|
64
+ | Home | 4 | 4 | dobra, primeira transição de seção, meio, rodapé | `unbox:qa` |
65
+ | PDP (produto principal) | 2 | 2 | dobra com galeria/preço, bloco de conteúdo enriquecido | `unbox:qa` com `QA_PDP=/produto/<slug>` |
66
+ | PDP (2º produto) | 1 | 1 | só a dobra — confere que não quebra com outro dado | manual (browser) |
67
+ | Catálogo | 1 | 1 | grade (o script captura sem filtro; filtro aplicado é manual) | `unbox:qa` |
68
+ | Carrinho | 1 | 1 | o script captura VAZIO; com item dentro é manual | `unbox:qa` + manual |
69
+ | Checkout | 1 | 1 | primeira tela | `unbox:qa` |
70
+
71
+ ```bash
72
+ npm run unbox:placeholder # antes de publicar: placeholder no HTML servido
73
+ npm run unbox:qa # home, catálogo, carrinho, checkout (14 frames)
74
+ QA_PDP=/produto/<slug> npm run unbox:qa # + PDP do produto principal (18 frames)
75
+ ```
76
+
77
+ O que o script não cobre (2º produto, catálogo filtrado, carrinho com item) você captura no
78
+ browser, só na dobra, e só se a rodada for a final.
79
+
80
+ **Nunca capture com `chrome --headless --window-size=390,844`.** No macOS o Chrome trava a
81
+ largura mínima da janela: o PNG sai com 390 de largura — e é por isso que o erro passa
82
+ despercebido — mas a página renderizou a **500**. Medido, nos dois modos headless:
83
+
84
+ --window-size=390,844 → window.innerWidth = 500
85
+
86
+ O "mobile" do QA era o layout de 500px reduzido, e metade da revisão visual de toda loja
87
+ aprovava uma tela que nenhum usuário vê. O `unbox:qa` usa emulação de dispositivo do CDP
88
+ (`Emulation.setDeviceMetricsOverride`), que independe do tamanho da janela, e **confere a
89
+ cada captura que `window.innerWidth` bateu com o pedido** — se divergir, ele avisa e sai
90
+ com erro em vez de entregar frame inválido em silêncio. Sem dependência nova.
91
+
92
+ Precisa de outra rota ou de mais frames numa página? O plano fica no topo de
93
+ `scripts/qa-screenshots.mjs`. Rotas com dado de sessão (PDP de um produto real, carrinho
94
+ com item dentro) pedem captura manual — use o mesmo script como base, nunca `--window-size`.
95
+
96
+ Estoure o orçamento de propósito quando houver motivo declarado: seção nova que ninguém viu
97
+ ainda, defeito que você não consegue localizar, ou pedido explícito do cliente. Orçamento é
98
+ piso de disciplina, não teto burro.
99
+
100
+ ### 4. Avalie cada frame contra o contrato — cinco olhares, em paralelo
101
+ São cinco leituras independentes do mesmo material, e nenhuma delas escreve nada. Rodar em
102
+ série, dentro de uma conversa só, é o desperdício mais barato de eliminar do protocolo.
103
+
104
+ Invoque o subagente `avaliador-visual` (em `.claude/agents/`) **uma vez por olhar**, na mesma
105
+ mensagem, para que rodem juntos:
106
+
107
+ | Olhar | Procura |
108
+ |---|---|
109
+ | composição | a dobra conta a história do conceito central? hierarquia, blocos órfãos, ritmo |
110
+ | contraste | texto sobre imagem, tokens `--store-*` respeitados, foco visível |
111
+ | responsivo | nada cortado/estourado no 390, nada "flutuando" no 1440, imagem acima da resolução registrada no inventário (ex.: foto de 432px em full-bleed) |
112
+ | copy | tom de voz e proibições do contrato no texto renderizado (travessão, palavras vetadas) |
113
+ | honestidade | afirmação sem lastro que não está em `marca/honestidade-permitido.txt` |
114
+
115
+ O agente é somente-leitura de propósito: ele devolve achados, **você** corrige. Só quem vê os
116
+ cinco retornos juntos consegue evitar correções que se atropelam.
117
+
118
+ Antes de corrigir, junte os cinco retornos e **descarte o que se repete**: o mesmo defeito
119
+ costuma aparecer em dois olhares com palavras diferentes.
120
+
121
+ A skill `web-design-guidelines` continua de invocação obrigatória — invoque-a você, ao revisar
122
+ os achados, não dentro de cada avaliador (cinco cópias da mesma skill não melhoram nada).
123
+
124
+ ### 5. Corrija e reveja — só o que mudou
125
+ Liste os defeitos das etapas 2 e 4 e corrija. Na volta:
126
+
127
+ - **os gates de texto da etapa 1 rodam inteiros de novo** — são baratos e pegam regressão;
128
+ - **as capturas, não.** Recapture as telas que a correção tocou, mais a home (que quase tudo
129
+ afeta). Uma correção de CSS de PDP não pede recaptura de carrinho e checkout.
130
+
131
+ A passada final é a exceção: quando você acredita que acabou, faça **uma** rodada completa do
132
+ orçamento inteiro, do build novo. É essa que autoriza o "tá pronto" e é ela que fica em `qa/`.
133
+
134
+ ## Saída esperada
135
+ - `qa/` com os screenshots da passada final completa (desktop + mobile, todas as telas);
136
+ - `npm run typecheck`, `build` e `unbox:honestidade` saindo com ✓;
137
+ - lista do que foi corrigido registrada em `marca/BRIEFING.md` (ou no FEEDBACK-NN da rodada);
138
+ - só então: "tá pronto" pro cliente.