Initialize backendized SurClaw report system
- Add React/Vite frontend for login, dashboard, reports, templates, users, settings, AI, speech, and media workflows. - Add NestJS/Prisma/PostgreSQL backend with auth, dashboard stats, reports, templates, users, departments, settings, files, AI, speech, audit logs, and HTML sanitization. - Add Prisma schema, migrations, seed data, persistent app sessions, Docker/Nginx deployment files, and upload volume configuration. - Add Vitest, Playwright, backend integration tests, and project documentation for requirements, design, permissions, API contracts, testing, deployment, security, and progress. - Configure production local fallback switch and remove unused Gemini direct dependency/env wiring.
This commit is contained in:
280
docs/permissions.md
Normal file
280
docs/permissions.md
Normal file
@@ -0,0 +1,280 @@
|
||||
# 权限设计
|
||||
|
||||
本文档描述后端化后的目标权限模型。当前版本登录认证已接入后端,但角色和部分页面级过滤仍主要在前端执行,不能作为生产安全边界;后端化后必须由服务端统一鉴权和授权。
|
||||
|
||||
## 已确定规则
|
||||
|
||||
- 超级管理员拥有全权限,可以查看和修改系统内任何数据。
|
||||
- 超级管理员默认属于 `admin` 部门,但查询、管理和授权不受部门限制。
|
||||
- 管理员只能查看、编辑和删除本部门报告。
|
||||
- 医生默认只能查看、编辑和删除本人报告。
|
||||
- 医生完成报告后仍允许修改,也允许删除本人已完成报告。
|
||||
- 完成报告后的每次修改都需要增加修订版本号,方便医疗文书追踪。
|
||||
- 模板按部门授权。
|
||||
- 管理员可以修改本部门模板,也可以使用被授权模板。
|
||||
- 医生不可以直接修改部门模板,但可以复制/新建自己的模板并修改。
|
||||
- 只有超级管理员能创建或授权管理员。
|
||||
- 一个部门只能有一个管理员。
|
||||
- 不设置患者维度权限。
|
||||
- 部门之间不存在上级/下级关系。
|
||||
- 不需要临时授权或会诊授权。
|
||||
- 不允许同一用户属于多个部门。
|
||||
- AI 代理只能接收当前报告内容作为上下文,不能读取跨部门报告。
|
||||
- 报告导出不需要水印、导出原因、审批或专门导出审计。
|
||||
- 前端菜单隐藏只是体验优化,所有权限必须在后端 API 层强校验。
|
||||
|
||||
## 角色定义
|
||||
|
||||
| 角色 | 代码建议 | 权限定位 |
|
||||
| --- | --- | --- |
|
||||
| 超级管理员 | `super` | 系统最高权限,跨部门、跨模板、跨用户管理。 |
|
||||
| 管理员 | `admin` | 部门级管理者,只管理本部门业务数据;每个部门最多一个管理员。 |
|
||||
| 医生 | `doctor` 或沿用 `user` | 普通报告创建者,主要管理本人报告,可复制或新建个人模板。 |
|
||||
|
||||
当前前端代码使用 `user` 表示医生。后端化时可以继续沿用 `user`,也可以迁移为更清晰的 `doctor`。如果迁移,需要同步前端类型、接口返回和历史数据。
|
||||
|
||||
## 数据边界
|
||||
|
||||
后端数据至少需要以下边界字段:
|
||||
|
||||
- `tenant_id`:医院或部署实例。单医院也建议预留。
|
||||
- `department_id`:科室。
|
||||
- `user_id`:用户。
|
||||
- `role`:用户角色。
|
||||
|
||||
报告、模板、用户、文件、操作日志都应带上 `tenant_id`。报告必须带 `department_id`。模板可以带拥有部门,也可以通过授权表关联部门。
|
||||
|
||||
组织规则:
|
||||
|
||||
- 每个用户只能属于一个部门。
|
||||
- 超级管理员默认部门为 `admin`。
|
||||
- 部门没有上下级层级。
|
||||
- 一个部门最多一个管理员,后端创建/修改管理员时必须校验唯一性。
|
||||
|
||||
## 报告权限
|
||||
|
||||
### 查看报告
|
||||
|
||||
| 角色 | 规则 |
|
||||
| --- | --- |
|
||||
| 超级管理员 | 可查看所有报告。 |
|
||||
| 管理员 | 只能查看本部门报告。 |
|
||||
| 医生 | 只能查看本人报告。 |
|
||||
|
||||
建议后端查询规则:
|
||||
|
||||
```text
|
||||
super: WHERE tenant_id = current.tenant_id
|
||||
admin: WHERE tenant_id = current.tenant_id AND department_id = current.department_id
|
||||
doctor: WHERE tenant_id = current.tenant_id AND author_id = current.user_id
|
||||
```
|
||||
|
||||
### 新建报告
|
||||
|
||||
| 角色 | 规则 |
|
||||
| --- | --- |
|
||||
| 超级管理员 | 可为任意部门创建报告,默认部门为 `admin`,也可在表单中选择目标部门。 |
|
||||
| 管理员 | 可在本部门创建报告。 |
|
||||
| 医生 | 可为自己创建报告,部门取当前用户部门。 |
|
||||
|
||||
建议新建报告时由后端写入 `author_id`、`department_id`、`tenant_id`,不要完全信任前端传入。
|
||||
|
||||
### 编辑报告
|
||||
|
||||
| 角色 | 规则 |
|
||||
| --- | --- |
|
||||
| 超级管理员 | 可编辑任何报告。 |
|
||||
| 管理员 | 可编辑本部门报告。 |
|
||||
| 医生 | 可编辑本人报告,包括已完成报告。 |
|
||||
|
||||
完成报告后仍允许修改。后端必须:
|
||||
|
||||
- 每次保存创建 `report_histories` 记录。
|
||||
- 已完成报告每次修改递增修订版本号。
|
||||
- 记录修改人、修改时间、修改动作和旧版本内容或旧版本引用。
|
||||
|
||||
### 删除报告
|
||||
|
||||
| 角色 | 规则 |
|
||||
| --- | --- |
|
||||
| 超级管理员 | 可删除任何报告。 |
|
||||
| 管理员 | 可删除本部门报告,包括已完成报告。 |
|
||||
| 医生 | 可删除本人报告,包括已完成报告。 |
|
||||
|
||||
实现建议:
|
||||
|
||||
- 后端可以先做软删除,保留 `deleted_at`、`deleted_by`,避免误删后无法恢复。
|
||||
- 如果未来接入正式病历归档流程,再考虑把“删除”改为“作废/归档”。
|
||||
|
||||
### 导出报告
|
||||
|
||||
| 角色 | 规则 |
|
||||
| --- | --- |
|
||||
| 超级管理员 | 可导出所有报告。 |
|
||||
| 管理员 | 可导出本部门报告。 |
|
||||
| 医生 | 可导出本人报告。 |
|
||||
|
||||
当前确定:报告导出不需要水印、导出原因、审批或专门导出审计。
|
||||
|
||||
## 模板权限
|
||||
|
||||
已确定:模板按部门授权。
|
||||
|
||||
建议数据模型:
|
||||
|
||||
- `templates`:模板主体。
|
||||
- `departments`:部门。
|
||||
- `template_department_permissions`:模板与部门授权关系。
|
||||
- `user_templates` 或在 `templates` 中增加 `owner_user_id`:医生复制/新建的个人模板。
|
||||
|
||||
建议权限规则:
|
||||
|
||||
| 角色 | 查看/使用模板 | 管理模板 |
|
||||
| --- | --- | --- |
|
||||
| 超级管理员 | 全部模板 | 全部模板,可授权给部门。 |
|
||||
| 管理员 | 本部门模板和被授权模板 | 可修改本部门模板,可使用被授权模板。 |
|
||||
| 医生 | 本部门被授权模板、自己的个人模板 | 不可修改部门模板;可复制/新建并修改自己的个人模板。 |
|
||||
|
||||
新建报告时,后端必须校验当前用户是否有权使用该模板。
|
||||
|
||||
模板授权粒度建议:
|
||||
|
||||
- 部门授权模板用于“部门可见/可使用”。
|
||||
- 模板归属部门用于判断管理员是否可以管理。
|
||||
- 医生个人模板只归属创建医生本人,不自动成为部门模板。
|
||||
|
||||
## 用户权限
|
||||
|
||||
| 角色 | 用户管理权限 |
|
||||
| --- | --- |
|
||||
| 超级管理员 | 创建、编辑、禁用、删除所有用户,分配部门和角色,创建或授权管理员。 |
|
||||
| 管理员 | 管理本部门医生;不能创建管理员;不能跨部门管理用户。 |
|
||||
| 医生 | 只能查看和修改自己的基础资料,密码修改走单独接口。 |
|
||||
|
||||
管理员规则:
|
||||
|
||||
- 只有超级管理员能创建或授权管理员。
|
||||
- 一个部门只能有一个管理员。
|
||||
- 管理员不能创建超级管理员。
|
||||
|
||||
## 系统设置权限
|
||||
|
||||
| 设置项 | 超级管理员 | 管理员 | 医生 |
|
||||
| --- | --- | --- | --- |
|
||||
| AI Provider 和密钥 | 可管理 | 不可管理 | 不可管理 |
|
||||
| 讯飞语音密钥 | 可管理 | 不可管理 | 不可管理 |
|
||||
| 全局抽帧策略 | 可管理 | 不可管理 | 不可管理 |
|
||||
| 部门默认模板 | 可管理全部部门 | 可管理本部门 | 不可管理 |
|
||||
| 个人默认模板 | 可配置自己默认值 | 可配置自己默认值 | 可配置自己默认值 |
|
||||
|
||||
建议把设置拆为:
|
||||
|
||||
- 全局设置:超级管理员维护。
|
||||
- 部门设置:超级管理员或本部门管理员维护。
|
||||
- 用户偏好:每个用户自己维护。
|
||||
|
||||
## 文件权限
|
||||
|
||||
文件包括签名、模板图片、报告图片、视频、关键帧、导出文件。
|
||||
|
||||
建议规则:
|
||||
|
||||
- 签名文件:用户本人、本部门管理员、超级管理员可访问。
|
||||
- 报告相关文件:继承报告权限。
|
||||
- 模板图片:继承模板权限。
|
||||
- 视频文件:继承报告权限,且建议限制下载或设置过期访问 URL。
|
||||
- 导出文件:继承报告导出权限;不要求专门导出审计。
|
||||
|
||||
## 操作记录与历史
|
||||
|
||||
虽然报告导出不需要专门审计,但以下写操作仍建议记录基础操作日志,便于排查和追踪:
|
||||
|
||||
- 登录成功/失败。
|
||||
- 新建、保存、完成、修改已完成报告。
|
||||
- 删除报告。
|
||||
- 新建、修改、删除模板。
|
||||
- 模板部门授权变更。
|
||||
- 新建、禁用、删除、改角色用户。
|
||||
- 修改 AI/语音密钥。
|
||||
- 修改系统设置。
|
||||
|
||||
报告历史是业务必需项:
|
||||
|
||||
- 报告每次保存保留历史版本。
|
||||
- 已完成报告每次修改递增修订版本号。
|
||||
- 历史记录应包含修改人、修改时间、修改动作、旧内容或旧内容引用。
|
||||
|
||||
日志建议包含:
|
||||
|
||||
- `tenant_id`
|
||||
- `actor_user_id`
|
||||
- `actor_role`
|
||||
- `action`
|
||||
- `target_type`
|
||||
- `target_id`
|
||||
- `department_id`
|
||||
- `ip`
|
||||
- `user_agent`
|
||||
- `created_at`
|
||||
- `metadata`
|
||||
|
||||
敏感病历正文和完整密钥不应写入普通日志;报告正文版本应放在报告历史表或对象存储中。
|
||||
|
||||
## AI 权限
|
||||
|
||||
AI 代理只能接收当前报告内容作为上下文:
|
||||
|
||||
- 不允许读取跨部门报告。
|
||||
- 不允许自动检索其他报告作为上下文。
|
||||
- 不需要患者维度权限。
|
||||
- AI 请求由后端代理发出,前端不接触真实 API Key。
|
||||
|
||||
如果用户在当前报告中选择了图片、关键帧或正文片段,这些内容必须先通过当前报告权限校验。
|
||||
|
||||
## API 权限落点
|
||||
|
||||
后端每个接口都要做权限校验。建议先在服务层写统一 guard/policy:
|
||||
|
||||
- `canViewReport(user, report)`
|
||||
- `canCreateReport(user, departmentId)`
|
||||
- `canEditReport(user, report)`
|
||||
- `canDeleteReport(user, report)`
|
||||
- `canExportReport(user, report)`
|
||||
- `canUseTemplate(user, template)`
|
||||
- `canManageTemplate(user, template)`
|
||||
- `canCreatePersonalTemplate(user)`
|
||||
- `canManageUser(actor, targetUser)`
|
||||
- `canCreateAdmin(actor, departmentId)`
|
||||
- `canManageSettings(user, scope, departmentId?)`
|
||||
|
||||
列表接口不能只在前端过滤,必须在数据库查询条件中限制可见范围。
|
||||
|
||||
## 已关闭问题
|
||||
|
||||
以下问题已经确认,不再作为阻塞项:
|
||||
|
||||
| 问题 | 结论 |
|
||||
| --- | --- |
|
||||
| 管理员是否可以编辑本部门医生创建的报告? | 可以。 |
|
||||
| 管理员是否可以删除本部门已完成报告? | 可以。 |
|
||||
| 医生是否可以删除本人已完成报告? | 可以。 |
|
||||
| 管理员是否可以创建其他管理员? | 不可以,只有超级管理员能创建/授权管理员。 |
|
||||
| 一个部门是否只能有一个管理员? | 是。 |
|
||||
| 管理员是否可以管理本部门模板内容? | 可以修改本部门模板,也可以使用被授权模板。 |
|
||||
| 模板授权粒度如何处理? | 部门模板按部门授权;医生不可改部门模板,但可复制/新建个人模板。 |
|
||||
| 超级管理员是否属于某个部门? | 默认属于 `admin` 部门。 |
|
||||
| 是否需要患者维度权限? | 不需要。 |
|
||||
| 报告完成后修改是否需要修订版本号? | 需要。 |
|
||||
| 报告导出是否需要水印、原因、审批或专门审计? | 不需要。 |
|
||||
| AI 能否读取跨部门报告作为上下文? | 不能,只能接收当前报告内容。 |
|
||||
| 部门是否有上下级关系? | 没有。 |
|
||||
| 是否需要临时授权或会诊授权? | 不需要。 |
|
||||
| 是否允许同一用户属于多个部门? | 不允许。 |
|
||||
|
||||
## 后续实现注意
|
||||
|
||||
- 数据库应对“一个部门一个管理员”设置唯一约束或事务校验。
|
||||
- 报告列表、模板列表、用户列表必须在 SQL 查询层过滤权限。
|
||||
- 医生个人模板和部门模板需要在数据模型上区分。
|
||||
- 已完成报告的修改需要版本号和历史记录,不应只覆盖最新内容。
|
||||
- 删除报告建议先做软删除,后续如有病历归档要求再调整为作废流程。
|
||||
Reference in New Issue
Block a user