Files
vscode-workbench/PLANNING/PROGRESS_D-01.md
T

63 lines
3.9 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.
# PROGRESS — D-01 · 用户-租户 membership + 跨租户切换
- 状态:done
> 日期 2026-09-13 · 范围:只改 `gj/dealerhub` 目录(后端 core + 前端 tenants/members/切换器)
## 设计(阶段一,任务卡要求先评审再动手——本轮设计与实现一致,评审记录在此)
- 模型(存量复用):`TenantMembership(user, tenant, role[owner|admin|member], is_active, joined_at)`,
唯一约束 `(user, tenant)`;存量回填(0002 迁移:超管=全租户,普通=default)iter6 已验证。
- 授权矩阵:
| 角色 | 切租户/看成员 | 邀请 | 改角色/禁用 | 移除 |
|---|---|---|---|---|
| owner | ✅ | ✅(任意角色) | ✅ | ✅(专属) |
| admin | ✅ | ✅(仅 member) | ✅(仅 member) | ❌ |
| member | ✅(自己有 membership 的) | ❌ | ❌ | ❌ |
| 非成员 | 403 | 403 | 403 | 403 |
| 未知租户 | 400(参数错误,非 403) | 400 | 400 | 400 |
| 超管 | 直通(bootstrap 契约) | 直通 | 直通 | 直通 |
- 切换流程:`POST /api/v1/tenants/<code>/switch/` 校验 membership → 返回 `{code,name,role}` +
写审计(`tenant_switch`);前端换 `localStorage.tenant` + 整页 reload(会话隔离无脏数据)。
- 兼容策略:存量 membership 不动;最后一个 owner 禁止移除/降级/禁用(服务端事务内强保)。
## 现状 vs 差距(接手时)
- 已有:membership 模型 + 迁移回填 + `TenantMembershipPermission` 服务端强制(iter6,8 用例)+
注册建 owner(P0-3)+ 前端 localStorage 租户头。
- 缺口:无切换端点、无成员管理接口、无前端切换器/成员页/无权限页。
## 改动
后端(`backend/apps/core/` + `backend/tests/`):
1. `tenants.py`(新建):`my_tenants`(我的租户+role)、`switch_tenant`(校验+审计)、
`tenant_members`(GET 列表 / POST 邀请:admin 仅 member,新用户≥8位密码事务创建)、
`tenant_member_detail`(PATCH 改角色/禁用 / DELETE 移除:admin 不动 owner/admin,
移除仅 owner,最后一个 owner 三禁)。
2. `urls.py`:四条路由挂 `core_urlpatterns`(即 `/api/v1/tenants/...`)。
3. `tests/test_tenant_switch.py`(新建,12 条):切换 200+role/无权 403/未知 400/mine 双租户/
member 邀 403/owner 邀 201+被邀可切/admin 邀 owner 403/admin 动 owner 403/
跨租户成员页 403/删最后 owner 400/owner 删 member/禁用后资源 403。
前端(`frontend/src/`):
4. `api/tenants.js`(新建):mine/switchTo/members/invite/updateMember/removeMember。
5. `pages/Members.vue`(新建):成员表(角色/状态标签)+ 邀请 dialog(新老用户兼容)+
改角色/禁用启用/移除(owner 专属按钮)+ 403 跳无权限页。
6. `pages/NoPermission.vue`(新建):无权限页 + 我的租户一键进入。
7. `layouts/MainLayout.vue`:租户 tag → 下拉切换器(`mine()` 列表,切后整页 reload)+
“成员”按钮 + 菜单加“租户成员”;`router/index.js` 加 `/members` + `/no-permission`。
## 边界遵守
- 无计费/套餐;单据/库存业务零改;权限全在服务端(前端只做展示与跳转)。
## 验证
```bash
pytest tests/test_tenant_switch.py tests/test_membership.py # 20 passed(12 新增 + 8 存量)
pytest -p no:cacheprovider # 524 passed, 4 skipped(512 基线 + 12 新增)
npm test # 17 pass / 0 fail
npm run build # ✓ built in 6.13s
manage.py makemigrations --check --dry-run # No changes detected
manage.py check # 0 issues
```
## 状态
done。遗留:切换端到端(前端下拉 → switch → reload 无脏数据)需 dev 服务联调时录屏补证据;
demo token 流不走 membership(既有旁路,未动)。