Files
leaudit-platform-backend/docs/superpowers/plans/2026-05-23-entry-module-phase2-scope-completion.md
T
2026-05-25 09:50:01 +08:00

249 lines
14 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.
# 入口模块重构第二阶段实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 补齐入口模块到普通文档、上传、规则分组、页面布局的闭环,让用户从某个入口进去后,只看到、上传、配置该入口范围内的业务数据。
**Architecture:** 第一阶段已完成入口上下文、菜单 features 过滤、公文列表/上传入口归属。第二阶段继续沿用 `selectedEntryModuleContext`,所有业务页面从该上下文读取 `entryModuleId/documentTypeIds`,后端继续用 `entry_module_id/type_id/group_id/tenant_code` 做数据收口,不新增权限体系。
**Tech Stack:** FastAPI、SQLAlchemy 原生 SQL、Next.js、React、现有 RBAC 权限、现有 `leaudit_entry_modules / leaudit_document_types / leaudit_evaluation_point_groups / leaudit_documents` 表。
---
## 一、执行原则
- 不再用入口名称判断业务类型。
- 不改现有 UI 视觉风格,只补数据范围、参数和必要提示。
- 不删除旧接口,先补安全约束和兼容字段。
- 先做普通文档链路,再做规则分组链路,最后处理重复侧边栏和验收。
- 每一批改完都跑 `py_compile``tsc`、目标 `eslint`
## 二、文件责任
- `legal-platform-frontend/lib/auth/entry-module-context.ts`:继续作为前端入口上下文唯一读写入口。
- `legal-platform-frontend/lib/api/legacy/files/documents.ts`:普通文档列表、上传 API 参数补入口模块字段。
- `legal-platform-frontend/app/(audit)/files/upload/*` 或实际上传客户端文件:上传表单带 `entryModuleId/typeId/groupId`
- `legal-platform-frontend/app/(audit)/documents/*` 或实际文档列表客户端文件:文档列表按入口上下文传 `entryModuleId/documentTypeIds`
- `fastapi_modules/fastapi_leaudit/controllers/documentController.py`:普通上传接口接收 `entryModuleId`
- `fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py`:创建文档写入 `entry_module_id`,校验 `group_id` 是二级分组且属于当前入口。
- `legal-platform-frontend/app/(audit)/rule-groups/RuleGroupsClient.tsx`:规则分组页读取入口上下文,只展示当前入口分组。
- `fastapi_modules/fastapi_leaudit/controllers/evaluationPointGroupController.py`:分组列表/创建/更新接收或校验入口模块参数。
- `fastapi_modules/fastapi_leaudit/services/impl/evaluationPointGroupServiceImpl.py`:一级/二级分组边界、入口模块归属、绑定二级分组校验。
- `legal-platform-frontend/components/layout/Layout.tsx`:处理公文详情页内部工作区侧栏和平台 Sidebar 重复问题。
---
## 三、任务拆分
### Task 1:普通文档上传写入入口模块
**目标:** 用户从入口模块进入上传页时,上传出来的文档写入 `entry_module_id/type_id/group_id/tenant_code`
**Files:**
- Modify: `fastapi_modules/fastapi_leaudit/controllers/documentController.py`
- Modify: `fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py`
- Modify: `legal-platform-frontend/lib/api/legacy/files/documents.ts`
- Modify: 实际上传页面客户端,先用 `rg -n "DocumentUpload|uploadDocument|/upload" legal-platform-frontend/app legal-platform-frontend/components`
- [x] 后端 `UploadDocument` 增加 `entryModuleId: int | None = Form(None)`
- [x] `DocumentService.Upload(...)` 增加 `EntryModuleId` 参数。
- [x] 创建 `LeauditDocument` 后写入 `entry_module_id`
- [x] 如果传了 `groupId`,校验该分组 `pid <> 0`
- [x] 如果传了 `entryModuleId + groupId`,校验二级分组所属入口等于 `entryModuleId`
- [x] 如果没传 `groupId`,只允许唯一二级分组时后端兜底;多个二级分组时报 400,让前端用户明确选择。
- [x] 前端上传 API 从 `readEntryModuleContext()` 读取 `entryModuleId/documentTypeIds`
- [x] 上传表单把 `entryModuleId`、选中的 `typeId`、选中的 `groupId` 一起提交。
**验收:**
- 上传成功后数据库 `leaudit_documents.entry_module_id` 有值。
- 多个二级分组时,不选 `groupId` 不能上传。
- 传一级分组 ID 时后端返回 400。
### Task 2:普通文档列表按入口模块过滤
**目标:** 从不同入口进入普通文档列表,只看到当前入口范围的文档。
**Files:**
- Modify: `legal-platform-frontend/lib/api/legacy/files/documents.ts`
- Modify: 普通文档列表客户端,先用 `rg -n "listDocuments|getDocuments|documents.searchParams" legal-platform-frontend/app legal-platform-frontend/components`
- Backend already has: `documentController.py``entry_module_id/type_ids``documentServiceImpl.py` 的过滤基础。
- [x] 文档列表页面读取入口上下文作用域(URL/session,由入口首页写入)。
- [x] 请求参数带 `entry_module_id`
- [x] 请求参数带 `type_ids`,作为入口文档类型范围的兜底过滤。
- [x] 保留现有搜索、分页、状态过滤,不改 UI。
- [x] 切换入口模块时清理 `documents.searchParams`,避免旧入口搜索条件污染新入口。
**验收:**
- 入口 A 上传的文档不出现在入口 B。
- 没有入口上下文时,保留原有列表行为。
### Task 3:规则分组页按入口模块收口
**目标:** 规则分组页只展示当前入口模块下的一级分组和二级分组。
**Files:**
- Modify: `legal-platform-frontend/app/(audit)/rule-groups/RuleGroupsClient.tsx`
- Modify: `legal-platform-frontend/app/api/rule-groups/*`
- Modify: `fastapi_modules/fastapi_leaudit/controllers/evaluationPointGroupController.py`
- Modify: `fastapi_modules/fastapi_leaudit/services/impl/evaluationPointGroupServiceImpl.py`
- [x] 前端读取 `entryModuleId`
- [x] 分组列表请求带 `entry_module_id`
- [x] 后端列表用 `entry_module_id` 过滤一级分组。
- [x] 二级分组根据父级一级分组自然收口。
- [x] 新建一级分组默认带当前入口 `entry_module_id`
- [x] 新建二级分组必须带 `document_type_id`,且文档类型属于当前入口。
- [x] 编辑二级分组时禁止移动到其他入口的一级分组下。
**验收:**
- 合同入口看不到公文入口的分组。
- 公文入口看不到合同入口的分组。
- 二级分组不能跨入口挂载。
### Task 4:规则绑定二级分组硬校验
**目标:** 规则只能绑定二级分组,不能绑定一级分组,也不能跨租户/跨入口污染。
**Files:**
- Modify: `fastapi_modules/fastapi_leaudit/services/impl/evaluationPointGroupServiceImpl.py`
- Review: `fastapi_modules/fastapi_leaudit/services/impl/ruleServiceImpl.py`
- [x] 保留新接口已有 `pid == 0` 拒绝绑定逻辑。
- [x] 在绑定保存时再次校验 group 所属入口对当前用户可见。
- [x] `_load_binding_map` 增加绑定级租户过滤:当前租户、`PUBLIC``PROVINCIAL` 可见,其它租户不可见。
- [x] 旧规则绑定兼容接口只允许唯一可访问二级分组场景写入。
- [x] 旧接口写入新绑定表时必须带 `tenant_code/scope_type`,保持第一阶段补丁。
**验收:**
- 一级分组绑定返回 400。
- 普通租户看不到其它租户绑定。
- 全局管理员能看到公共/省级范围绑定。
### Task 5:重复侧边栏处理
**目标:** 公文详情页不要同时出现平台 Sidebar 和公文工作区 Sidebar。
**Files:**
- Modify: `legal-platform-frontend/components/layout/Layout.tsx`
- Review: `legal-platform-frontend/components/govdoc-audit/GovdocAuditResultPage.tsx`
- [x] 确认哪些公文页面内部有 `GovdocWorkspaceSidebar`
- [x] `Layout.tsx` 对公文详情/结果页隐藏平台 Sidebar。
- [x] 公文列表、上传、概览仍保留平台 Sidebar。
- [x] 不改公文工作区内部 UI,只处理外层布局冲突。
**验收:**
- `/govdoc/audits` 只有平台 Sidebar。
- `/govdoc/[id]` 或详情页只有公文工作区 Sidebar。
- 移动端布局不新增横向溢出。
### Task 6:前端权限和 UI 一致性复查
**目标:** features 只是入口功能编排,不能绕过 RBAC 页面/API 权限。
**Files:**
- Review: `legal-platform-frontend/components/layout/Sidebar.tsx`
- Review: `legal-platform-frontend/lib/auth/entry-module-menu.ts`
- Review: `legal-platform-frontend/lib/auth/user-routes.ts`
- [x] 确认菜单先从 RBAC 路由结果生成,再按 features 过滤。
- [x] 没有合同模板页面权限时,即使入口启用合同模板 feature,也不显示模板菜单。
- [x] 没有规则分组权限时,即使入口启用 `rule_groups`,也不显示规则分组菜单。
- [x] 所有新增提示沿用现有 CSS 变量和组件风格。
**验收:**
- 入口 features 不能“放大权限”,只能“收窄菜单”。
---
## 四、并行安排
建议用 subagent 并行:
- Worker ATask 1 普通文档上传链路。
- Worker BTask 2 普通文档列表过滤。
- Worker CTask 3/4 规则分组和绑定后端校验。
- Worker DTask 5 重复侧边栏处理。
- 主线程:整合冲突、跑验证、更新计划文档。
注意:Worker A 和 Worker B 可能同时改 `lib/api/legacy/files/documents.ts`,需要一个人先做 API 类型,另一个只改页面调用,避免冲突。
---
## 五、验证命令
后端:
```bash
python -m py_compile fastapi_modules/fastapi_leaudit/controllers/documentController.py fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py fastapi_modules/fastapi_leaudit/controllers/evaluationPointGroupController.py fastapi_modules/fastapi_leaudit/services/impl/evaluationPointGroupServiceImpl.py fastapi_modules/fastapi_leaudit/services/impl/ruleServiceImpl.py
```
前端:
```bash
cd legal-platform-frontend
npx tsc --noEmit --pretty false
npx eslint --no-ignore lib/auth/entry-module-context.ts lib/auth/entry-module-menu.ts components/layout/Sidebar.tsx components/layout/Layout.tsx
```
手工验收:
- 创建一个名称不含“合同”的合同入口,启用合同模板功能,检查模板搜索/模板列表显示。
- 创建一个名称不含“公文”的公文入口,启用公文功能,检查公文列表/上传显示。
- 从入口 A 上传普通文档,入口 B 不应看到。
- 从入口 A 进入规则分组,只看到入口 A 的一级/二级分组。
- 尝试把规则绑到一级分组,应失败。
- 公文详情页不出现双侧栏。
执行记录(2026-05-23):
- 已跑后端目标编译:`python -m py_compile ...`,通过。
- 已跑前端类型检查:`npx tsc --noEmit --pretty false`,通过。
- 已跑目标 eslint0 error,剩余 31 个 warning 为既有未使用变量 / any / hook dependency 类警告。
- 已用 Playwright 真实账号 `000/admin06111` 做首页和侧边栏 smoke
- 登录成功。
- 点击入口后进入 `/documents/list?entryModuleId=...&documentTypeIds=...`
- 侧边栏顺序为:首页、文件上传、文档列表、规则管理。
- 文档列表没有重复。
- 上传文档按钮可见。
- 已用 Playwright 真实后端链路跑优先项 `2/3/4/5``node /tmp/leaudit-playwright-priority-2-5-v3.js`,结果 `25 pass / 0 fail`
- 上传携带 `entryModuleId/groupId` 成功,文档详情返回正确 `typeId/groupId/tenantCode`
- 文档列表按入口 A/B 隔离通过。
- 规则分组按入口 A/B 隔离通过。
- 一级分组绑定规则集返回 400。
- 二级分组绑定规则集返回 200。
- 无入口模块创建/编辑/删除权限用户直接调接口返回 403。
- 修复一次 Playwright 暴露的后端 500
- 文件:`fastapi_modules/fastapi_leaudit/services/impl/evaluationPointGroupServiceImpl.py`
- 方法:`_get_binding_row`
- 原因:SQL 文本没有使用 f-string`{access_filter}` 原样发送到 PostgreSQL。
- 修复:把查询文本改为 f-string,入口模块/租户可见性过滤正常注入。
- 已跑后端规则绑定范围单测:`pytest -q tests/test_rule_group_binding_scope.py`,结果 `4 passed`
- 已重新跑前端类型检查:`npx tsc --noEmit --pretty false`,通过。
- 已重新跑目标 eslint0 error,剩余 6 个 warning,为既有 `<img>`、未使用变量类提示。
- 仍需继续做真实浏览器页面级验收:
- 入口模块管理页功能勾选保存和回显。
- 上传页真实表单选择文档类型、二级分组后提交。
- 规则分组页面真实 UI 下只展示当前入口范围。
- 公文列表、公文上传、公文详情页侧边栏真实页面检查。
- 多租户可见性需要用不同租户账号逐个验证。
下一步执行顺序:
1. Playwright 页面级验收入口模块管理页:新建/编辑入口,检查 `menu_profile/features/tenants` 保存和回显。
2. Playwright 页面级验收上传页:确认文件上传在 UI 上第二位,选择文档类型和二级分组后真实提交。
3. Playwright 页面级验收规则分组页:入口 A/B 切换后页面树、绑定按钮、绑定弹窗范围正确。
4. Playwright 页面级验收公文入口:名称不含“公文”但配置公文功能时,公文列表/上传可进入且标题不写死。
5. 多租户账号验证:分别用云浮、揭阳、梅州或可用测试账号验证入口模块可见性和入口管理权限。
6. 根据页面级验收结果修复前端展示问题,再回跑 `tsc`、目标 eslint、Playwright。
---
## 六、暂缓项
- 暂不删除旧 `leaudit_rule_type_bindings` 表。
- 暂不重写评查运行引擎。
- 暂不做同一入口模块按租户覆盖 features。
- 暂不大改页面视觉,只做现有 UI 风格内的补充。