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

14 KiB
Raw Blame History

入口模块重构第二阶段实施计划

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_compiletsc、目标 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

  • 后端 UploadDocument 增加 entryModuleId: int | None = Form(None)

  • DocumentService.Upload(...) 增加 EntryModuleId 参数。

  • 创建 LeauditDocument 后写入 entry_module_id

  • 如果传了 groupId,校验该分组 pid <> 0

  • 如果传了 entryModuleId + groupId,校验二级分组所属入口等于 entryModuleId

  • 如果没传 groupId,只允许唯一二级分组时后端兜底;多个二级分组时报 400,让前端用户明确选择。

  • 前端上传 API 从 readEntryModuleContext() 读取 entryModuleId/documentTypeIds

  • 上传表单把 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.pyentry_module_id/type_idsdocumentServiceImpl.py 的过滤基础。

  • 文档列表页面读取入口上下文作用域(URL/session,由入口首页写入)。

  • 请求参数带 entry_module_id

  • 请求参数带 type_ids,作为入口文档类型范围的兜底过滤。

  • 保留现有搜索、分页、状态过滤,不改 UI。

  • 切换入口模块时清理 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

  • 前端读取 entryModuleId

  • 分组列表请求带 entry_module_id

  • 后端列表用 entry_module_id 过滤一级分组。

  • 二级分组根据父级一级分组自然收口。

  • 新建一级分组默认带当前入口 entry_module_id

  • 新建二级分组必须带 document_type_id,且文档类型属于当前入口。

  • 编辑二级分组时禁止移动到其他入口的一级分组下。

验收:

  • 合同入口看不到公文入口的分组。
  • 公文入口看不到合同入口的分组。
  • 二级分组不能跨入口挂载。

Task 4:规则绑定二级分组硬校验

目标: 规则只能绑定二级分组,不能绑定一级分组,也不能跨租户/跨入口污染。

Files:

  • Modify: fastapi_modules/fastapi_leaudit/services/impl/evaluationPointGroupServiceImpl.py

  • Review: fastapi_modules/fastapi_leaudit/services/impl/ruleServiceImpl.py

  • 保留新接口已有 pid == 0 拒绝绑定逻辑。

  • 在绑定保存时再次校验 group 所属入口对当前用户可见。

  • _load_binding_map 增加绑定级租户过滤:当前租户、PUBLICPROVINCIAL 可见,其它租户不可见。

  • 旧规则绑定兼容接口只允许唯一可访问二级分组场景写入。

  • 旧接口写入新绑定表时必须带 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

  • 确认哪些公文页面内部有 GovdocWorkspaceSidebar

  • Layout.tsx 对公文详情/结果页隐藏平台 Sidebar。

  • 公文列表、上传、概览仍保留平台 Sidebar。

  • 不改公文工作区内部 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

  • 确认菜单先从 RBAC 路由结果生成,再按 features 过滤。

  • 没有合同模板页面权限时,即使入口启用合同模板 feature,也不显示模板菜单。

  • 没有规则分组权限时,即使入口启用 rule_groups,也不显示规则分组菜单。

  • 所有新增提示沿用现有 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 类型,另一个只改页面调用,避免冲突。


五、验证命令

后端:

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

前端:

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/5node /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 风格内的补充。