From a66c97523ba546d069bb948f41f9ec491a7d59b8 Mon Sep 17 00:00:00 2001 From: liuyun Date: Wed, 14 Oct 2026 11:20:12 +0800 Subject: [PATCH] =?UTF-8?q?docs(openspec):=20=E6=9C=8D=E5=8A=A1=E6=9C=BA?= =?UTF-8?q?=E6=9E=84=E7=AB=AF=20C0=20=E5=9F=BA=E7=A1=80=E9=AA=A8=E6=9E=B6?= =?UTF-8?q?=20change=20=E6=8F=90=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit proposal + 5 specs(shared/data-model、shared/api-contract、backend/org、 backend/catalog、frontend/ad/svc-org-base)+ design + tasks Co-Authored-By: Claude Opus 4.8 --- .../changes/svc-org-c0-base/.openspec.yaml | 2 + openspec/changes/svc-org-c0-base/design.md | 52 ++++++++++++++++++ openspec/changes/svc-org-c0-base/proposal.md | 34 ++++++++++++ .../specs/backend/catalog/spec.md | 33 ++++++++++++ .../svc-org-c0-base/specs/backend/org/spec.md | 33 ++++++++++++ .../specs/frontend/ad/svc-org-base/spec.md | 26 +++++++++ .../specs/shared/api-contract/spec.md | 19 +++++++ .../specs/shared/data-model/spec.md | 54 +++++++++++++++++++ openspec/changes/svc-org-c0-base/tasks.md | 36 +++++++++++++ 9 files changed, 289 insertions(+) create mode 100644 openspec/changes/svc-org-c0-base/.openspec.yaml create mode 100644 openspec/changes/svc-org-c0-base/design.md create mode 100644 openspec/changes/svc-org-c0-base/proposal.md create mode 100644 openspec/changes/svc-org-c0-base/specs/backend/catalog/spec.md create mode 100644 openspec/changes/svc-org-c0-base/specs/backend/org/spec.md create mode 100644 openspec/changes/svc-org-c0-base/specs/frontend/ad/svc-org-base/spec.md create mode 100644 openspec/changes/svc-org-c0-base/specs/shared/api-contract/spec.md create mode 100644 openspec/changes/svc-org-c0-base/specs/shared/data-model/spec.md create mode 100644 openspec/changes/svc-org-c0-base/tasks.md diff --git a/openspec/changes/svc-org-c0-base/.openspec.yaml b/openspec/changes/svc-org-c0-base/.openspec.yaml new file mode 100644 index 0000000..49ea85b --- /dev/null +++ b/openspec/changes/svc-org-c0-base/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-10-14 diff --git a/openspec/changes/svc-org-c0-base/design.md b/openspec/changes/svc-org-c0-base/design.md new file mode 100644 index 0000000..5fe3eb1 --- /dev/null +++ b/openspec/changes/svc-org-c0-base/design.md @@ -0,0 +1,52 @@ +## Context + +服务机构端 P0 在 sysmgr 脚手架(ec-nest + ec-admin)上落地。脚手架已提供:多租户过滤(tenant_code)、RBAC(resource 树 + 权限码)、审计日志、软删(deleted_at)、错误码注册表。C0 只做映射 + 建业务表 + 配角色/权限/菜单/错误码,不侵入脚手架。 + +## Goals / Non-Goals + +**Goals:** + +- 定死机构=租户映射,业务表复用脚手架多租户过滤。 +- `staff` 持 `user_id` 关联账号,不动 `sys_user`。 +- C0 建 9 张业务表 + 复用 `sys_user`。 +- 5 业务角色 + 权限码 + 菜单 + 错误码 + 审计落地。 + +**Non-Goals:** + +- 不实现 C1–C4 业务(待遇档案/派单/留痕/质控)。 +- 不接真实 COS 上传(占位)。 +- 不做护理员 APP、家属端。 + +## Decisions + +1. **机构=租户,tenant_code 作全局键**(备选:扩展 sys_tenant → 弃,污染框架)。 +2. **staff.user_id 关联 user,不动 sys_user**(备选:user.staff_id → 弃,动框架;user.ext_type/ext_id 多态 → 弃,YAGNI + 无外键保障)。 +3. **业务角色用脚手架角色 + 权限码**(PRD 的 `user.role` 逗号分隔不照搬,用 user↔role 多对多实现多角色并集)。 +4. **主键 UUID v7**(备选 varchar32 → 弃,跟随脚手架)。 +5. **软删 deleted_at**(备选 is_deleted 布尔 → 弃,跟随脚手架)。 + +## 数据模型(DDL 概览) + +通用字段:`created_at`/`created_by`/`updated_at`/`updated_by`/`deleted_at`。 + +- **org**:org_code(PK, 与 tenant_code 同值)、org_name、org_type、credit_code、loc_code、loc_name、svc_source、license_no、address、contact_name、contact_phone、bed_count、sign_date +- **staff**:staff_id(PK uuid)、tenant_code、user_id(unique 可空 → user.id)、name、id_card_no(加密)、person_code、phone、job_type、work_type、entry_date、leave_date、employ_status、cert_type/cert_no/cert_level/cert_expire/cert_status、cert_verify_url、group_leader_id +- **svc_national**(L1):nat_id、nat_code(unique varchar20)、nat_name、nat_category、nat_sub_category、recommend_staff、recommend_duration、is_medical、version +- **svc_local**(L2):loc_id、loc_code、local_item_name、local_category、svc_time、min_freq、staff_qual、is_medical、source_doc、map_status +- **svc_mapping**(L3):map_id、loc_id、nat_id(可空)、map_type、map_note、status +- **svc_org**(L4):org_svc_id、tenant_code、src_type、src_id、is_enabled、price(预留)、price_effective(预留)、is_new_national +- **dict_abnormal_type**:code、name、sort;**dict_photo_tier**:code、name、tier +- **loc_config**:loc_code(PK)、loc_name、svc_source、item_count_rule(预留) + +索引:`staff.user_id` 唯一、`staff.tenant_code`、`svc_national.nat_code` 唯一、`svc_local.loc_code`、`svc_org.tenant_code`。 + +## Risks / Trade-offs + +- [org 表与 sys_tenant 1:1 但分表] → 以 `code = tenant_code` 同值保证一致;创建机构时事务内同步建 tenant。 +- [staff.user_id 无法用 DB 外键到不同库] → 同库内仍可建外键;业务层再校验 user 存在 + 唯一。 +- [目录四层数据初始化量大] → seed 提供 L1 36 项 + 昆明 L2 45 项 + L3 映射;州市按需插入 loc_config + svc_local。 + +## Migration Plan + +- 新增 Prisma 迁移建 9 张表;seed 初始化目录(L1/L2/L3)、默认角色与权限码;不迁移旧数据(新库)。 +- 回滚:删除本次迁移即可(纯新增,无破坏性改动)。 diff --git a/openspec/changes/svc-org-c0-base/proposal.md b/openspec/changes/svc-org-c0-base/proposal.md new file mode 100644 index 0000000..d7c23e9 --- /dev/null +++ b/openspec/changes/svc-org-c0-base/proposal.md @@ -0,0 +1,34 @@ +## Why + +投云长护险「服务机构端」P0 要在 sysmgr 脚手架(ec-nest + ec-admin)上落地四块业务(待遇档案/派单工单/履约留痕/质控闸门)。C0 是地基:先定死「机构=租户」映射、账号/人员/角色、数据模型基线、审计与错误码,否则 C1–C4 各自为政、必然返工。 + +## What Changes + +- 新增业务数据模型基线:`org`、`staff`、服务目录四层(`svc_national/svc_local/svc_mapping/svc_org`)、业务字典(`dict_abnormal_type/dict_photo_tier`)、属地配置 `loc_config`。 +- 定死机构=租户映射:机构唯一标识 = 脚手架 `tenant_code`;`org` 独立业务表,不扩展 `sys_tenant`。 +- 定死账号/人员分离:`staff`(业务新表)持 `user_id` 外键关联脚手架 `sys_user`(**不动 sys_user**);业务角色 nurse/leader/qc/admin/director 建成脚手架角色。 +- 复用脚手架多租户过滤、RBAC、审计、错误码机制,落地服务机构端权限码与业务错误码。 +- 后台新增业务菜单骨架(服务对象/排班派单/工单留痕/质控中心/文书/系统设置业务配置)。 +- 照片存储(腾讯云 COS)本期只占位,不接真实上传。 + +## Capabilities + +### New Capabilities + +- `shared/data-model`: 服务机构端 C0 数据模型字段字典(org/staff/目录四层/字典/loc_config + 枚举 + 多租户键约定) +- `shared/api-contract`: 统一响应(含 hint)+ 业务错误码(1001–4001)+ C0 接口契约 +- `backend/org`: 机构(org)与人员(staff)域——机构=租户、staff.user_id 关联账号、角色权限、审计 +- `backend/catalog`: 服务目录四层(L1–L4)+ 属地配置(loc_config)+ 业务字典 +- `frontend/ad/svc-org-base`: 机构管理后台基础骨架——登录落地、业务菜单、权限控制、属地提示 + +### Modified Capabilities + +(无) + +## Impact + +- 后端 ec-nest:新增 org/staff/catalog 业务模块(纯新增,不侵入脚手架)。 +- 前端 ec-admin:新增业务菜单与页面骨架(纯新增)。 +- 数据:新增 9 张业务表(迁移);复用脚手架 `sys_user`(不加列)。 +- 部署:SaaS 多租户,每机构 = 一个 tenant。 +- 契约锚点:`shared/data-model`、`shared/api-contract` 先行。 diff --git a/openspec/changes/svc-org-c0-base/specs/backend/catalog/spec.md b/openspec/changes/svc-org-c0-base/specs/backend/catalog/spec.md new file mode 100644 index 0000000..8030213 --- /dev/null +++ b/openspec/changes/svc-org-c0-base/specs/backend/catalog/spec.md @@ -0,0 +1,33 @@ +## Purpose + +定义服务机构端服务目录四层(L1–L4)与属地配置、业务字典的后端行为——按属地加载目录、机构不可改目录、国家新增项显式提示。 + +## ADDED Requirements + +### Requirement: 属地目录加载 +后端 MUST 按机构 `loc_code` 加载对应目录:昆明加载本地 45 项,新建制州市加载国家 36 项。 + +#### Scenario: 昆明机构加载 +- **WHEN** 昆明机构请求目录 +- **THEN** 返回本地 45 项(系统内置 L3 映射) + +### Requirement: 机构不可改目录 +机构 MUST 只能对 L4 勾选 + 配价(改 `is_enabled`/`price`),不可新增/修改 L1–L3 目录。 + +#### Scenario: 机构改目录被拒 +- **WHEN** 机构尝试新增或修改目录项 +- **THEN** 返回 403 + +### Requirement: 国家新增项显式提示 +国家目录有而昆明本地目录没有的 5 项 MUST 在昆明机构勾选界面显式列出并标注「过渡期新增·建议纳入」。 + +#### Scenario: 昆明机构看到新增项 +- **WHEN** 昆明机构请求可勾选项 +- **THEN** 返回国家新增 5 项并标记 is_new_national + +### Requirement: 属地配置驱动 +新增州市 MUST 仅需插入 `loc_config` + `svc_local` 数据即生效,不改代码。 + +#### Scenario: 新增州市零代码 +- **WHEN** 插入某新州市的 loc_config 与 svc_local +- **THEN** 该州市机构登录即加载新目录,无需发版 diff --git a/openspec/changes/svc-org-c0-base/specs/backend/org/spec.md b/openspec/changes/svc-org-c0-base/specs/backend/org/spec.md new file mode 100644 index 0000000..b1361ba --- /dev/null +++ b/openspec/changes/svc-org-c0-base/specs/backend/org/spec.md @@ -0,0 +1,33 @@ +## Purpose + +定义服务机构端机构(org)与人员(staff)域的后端行为——机构=租户映射、staff.user_id 关联账号、角色权限与审计。 + +## ADDED Requirements + +### Requirement: 机构与租户绑定 +后端 MUST 以脚手架 `tenant_code` 作为机构唯一标识,业务表统一带 `tenant_code` 并继承脚手架多租户过滤。 + +#### Scenario: 跨机构数据隔离 +- **WHEN** A 机构账号查询业务数据 +- **THEN** 只返回本机构(本 tenant)数据,访问他机构返回 4001 + +### Requirement: 人员账号关联 +`staff` 实体 MUST 持 `user_id` 关联脚手架 user;护理员/组长账号通过 `staff.user_id` 定位本人人员档案;院长/质控/管理员账号无 staff 记录。 + +#### Scenario: 护理员定位人员 +- **WHEN** 护理员登录后请求本人信息 +- **THEN** 系统按 `staff.user_id = 当前 user.id` 返回唯一 staff 记录 + +### Requirement: 角色与权限 +业务角色 nurse/leader/qc/admin/director MUST 建成脚手架角色并按权限码授权;权限取角色并集;仅持 director 的账号写接口 MUST 返回 403。 + +#### Scenario: 仅院长写接口被拒 +- **WHEN** 仅持 director 的账号调用写接口 +- **THEN** 返回 403;若同时持 qc/admin,则按并集放行 + +### Requirement: 完整审计 +建档、改状态、派单、放行、导入、导出、明文查看身份证等业务动作 MUST 全量落审计日志(谁/何时/动作/对象/前后值)。 + +#### Scenario: 改状态落审计 +- **WHEN** 质控员变更老人待遇状态 +- **THEN** 写入一条审计日志,含操作人、时间、前后值 diff --git a/openspec/changes/svc-org-c0-base/specs/frontend/ad/svc-org-base/spec.md b/openspec/changes/svc-org-c0-base/specs/frontend/ad/svc-org-base/spec.md new file mode 100644 index 0000000..4b7abd7 --- /dev/null +++ b/openspec/changes/svc-org-c0-base/specs/frontend/ad/svc-org-base/spec.md @@ -0,0 +1,26 @@ +## Purpose + +定义机构管理后台基础骨架——登录后落地、业务菜单、权限控制与属地提示,作为服务机构端后台页面的容器。 + +## ADDED Requirements + +### Requirement: 登录落地 +机构后台登录后 MUST 直接落地「服务对象」列表页,不做看板首页。 + +#### Scenario: 登录落地 +- **WHEN** 机构账号登录成功 +- **THEN** 进入服务对象列表页 + +### Requirement: 业务菜单 +后台 MUST 保留脚手架菜单并新增业务菜单:服务对象/排班派单/工单留痕/质控中心/文书档案;系统设置内新增业务配置项。 + +#### Scenario: 菜单可见 +- **WHEN** 登录后台 +- **THEN** 脚手架菜单与业务菜单同时可见,按角色控制可见性 + +### Requirement: 属地提示 +登录页 MUST 显示机构属地与加载的目录(如「属地:昆明市 · 目录:昆明市 45 项」)。 + +#### Scenario: 属地可见 +- **WHEN** 打开登录页 +- **THEN** 显示机构属地与目录信息 diff --git a/openspec/changes/svc-org-c0-base/specs/shared/api-contract/spec.md b/openspec/changes/svc-org-c0-base/specs/shared/api-contract/spec.md new file mode 100644 index 0000000..54f29b8 --- /dev/null +++ b/openspec/changes/svc-org-c0-base/specs/shared/api-contract/spec.md @@ -0,0 +1,19 @@ +## Purpose + +定义服务机构端 C0 的统一响应契约与业务错误码,作为前后端接口交互的唯一约定。 + +## ADDED Requirements + +### Requirement: 统一响应结构 +所有接口 MUST 返回统一响应结构 `{code, message, data, hint}`;`code=0` 成功,非 0 失败;硬锁拒绝时 `hint` MUST 提供用户可读的「怎么解」提示。 + +#### Scenario: 硬锁拒绝带 hint +- **WHEN** 接口因硬锁拒绝(如无有效待遇) +- **THEN** 返回非 0 code 与可读 message,且 `hint` 说明「先做什么才能做」 + +### Requirement: 业务错误码 +业务错误码 MUST 落地为 5 位码 [域码2][序3],并覆盖:1001 无有效待遇、1002 无有效计划、1003 无有效工单、1004 留痕不完整、1005 未质控、1006 资质不匹配(提示级)、2001 时间冲突(硬拒)、2002 项数不满足(提示)、3001 必拍未拍(硬拒)、3002 定位失败(非错误)、3003 扑空登记、3004 垫付不计费、4001 越权或自审自放行。 + +#### Scenario: 资质不匹配提示级 +- **WHEN** 派单时护理员资质不匹配 +- **THEN** 返回 1006,前端仅提示、允许继续(本期不拦截,二期改硬拒) diff --git a/openspec/changes/svc-org-c0-base/specs/shared/data-model/spec.md b/openspec/changes/svc-org-c0-base/specs/shared/data-model/spec.md new file mode 100644 index 0000000..f7e1e59 --- /dev/null +++ b/openspec/changes/svc-org-c0-base/specs/shared/data-model/spec.md @@ -0,0 +1,54 @@ +## Purpose + +定义服务机构端 C0 的数据模型字段字典——机构/人员/服务目录四层/字典/属地配置的实体、字段、枚举与多租户键约定,作为前后端字段命名的唯一锚点。 + +## ADDED Requirements + +### Requirement: 多租户键约定 +服务机构端所有业务实体 MUST 携带 `tenant_code` 字段作为多租户隔离键,其值为机构唯一标识(= 脚手架租户 code)。 + +#### Scenario: 跨机构隔离 +- **WHEN** 业务表写入一条记录 +- **THEN** 该记录 MUST 带 `tenant_code`,且读操作按当前租户自动过滤,不返回其他租户数据 + +### Requirement: 机构实体 org +`org` 表 MUST 存在,主键为机构 code(与 `tenant_code` 同值),承载机构业务字段:org_name、org_type、credit_code、loc_code、loc_name、svc_source、license_no、address、contact_name、contact_phone、bed_count、sign_date。 + +#### Scenario: 机构唯一标识 +- **WHEN** 创建一个机构 +- **THEN** 其 code 与脚手架的 tenant code 一致且全局唯一 + +### Requirement: 人员实体 staff +`staff` 表 MUST 存在,承载人员/资质字段(name、id_card_no、phone、job_type、work_type、employ_status、cert_type/cert_no/cert_level/cert_expire/cert_status、group_leader_id),并 MUST 带 `user_id` 关联脚手架 `user.id`(可空、1:1)。 + +#### Scenario: 账号关联人员 +- **WHEN** 护理员登录并定位本人 staff +- **THEN** 通过 `staff.user_id = user.id` 唯一定位到一条 staff 记录 + +### Requirement: 软删约定 +服务机构端业务实体 MUST 采用脚手架 `deleted_at`(时间戳)软删,不物理删除。 + +#### Scenario: 软删保留 +- **WHEN** 删除一条业务记录 +- **THEN** 记录置 `deleted_at`,读操作默认排除,物理数据保留 + +### Requirement: 主键约定 +业务实体主键 MUST 采用脚手架 UUID v7;业务码(机构 code、项目代码)MUST 建唯一索引。 + +#### Scenario: 主键唯一 +- **WHEN** 新增业务记录 +- **THEN** 生成 UUID v7 主键,业务码唯一索引防重复 + +### Requirement: 目录四层实体 +`svc_national`(L1)、`svc_local`(L2)、`svc_mapping`(L3)、`svc_org`(L4) 四表 MUST 存在,字段按 PRD §7.2 定义;L3 映射表不提供机构侧接口。 + +#### Scenario: 目录分层 +- **WHEN** 加载某机构属地目录 +- **THEN** 按 L1/L2 取目录、L4 取机构勾选与配价、L3 仅内部映射 + +### Requirement: 字典与属地配置实体 +`dict_abnormal_type`、`dict_photo_tier`、`loc_config` 三表 MUST 存在,承载异常分类、拍照分档、属地目录来源与项数规则配置。 + +#### Scenario: 属地配置驱动目录 +- **WHEN** 新增一个州市 +- **THEN** 插入一条 `loc_config` + 一批 `svc_local` 即生效,无需改代码 diff --git a/openspec/changes/svc-org-c0-base/tasks.md b/openspec/changes/svc-org-c0-base/tasks.md new file mode 100644 index 0000000..33e0848 --- /dev/null +++ b/openspec/changes/svc-org-c0-base/tasks.md @@ -0,0 +1,36 @@ +# Tasks — svc-org-c0-base + +## 1. 契约先行(shared) + +- [ ] 1.1 定稿 `shared/data-model`:org/staff/目录四层/字典/loc_config 实体 + 枚举 + 多租户键(本 change 的 spec 已列,补全枚举值)。 +- [ ] 1.2 定稿 `shared/api-contract`:统一响应(含 hint)+ 错误码 1001–4001 + C0 接口清单。 + +## 2. 后端数据层(ec-nest) + +- [ ] 2.1 `schema.prisma` 新增 9 个业务模型(org/staff/svc_national/svc_local/svc_mapping/svc_org/dict_abnormal_type/dict_photo_tier/loc_config),staff.user_id 关联 User。 +- [ ] 2.2 `prisma migrate dev --name c0_base` + `prisma generate`。 +- [ ] 2.3 seed:L1 36 项、昆明 L2 45 项、L3 映射、默认角色 + 权限码 + 示例机构。 + +## 3. 后端业务域(ec-nest,纯新增) + +- [ ] 3.1 权限码注册:`permissions.ts` 加 elder/plan/order/record/abnormal/qc/svc-org/staff/export 权限码。 +- [ ] 3.2 `org` 模块(controller/service/dto):机构信息读写、机构=租户创建。 +- [ ] 3.3 `staff` 模块:人员 CRUD、user_id 关联账号、group_leader_id 归属。 +- [ ] 3.4 `catalog` 模块:属地目录加载(按 loc_code)、机构项目库勾选/配价、国家新增项、字典与 loc_config。 +- [ ] 3.5 统一响应补 `hint` 字段 + 业务错误码注册(error-codes.ts)。 +- [ ] 3.6 审计:org/staff/catalog 写操作挂 `@AuditLog`。 + +## 4. 前端后台(ec-admin,纯新增) + +- [ ] 4.1 业务菜单骨架:服务对象/排班派单/工单留痕/质控中心/文书档案 + 系统设置业务配置项。 +- [ ] 4.2 登录后落地服务对象列表页(占位页)。 +- [ ] 4.3 登录页属地提示(机构属地 + 目录)。 +- [ ] 4.4 角色权限控制(按权限码隐藏菜单/按钮)。 + +## 5. 验证 + +- [ ] 5.1 跨机构隔离:A 机构账号查不到 B 机构数据(4001)。 +- [ ] 5.2 角色并集 + 仅 director 写接口 403。 +- [ ] 5.3 昆明机构加载 45 项 + 国家新增 5 项显式提示。 +- [ ] 5.4 审计动作全量落日志。 +- [ ] 5.5 前端 Mock 验收通过(前端先于后端按 api-contract 联调)。