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

18 KiB
Raw Blame History

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(...) / 跳转引用 / 语言包中的路径引用。

三、执行步骤

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 复用

五、验收命令(参考)

# 后端
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. 作业规范(协议要点)

一、接单流程(强制顺序)

1. 通读任务卡 → 确认「边界」段(哪些文件不许动)
2. 读项目根 README + 最近 2 份 PROGRESS/迭代报告(了解项目惯例与雷区)
3. 跑「基线测试」——确认开工前测试是绿的;有红的先记录,不背锅
4. 实施(最小变更原则)
5. 跑「验收命令」——全绿
6. 写 PROGRESS_<任务ID>.md 到项目根
7. 交付:代码 + PROGRESS + 关键命令输出摘要

禁止跳步:不读文档就动手、不跑基线就改代码、不跑验收就宣称完成——三者任一发生,交付直接打回。


二、PROGRESS 文件格式(交付凭证)

写到项目根目录,文件名 PROGRESS_<任务ID>.md:

# 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 and eslint-plugin-react-dom for React-specific lint rules:

// 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 系统检查

$ cd chunyu_project && python manage.py check
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. 收工检查(提交前逐条打勾)

[ ] 第 1 节「验收标准」逐条已满足,且每条都有原始命令输出支撑
[ ] 「边界」段列出的文件一个都没动
[ ] 既有测试没被删/没被跳过(只许更绿)
[ ] 卡外的一律没夹带(顺手发现的 bug 写进 PROGRESS「遗留问题」)
[ ] PROGRESS_C-01.md 已写到项目根,格式符合第 2 节
[ ] 基线对照写了「开工前 → 完工后」两段真实数字
[ ] 未验证项已明确标注(不许虚报)

本包由 PLANNING/tools/handoff_bundle.py 生成 · 规范见 PLANNING/03-执行协议.md §七