Files
vscode-workbench/PLANNING/bundles/bundle-C-01-baseline.md
T

358 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Handoff Bundle — C-01 路由/代理前缀冲突修复
生成时间:2026-09-11 23:18 +0800
项目:`chunyu` 项目根:`C:\Users\12914\Desktop\vscode\chunyu_project_react`
优先级:P0 · 里程碑 M1 · 预估 1 天
建议模型:deepseek-v4.1-flash 复核:glm-5.3-flash
依赖:无
进度文件:`PROGRESS_C-01.md`(写到项目根)
> 这是一份**自包含**交接包:接手模型读完本节即可开工,不需要再问路径、命令、上下文。
> 卡内所有硬约束以第 1 节为准;本包的其余部分是上下文,**不得覆盖卡内约束**。
---
## 0. 接手须知(先读)
1. 本包是「C-01」的完整上下文。若你是接手上游的部分成果,**不要重做已验证部分**——
先跑第 5 节的基线命令确认当前状态,再从断点继续。
2. 密钥零接触:`.env`、`(服务器数据)`、`~/.dsh/secrets` —— 只读都不行。
3. 交付 = 代码 + 项目根 `PROGRESS_C-01.md`(格式见第 2 节)+ 关键命令的**原始输出**。
4. 验收标准全绿才可声明 done;跑不绿就写 partial/blocked 并附原始输出。
5. 完成后逐条对照第 1 节「验收标准」自检,未验证项必须写明——**虚报验收直接降级**。
---
## 1. 任务卡全文
# C-01 · 路由/代理前缀冲突修复
| 字段 | 值 |
|---|---|
| 项目 | 可乐工具 · `vscode/chunyu_project_react`(前端)+ `vscode/chunyu_project`(后端) |
| 优先级 | P0 · M1 |
| 建议模型 | deepseek-v4.1-flash(主)/ glm-5.3-flash(全量回归复核) |
| 依赖 | 无 |
| 预估 | 1 天 |
## 一、背景(为什么做)
2026-09-10 页面健康检查实测:**开发环境 22 条路由、生产环境 7 条路由被 API 代理劫持**——用户刷新页面、收藏链接、分享链接时直接打开 Django 404 或原始 JSON,而不是前端页面。SPA 内部点击导航不受影响,所以**藏得深、咬得狠**。
证据:`vscode/docs/页面健康检查报告.md`(问题清单 1.1 / 1.2)。
根因:前端路由与后端 API 共用了一组顶级路径段(`/api`、`/article`、`/learn`、`/user`、`/bug`、`/chat`、`/history`、`/message`、`/s`、`/search`、`/tool`),vite 代理用**前缀匹配**、生产 nginx 用**带尾斜杠的正则**,两边都会误伤前端路由。
## 二、目标(交付物)
1. **前端冲突路由改名**(推荐方案 A,报告结论"一劳永逸,趁早改便宜"):
- `/api` 及其子路由(`/api-directory`、`/api-docs`、`/api-detail/:id`、`/api/ip-location` 等 5 个数据 API 页)→ `/open-api/*`
- `/article/:id` → `/post/:id`(或 `/article-detail/:id`)
- `/user/:id` → `/user-home/:id`(项目已有 `/user-home` 路由,可复用)
2. **代理收窄**:vite 代理不再是宽前缀——改为**精确路径清单 / 正则白名单**(先枚举后端真实 URL:`chunyu_project/config/urls.py` + 各 app `urls.py`,以枚举结果为准)。
3. **生产 nginx 同步**:`nginx-docker.conf` 同样收窄,并覆盖 `/article/:id`、`/user/:id`、`/api/*` 五条数据页的冲突段。
4. **回归脚本**:提交一个可重复运行的 73 路由检查脚本(如 `scripts/check_routes.mjs`),检测逻辑三件套:① 是否返回 Django 404/JSON(劫持)② `#root` 是否空(白屏)③ 正文长度。
5. 全量更新 `navigation(...)` / 跳转引用 / 语言包中的路径引用。
## 三、执行步骤
```text
1. 枚举后端真实 API 路径(config/urls.py + 全部 app urls.py),产出一张「API 路径清单」
2. 对照前端 73 条路由,标记全部冲突项(不只报告里那 7 条)
3. 执行改名 + 同步全部引用(grep 旧路径确认零残留)
4. 收窄 vite 代理 → 启动 dev 双端,跑回归脚本至 73/73
5. 收窄 nginx-docker.conf,静态审查冲突模式段
6. 提交:代码 + 回归脚本 + 检查报告(贴进 PROGRESS)
```
## 四、验收标准
- [ ] dev 环境:73 条路由直访全部返回 SPA(无 Django 404/JSON 劫持、无白屏)
- [ ] 生产 nginx 配置:审查确认 7 条冲突段全部让路(含 `/article/:id`、`/user/:id`——核心分享场景)
- [ ] `grep -rn "旧路径"` 零残留(含 App.tsx、页面组件、i18n 词条)
- [ ] API 调用回归正常(登录、文章列表、工具使用等核心接口抽查 via 代理)
- [ ] SPA 内部导航抽查正常(首页→文章→详情)
- [ ] 回归脚本已入库,可被 CI 复用
## 五、验收命令(参考)
```bash
# 后端
cd chunyu_project && python manage.py runserver 8002
# 前端
cd chunyu_project_react && npm run dev # 5173
# 路由回归(脚本由本任务交付)
node scripts/check_routes.mjs --base http://127.0.0.1:5173
# 期望输出:PASS 73/73,hijacked=0,blank=0
# 引用残留检查
grep -rn "'/api-docs'\|'/api-directory'\|/article/\|/user/" src/ --include="*.tsx" --include="*.ts" | grep -v open-api
```
## 六、边界(不许做)
- 不动后端 API 的响应结构(纯路由层工作)
- 不重构页面组件内部逻辑
- 不修改 `docs/` 下既有报告
- 新增路由名后必须保留旧路径的**客户端重定向**(302 内的 SPA `Navigate`)——已分享出去的链接不能全死
## 七、交接
交付 = 代码 + `scripts/check_routes.mjs` + **PROGRESS_C-01.md**(含 73/73 输出与占位截图说明)。
格式见 `PLANNING/03-执行协议.md`。
---
## 2. 作业规范(协议要点)
## 一、接单流程(强制顺序)
```text
1. 通读任务卡 → 确认「边界」段(哪些文件不许动)
2. 读项目根 README + 最近 2 份 PROGRESS/迭代报告(了解项目惯例与雷区)
3. 跑「基线测试」——确认开工前测试是绿的;有红的先记录,不背锅
4. 实施(最小变更原则)
5. 跑「验收命令」——全绿
6. 写 PROGRESS_<任务ID>.md 到项目根
7. 交付:代码 + PROGRESS + 关键命令输出摘要
```
**禁止跳步**:不读文档就动手、不跑基线就改代码、不跑验收就宣称完成——三者任一发生,交付直接打回。
---
## 二、PROGRESS 文件格式(交付凭证)
写到**项目根目录**,文件名 `PROGRESS_<任务ID>.md`:
```markdown
# PROGRESS — <任务ID> <任务名>
- 状态:done | partial | blocked
- 执行模型:<模型名>
- 日期:YYYY-MM-DD
- 分支/提交:<commit hash 或"未提交">
## 三、质量红线(硬性)
1. **不许伪造**:测试跑不绿就写 partial/blocked,附原始输出。伪造一次 = 该模型在该项目永久降级为 C 级。
2. **不许删测试**:既有测试只许更绿。删测试用例、跳过断言、注释掉失败用例 = 交付无效。
3. **不许夹带**:任务卡外的一律不做。看到顺手能修的 bug,写进 PROGRESS 的「遗留问题」,不顺手改。
4. **不许碰密钥**:`.env`、`~/.dsh/secrets`、`(服务器数据)` 目录——只读都不许,物理隔离。
5. **不许破坏契约**:改 API 响应结构/字段名必须保持向后兼容或双写过渡,并在 PROGRESS 说明。
6. **不许强推**:不执行 `git push --force`、不 rebase 他人提交、不 git reset 别人的改动。
7. **不许超时硬干**:预计超预算时,先交「阶段报告 + 断点说明」,让调度器续派,不许烂尾。
---
## 四、各项目雷区(前人踩过的坑,直接记)
### 可乐工具(chunyu)
- **vite 代理前缀匹配过宽**:`/api` 会连 `/api-docs` 一起劫持——改代理时必须用精确规则(见 C-01)。
- **生产 nginx 正则带尾斜杠**:`^/(api|user|...)/` 依然劫持子路径,改完前端要同步审查 `nginx-docker.conf`。
- 前端 67 页组件,路由引用散落各处——改路由名必须 grep 全量 `navigation(` 调用。
- 后端全异步(adrf):新视图必须 async,不要写同步视图混挂。
### EnglishDrill
- **granian 孤儿 worker**:只杀父进程会留 worker 占端口,表现为"改了代码不生效"。用 `tools/devserver.ps1 restart`。
- **E2E 双模式**:`tests/e2e/run_e2e.py`(默认 ASGI 进程内 / `--http` 真实 granian)。隔离库 `backend/.tmp/e2e-db.sqlite3`,不碰开发库。
- **值收口层**:外部 id 必须走 `core/helpers.py` 的 `as_int` 等收口函数,禁止裸 `int()` 进 ORM(曾造成 44 处 5xx)。
- **stats 口径**:分类统计必须带 `is_deleted=False`,否则和 `/api/categories` 打架(BUG-2 教训)。
- 前端登录守卫在 `src/App.tsx:29`。
### dealerhub
- 460 passed / 4 skipped 是基线;4 个跳过是 PG 并发用例(D-02 处理)。
- 测试命令:`pytest`(在 `backend/`);前端 `npm test` + `npm run build`。
- `makemigrations --check --dry-run` 必须干净。
- 演示数据重建:`seed_demo --reset`;改数据模型要同步改 seed。
### DSP
- 双端:Web(Vue3)+ Android;后端 Django + Channels。
- 转码依赖本地 ffmpeg;nginx 托管静态视频。
- 无 E2E 套件——S-01 会建;在此之前以 `backend/tests` 为准。
### DSH / 基础设施
- `~/.dsh/settings.yaml` 是**热配置**:改前备份(`.bak_<日期>`),改后 YAML 解析校验。插件曾覆盖式写入破坏能力声明(2026-09-08 事故)。
- 测试:`server/` 下 `pytest -q`,用独立测试库 `postgres_test`,conftest 拒绝在生产库跑。
- 探活:`GET /healthz`。
---
---
## 3. 项目上下文
### 3.1 项目 README:`chunyu_project_react/README.md`
```markdown
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
## React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
…(已截断:原文 73 行 / 2425 字符)
```
### 3.2 最近 PROGRESS(0 份)
(该项目尚无 PROGRESS —— 本卡可能是首张卡)
---
## 4. 相关源码清单
卡内点名过的路径,逐个核实:
- `vscode/docs/页面健康检查报告.md` → 文件 docs/页面健康检查报告.md(vscode,5039 B,改于 2026-09-10 18:56)
- `nginx-docker.conf` → 文件 nginx-docker.conf(vscode,3149 B,改于 2026-09-05 11:49)
- `docs/` → 目录 chunyu_project_react/docs(chunyu)
- `PLANNING/03-执行协议.md` → 文件 PLANNING/03-执行协议.md(vscode,5486 B,改于 2026-09-11 22:37)
**未解析的线索**(卡里提到但当前树中找不到 —— 可能是路径漂移,接手时按候选或自行搜索确认):
- `chunyu_project/config/urls.py` —— 近似候选:chunyu_project/air_quality/urls.py、chunyu_project/api/urls.py、chunyu_project/apidirectory/urls.py
- `urls.py` —— 近似候选:chunyu_project/air_quality/urls.py、chunyu_project/api/urls.py、chunyu_project/apidirectory/urls.py
- `scripts/check_routes.mjs`
**项目根一级结构**(先看哪儿):
- `chunyu_project_react` → docs/,public/,src/,test-results/,tests/,Dockerfile,README.md,_add_timestamp.cjs,_patch_date_calc.cjs,_verify.cjs,add_login_record.cjs,article-editor-dark-final.png,article-editor-dark-rich.png,article-editor-dark-verified.png…
---
## 5. 基线测试命令与输出
> 以下为打包时实跑捕获(超时上限 90s/条,重型套件已跳过)。开工前请自行复跑确认,不要直接抄这里的结论。
### 前端类型/构建检查(重)
```bash
cd chunyu_project_react && npm run build
```
[SKIP] 标记为重型(全量套件可能跑很久)——打包时未执行,接手模型必须自己跑一遍并记录真实输出
### 后端 Django 系统检查
```bash
$ cd chunyu_project && python manage.py check
```
```text
System check identified some issues:
WARNINGS:
?: (urls.W005) URL namespace 'shorturl' isn't unique. You may not be able to reverse all URLs in this namespace
api.TranslateUsage: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ApiConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
apidirectory.ApiCategory: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ApidirectoryConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
apidirectory.ApiFavorite: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ApidirectoryConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
apidirectory.ApiItem: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ApidirectoryConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
app.Changelog: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the AppConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
tool.ColorHistory: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ToolConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
tool.CompressionHistory: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ToolConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
tool.Tool: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ToolConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
tool.ToolCategory: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ToolConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
tool.ToolFavorite: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ToolConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
tool.ToolUsageRecord: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
HINT: Configure the DEFAULT_AUTO_FIELD setting or the ToolConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
System check identified 12 issues (0 silenced).
```
→ 退出码 0,耗时 2.4s,末行判读:System check identified 12 issues (0 silenced).(期望:System check identified no issues)
---
## 6. 收工检查(提交前逐条打勾)
```text
[ ] 第 1 节「验收标准」逐条已满足,且每条都有原始命令输出支撑
[ ] 「边界」段列出的文件一个都没动
[ ] 既有测试没被删/没被跳过(只许更绿)
[ ] 卡外的一律没夹带(顺手发现的 bug 写进 PROGRESS「遗留问题」)
[ ] PROGRESS_C-01.md 已写到项目根,格式符合第 2 节
[ ] 基线对照写了「开工前 → 完工后」两段真实数字
[ ] 未验证项已明确标注(不许虚报)
```
---
*本包由 `PLANNING/tools/handoff_bundle.py` 生成 · 规范见 `PLANNING/03-执行协议.md` §七*