# 模式 A — 客户端 SDK 代码插入

## ⚠️ 前置强制检查（不得跳过）

**开始插入代码前，必须按以下顺序执行，每步完成后才能进入下一步：**

### Stage 0: 读取 SDK 主文档（必须完成，禁止跳过）

1. **读 `references/sdk-index.md`** 找到对应 SDK 的主文档路径
2. **读 SDK 主文档的「集成 SDK」章节**，了解：
   - **npm 包名**（如 `thinkingdata-browser`、`@thinkingdata/react-native-sdk`）
   - **import/require 语句**的写法
   - **所有集成方式**（如 JS SDK 有 npm / CDN同步 / CDN异步 三种）
3. 根据项目特征选择集成方式：
   - 有 `package.json` + 构建工具 → npm 集成
   - 纯 HTML / 无构建工具 → CDN 方式
4. 读 `~/.ae-tracking/wiki/te-docs/synthesis/sdk-selection.md` 确认 appType 对应的 npm 包名与 init 签名
5. 读对应 cheatsheet（如 `js-sdk-cheatsheet.md`）补充细节

**⚠️ 禁止**：跳过 Stage 0 直接写代码、凭猜测选择集成方式、使用不确定的 CDN URL

### Stage 0 中期语言识别（不得跳过）

读取 SDK 主文档时，若文档使用多语言 tab 格式（如 `::: el-tab-pane label=Java` / `label=Kotlin` 或 ` ```java` / ` ```kotlin`），**必须确认当前任务使用的语言**：

- Android 文档：识别 `label=Java` vs `label=Kotlin` 对应的代码块
- iOS 文档：识别 `label=Objective-C` vs `label=Swift` 对应的代码块
- 其他多语言文档：同理

**⚠️ 禁止**在未确认语言的情况下复制代码示例，禁止混用不同语言的代码片段。

### Stage 0.5: SDK 集成确认（Stage 0 完成后必须执行）

根据第 3 步选择的集成方式，向用户确认 SDK 是否已引入：

**需要代码改动的集成方式（npm / Gradle / CocoaPods / Maven / pip / go get 等）**：

```
检测到项目使用 <集成方式>，需要修改配置文件添加依赖。

是否需要我直接修改配置文件添加 SDK 依赖？
- yes → Edit 修改配置文件（如 package.json / build.gradle / Podfile 等），完成后进入 Stage 1
- no → 参考以下文档完成 SDK 引入，完成后回答 yes 继续

文档：<wiki 文档路径>
```

- 用户 `yes` → 执行 Edit 修改配置文件，完成后进入 Stage 1
- 用户 `no` → 显示文档路径，暂停等待用户完成

**无需代码改动的集成方式（CDN script 标签 / UnityPackage / 手动放置文件等）**：

```
项目使用 <集成方式>，无需修改配置文件。

请参考以下文档完成 SDK 引入，完成后回答 yes 继续。

文档：<wiki 文档路径>
```

等待用户确认完成后，进入 Stage 1。

---

## Stage 1: Explore
1. Grep 入口：`src/main.*`、`src/App.*`、`pages/_app.*`、`index.html`
2. Grep 现有埋点：`ta\.track|thinkingdata|TA\.init|// @tracking`
3. Grep 路由：`react-router|vue-router|next/router`
4. Grep 用户态：`(handleLogin|onLogin|signIn|doLogin)` / `(handleLogout|signOut)`
5. **Grep 业务触发点**（找事件对应的业务动作，这是插入 track() 调用的正确位置）：
   - 按钮/点击：`(onClick|handleClick|onTap|@click|\.click\()` 
   - 表单提交：`(onSubmit|handleSubmit|onFormSubmit)`
   - 页面进入：`(onMounted|onShow|onLoad|componentDidMount|useEffect.*\[.*\])`
   - 购买/支付：`(onPurchase|handlePurchase|doPurchase|payOrder)`
   - 搜索：`(onSearch|handleSearch|doSearch)`
   - 自定义事件：`(emit|trigger|dispatch|sendEvent)`
- Astro 专属：
  - 入口：`src/middleware.ts`（SSR 中间件，适合 page_view）、`src/layouts/*.astro`（全局布局插 init）、`astro.config.mjs`（integrations）
  - 客户端组件：`*.astro` 文件里 `<script>` 块、含 `client:*` 指令的 React/Vue island 组件
- **每找到一个业务触发点，记录它对应的文件:行号和业务含义**，供 Stage 2 映射使用

## Stage 2: Insertion Plan（markdown 表格）

**平台过滤**：
- xlsx "采集端" 值为 `客户端` / `client` → `platform: "client"`（仅客户端采集）
- xlsx "采集端" 值为 `客户端,服务端` / `client,server` → `platform: "both"`（两端都采集）
- xlsx "采集端" 值为 `服务端` / `server` → `platform: "server"`（仅服务端采集，不在客户端生成）
- 只插入 `platform === "client"` 或 `platform === "both"` 的事件

**⚠️ 自动采集事件处理**：
- 自动采集事件（如 `ta_page_view`、`ta_app_crash` 等）由 SDK 内部自动采集，**不需要手动插入 track() 代码**
- 但需要在 SDK 初始化后**开启对应的自动采集开关**，才会生效
- ⚠️ **必须先读 `references/autotrack-enum.md`** 查询正确枚举值再写代码；不得猜测（如 Unity 的 `AppStart` ≠ `APP_START`）
- 在插入计划中标注需要开启的自动采集事件，供用户在 Stage 3 中确认

```
## SDK 初始化
- 文件: <path>:<line>
- 代码: init(...) with appId/SERVER_URL

## 自动采集事件开关（如需要）
- 枚举值查 `references/autotrack-enum.md`，不得猜测
- 文件: <path>:<line>
- enableAutoTrack({...}) 或 quick("autoTrack")

## 公共事件属性
- 文件: <path>:<line>
- setSuperProperties({...})

## 用户属性
- 文件: <path>:<line>
- user_set / user_setOnce / user_add

## 事件组: <tag>
- <event_name>: <file>:<line> [业务动作: <业务含义>]
  插入位置说明: <为什么要在这里插，比如"用户点击支付按钮后调用">
- ...
```

**⚠️ 业务动作映射是插入计划的核心**：
- 必须把每个事件映射到具体的业务动作（如"用户点击登录按钮"、"订单提交成功回调"）
- 业务动作必须来自 Stage 1 探索结果，不能猜测
- 如果某个事件找不到对应的业务触发点，在 plan 中标注 `⚠️ 未找到触发点，需人工确认`

**⚠️ Stage 2 完成后必须展示「插入位置预览」**，让用户确认每个事件的插入位置是否符合业务预期：

```
## 插入位置预览

| 事件 | 文件位置 | 业务动作 | 确认 |
|---|---|---|---|
| payment_success | src/pages/Pay.jsx:42 | 用户点击"确认支付"按钮 | ok / 修改 |
| user_login | src/pages/Login.jsx:28 | 用户点击"登录"按钮 | ok / 修改 |
```

- 用户 `ok` → 进入 Stage 3
- 用户说"修改" → 针对具体事件重新映射到正确的业务触发点
- **不得跳过此预览确认直接进入 Stage 3**

展示后问用户 `ok` 进入 Stage 3，或 "回到事件 X 改映射"。

## Stage 3: 分批 Edit
- Batch 1: SDK init + 公共属性
- Batch 2: 用户属性
- Batch 3..N: 按 `event_tag` 分组
- 每批用 Edit 工具；写完打印文件清单 + 新增行数，问 `ok / undo`
- `undo` → 反向 Edit 回滚本批

## Stage 3.5：⚠️ 语言风格校验（不得跳过）

每批 Edit 完成后，对改动的文件做语言风格检查：

| 语言 | 检查规则 |
|---|---|
| **Kotlin** | 文件中不得包含 `;`（行尾分号），如发现立即修正 |
| **Java** | 每条语句必须以 `;` 结尾，如缺失立即修正 |
| **Swift** | 不得使用 `var` 声明可选类型，应使用 `let` + `?`；不得出现 `@objc` 除非必要 |
| **Objective-C** | 方法调用必须使用 `[self method]` 语法，不得出现 `.` 调用；必须使用 `nil` 而非 `null` |

**若发现语言风格错误**：
1. 立即用正确语法替换
2. 在本批确认时标注 `⚠️ 已自动修正：<错误描述> → <正确写法>`

## Stage 4: 汇总
- 打印所有改过的文件 + 每文件新增的事件列表
- 提示用户考虑跑 F 模式

## 代码风格
- 单例：新建 `src/lib/tracking.ts`（若不存在），export `ta` 单例
- 每个 track 调用前加 `// @tracking <event_name>` 注释
- 不加 try/catch
- 事件名 / 属性名严格来自 plan，不改
- Astro：SDK init 放 `src/layouts/BaseLayout.astro` 的 `<script>` 块里；page_view 用 middleware 或 `Astro.url.pathname` 监听

## 前置检查
- `git status --porcelain` 非空 → 拒绝，提示用户先 commit/stash

## Stage 5: 验证步骤（insert 模式专用）

**⚠️ insert 模式 debug 默认关闭，不得引导用户到 Debug 页面查看数据**

### 验证步骤
1. **集成 SDK**（按集成方式选择对应步骤）
   - **npm / 包管理器集成**（JavaScript/React Native/Flutter/uni-app）：执行 `npm install` 或对应包管理器命令安装 SDK
   - **构建工具集成**（Unity/Unreal）：通过 Package Manager 或 Epic Games Launcher 添加 SDK 依赖
   - **依赖管理集成**（Android/iOS）：在 `build.gradle` / `Podfile` 中添加 SDK 依赖
   - **手动下载集成**（Web H5/小程序/游戏引擎等）：下载 SDK 文件并放置到项目对应目录

   参考 `references/sdk-index.md` 中对应 SDK 的官方文档

2. **打开 AE 实时数据页面**（非 Debug 页面）
   - `https://<host>/#/data/realtime`
   - 因为 debug 模式关闭，数据走正常上报流程，实时数据页面才能看到

3. **操作应用触发事件**，查看是否有数据上报

### 上线前检查清单
- [ ] 确认 `debug: false` 或配置中无 debug 字段
- [ ] SDK 已正确集成（依赖已添加 / 文件已放置）
- [ ] 实时数据页面能看到事件上报
