diff --git a/docs/BUG_ANALYSIS_CATEGORY_ID_EMPTY.md b/docs/BUG_ANALYSIS_CATEGORY_ID_EMPTY.md
new file mode 100644
index 0000000..8aa76e1
--- /dev/null
+++ b/docs/BUG_ANALYSIS_CATEGORY_ID_EMPTY.md
@@ -0,0 +1,203 @@
+# Bug 分析报告:商品编辑保存时 `category_id` 为空
+
+**状态**:调研完成,待修复
+**严重性**:🔴 P0 — 所有票务/普通商品编辑后无法保存
+**影响范围**:vr-shopxo-plugin Phase 2 以降的所有商品编辑场景
+**调研人**:西莉雅
+**日期**:2026-04-19
+
+---
+
+## 一、现象描述
+
+| 场景 | 结果 |
+|------|------|
+| 商品列表 → 点编辑 | 分类正常显示 ✅ |
+| 编辑页手动选择分类 | UI 正常选中 ✅ |
+| 点击保存 | 弹窗提示"至少需要选择一个商品分类" ❌ |
+| 反复重试 | 每次都报错,即使选了多个分类也报错 |
+
+**关键特征**:分类在表单上显示正常(说明 DB 有数据、模板渲染正确),但保存时服务端收到的 `category_id` 为空。
+
+---
+
+## 二、数据流追踪
+
+### 2.1 正常保存流程
+
+```
+浏览器 POST 提交
+ → category_id=911&category_id=912&...
+ → ThinkPHP input() 接收
+ → GoodsService::GoodsSave($params)
+ → $category_ids = $params['category_id'] (转数组)
+ → ParamsChecked: empty($params['category_id']) → 【若为空则报错】
+ → GoodsCategoryInsert($category_ids, $goods_id) (写入 goods_category_join)
+```
+
+### 2.2 关键代码节点现状
+
+| 文件 | 路径 | 是否被 antigravity 修改 |
+|------|------|------------------------|
+| GoodsController | `app/admin/controller/Goods.php` | ❌ 未改动 |
+| GoodsService | `app/service/GoodsService.php` | ❌ 未改动 |
+| saveinfo.html | `app/admin/view/default/goods/saveinfo.html` | ❌ 未改动 |
+| common.js (验证逻辑) | `public/static/common/js/common.js` | ❌ 未改动 |
+| AdminGoodsSave.php | `app/plugins/vr_ticket/hook/AdminGoodsSave.php` | ✅ 新引入 |
+| AdminGoodsSaveHandle.php | `app/plugins/vr_ticket/hook/AdminGoodsSaveHandle.php` | ✅ 新引入 |
+| config.json | `app/plugins/vr_ticket/config.json` | ✅ 新增 hooks 注册 |
+
+**结论**:Bug 不在 ShopXO Core,也不在 AdminGoodsSaveHandle(该钩子只处理 `item_type`,不碰 `category_id`)。问题指向 `AdminGoodsSave.php`。
+
+---
+
+## 三、根因分析
+
+### 3.1 `AdminGoodsSave.php` 的注入内容
+
+```php
+// GoodsService::SaveInfo() 中调用
+$assign[$hook_name.'_data'] = MyEventTrigger($hook_name, [
+ 'hook_name' => 'plugins_view_admin_goods_save',
+ 'data' => &$data, // 商品数据(含 category_ids)
+ 'params' => &$params,
+]);
+// 模板中 {{$hook|raw}} 将其输出到表单底部
+```
+
+`AdminGoodsSave.php` 的 `handle()` 返回一段 HTML,**直接嵌入商品编辑表单底部**:
+
+```html
+
+
+
+
+
+
+
+```
+
+### 3.2 冲突机制(推断)
+
+**时序**:
+
+```
+1. PHP 渲染表单 →