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:
@@ -0,0 +1,37 @@
|
|||||||
|
-- 2026-05-05
|
||||||
|
-- F1-5b BE-1: manager 角色去除 view_tasks 权限
|
||||||
|
--
|
||||||
|
-- 背景: Wave 1 走查发现 manager 角色用户进入 task-list 页面收到 403 "权限不足"。
|
||||||
|
-- 根因定位: require_permission 通过,但 task_manager._get_assistant_id 因
|
||||||
|
-- manager 在 user_assistant_binding 无有效绑定而抛 403,detail 与权限错误同名。
|
||||||
|
--
|
||||||
|
-- 设计决策(Neo 2026-05-05): task-list 是助教个人工作台业务概念,
|
||||||
|
-- manager(店长)角色没有"我自己的任务"业务场景,监督需求由 board-coach
|
||||||
|
-- 等汇总看板覆盖。从权限矩阵层面移除 manager 的 view_tasks。
|
||||||
|
--
|
||||||
|
-- 影响:
|
||||||
|
-- - manager 登录后小程序 tabBar 不再显示"任务" tab(getVisibleTabs 自动隐藏)
|
||||||
|
-- - manager 直接调用 GET /api/xcx/tasks 仍返回 403,但根因变为 require_permission
|
||||||
|
-- 拦截而非 _get_assistant_id 的语义错位
|
||||||
|
-- - coach / head_coach 角色 view_tasks 权限不变,助教工作台正常使用
|
||||||
|
--
|
||||||
|
-- 兼容性:
|
||||||
|
-- - 不改 schema,仅 seed 数据 DELETE
|
||||||
|
-- - 已登录的 manager 用户 access_token 中 roles=[manager] 不变,但下次请求
|
||||||
|
-- /api/xcx/me 拿到的 permissions 列表立即少了 view_tasks(get_user_permissions
|
||||||
|
-- 每次请求都查 DB,无缓存)
|
||||||
|
-- - 前端 tabBar 在 onShow 时调 checkPageAccess + getVisibleTabs 重算,自动隐藏
|
||||||
|
--
|
||||||
|
-- 回滚:
|
||||||
|
-- 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');
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
# 2026-05-05 · F1-5b BE-1 task-list 403 根因定位 + 修复(B 方案)
|
||||||
|
|
||||||
|
> Wave 1 / F1-5b Wave A 第 7 项任务(详见 `docs/_overview/wave1-findings/F1-5b-tasks.md` §4.2)
|
||||||
|
>
|
||||||
|
> 工作量评估 M / 3-4h(实际 ~ 2h:1.5h 根因定位 + 0.5h B 方案实施)。
|
||||||
|
>
|
||||||
|
> **Neo 2026-05-05 拍板 B 方案**:任务 tab 只对助教身份开放,管理身份移除 view_tasks 权限。
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
Wave 1 走查发现小程序 manager 角色用户(Neo, user_id=8778)访问 `pages/task-list` 时收到 403 "权限不足"。原假设:`require_permission` 与 JWT 中的 site_id 不一致。
|
||||||
|
|
||||||
|
## 根因(已完全证实,非 require_permission 问题)
|
||||||
|
|
||||||
|
403 **不来自** `require_permission`,而来自 `task_manager._get_assistant_id()` 第 104 行硬编码的 `raise HTTPException(status_code=403, detail="权限不足")`,与权限校验 detail 完全相同。
|
||||||
|
|
||||||
|
### 完整证据链
|
||||||
|
|
||||||
|
#### 证据 1 — JWT 与 DB 状态完全一致
|
||||||
|
|
||||||
|
```
|
||||||
|
JWT payload: sub=8778, site_id=2790685415443269, aud=miniapp, roles=[manager]
|
||||||
|
auth.users[8778]: status=approved
|
||||||
|
auth.user_site_roles[8778]: site=2790685415443269 role_id=170(manager) is_removed=false
|
||||||
|
auth.role_permissions[170]: 5 项含 view_tasks
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 证据 2 — require_permission 通过
|
||||||
|
|
||||||
|
在 `app/middleware/permission.py:81` 临时插桩(已移除)证实:
|
||||||
|
|
||||||
|
```
|
||||||
|
uid=8778(int) site=2790685415443269(int) required=('view_tasks',)
|
||||||
|
got=['view_board', 'view_board_coach', 'view_board_customer', 'view_board_finance', 'view_tasks']
|
||||||
|
missing=set()
|
||||||
|
```
|
||||||
|
|
||||||
|
`/api/xcx/me` 返回的 permissions 列表也含 view_tasks,与 require_permission 内部查询完全一致。
|
||||||
|
|
||||||
|
#### 证据 3 — 403 来自 _get_assistant_id
|
||||||
|
|
||||||
|
`apps/backend/app/services/task_manager.py:84-105`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def _get_assistant_id(conn, user_id: int, site_id: int) -> int:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT assistant_id
|
||||||
|
FROM auth.user_assistant_binding
|
||||||
|
WHERE user_id = %s AND site_id = %s AND assistant_id IS NOT NULL
|
||||||
|
AND is_removed = false
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT 1
|
||||||
|
""",
|
||||||
|
(user_id, site_id),
|
||||||
|
)
|
||||||
|
row = cur.fetchone()
|
||||||
|
if not row:
|
||||||
|
raise HTTPException(status_code=403, detail="权限不足") # ← 此处!
|
||||||
|
return row[0]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 证据 4 — Neo 在 user_assistant_binding 无可用绑定
|
||||||
|
|
||||||
|
```
|
||||||
|
id=298 assistant_id=None is_removed=false ← 唯一 is_removed=false 但 assistant_id 为 NULL
|
||||||
|
id=297 assistant_id=3137... is_removed=true
|
||||||
|
id=295 assistant_id=2964640... is_removed=true
|
||||||
|
id=290 assistant_id=3124582... is_removed=true
|
||||||
|
id=289 assistant_id=2964673... is_removed=true
|
||||||
|
id=288 assistant_id=2964673... is_removed=true
|
||||||
|
... 共 11 条,is_removed=true 的有 10 条,is_removed=false 的 1 条但 assistant_id=NULL
|
||||||
|
```
|
||||||
|
|
||||||
|
SQL `WHERE assistant_id IS NOT NULL AND is_removed = false` 返回 0 行 → `_get_assistant_id` 抛 403。
|
||||||
|
|
||||||
|
## 设计层冲突
|
||||||
|
|
||||||
|
### 当前实现(coach 视角)
|
||||||
|
|
||||||
|
`get_task_list_v2` 整个查询基于**单一 assistant_id**:
|
||||||
|
|
||||||
|
- `WHERE assistant_id = %s`
|
||||||
|
- `batch_query_for_task_list(... assistant_id ...)`
|
||||||
|
- `build_performance_summary(... assistant_id ...)`
|
||||||
|
|
||||||
|
只服务"助教看自己的任务"场景。
|
||||||
|
|
||||||
|
### 前端调用(manager 也走此入口)
|
||||||
|
|
||||||
|
`pages/task-list` 在 manager 角色下也展示("查看任务")。从 manager 视角期望"看 site 下所有任务"(或某种聚合视图),但后端不支持。
|
||||||
|
|
||||||
|
## 三个候选修复方案
|
||||||
|
|
||||||
|
| 方案 | 内容 | 影响 | 工作量 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| **A** 改后端 | manager 角色绕过 _get_assistant_id,改成查 site 下所有 assistants 的任务聚合 | 大,触及核心 SQL/分页/绩效汇总 | L 4-6h |
|
||||||
|
| **B** 改前端 | manager 角色下隐藏/禁用 task-list tab(走 board-coach 等管理者视角) | 中,需对齐产品设计 | S 1h |
|
||||||
|
| **C** 数据修复 | 给 Neo (manager) 创建一条 user_assistant_binding(is_removed=false + 真实 assistant_id) | 极小,但绕过设计 | XS 5min |
|
||||||
|
|
||||||
|
### 方案推荐(待 Neo 决策)
|
||||||
|
|
||||||
|
**首选 B**:从架构上更合理,task-list 设计是助教视角,manager 应有自己的"管理任务概览"页面(可以 Wave B 新建)。
|
||||||
|
|
||||||
|
**次选 A**:工作量大但保持 task-list 兼容多角色。
|
||||||
|
|
||||||
|
**不推荐 C**:绕过设计,后续维护混乱(其他 manager 也会遇到同样问题)。
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
|
||||||
|
无代码改动(本次仅完成根因定位),无任何端影响。
|
||||||
|
|
||||||
|
## 测试
|
||||||
|
|
||||||
|
无新增测试。诊断脚本:
|
||||||
|
|
||||||
|
- `_DEL/walkthrough_f1_5b/step_be1_perm_probe.py` — 权限链路 SQL 直查
|
||||||
|
- `_DEL/walkthrough_f1_5b/step_be1_user_status.py` — auth.users 状态
|
||||||
|
- `_DEL/walkthrough_f1_5b/step_be1_simulate_perm.py` — 模拟 require_permission SQL
|
||||||
|
- `_DEL/walkthrough_f1_5b/step_be1_uab_probe.py` — user_assistant_binding 完整状态(根因)
|
||||||
|
|
||||||
|
## Neo 决策(2026-05-05)
|
||||||
|
|
||||||
|
> "这是一个产品设计的问题,不是 bug。任务的 tab 只有助教身份的用户可以进入并查看,让管理身份的用户进入没有意义。因为他们使用业务场景中不存在任务方面的场景。"
|
||||||
|
|
||||||
|
→ 选 **B 方案**:DB 层从 manager 角色移除 view_tasks 权限,前端 tabBar 自动隐藏,后端 require_permission 自动拦截。
|
||||||
|
|
||||||
|
## B 方案实施
|
||||||
|
|
||||||
|
### Migration
|
||||||
|
|
||||||
|
`db/zqyy_app/migrations/20260505__remove_manager_view_tasks.sql`:
|
||||||
|
|
||||||
|
```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');
|
||||||
|
```
|
||||||
|
|
||||||
|
### docs/database/ 同步
|
||||||
|
|
||||||
|
`docs/database/changes/2026-05-05__remove_manager_view_tasks.md`(完整变更说明 + 兼容性 + 回滚 + 4 条校验 SQL)。
|
||||||
|
|
||||||
|
### 测试库执行结果
|
||||||
|
|
||||||
|
```
|
||||||
|
改前 manager 权限: [view_board, view_board_coach, view_board_customer, view_board_finance, view_tasks]
|
||||||
|
改后 manager 权限: [view_board, view_board_coach, view_board_customer, view_board_finance]
|
||||||
|
view_tasks 现绑定到角色: [coach, head_coach] (manager 已剥离)
|
||||||
|
Neo (user_id=8778) 实际权限: [view_board, view_board_coach, view_board_customer, view_board_finance]
|
||||||
|
```
|
||||||
|
|
||||||
|
4 条校验 SQL 全部 PASS。
|
||||||
|
|
||||||
|
### 4a 端到端走查(live 模式)
|
||||||
|
|
||||||
|
**前提**:Neo (manager) relaunch 小程序触发 onLaunch 重新拉权限。
|
||||||
|
|
||||||
|
| 维度 | 改前 | 改后 |
|
||||||
|
|------|------|------|
|
||||||
|
| globalData.permissions | 5 项含 view_tasks | 4 项不含 view_tasks |
|
||||||
|
| globalData.visibleTabs | [task, board, my] | **[board, my]** |
|
||||||
|
| 小程序 tabBar 实际渲染 | 显示"任务" tab | **"任务" tab 已隐藏** |
|
||||||
|
| 强制调 GET /api/xcx/tasks | 403 "权限不足"(根因 _get_assistant_id) | 403 "权限不足"(根因 require_permission) |
|
||||||
|
|
||||||
|
外观 status code 不变,但语义从"业务逻辑错位"转为"权限正确拦截"。
|
||||||
|
|
||||||
|
### 4b sandbox 验证
|
||||||
|
|
||||||
|
权限校验与 sandbox 业务时钟无关(权限查 auth.role_permissions,sandbox 影响 ETL 视图),无需重复走查。
|
||||||
|
|
||||||
|
## 临时 debug 代码已清理
|
||||||
|
|
||||||
|
- `permission.py` 中临时 insert 的诊断 print(已 revert)
|
||||||
|
- `tmp/be1_diag.txt` 临时诊断文件(已删除)
|
||||||
|
|
||||||
|
## 回滚策略
|
||||||
|
|
||||||
|
```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'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
幂等回滚。已记入 `docs/database/changes/2026-05-05__remove_manager_view_tasks.md`。
|
||||||
|
|
||||||
|
## Co-Authored-By
|
||||||
|
|
||||||
|
Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||||
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