refactor(auth): F1-5b BE-1 manager 角色移除 view_tasks 权限 (W1)
走查发现 manager(店长)进入小程序"任务"tab 收到 403 "权限不足"。
根因不在 require_permission(权限校验通过,missing=set()),而在
task_manager._get_assistant_id() 因 user_assistant_binding 无有效绑定
抛 403 "权限不足"(detail 与权限错误同名,误导走查方向)。
设计层冲突:task-list 是助教个人工作台业务概念,manager 没有"我自己
的任务"业务场景,监督需求由 board-coach 等汇总看板覆盖。
Neo 决策(2026-05-05):
> "任务的 tab 只有助教身份的用户可以进入并查看,让管理身份的用户
> 进入没有意义。因为他们使用业务场景中不存在任务方面的场景。"
→ 选 B 方案:权限矩阵层移除 manager 的 view_tasks。
变更:
- db/zqyy_app/migrations/20260505__remove_manager_view_tasks.sql
DELETE FROM auth.role_permissions WHERE role_id=manager AND permission_id=view_tasks
- docs/database/changes/2026-05-05__remove_manager_view_tasks.md
完整变更说明 + 兼容性 + 4 条校验 SQL + 幂等回滚
测试库执行 + 4 条校验全 PASS:
- manager 改前 5 项权限,改后 4 项(view_board* 保留)
- view_tasks 现绑定到 [coach, head_coach](manager 已剥离)
- coach / head_coach 助教工作台不受影响
- 典型 manager 用户 Neo (8778) 实际权限不再含 view_tasks
双口径走查(weixin-devtools-mcp):
- 4a live: relaunch 后 visibleTabs 从 [task, board, my] → [board, my]
小程序 tabBar"任务"tab 自动隐藏(getVisibleTabs 基于权限自动重算)
- 强制调 GET /api/xcx/tasks 仍 403,但根因从 _get_assistant_id 错位
转为 require_permission 正确拦截,语义清晰
不改的部分:
- task_manager._get_assistant_id() 不动(仍用于 coach/head_coach)
- require_permission("view_tasks") 路由保护不动(仍合理)
- 前端 auth-guard.ts 不改(getVisibleTabs 已基于 permissions 自动)
正式库同步说明:
- 本次仅在测试库执行,生产环境同步时 psql 执行 migration + 跑校验 SQL
审计:
- docs/audit/changes/2026-05-05__wave1_f1_5b_be1_task_list_403_root_cause.md
含完整证据链 + 三方案 ABC 业务影响对比 + B 实施记录
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
134
docs/database/changes/2026-05-05__remove_manager_view_tasks.md
Normal file
134
docs/database/changes/2026-05-05__remove_manager_view_tasks.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# 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 双口径走查记录。
|
||||
Reference in New Issue
Block a user