# 2026-05-05 · manager 角色去除 view_tasks 权限 > F1-5b BE-1 修复(方案 B,Neo 2026-05-05 决策) > > migration: `db/zqyy_app/migrations/20260505__remove_manager_view_tasks.sql` ## 背景 Wave 1 走查发现 manager 角色用户进入小程序"任务" tab 收到 403 "权限不足"。BE-1 根因定位详见 `docs/audit/changes/2026-05-05__wave1_f1_5b_be1_task_list_403_root_cause.md`。 **业务侧结论**:`pages/task-list` 是助教个人工作台业务概念,manager(店长)角色没有"我自己的任务"业务场景。监督需求由 board-coach / board-finance 等汇总看板覆盖。从权限矩阵层面移除 manager 的 view_tasks 才是正确做法。 ## 变更说明 ### 数据变更 ```sql DELETE FROM auth.role_permissions WHERE role_id = (SELECT id FROM auth.roles WHERE code = 'manager') AND permission_id = (SELECT id FROM auth.permissions WHERE code = 'view_tasks'); ``` 仅移除一条 `(manager, view_tasks)` 关联记录。 ### Schema 变更 无。`auth.role_permissions` 表结构不变,仅 seed 数据 DELETE 一条。 ### 权限矩阵改前/改后 | 角色 | 改前 | 改后 | |------|------|------| | coach(助教) | view_tasks | **view_tasks(保留)** | | head_coach(主教练) | view_tasks | **view_tasks(保留)** | | manager(店长) | view_board / view_board_coach / view_board_customer / view_board_finance / **view_tasks** | view_board / view_board_coach / view_board_customer / view_board_finance | | staff(员工) | (无 view_tasks) | (无 view_tasks,不变) | ## 兼容性 ### 后端 - 所有用 `require_permission("view_tasks")` 保护的端点(/api/xcx/tasks/* 等):manager 调用会被 require_permission 拦截返回 403,detail "权限不足"。**根因从 _get_assistant_id 的语义错位转为 require_permission 正确拦截**,响应外观不变(都是 403 + 权限不足),但语义清晰 - get_user_permissions 无缓存,改动**立即生效**(不需重启) - /api/xcx/me 返回的 permissions 列表立即少 view_tasks ### 小程序 - `auth-guard.ts::getVisibleTabs()` 基于 permissions 自动重算 → manager 登录后 tabBar 不再显示"任务" tab - 已在线 manager 用户:下次 onShow 时 checkPageAccess 重查权限,自动隐藏"任务" tab - 任务相关页面(task-list / task-detail 等)在 manager 角色下被路由守卫直接跳到 getPermissionHome(看板),不再触发 403 ### admin-web / tenant-admin - 不受影响。两个 admin 后台用 super_admin / site_admin / tenant_admin 角色,与小程序 manager 是独立角色体系。 ### ETL - 无影响。 ## 回滚策略 ```sql INSERT INTO auth.role_permissions (role_id, permission_id) SELECT (SELECT id FROM auth.roles WHERE code = 'manager'), (SELECT id FROM auth.permissions WHERE code = 'view_tasks') WHERE NOT EXISTS ( SELECT 1 FROM auth.role_permissions rp JOIN auth.roles r ON rp.role_id = r.id JOIN auth.permissions p ON rp.permission_id = p.id WHERE r.code = 'manager' AND p.code = 'view_tasks' ); ``` 幂等回滚,避免 PRIMARY KEY 冲突。 ## 验证 SQL(已在测试库执行通过) ### 校验 1:manager 不再拥有 view_tasks ```sql SELECT COUNT(*) FROM auth.role_permissions rp JOIN auth.roles r ON rp.role_id = r.id JOIN auth.permissions p ON rp.permission_id = p.id WHERE r.code = 'manager' AND p.code = 'view_tasks'; -- 期望: 0 ``` ### 校验 2:coach / head_coach 仍保留 view_tasks ```sql SELECT r.code FROM auth.role_permissions rp JOIN auth.roles r ON rp.role_id = r.id JOIN auth.permissions p ON rp.permission_id = p.id WHERE p.code = 'view_tasks' ORDER BY r.code; -- 期望: coach, head_coach ``` ### 校验 3:manager 仍有 4 项看板权限 ```sql SELECT array_agg(p.code ORDER BY p.code) FROM auth.role_permissions rp JOIN auth.roles r ON rp.role_id = r.id JOIN auth.permissions p ON rp.permission_id = p.id WHERE r.code = 'manager'; -- 期望: {view_board, view_board_coach, view_board_customer, view_board_finance} ``` ### 校验 4:典型 manager 用户(Neo, user_id=8778)实际权限链路 ```sql SELECT array_agg(DISTINCT p.code ORDER BY p.code) FROM auth.user_site_roles usr JOIN auth.role_permissions rp ON usr.role_id = rp.role_id JOIN auth.permissions p ON rp.permission_id = p.id WHERE usr.user_id = 8778 AND usr.site_id = 2790685415443269 AND usr.is_removed = false; -- 期望: {view_board, view_board_coach, view_board_customer, view_board_finance} ``` ## 正式库执行说明 本次 migration **仅在测试库执行**。生产环境同步时: ```bash psql "$APP_DB_DSN" -f db/zqyy_app/migrations/20260505__remove_manager_view_tasks.sql ``` 执行前后必须跑 4 条校验 SQL 对比 改前/改后 状态。 ## 端到端走查(Neo 实地确认) 详见 `docs/audit/changes/2026-05-05__wave1_f1_5b_be1_task_list_403_root_cause.md`(同日)审计末尾的 4a/4b 双口径走查记录。