# 豆包智能服务前端开发入口

本文件是豆包智能服务前端开发的入口，用于定位前端工程规则、调试方式和框架资料；涉及具体框架 API、组件或开发规范时，再查阅 `frontend/` 下的对应文档。

## 先判断任务

| 场景 | 先做什么 |
|------|----------|
| 找不到前端目录 | 读取 `.dbx/config.json` 的 `frontend.directory`；缺失时再按项目结构判断，常见目录是 `doubao-agentic-service` |
| 需要新建智能服务前端工程 | 使用公开版智能服务框架创建命令；不要在已有 dbx 项目里另起一套平行前端 |
| 卡片没出现、模型没调 tool、Manifest 绑定不确定 | 先读 [Simulator Eval 指南](local-debug/simulator-eval.md)，用 `dbx simulator eval` 验证 Skill、MCP、Manifest、tool result 和 `card_delta` |
| 需要看页面、卡片样式、点击或路由 | 先读 [本地调试总流程](local-debug/overview.md)，用 `dbx dev` 打开 Web 模拟器 |
| 开发对话卡片 Widget | 先读 [frontend/widget-templates/overview.md](frontend/widget-templates/overview.md) 选模板，再读 [frontend/guides/component-development.md](frontend/guides/component-development.md) |
| 使用内置组件 props 或事件 | 读 [frontend/components/overview.md](frontend/components/overview.md)，不要猜 props |
| 调用智能服务的端能力 API | 先读 [frontend/doubao-agentic-service-api/quick-reference.md](frontend/doubao-agentic-service-api/quick-reference.md)，再读命中的分组文件 |
| 登录、隐私授权、自定义登录页 | 先读 [auth.md](auth.md)，需要前端模板时读 [frontend/guides/auth.md](frontend/guides/auth.md) |

## dbx 工程规则

- 前端源码不放在 `.dbx/workspace` 下；`.dbx/workspace` 只保存打包产物和中间文件。
- 前端目录优先来自 `.dbx/config.json` 的 `frontend.directory`。
- 如果前端脚手架不存在，先修复初始化流程；只有用户明确要求新建智能服务工程时，才执行创建命令。
- 在 `src/config/runtime.ts` 集中维护非敏感的 `appId` 和 `apiBaseUrl`；`src/app.config.ts` 引用 `runtimeConfig.appId`，普通 HTTP 请求通过统一 client 使用 `runtimeConfig.apiBaseUrl`。不要在 Page / Widget 中硬编码 AppID 或服务端 URL，AppSecret 绝不进入前端配置。
- 构建或上传前，将 `runtimeConfig.appId`、`runtimeConfig.apiBaseUrl` 与 Manifest 的 `app_key`、`mcp_server.end_point` 作为同一配置组恢复为用户确认的正式值。
- 对话卡片的 `widget_id` 来自前端工程 `src/app.config.ts` 的 `defineAppConfig({ widgets })`，Manifest 只引用这个 `widget_id`，不要在 Manifest 里写 UI 字段映射。

新建智能服务工程时，dbx 默认使用公开版智能服务框架包：

```bash
pnpm create @doubao-apps my-doubao-app --template starter -y
cd my-doubao-app
pnpm install
```

就地创建时使用 `.` 作为目录名：

```bash
pnpm create @doubao-apps . --template starter -y
pnpm install
```

## dbx 调试顺序

`dbx simulator eval` 验证后端出卡数据链路，不验证前端视觉效果：

```bash
dbx simulator eval --query "<当前轮用户问题>" --verbose
```

`dbx dev` 用于看真实 Page / Widget 渲染、交互和路由：

```bash
dbx dev --mcp-endpoint http://127.0.0.1:<port>/mcp
```

如果只是看 UI，直接运行 `dbx dev`；如果不确定 MCP tool、Manifest、`tool_card_binding` 或 `card_delta` 是否正确，先 eval。

## Page 和 Widget 规则

- Page 放在 `src/pages/<page-name>/index.tsx`，入口使用 `definePage`。
- Widget 放在 `src/widgets/<widget-name>/index.tsx`，入口使用 `defineWidget`。
- 对话卡片 Widget 必须先读 [frontend/widget-templates/overview.md](frontend/widget-templates/overview.md)，选择合适的 `@doubao-apps/template` 模板；不要手写 `view` / `text` / `image` 拼卡片布局。
- Page / Widget 默认使用 `getViewData<T>()`，不要使用裸 `getViewData()`、`getViewData<any>()` 或 `: any`。
- `useState`、`useEffect` 等 Hooks 从 `@doubao-apps/framework` 导入，不要从 `react` 导入。
- `request`、`getLocation`、`showToast`、`navigateTo` 等端能力从 `@doubao-apps/framework/api` 导入。
- `app.config.ts` 使用 `@doubao-apps/framework/config` 导入 `defineAppConfig`；`@doubao-apps/kit` 只作为 CLI / SDK / 构建工具链包使用。
- 普通 HTTP 请求使用 `runtimeConfig.apiBaseUrl`，不要在组件里硬编码服务端 URL。

```ts
// src/config/runtime.ts：只放会进入前端产物的非敏感配置
export const runtimeConfig = {
  appId: process.env.PUBLIC_APP_ID || 'db_xxxxxx',
  apiBaseUrl: process.env.PUBLIC_API_BASE || 'https://example.com'
};
```

```ts
import { defineAppConfig } from '@doubao-apps/framework/config';
import { runtimeConfig } from './config/runtime';

export default defineAppConfig({
  appId: runtimeConfig.appId,
  name: '我的豆包应用',
  widgets: [
    {
      entry: 'widgets/order-summary/index',
      id: 'order-summary',
      name: '订单摘要卡片',
      titleType: 'none'
    }
  ]
});
```

## 环境变量

CLI 会读取项目根目录的 `.env`、`.env.local`、`.env.[mode]`、`.env.[mode].local`。运行时代码中只自动替换 `PUBLIC_` 前缀变量，并且必须使用 `process.env.PUBLIC_XXX` 或 `import.meta.env.PUBLIC_XXX` 访问。

```env
PUBLIC_APP_ID=db_xxxxxx
PUBLIC_API_BASE=https://example.com
```

```ts
export const runtimeConfig = {
  appId: process.env.PUBLIC_APP_ID,
  apiBaseUrl: process.env.PUBLIC_API_BASE
};
```

不要把密钥、token、cookie 放进 `PUBLIC_` 变量；它们会被打进运行时代码。

## 智能服务框架 Reference

以下文件由 SDK skill 同步而来，按需读取：

| 文件 | 内容 |
|------|------|
| [frontend/guides/component-development.md](frontend/guides/component-development.md) | Page / Widget 开发、生命周期、布局、viewData |
| [frontend/guides/auth.md](frontend/guides/auth.md) | `src/mcp-ui` 登录、隐私授权、自定义登录页 |
| [frontend/guides/expired-widget.md](frontend/guides/expired-widget.md) | 失效卡片处理 |
| [frontend/guides/best-practices.md](frontend/guides/best-practices.md) | 代码组织、组件设计、Hooks、样式、错误处理 |
| [frontend/rules/dos-and-donts.md](frontend/rules/dos-and-donts.md) | 智能服务框架推荐做法和禁止做法 |
| [frontend/examples/common-patterns.md](frontend/examples/common-patterns.md) | 异步调用、状态管理、页面导航 |
| [frontend/examples/doubao-agentic-service-api-recipes.md](frontend/examples/doubao-agentic-service-api-recipes.md) | 端能力组合示例 |
| [frontend/examples/page-widget-basics.md](frontend/examples/page-widget-basics.md) | Page / Widget 基础示例 |
| [frontend/framework/core.md](frontend/framework/core.md) | Framework 核心入口、生命周期和 Hooks |
| [frontend/doubao-agentic-service-api/quick-reference.md](frontend/doubao-agentic-service-api/quick-reference.md) | 智能服务的端能力 API 速查 |
| [frontend/doubao-agentic-service-api/groups.md](frontend/doubao-agentic-service-api/groups.md) | 智能服务的端能力 API 分组目录 |
| [frontend/components/overview.md](frontend/components/overview.md) | 内置组件 props / 事件索引 |
| [frontend/widget-templates/overview.md](frontend/widget-templates/overview.md) | Widget 模板 SDK 原始索引 |

---

<!-- BEGIN GENERATED SDK FRONTEND SKILL -->
## 豆包智能服务开发指南

本文件供开发者和 AI coding agents（如 Claude、Copilot、Cursor）使用，提供豆包智能服务框架的快速入门、开发规则和文档导航。

---

### 快速开始

#### 1. 项目介绍

豆包智能服务框架，基于 Lynx 渲染引擎提供完整的豆包智能服务开发和构建能力。

**核心特性**：
- **React 风格开发**：使用 TSX/JSX 语法和 React Hooks
- **Lynx 渲染引擎**：Page 和 Widget 由 Lynx 渲染，元素、布局和 CSS 行为遵循 Lynx 规则，不等同于 Web DOM/CSS
- **豆包智能服务的端能力 API**：网络、存储、位置、导航、Toast 等系统能力，从 `@doubao-dev/framework/api` 导入；也称 Open API
- **完整工具链**：CLI、调试工具、构建能力

#### 2. 环境准备

**必需环境**：
- Node.js 22+
- pnpm（推荐）：`npm install -g pnpm`


#### 3. 创建项目

公网使用 `dbx` 初始化豆包智能服务项目：

```bash
dbx init my-doubao-app
```

`dbx init` 会创建或接入前端工程，并安装 CLI 内置的 Skill。


#### 4. 项目结构

```
my-doubao-app/
├── package.json          # 依赖管理
└── src/
    ├── app.ts            # 应用入口
    ├── app.config.ts     # 应用配置
    ├── auth/             # 可选登录、隐私授权和自定义登录页约定目录
    ├── pages/            # 页面目录（全屏UI）
    │   └── home/
    │       ├── index.tsx
    │       └── index.scss
    └── widgets/          # 卡片目录（聊天UI）
        └── hello-world/
            ├── index.tsx
            └── index.scss
```

旧项目的 `src/mcp-ui` 在没有 `src/auth` 入口时继续作为兼容 fallback；新项目统一使用 `src/auth`。

---

### 核心规则（必读）

#### 推荐做法

- **优先使用 pnpm** 作为包管理器
- **分离样式文件**：每个组件使用独立的 `.scss` 文件
- **配置 App 元信息**：`src/app.config.ts` 需要配置 `appId` 和 `name`；`appId` 使用开放平台 `db_xxxxxx` 风格；`pages` / `widgets` 是可选的显式入口配置
- **环境变量**：项目根目录 `.env*` 中需要进入运行时代码的变量必须使用 `PUBLIC_` 前缀，并通过 `process.env.PUBLIC_XXX` 或 `import.meta.env.PUBLIC_XXX` 读取；不要写裸变量 `PUBLIC_XXX`，也不要给密钥、token、cookie 使用 `PUBLIC_`
- **使用生命周期钩子**：Page / Widget 默认直接导出 JSX 组件函数，并在函数内使用 `useShow`、`useMounted` 等 Hooks
- **TypeScript 类型**：所有 Page / Widget 使用 `useViewData<T>()`，为 viewData、props 和 state 提供明确类型；不要使用裸 `useViewData()`、`useViewData<any>()`、`: any`
- **豆包智能服务的端能力 API 导入**：`request`、`getLocation`、`showToast`、`navigateTo` 等端能力从 `@doubao-dev/framework/api` 导入；参数和返回值以 [豆包智能服务的端能力 API 速查](frontend/doubao-agentic-service-api/quick-reference.md) / [分组目录](frontend/doubao-agentic-service-api/groups.md) 为准。本文档中的 “Open API” 与“豆包智能服务的端能力 API”是同一套运行时 API，不是开放平台 HTTP OpenAPI
- **豆包智能服务的端能力 API 查询**：需要端能力时，先用 [豆包智能服务的端能力 API 速查](frontend/doubao-agentic-service-api/quick-reference.md) 的能力索引和分组表定位候选 API，再进入分组详情确认参数、返回值和调用时机
- **异步状态**：豆包智能服务的端能力 API 和异步请求必须在 `useEffect`、生命周期钩子或事件处理函数中调用，并包含 loading、error、success 状态
- **内置组件**：`button`、`switch`、`slider` 等直接使用小写标签，不要从组件包 import；`button` 点击使用 `onClick`，不要使用 `onTap` / `bindtap`；`switch.onChange` 直接接收 `boolean`，`slider.onChange` 直接接收 `number`，`slider` 不支持 `step` / `defaultValue`；事件和 props 先查 [组件 API](frontend/components/overview.md)
- **Lynx 渲染规则**：实现 Page / Widget 的布局或样式前，先按 [Lynx API 文档导航](frontend/lynx/overview.md) 读取匹配文档；不要套用 Web HTML/CSS 的默认行为
- **Framework Hooks**：`useState`、`useEffect` 等 Hooks 必须从 `@doubao-dev/framework` 导入，不要从 `react` 导入
- **调试现场读取**：本地 Web SDK 调试台可通过 Debugger MCP 暴露只读运行现场；需要读取 runtime console、trace events、simulator tool calls 或 log snapshot 时，先查 [Debugger MCP 协议](frontend/guides/debugger-mcp.md)
- **错误处理**：处理边界情况和错误状态

#### 禁止做法

- **不写内联样式**：避免在 TSX 中直接写 style
- **不在渲染期间请求**：不要在组件函数或对象入口的 `render()` 中直接调用 `request`、`getLocation`、`showToast`、`navigateTo`、`fetch` 等异步或系统 API
- **不过度嵌套**：保持组件层级扁平化
- **不忽略类型**：避免使用 `any` 类型
- **先查文档再使用 API**：使用任何 API 前先查文档，确认参数、返回值、调用时机和使用限制

#### Page / Widget 推荐入口模板

开发 Page / Widget 时，先确定视图输入类型、入口组件和 `src/app.config.ts` 注册方式。需要调用端能力时，在这个入口形态上补充
[常用开发模式](frontend/examples/common-patterns.md) 中的异步状态；具体端能力组合示例见
[豆包智能服务的端能力 API 使用配方](frontend/examples/doubao-agentic-service-api-recipes.md)。

```tsx
import { useViewData } from '@doubao-dev/framework';
import './index.scss';

interface LocationCardData {
  title?: string;
}

export default function LocationCard() {
  const viewData = useViewData<LocationCardData>();

  return <view className="location-card">{viewData.title || '位置卡片'}</view>;
}
```

```ts
// src/app.config.ts：使用数组写法；entry 写到 index，不要省略入口文件名
import { defineAppConfig } from '@doubao-dev/framework/config';

export default defineAppConfig({
  appId: 'db_xxxxxx',
  name: '位置能力示例',
  widgets: [
    {
      entry: 'widgets/location-card/index',
      id: 'location-card',
      name: '位置卡片',
      description: '展示位置能力结果',
      titleType: 'none'
    }
  ]
});
```

端能力参数/返回值和内置组件 props 的高风险细节维护在 reference 子文档中；生成前优先查对应小节，不要在主流程里临时扩展字段。
如果需求里混入 `fetch`、`window`、`document`、`localStorage`、`style={{}}` 等 Web/H5 写法，先按文档导航里的“Web 写法纠偏”确认替代写法，再实现。

查看 reference 时，以当前 `SKILL.md` 所在目录为基准解析相对链接；组件事件细节见 [组件 API](frontend/components/overview.md)。

#### ⚠️ 文件命名约束

页面/卡片目录下的入口文件必须命名为 **`index.tsx`**，样式文件为 **`index.scss`**。

**详细规则** → [frontend/rules/dos-and-donts.md](frontend/rules/dos-and-donts.md)

---

### 组件开发速记

- **Page**：全屏 UI，放在 `src/pages/<page-name>/index.tsx` 和 `index.scss`，默认直接导出组件函数。
- **Widget**：聊天流卡片，放在 `src/widgets/<widget-name>/index.tsx`，默认直接导出组件函数；卡片开发必须优先使用 [Widget 模板库](frontend/widget-templates/overview.md) 中的 `@doubao-dev/template` 模板，不要手写 `view` / `text` / `image` 拼卡片布局。
- **入口形态**：Page / Widget 直接默认导出 JSX 组件函数；生命周期默认使用 Framework Hooks。
- **入口注册**：`src/app.config.ts` 通过 `defineAppConfig` 配置 `appId`、`name`，`appId` 使用开放平台 `db_xxxxxx` 风格，并按需声明 `pages` / `widgets`。
- **自动发现**：一级 `src/pages/*/index.tsx`、`src/widgets/*/index.tsx` 可自动发现；需要 metadata、稳定首页顺序或多级目录时显式声明。
- **数组写法**：只声明入口可写字符串；补 metadata 时写对象。Page 对象使用 `title`，Widget 对象使用 `name`，`entry` 写完整到 `index`。

```ts
import { defineAppConfig } from '@doubao-dev/framework/config';

export default defineAppConfig({
  appId: 'db_xxxxxx',
  name: '我的豆包应用',
  pages: [
    'pages/home/index',
    {
      entry: 'pages/account/settings/index',
      title: '账号设置页'
    }
  ],
  widgets: [
    {
      entry: 'widgets/order/detail/index',
      titleType: 'none'
    },
    {
      entry: 'widgets/order/summary/index',
      id: 'order-summary',
      name: '订单摘要卡片',
      titleType: 'none'
    }
  ]
});
```

详细 Page / Widget 生命周期、布局、metadata、boxType 和 viewData 示例见 [组件开发指南](frontend/guides/component-development.md)，基础示例对比见 [page-widget-basics.md](frontend/examples/page-widget-basics.md)。

#### 环境变量

CLI 会读取项目根目录的 `.env`、`.env.local`、`.env.[mode]`、`.env.[mode].local`。运行时代码中只自动替换
`PUBLIC_` 前缀变量，并且必须使用 `process.env.PUBLIC_XXX` 或 `import.meta.env.PUBLIC_XXX` 访问。

```env
PUBLIC_API_BASE=https://example.com
```

```ts
const apiBase = process.env.PUBLIC_API_BASE;
```

指定 mode 时使用 `--env-mode`：

```bash
doubao dev --env-mode ppe
doubao build --env-mode ppe
```

不要把密钥、token、cookie 放进 `PUBLIC_` 变量；它们会被打进运行时代码。

---

### Web SDK Debugger MCP 速记

- `doubao dev` 打开 Web SDK 调试台时，本地调试服务可暴露 `POST /__wsd_mcp`，协议为 MCP Streamable HTTP。
- 这是 debugger 自身的只读观测接口，不替代用户业务 MCP server；只用于读取当前 Page / Widget / App
  runtime console、trace events、simulator tool calls 和 log snapshot。
- 常用 tools：`list_console_messages`、`get_console_message`、`get_log_snapshot`、
  `list_agent_trace_events`、`list_agent_tool_calls`。
- 当 debugger server 尚未收到快照，或当前没有 Page / Widget 运行现场时，tools 返回 `{ "stored": false }`。
- 详细 endpoint、分页字段、tool 参数、返回结构和安全边界见 [Debugger MCP 协议](frontend/guides/debugger-mcp.md)。

---

### 文档导航

| 任务 | 必读 | 可选 | 不要读 / 不要做 |
|-----|----------|--------|------|
| 创建 Page | [component-development.md](frontend/guides/component-development.md) 的 Page 开发、[dos-and-donts.md](frontend/rules/dos-and-donts.md) 的 Page 布局规则 | [page-widget-basics.md](frontend/examples/page-widget-basics.md) 的 Page 完整示例 | 不要同时加载全部 guides；不要把 Page metadata 写进源码入口 |
| 创建 Widget | [Widget 模板库](frontend/widget-templates/overview.md) 的选型指南和模板 props、[component-development.md](frontend/guides/component-development.md) 的 Widget 开发 | [page-widget-basics.md](frontend/examples/page-widget-basics.md) 的 Widget 模板接入示例 | 不要手写卡片布局；不要把 Widget metadata 写进源码入口 |
| 配置入口、metadata、多级目录、首页顺序 | [dos-and-donts.md](frontend/rules/dos-and-donts.md) 的 App 配置、入口和命名规则 | [component-development.md](frontend/guides/component-development.md) 的 Page / Widget 开发流程 | 不要省略显式入口的 `/index` |
| 调用豆包智能服务的端能力 API | [豆包智能服务的端能力 API 速查](frontend/doubao-agentic-service-api/quick-reference.md) 找 API 分组，再读命中的 `frontend/doubao-agentic-service-api/<group>.md` | [doubao-agentic-service-api-recipes.md](frontend/examples/doubao-agentic-service-api-recipes.md)、[common-patterns.md](frontend/examples/common-patterns.md) | 不要先读整个 `doubao-agentic-service-api/` 目录；不要在组件渲染期间调用异步 API |
| 网络请求、loading / error / success 状态 | [common-patterns.md](frontend/examples/common-patterns.md) 的异步调用和状态管理 | [豆包智能服务的端能力 API 速查](frontend/doubao-agentic-service-api/quick-reference.md) 和命中的 API 分组 | 不要用浏览器 `fetch` 代替 `request` |
| 页面导航、参数传递、返回 | [common-patterns.md](frontend/examples/common-patterns.md) 的页面导航 | [豆包智能服务的端能力 API 速查](frontend/doubao-agentic-service-api/quick-reference.md) 和命中的路由分组 | 不要套用其他小程序的路由参数 |
| 处理 Page / Widget 的 Lynx 布局或样式 | 先读 [Lynx API 文档导航](frontend/lynx/overview.md)，再只读命中的 `layout/` 或 `css/` 文档 | [Lynx 速查](frontend/lynx/quick-reference.md)、[Lynx 最佳实践](frontend/lynx/best-practices.md) | 不要假设 Web HTML/CSS 默认行为；不要一次加载整个 Lynx reference |
| 使用内置组件 props / 事件 | [组件 API](frontend/components/overview.md) | [page-widget-recipes.md](frontend/examples/page-widget-recipes.md) 的组件状态组合写法 | 不要在本技能猜测完整 props；不要 import 内置组件 |
| 纠正 Web / H5 / 其他小程序写法 | [dos-and-donts.md](frontend/rules/dos-and-donts.md) | [common-patterns.md](frontend/examples/common-patterns.md)、[doubao-agentic-service-api-recipes.md](frontend/examples/doubao-agentic-service-api-recipes.md) | 不要使用 `window`、`document`、`localStorage`、内联 `style`、`onTap`、`bindtap` |
| 登录、隐私授权、自定义登录页 | [auth.md](frontend/guides/auth.md) | [Framework 核心入口、生命周期和 Hooks](frontend/framework/core.md) 查相关 define API | 不要把登录与授权入口当普通 Page / Widget 配置 |
| 过期 Widget 处理 | [expired-widget.md](frontend/guides/expired-widget.md) | [豆包智能服务的端能力 API 速查](frontend/doubao-agentic-service-api/quick-reference.md) 查相关端能力 | 不要自行拼装过期卡片 UI，优先使用 `expiredWidget()` |
| 读取 Web SDK 调试现场 | [Debugger MCP 协议](frontend/guides/debugger-mcp.md) | [troubleshooting.md](frontend/guides/troubleshooting.md) | 不要把 `POST /__wsd_mcp` 转发到公网；不要把它当用户业务 MCP server |
| 性能优化 | [performance-optimization.md](frontend/guides/performance-optimization.md) | [best-practices.md](frontend/guides/best-practices.md) | 不要先做无关重构 |
| 构建、运行、样式或 API 异常排查 | [troubleshooting.md](frontend/guides/troubleshooting.md) | 命中 API 时再读 [豆包智能服务的端能力 API 速查](frontend/doubao-agentic-service-api/quick-reference.md) 和分组详情 | 不要一次读取全部 reference |
| 查 Framework 核心入口、生命周期或 Hooks | [Framework 核心入口、生命周期和 Hooks](frontend/framework/core.md) | [component-development.md](frontend/guides/component-development.md) 对应章节 | 不要从 `react` 直接导入 Hooks |
| 代码组织、可维护性、错误处理 | [best-practices.md](frontend/guides/best-practices.md) | [dos-and-donts.md](frontend/rules/dos-and-donts.md) | 不要让通用最佳实践覆盖当前任务的 SDK 硬规则 |

### 依赖包

- **Framework**：`@doubao-dev/framework` - 核心框架、视图入口、Hooks、viewData
- **端能力 API**：`@doubao-dev/framework/api` - 网络、存储、位置、导航、Toast 等系统能力
- **Framework Config**：`@doubao-dev/framework/config` - `defineAppConfig` 和配置类型
- **开发工具**：公网统一使用 `dbx`；本地调试使用 `dbx dev`，构建上传使用 `dbx app artifacts upload`

- **Widget 模板**：`@doubao-dev/template` - Widget 卡片模板组件和模板 UI 原子组件

Lynx 组件库完整参考：<https://lynxjs.org/llms.txt>
<!-- END GENERATED SDK FRONTEND SKILL -->
