sales-app-extensibility

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Sales App Extensibility

Sales App 扩展性

When this skill applies

适用场景

Use this skill when building, customizing, or deploying extensions for VTEX Sales App.
  • Adding features to the cart page (promotions, loyalty, services)
  • Adding features to the Product Detail Page (badges, recommendations, warranties)
  • Adding features to the menu (user profile, navigation, metrics)
  • Integrating external APIs into Sales App extensions
  • Generating, scaffolding, or validating extension code for Sales App
Do not use this skill for:
  • Regular FastStore storefront customization (use
    faststore-storefront
    )
  • Building VTEX IO apps (use
    vtex-io-*
    skills)
  • Sales App core development or framework modifications
当你需要构建、定制或部署VTEX Sales App扩展时使用此技能。
  • 为购物车页面添加功能(促销、会员服务、增值服务)
  • 为商品详情页(PDP)添加功能(标识、推荐、保修服务)
  • 为菜单添加功能(用户资料、导航、数据统计)
  • 将外部API集成到Sales App扩展中
  • 生成、搭建或验证Sales App扩展代码
请勿将此技能用于:
  • 常规FastStore店铺定制(请使用
    faststore-storefront
    技能)
  • 构建VTEX IO应用(请使用
    vtex-io-*
    系列技能)
  • Sales App核心开发或框架修改

Prerequisite: FastStore project

先决条件:FastStore 项目

The project root must contain:
biome.json
,
faststore.json
,
package.json
,
tsconfig.json
,
turbo.json
.
If any are missing, STOP. The user must install FastStore first:
bash
npx @vtex/fsp-cli init
项目根目录必须包含:
biome.json
faststore.json
package.json
tsconfig.json
turbo.json
如果缺少任何文件,请停止操作。用户必须先安装FastStore:
bash
npx @vtex/fsp-cli init

Prompt: "What is the application name?" → enter name or press Enter for default

提示:"What is the application name?" → 输入应用名称或按回车使用默认值

cd <application-name> && yarn

Documentation: https://beta.fast.store/getting-started
cd <application-name> && yarn

文档:https://beta.fast.store/getting-started

Prerequisite: Sales App module

先决条件:Sales App 模块

Inside the FastStore project, a Sales App workspace must exist (typically at
packages/sales-app
) with
src/
,
package.json
, and
tsconfig.json
. Check root
package.json
"workspaces"
for a path containing
sales-app
. If missing, STOP:
bash
yarn add @vtex/sales-app -D -W
npx fsp create
在FastStore项目中,必须存在Sales App工作区(通常位于
packages/sales-app
),且包含
src/
package.json
tsconfig.json
。检查根目录
package.json
"workspaces"
字段,确认是否包含指向
sales-app
的路径。如果缺少,请停止操作
bash
yarn add @vtex/sales-app -D -W
npx fsp create

Prompts: account name → "Sales App" → path (default or custom)

提示:账户名称 → "Sales App" → 路径(默认或自定义)

Then add the path to root package.json "workspaces" array

然后将路径添加到根目录package.json的"workspaces"数组中

yarn install

Documentation: https://beta.fast.store/sales-app/setting-up

**Do NOT proceed to discovery or code generation until both prerequisites are confirmed.**
yarn install

文档:https://beta.fast.store/sales-app/setting-up

**在确认两个先决条件都满足之前,请勿进行发现或代码生成步骤。**

Decision rules

决策规则

Follow the mandatory 6-step workflow in order. Do not skip steps.
StepPurposeGate
0Check prerequisitesFastStore + Sales App installed → proceed; otherwise STOP
1DiscoveryUnderstand what the user wants to build
2Requirements & PlanMap requirements → generate plan → wait for user approval
3Code Generation & ValidationGenerate component + CSS + index.tsx → validate
4DocumentationGenerate
docs/<ExtensionName>.md
explaining the extension
5Local TestingProvide dev commands and URLs
6Build & DeployBuild command → deployment guide
请严格按照以下6步工作流执行,不得跳过任何步骤。
步骤目的准入条件
0检查先决条件已安装FastStore + Sales App → 继续;否则停止
1需求发现理解用户想要构建的功能
2需求与规划梳理需求 → 生成规划 → 等待用户确认
3代码生成与验证生成组件 + CSS + index.tsx → 验证
4文档生成生成
docs/<ExtensionName>.md
说明扩展功能
5本地测试提供开发命令和测试URL
6构建与部署提供构建命令 → 部署指南

Extension point selection

扩展点选择

Extension PointCategoryAvailable HooksLayout Shift
cart.cart-list.after
CartuseCart, useExtensionNo
cart.cart-item.after
CartuseCart, useCartItem, useExtensionYes
cart.order-summary.after
CartuseCart, useExtensionYes
pdp.sidebar.before
PDPusePDP, useCart, useExtensionYes
pdp.sidebar.after
PDPusePDP, useCart, useExtensionYes
pdp.content.after
PDPusePDP, useCart, useExtensionYes
menu.item
MenuuseExtensionNo
menu.drawer-content
MenuuseCurrentUser, useExtensionNo
扩展点分类可用Hooks是否会导致布局偏移
cart.cart-list.after
购物车useCart, useExtension
cart.cart-item.after
购物车useCart, useCartItem, useExtension
cart.order-summary.after
购物车useCart, useExtension
pdp.sidebar.before
PDPusePDP, useCart, useExtension
pdp.sidebar.after
PDPusePDP, useCart, useExtension
pdp.content.after
PDPusePDP, useCart, useExtension
menu.item
菜单useExtension
menu.drawer-content
菜单useCurrentUser, useExtension

Hook availability

Hook 可用性

  • useCart → all cart + PDP extensions
  • useCartItem
    cart.cart-item.after
    only
  • useCurrentUser
    menu.drawer-content
    only
  • usePDP → PDP extensions only
  • useExtension → all extension points
  • useCart → 所有购物车 + PDP扩展
  • useCartItem → 仅适用于
    cart.cart-item.after
  • useCurrentUser → 仅适用于
    menu.drawer-content
  • usePDP → 仅适用于PDP扩展
  • useExtension → 所有扩展点

Template selection

模板选择

  • No API + no hooks → simple template
  • No API + hooks → hook template
  • API + no auth → API template
  • API + VTEX IO proxy → IO proxy template (recommended)
  • API + direct auth → direct auth template (insecure, warn user)
  • API doc provided → generate TypeScript interfaces from extracted response shapes; no API doc → use
    ${DATA_INTERFACE}
    placeholder
  • 无API + 无hooks → 简单模板
  • 无API + 有hooks → Hook模板
  • 有API + 无鉴权 → API模板
  • 有API + VTEX IO代理 → IO代理模板(推荐)
  • 有API + 直接鉴权 → 直接鉴权模板(不安全,需提醒用户)
  • 提供API文档 → 从提取的响应结构生成TypeScript接口;无API文档 → 使用
    ${DATA_INTERFACE}
    占位符

API authentication strategy

API鉴权策略

  1. Recommended: VTEX IO Proxy App — IO app stores keys server-side. Extension uses
    credentials: 'include'
    with a relative path (
    /_v/my-api/data
    ).
  2. Insecure: Direct Auth — Keys in frontend code, visible in browser. Testing/development only.
  1. 推荐:VTEX IO代理应用 — IO应用在服务端存储密钥。扩展使用
    credentials: 'include'
    相对路径
    /_v/my-api/data
    )。
  2. 不安全:直接鉴权 — 密钥存于前端代码中,可在浏览器中查看。仅用于测试/开发环境。

Hard constraints

硬性约束

Constraint: Component must return JSX.Element, never null

约束:组件必须返回JSX.Element,绝对不能返回null

defineExtensions
expects
ExtensionPointComponent
which returns
Element
, not
Element | null
.
Why this matters Returning
null
causes a TypeScript compilation error. The build will fail.
Detection
return null
in any component registered with
defineExtensions
.
Correct
typescript
export function MyExtension(): JSX.Element {
  if (!data) return (<></>);
  return <div>{data.value}</div>;
}
Wrong
typescript
export function MyExtension(): JSX.Element | null {
  if (!data) return null;
  return <div>{data.value}</div>;
}
defineExtensions
要求
ExtensionPointComponent
返回
Element
,而非
Element | null
重要性 返回null会导致TypeScript编译错误,构建将失败。
检测方式 任何通过
defineExtensions
注册的组件中出现
return null
正确示例
typescript
export function MyExtension(): JSX.Element {
  if (!data) return (<></>);
  return <div>{data.value}</div>;
}
错误示例
typescript
export function MyExtension(): JSX.Element | null {
  if (!data) return null;
  return <div>{data.value}</div>;
}

Constraint: Guard optional properties before use

约束:使用可选属性前必须进行校验

CartItem.manualPrice
(number | undefined),
CartItem.productRefId
(string | undefined),
CartItem.attachments
(Attachment[] | undefined) must be guarded.
Why this matters TypeScript strict mode rejects accessing possibly-undefined values.
Detection
item.manualPrice
,
item.productRefId
, or
item.attachments
without
?.
,
??
,
&&
, or
!= null
.
Correct
typescript
const price = item.manualPrice ?? item.sellingPrice;
const refId = item.productRefId ?? 'N/A';
const count = item.attachments?.length ?? 0;
Wrong
typescript
const price = item.manualPrice;
const refId = item.productRefId.toUpperCase();
const count = item.attachments.length;
CartItem.manualPrice
(number | undefined)、
CartItem.productRefId
(string | undefined)、
CartItem.attachments
(Attachment[] | undefined)必须先校验再使用。
重要性 TypeScript严格模式禁止访问可能未定义的值。
检测方式 使用
item.manualPrice
item.productRefId
item.attachments
时未使用
?.
??
&&
!= null
进行校验。
正确示例
typescript
const price = item.manualPrice ?? item.sellingPrice;
const refId = item.productRefId ?? 'N/A';
const count = item.attachments?.length ?? 0;
错误示例
typescript
const price = item.manualPrice;
const refId = item.productRefId.toUpperCase();
const count = item.attachments.length;

Constraint: useCartItem().item may be undefined

约束:useCartItem().item可能为undefined

item
from
useCartItem()
is
CartItem | undefined
.
Why this matters Accessing properties on
undefined
causes a runtime crash.
Detection Destructured
item
from
useCartItem()
used without
if (!item)
guard.
Correct
typescript
const { item } = useCartItem();
if (!item) return (<></>);
return <div>{item.name}</div>;
Wrong
typescript
const { item } = useCartItem();
return <div>{item.name}</div>;
useCartItem()
获取的
item
类型为
CartItem | undefined
重要性 访问undefined的属性会导致运行时崩溃。
检测方式
useCartItem()
解构的
item
未使用
if (!item)
进行校验就直接使用。
正确示例
typescript
const { item } = useCartItem();
if (!item) return (<></>);
return <div>{item.name}</div>;
错误示例
typescript
const { item } = useCartItem();
return <div>{item.name}</div>;

Constraint: Never expose authentication keys in frontend code

约束:绝对不能在前端代码中暴露鉴权密钥

API keys in
fetch
headers are visible in the browser network tab.
Why this matters Leaked keys compromise the external service.
Detection Literal auth header values in
fetch()
:
'x-api-key': '...'
,
'Authorization': 'Bearer ...'
.
Correct
typescript
const response = await fetch('/_v/my-api/data', {
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
});
Wrong
typescript
const response = await fetch('https://api.example.com/data', {
  headers: { 'x-api-key': 'sk-secret-key-12345' },
});
fetch
请求头中的API密钥可在浏览器网络面板中查看。
重要性 密钥泄露会危及外部服务安全。
检测方式
fetch()
中出现字面量鉴权头值:
'x-api-key': '...'
'Authorization': 'Bearer ...'
正确示例
typescript
const response = await fetch('/_v/my-api/data', {
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
});
错误示例
typescript
const response = await fetch('https://api.example.com/data', {
  headers: { 'x-api-key': 'sk-secret-key-12345' },
});

Constraint: IO Proxy must use relative paths only

约束:IO代理必须仅使用相对路径

The Sales App internal proxy resolves the domain automatically.
Why this matters A full URL bypasses the proxy, breaking session cookies and causing CORS errors.
Detection
fetch('https://{account}.myvtex.com/...')
in IO proxy components.
Correct
typescript
await fetch('/_v/my-loyalty-api/points', { credentials: 'include' });
Wrong
typescript
await fetch('https://myaccount.myvtex.com/_v/my-loyalty-api/points');
Sales App内部代理会自动解析域名。
重要性 使用完整URL会绕过代理,破坏会话cookie并导致CORS错误。
检测方式 IO代理组件中出现
fetch('https://{account}.myvtex.com/...')
正确示例
typescript
await fetch('/_v/my-loyalty-api/points', { credentials: 'include' });
错误示例
typescript
await fetch('https://myaccount.myvtex.com/_v/my-loyalty-api/points');

Constraint: defineExtensions is required in index.tsx

约束:index.tsx中必须使用defineExtensions

Entry point must use
defineExtensions
from
@vtex/sales-app
.
Why this matters Without it, the build succeeds but no extensions render.
Detection Missing
defineExtensions
import or call in
index.tsx
.
Correct
typescript
import { defineExtensions } from '@vtex/sales-app';
import { MyExtension } from './components/MyExtension';
export default defineExtensions({ 'cart.cart-list.after': MyExtension });
Wrong
typescript
import { MyExtension } from './components/MyExtension';
export default { 'cart.cart-list.after': MyExtension };
入口文件必须使用
@vtex/sales-app
中的
defineExtensions
重要性 如果不使用,构建会成功但扩展无法渲染。
检测方式
index.tsx
中缺少
defineExtensions
的导入或调用。
正确示例
typescript
import { defineExtensions } from '@vtex/sales-app';
import { MyExtension } from './components/MyExtension';
export default defineExtensions({ 'cart.cart-list.after': MyExtension });
错误示例
typescript
import { MyExtension } from './components/MyExtension';
export default { 'cart.cart-list.after': MyExtension };

Constraint: Extension point names must match exactly

约束:扩展点名称必须完全匹配

IDs are a fixed set. Non-existent names silently fail.
Why this matters The extension renders nowhere. No build error — invisible at runtime.
Detection Any name not in:
cart.cart-list.after
,
cart.cart-item.after
,
cart.order-summary.after
,
pdp.sidebar.before
,
pdp.sidebar.after
,
pdp.content.after
,
menu.item
,
menu.drawer-content
.
Correct
typescript
defineExtensions({ 'cart.cart-list.after': MyExtension });
Wrong
typescript
defineExtensions({ 'cart.list.after': MyExtension });
扩展点ID是固定集合,不存在的名称会导致静默失败。
重要性 扩展无法在任何位置渲染,且无构建错误——仅在运行时不可见。
检测方式 使用的名称不在以下列表中:
cart.cart-list.after
cart.cart-item.after
cart.order-summary.after
pdp.sidebar.before
pdp.sidebar.after
pdp.content.after
menu.item
menu.drawer-content
正确示例
typescript
defineExtensions({ 'cart.cart-list.after': MyExtension });
错误示例
typescript
defineExtensions({ 'cart.list.after': MyExtension });

Constraint: Hooks must be used in compatible extension points

约束:Hooks必须在兼容的扩展点中使用

Each hook has an
available_in
restriction.
Why this matters Hook context is only mounted for specific extension points. Using elsewhere throws runtime errors.
Detection
useCartItem
in PDP/menu.
useCurrentUser
in cart.
usePDP
in menu/cart-list.
Correct
typescript
// useCartItem in cart.cart-item.after ✓
defineExtensions({ 'cart.cart-item.after': ItemWarranty });
Wrong
typescript
// useCartItem in pdp.sidebar.after ✗ — will fail at runtime
defineExtensions({ 'pdp.sidebar.after': ItemWarranty });
每个Hook都有
available_in
限制。
重要性 Hook上下文仅在特定扩展点中挂载,在其他位置使用会抛出运行时错误。
检测方式 在PDP/菜单中使用
useCartItem
;在购物车中使用
useCurrentUser
;在菜单/购物车列表中使用
usePDP
正确示例
typescript
// useCartItem 在 cart.cart-item.after 中使用 ✓
defineExtensions({ 'cart.cart-item.after': ItemWarranty });
错误示例
typescript
// useCartItem 在 pdp.sidebar.after 中使用 ✗ — 运行时会失败
defineExtensions({ 'pdp.sidebar.after': ItemWarranty });

Constraint: Always present execution plan and wait for approval

约束:必须先展示执行计划并等待用户确认

Do not generate code until the user confirms the plan.
Why this matters Generating without agreement wastes effort and may produce the wrong extension.
Detection Jumping from discovery to code generation without presenting a plan.
Correct Discovery → Requirements → Present plan → User approves → Generate code.
Wrong Discovery → Generate code immediately.
在用户确认计划之前,请勿生成代码。
重要性 未经确认就生成代码会浪费精力,且可能生成不符合需求的扩展。
检测方式 从需求发现直接跳转到代码生成,未展示计划。
正确流程 需求发现 → 需求梳理 → 展示计划 → 用户确认 → 生成代码。
错误流程 需求发现 → 立即生成代码。

Preferred pattern

推荐模式

Workflow overview

工作流概述

Step 0 — Check FastStore + Sales App prerequisites. STOP if missing.
Step 1 — Discovery. Detect use case from keywords, ask follow-up questions, determine API auth strategy. If the user provides API documentation (URL, OpenAPI/Swagger file, Markdown, or inline text), ingest it to extract endpoint details and response shapes — skip the equivalent manual questions. Validate extracted information with the user. Load the discovery reference for detailed question flows and the API Documentation Ingestion section.
Step 2 — Map requirements to extension point + hooks + template. Present plan. Wait for approval.
Step 3 — Generate component, CSS, and index.tsx. Validate against the 10-point checklist. If API documentation was ingested in Step 1, generate TypeScript interfaces from the extracted response shapes and use them in the component instead of the
${DATA_INTERFACE}
placeholder. If the extension calls 2+ endpoints, extract fetch logic into custom hook(s). Load the code templates reference for all template patterns, the type generation rules, the custom fetch hook pattern, and the types reference for hook return types and TypeScript definitions.
Step 4 — Generate documentation file at
docs/<ExtensionName>.md
inside the Sales App package. Create the
docs/
folder if it does not exist. The document must contain:
  1. Extension name — title matching the component name.
  2. Overview — one-paragraph summary of what the extension does and why it was built.
  3. Extension point — which extension point it registers on (e.g.,
    cart.cart-list.after
    ) and why that point was chosen.
  4. Hooks used — list each hook (
    useCart
    ,
    usePDP
    , etc.) with a brief explanation of what data it provides to this extension.
  5. Component structure — description of the component tree, props, and state management.
  6. Styling — CSS module file name and summary of key classes.
  7. API integration (if applicable) — endpoint, auth strategy (IO Proxy or direct), request/response shape.
    • Source documentation: URL or file path of the original API documentation, if provided.
    • Generated types: list of TypeScript interfaces generated from the API documentation.
    • Note which fields are optional (
      ?
      ) vs required per the documentation.
  8. How to test — dev server command and URL to reach the extension.
  9. Known constraints — any guards, edge cases, or limitations (e.g.,
    useCartItem().item
    may be undefined).
Template for the documentation file:
markdown
undefined
步骤0 — 检查FastStore + Sales App先决条件。如果缺少,停止操作。
步骤1 — 需求发现。从关键词中检测用例,提出后续问题,确定API鉴权策略。如果用户提供了API文档(URL、OpenAPI/Swagger文件、Markdown或内联文本),导入文档以提取端点详情和响应结构——跳过相应的手动提问环节。与用户确认提取的信息是否正确。如需详细的提问流程和API文档导入说明,请查看需求发现参考文档
步骤2 — 将需求映射到扩展点 + Hooks + 模板。展示计划,等待用户确认。
步骤3 — 生成组件、CSS和index.tsx。根据10点检查清单进行验证。如果步骤1中导入了API文档,从提取的响应结构生成TypeScript接口,并在组件中使用这些接口替代
${DATA_INTERFACE}
占位符。如果扩展调用2个及以上端点,将fetch逻辑提取到自定义Hook中。如需所有模板模式、类型生成规则、自定义fetch Hook模式以及Hook返回类型和TypeScript定义,请查看代码模板参考文档类型参考文档
步骤4 — 在Sales App包内生成文档文件
docs/<ExtensionName>.md
。如果
docs/
文件夹不存在,请创建。文档必须包含以下内容:
  1. 扩展名称 — 与组件名称匹配的标题。
  2. 概述 — 一段文字总结扩展的功能和构建目的。
  3. 扩展点 — 扩展注册的位置(例如
    cart.cart-list.after
    )以及选择该位置的原因。
  4. 使用的Hooks — 列出每个Hook(
    useCart
    usePDP
    等),并简要说明它为该扩展提供了哪些数据。
  5. 组件结构 — 描述组件树、属性和状态管理方式。
  6. 样式 — CSS模块文件名和关键类的说明。
  7. API集成(如适用) — 端点、鉴权策略(IO代理或直接鉴权)、请求/响应结构。
    • 源文档:如果提供了原始API文档,请注明其URL或文件路径。
    • 生成的类型:列出从API文档生成的TypeScript接口。
    • 标注哪些字段是可选(
      ?
      )的,哪些是必填的。
  8. 测试方法 — 开发服务器命令和访问扩展的URL。
  9. 已知约束 — 任何校验规则、边缘情况或限制(例如
    useCartItem().item
    可能为undefined)。
文档文件模板:
markdown
undefined

<ExtensionName>

<ExtensionName>

Overview

概述

<One-paragraph description of the extension purpose and value.>
<一段描述扩展用途和价值的文字。>

Extension point

扩展点

  • Point:
    <extension.point.name>
  • Rationale: <Why this extension point was selected.>
  • 位置:
    <extension.point.name>
  • 选择理由: <选择该扩展点的原因。>

Hooks used

使用的Hooks

HookPurpose
useCart
<What data it provides here>
Hook用途
useCart
<在此处提供的数据内容>

Component structure

组件结构

<Describe the component tree, key props, and internal state.>
<描述组件树、关键属性和内部状态。>

Styling

样式

  • File:
    <ComponentName>.module.css
  • <Summary of key CSS classes and design decisions.>
  • 文件:
    <ComponentName>.module.css
  • <关键CSS类和设计决策的说明。>

API integration

API集成

  • Endpoint:
    /_v/...
  • Auth strategy: IO Proxy / Direct / None
  • Request/Response: <Brief shape description.>
  • 端点:
    /_v/...
  • 鉴权策略: IO代理 / 直接鉴权 / 无
  • 请求/响应: <简要描述结构。>

How to test

测试方法

Run
yarn fsp dev {account}
and navigate to
https://{account}.myvtex.com/sales-app/...
to verify the extension renders.
运行
yarn fsp dev {account}
,并导航到
https://{account}.myvtex.com/sales-app/...
验证扩展是否渲染。

Known constraints

已知约束

  • <Guard or limitation 1>
  • <Guard or limitation 2>

**Step 5** — Provide local dev commands and test URLs. Load the [dev/build/deploy reference](references/local-dev-build-and-deploy.md).

**Step 6** — Build command and deployment guide. Load the [dev/build/deploy reference](references/local-dev-build-and-deploy.md).
  • <校验规则或限制1>
  • <校验规则或限制2>

**步骤5** — 提供本地开发命令和测试URL。如需详细信息,请查看[开发/构建/部署参考文档](references/local-dev-build-and-deploy.md)。

**步骤6** — 提供构建命令和部署指南。如需详细信息,请查看[开发/构建/部署参考文档](references/local-dev-build-and-deploy.md)。

Reference Files

参考文件

Load these on demand based on what the task requires. Do not load all of them upfront.
FileLoad when…
references/extension-points-hooks-and-types.mdChoosing an extension point, selecting hooks, looking up TypeScript types (
CartItem
,
ProductSku
,
Totalizers
,
Attachment
), or checking hook return values and availability per extension point
references/code-templates-and-patterns.mdGenerating extension code — simple, hook, API, IO Proxy, or Direct Auth templates; CSS module pattern;
index.tsx
with
defineExtensions
; hook initialization; validation checklist
references/discovery-and-use-cases.mdRunning Step 1 (Discovery) — use case detection keywords, follow-up questions, API auth decision tree, IO Proxy vs Direct Auth flow
references/local-dev-build-and-deploy.mdRunning Steps 5–6 — dev server commands, test URLs, build command, common build errors, FastStore WebOps deployment, monitoring, rollback
根据任务需求按需加载这些文件,无需预先全部加载。
文件加载时机
references/extension-points-hooks-and-types.md选择扩展点、挑选Hooks、查询TypeScript类型(
CartItem
ProductSku
Totalizers
Attachment
),或检查Hook返回值和各扩展点的Hook可用性时
references/code-templates-and-patterns.md生成扩展代码时——简单模板、Hook模板、API模板、IO代理模板或直接鉴权模板;CSS模块模式;使用
defineExtensions
index.tsx
;Hook初始化;验证检查清单
references/discovery-and-use-cases.md执行步骤1(需求发现)时——用例检测关键词、后续问题、API鉴权决策树、IO代理与直接鉴权流程
references/local-dev-build-and-deploy.md执行步骤5-6时——开发服务器命令、测试URL、构建命令、常见构建错误、FastStore WebOps部署、监控、回滚

Common failure modes

常见失败模式

  • Returning null instead of empty fragment
    return null
    not allowed; use
    return (<></>)
    . Build fails.
  • Accessing item.manualPrice without guard — TypeScript "possibly undefined" error. Use
    ??
    .
  • Using useCartItem outside cart.cart-item.after — Hook context only exists there. Runtime error.
  • Hardcoding auth tokens in frontend fetch — Keys visible in browser. Use VTEX IO proxy.
  • Using full URL with IO Proxy — Bypasses internal proxy. Use relative path
    /_v/...
    .
  • Placing code outside packages/sales-app/src/ — Not included in build.
  • Missing defineExtensions in index.tsx — Extension compiles but never renders.
  • Skipping prerequisite checks — Generating code without FastStore/Sales App installed.
  • Not presenting plan — User may want a different approach. Always confirm.
  • Invented extension point names
    cart.list.after
    instead of
    cart.cart-list.after
    fails silently.
  • Skipping documentation — Extension generated without
    docs/<ExtensionName>.md
    . Future developers won't understand the extension's purpose, hooks, or constraints.
  • Inventing API response types — Generated interface doesn't match actual API. If documentation was provided, derive types from it; if not, ask the user for a sample JSON response.
  • Ignoring provided API documentation — User provided a URL or file but agent asked manual questions anyway. Always check for documentation first and use the API Documentation Ingestion flow.
  • Inline fetch with 2+ endpoints — Multiple
    fetch
    calls inside the component body. Extract into custom hook(s) in
    hooks/use{Purpose}.ts
    .
  • 返回null而非空片段 — 不允许
    return null
    ;请使用
    return (<></>)
    。构建会失败。
  • 未校验就访问item.manualPrice — TypeScript提示"可能未定义"错误。请使用
    ??
  • 在cart.cart-item.after之外使用useCartItem — Hook上下文仅在该扩展点存在。运行时会出错。
  • 在前端fetch中硬编码鉴权令牌 — 密钥可在浏览器中查看。请使用VTEX IO代理。
  • IO代理使用完整URL — 绕过内部代理。请使用相对路径
    /_v/...
  • 代码放在packages/sales-app/src/之外 — 不会被包含在构建中。
  • index.tsx中缺少defineExtensions — 扩展编译成功但无法渲染。
  • 跳过先决条件检查 — 在未安装FastStore/Sales App的情况下生成代码。
  • 未展示计划 — 用户可能需要不同的实现方式。请务必先确认。
  • 使用不存在的扩展点名称** — 例如使用
    cart.list.after
    而非
    cart.cart-list.after
    会导致静默失败。
  • 跳过文档生成 — 生成的扩展没有
    docs/<ExtensionName>.md
    。后续开发者无法理解扩展的用途、使用的Hooks或约束。
  • 自行编写API响应类型 — 生成的接口与实际API不匹配。如果提供了文档,请从中推导类型;如果没有,请向用户索要JSON响应示例。
  • 忽略用户提供的API文档 — 用户提供了URL或文件,但仍手动提问。请始终先检查是否有文档,并使用API文档导入流程。
  • 在组件中内联多个fetch调用 — 组件体内有2个及以上
    fetch
    调用。请将逻辑提取到
    hooks/use{Purpose}.ts
    中的自定义Hook。

Review checklist

检查清单

  • FastStore installed (biome.json, faststore.json, package.json, tsconfig.json, turbo.json)?
  • Sales App module installed (src/, package.json, tsconfig.json in sales-app directory)?
  • Discovery completed and use case identified?
  • Execution plan approved by user?
  • Extension point is valid (from the 8-point reference)?
  • Hooks compatible with chosen extension point?
  • Component returns JSX.Element, never null?
  • Optional properties guarded (manualPrice, productRefId, attachments)?
  • useCartItem().item checked for undefined?
  • No auth credentials exposed in frontend code?
  • IO Proxy uses relative path (/_v/...)?
  • defineExtensions configured in index.tsx?
  • CSS file path matches component name?
  • Documentation generated at
    docs/<ExtensionName>.md
    ?
  • Documentation covers overview, extension point, hooks, structure, and constraints?
  • If API documentation was provided, TypeScript interfaces match the documented response shape?
  • If 2+ API endpoints used, fetch logic extracted into custom hook(s) in
    hooks/
    ?
  • Build passes:
    yarn fsp build {account} sales-app
    ?
  • Tested locally:
    yarn fsp dev {account}
    ?
  • 已安装FastStore(包含biome.json、faststore.json、package.json、tsconfig.json、turbo.json)?
  • 已安装Sales App模块(sales-app目录下有src/、package.json、tsconfig.json)?
  • 已完成需求发现并确定用例?
  • 执行计划已获得用户确认?
  • 扩展点有效(属于8个参考扩展点之一)?
  • Hooks与所选扩展点兼容?
  • 组件返回JSX.Element,从未返回null?
  • 可选属性已校验(manualPrice、productRefId、attachments)?
  • 已检查useCartItem().item是否为undefined?
  • 前端代码中未暴露鉴权凭证?
  • IO代理使用了相对路径(/_v/...)?
  • index.tsx中配置了defineExtensions?
  • CSS文件路径与组件名称匹配?
  • 已在
    docs/<ExtensionName>.md
    生成文档?
  • 文档涵盖了概述、扩展点、Hooks、结构和约束?
  • 如果提供了API文档,TypeScript接口与文档中的响应结构匹配?
  • 如果使用了2个及以上API端点,fetch逻辑已提取到hooks/中的自定义Hook?
  • 构建通过:
    yarn fsp build {account} sales-app
  • 已在本地测试:
    yarn fsp dev {account}

Related skills

相关技能

  • faststore-storefront
    — storefront customization outside Sales App
  • vtex-io-app-contract
    — building VTEX IO proxy apps for secure API integration
  • faststore-storefront
    — Sales App之外的店铺定制
  • vtex-io-app-contract
    — 构建用于安全API集成的VTEX IO代理应用

Reference

参考链接