From d2c75bd04c9bd35ce297f0676620c1cb12c06e6a Mon Sep 17 00:00:00 2001 From: liuyun Date: Sat, 10 Oct 2026 21:17:45 +0800 Subject: [PATCH] chore(openspec): sync foundation specs to main, archive init-shared-foundation Co-Authored-By: Claude Opus 4.8 --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../specs/shared/api-contract/spec.md | 0 .../specs/shared/data-model/spec.md | 0 .../specs/shared/platform/spec.md | 0 .../tasks.md | 0 openspec/specs/shared/api-contract/spec.md | 61 +++++++++++++++++++ openspec/specs/shared/data-model/spec.md | 60 ++++++++++++++++++ openspec/specs/shared/platform/spec.md | 39 ++++++++++++ 10 files changed, 160 insertions(+) rename openspec/changes/{init-shared-foundation => archive/2026-10-10-init-shared-foundation}/.openspec.yaml (100%) rename openspec/changes/{init-shared-foundation => archive/2026-10-10-init-shared-foundation}/design.md (100%) rename openspec/changes/{init-shared-foundation => archive/2026-10-10-init-shared-foundation}/proposal.md (100%) rename openspec/changes/{init-shared-foundation => archive/2026-10-10-init-shared-foundation}/specs/shared/api-contract/spec.md (100%) rename openspec/changes/{init-shared-foundation => archive/2026-10-10-init-shared-foundation}/specs/shared/data-model/spec.md (100%) rename openspec/changes/{init-shared-foundation => archive/2026-10-10-init-shared-foundation}/specs/shared/platform/spec.md (100%) rename openspec/changes/{init-shared-foundation => archive/2026-10-10-init-shared-foundation}/tasks.md (100%) create mode 100644 openspec/specs/shared/api-contract/spec.md create mode 100644 openspec/specs/shared/data-model/spec.md create mode 100644 openspec/specs/shared/platform/spec.md diff --git a/openspec/changes/init-shared-foundation/.openspec.yaml b/openspec/changes/archive/2026-10-10-init-shared-foundation/.openspec.yaml similarity index 100% rename from openspec/changes/init-shared-foundation/.openspec.yaml rename to openspec/changes/archive/2026-10-10-init-shared-foundation/.openspec.yaml diff --git a/openspec/changes/init-shared-foundation/design.md b/openspec/changes/archive/2026-10-10-init-shared-foundation/design.md similarity index 100% rename from openspec/changes/init-shared-foundation/design.md rename to openspec/changes/archive/2026-10-10-init-shared-foundation/design.md diff --git a/openspec/changes/init-shared-foundation/proposal.md b/openspec/changes/archive/2026-10-10-init-shared-foundation/proposal.md similarity index 100% rename from openspec/changes/init-shared-foundation/proposal.md rename to openspec/changes/archive/2026-10-10-init-shared-foundation/proposal.md diff --git a/openspec/changes/init-shared-foundation/specs/shared/api-contract/spec.md b/openspec/changes/archive/2026-10-10-init-shared-foundation/specs/shared/api-contract/spec.md similarity index 100% rename from openspec/changes/init-shared-foundation/specs/shared/api-contract/spec.md rename to openspec/changes/archive/2026-10-10-init-shared-foundation/specs/shared/api-contract/spec.md diff --git a/openspec/changes/init-shared-foundation/specs/shared/data-model/spec.md b/openspec/changes/archive/2026-10-10-init-shared-foundation/specs/shared/data-model/spec.md similarity index 100% rename from openspec/changes/init-shared-foundation/specs/shared/data-model/spec.md rename to openspec/changes/archive/2026-10-10-init-shared-foundation/specs/shared/data-model/spec.md diff --git a/openspec/changes/init-shared-foundation/specs/shared/platform/spec.md b/openspec/changes/archive/2026-10-10-init-shared-foundation/specs/shared/platform/spec.md similarity index 100% rename from openspec/changes/init-shared-foundation/specs/shared/platform/spec.md rename to openspec/changes/archive/2026-10-10-init-shared-foundation/specs/shared/platform/spec.md diff --git a/openspec/changes/init-shared-foundation/tasks.md b/openspec/changes/archive/2026-10-10-init-shared-foundation/tasks.md similarity index 100% rename from openspec/changes/init-shared-foundation/tasks.md rename to openspec/changes/archive/2026-10-10-init-shared-foundation/tasks.md diff --git a/openspec/specs/shared/api-contract/spec.md b/openspec/specs/shared/api-contract/spec.md new file mode 100644 index 0000000..417d028 --- /dev/null +++ b/openspec/specs/shared/api-contract/spec.md @@ -0,0 +1,61 @@ +# API Contract Specification + +## Purpose + +定义所有接口的统一契约:响应封装、错误码、分页、鉴权层级与认证接口,作为前后端联调的唯一锚点。 + +## Requirements + +### Requirement: 统一响应封装 +所有接口 SHALL 返回 `{ code, message, data }` 结构;code=0 表示成功。 + +#### Scenario: 成功响应 +- **WHEN** 接口处理成功 +- **THEN** 返回 code=0、message=ok、data 为业务数据 + +#### Scenario: 失败响应 +- **WHEN** 接口处理失败 +- **THEN** 返回非 0 code 与可读 message,data 为空 + +### Requirement: 错误码分段 +错误码 SHALL 与 HTTP 状态对齐分段:401xx 认证、403xx 授权、400xx 参数、404xx 资源、409xx 冲突、500xx 系统。 + +#### Scenario: 未登录 +- **WHEN** 未携带有效 token 访问受保护接口 +- **THEN** HTTP 401,code 为 401xx 段 + +### Requirement: 分页约定 +列表接口 SHALL 使用 page/pageSize 分页,返回 `{ list, total, page, pageSize }`。 + +#### Scenario: 分页查询 +- **WHEN** 客户端传 page=1&pageSize=20 +- **THEN** 返回 data 含 list、total、page、pageSize + +### Requirement: 三级鉴权 +接口 SHALL 分为三级:公开接口无需 token;未登记接口仅需登录;登记为「接口」资源的接口需 token 且当前用户具备对应 code(权限标识)。 + +#### Scenario: 未登记接口 +- **WHEN** 已登录用户访问未登记为资源的接口 +- **THEN** 校验通过(仅需登录态) + +#### Scenario: 登记接口越权 +- **WHEN** 已登录用户访问登记为接口资源、但自身角色无该 permission 的接口 +- **THEN** 系统返回 403 + +### Requirement: 认证接口 +系统 SHALL 提供登录、刷新令牌、登出接口;登录需 tenantCode+username+password,返回 access token 与 refresh token。 + +#### Scenario: 登录成功 +- **WHEN** 用户提供正确的租户、账号与密码 +- **THEN** 返回 access token(2h 过期)与 refresh token(7d 过期) + +#### Scenario: 刷新令牌 +- **WHEN** access 过期后客户端携带 refresh token 请求刷新 +- **THEN** 系统签发新 access 与 refresh,并作废旧 refresh + +### Requirement: 核心域接口目录 +系统 SHALL 为每个核心域提供 REST 资源接口(复数、kebab-case):/users、/roles、/resources、/orgs、/dict-types、/configs、/audit-logs、/login-logs。 + +#### Scenario: 资源 CRUD +- **WHEN** 管理端操作某核心域 +- **THEN** 通过对应复数资源路径进行增删改查 diff --git a/openspec/specs/shared/data-model/spec.md b/openspec/specs/shared/data-model/spec.md new file mode 100644 index 0000000..81b62df --- /dev/null +++ b/openspec/specs/shared/data-model/spec.md @@ -0,0 +1,60 @@ +# Data Model Specification + +## Purpose + +定义系统数据模型的字段字典:实体目录、公共字段、枚举、状态机与命名约定,作为前后端字段一致性的唯一锚点。 + +## Requirements + +### Requirement: 业务实体公共字段 +所有业务软删实体 SHALL 携带公共字段:id(UUID v7)、tenant_code、created_at、created_by、updated_at、deleted_at;日志/会话类实体不携带 deleted_at。 + +#### Scenario: 创建记录 +- **WHEN** 创建任一业务实体记录 +- **THEN** 系统自动填充 id、tenant_code、created_at、created_by + +#### Scenario: 软删 +- **WHEN** 删除业务实体 +- **THEN** 系统置 deleted_at 而非物理删除 + +### Requirement: 实体目录 +系统 SHALL 包含实体 tenant、user、role、resource、org、dict_type、dict_item、config、audit_log、login_log、refresh_token,以及关联表 user_role、role_resource、role_org。 + +#### Scenario: 字典拆分 +- **WHEN** 维护数据字典 +- **THEN** 字典分为 dict_type(类型)与 dict_item(项)两类,经 dict_type_code 关联 + +### Requirement: 资源类型与代码 +resource 实体 SHALL 通过 type 字段区分菜单(menu)、按钮(button)、接口(api)三种类型;「目录」由菜单节点是否拥有菜单子节点推导,不设独立类型。每个 resource SHALL 拥有租户内唯一的 code,作为关联键与权限标识。 + +#### Scenario: 按钮鉴权点 +- **WHEN** 前端需要按钮级权限 +- **THEN** 该按钮登记为 type=button 的资源,并携带 code 权限标识 + +### Requirement: 引用键约定 +所有跨实体引用 SHALL 优先使用业务键:角色、资源、组织、字典类型、租户用 code,树的父引用用 parent_code;对用户的引用 SHALL 使用用户 id。关联表 sys_user_role、sys_role_resource、sys_role_org 分别保存 user_id+role_code、role_code+resource_code、role_code+org_code;其余引用(user.org_code、dict_item.dict_type_code、resource.parent_code、org.parent_code)同理。 + +#### Scenario: 为角色分配资源 +- **WHEN** 管理员为角色分配资源 +- **THEN** 关联记录保存 role_code 与 resource_code + +### Requirement: 数据权限档位 +role 实体 SHALL 通过 data_scope 字段支持全部/本部门/本部门及以下/本人/自定义五档;「自定义」经 role_org 关联表声明可见部门。 + +#### Scenario: 本部门及以下 +- **WHEN** 角色数据权限为「本部门及以下」 +- **THEN** 该角色用户仅可见本部门及下级部门的数据 + +### Requirement: 命名与表前缀 +所有脚手架表 SHALL 以 sys_ 前缀命名,数据库列名采用 snake_case。 + +#### Scenario: 表命名 +- **WHEN** 新建脚手架表 +- **THEN** 表名以 sys_ 开头,列名使用 snake_case + +### Requirement: 用户状态机 +user 实体 SHALL 支持启用/停用/锁定状态;停用与锁定的用户 SHALL 无法登录。 + +#### Scenario: 锁定登录 +- **WHEN** 锁定用户尝试登录 +- **THEN** 系统拒绝登录并提示账号已锁定 diff --git a/openspec/specs/shared/platform/spec.md b/openspec/specs/shared/platform/spec.md new file mode 100644 index 0000000..5dde1cd --- /dev/null +++ b/openspec/specs/shared/platform/spec.md @@ -0,0 +1,39 @@ +# Platform Specification + +## Purpose + +定义跨前后端、跨模块的全局规范:时间、多租户隔离、URL 契约与安全红线,作为所有 spec 的共同约束。 + +## Requirements + +### Requirement: 统一时间戳格式 +系统 SHALL 在 API 层以 Unix 毫秒时间戳(number)表示所有时间字段,前端负责本地化显示。 + +#### Scenario: 接口返回时间 +- **WHEN** 任一接口返回时间字段 +- **THEN** 该字段为 Unix 毫秒整数(number),不返回格式化字符串 + +### Requirement: 多租户数据隔离 +所有业务数据 SHALL 归属某一租户;任何业务接口 SHALL 仅返回当前租户的数据。 + +#### Scenario: 跨租户越权 +- **WHEN** 用户 A(租户 1)请求租户 2 的数据 +- **THEN** 系统拒绝或返回空,绝不返回租户 2 的数据 + +### Requirement: URL 契约 +所有 API SHALL 统一挂载在 `/api/v1` 前缀下。 + +#### Scenario: 版本前缀 +- **WHEN** 客户端调用任一业务接口 +- **THEN** 路径以 `/api/v1` 开头 + +### Requirement: 安全红线 +系统 SHALL 不以明文存储或传输密码;日志 SHALL 对手机号、邮箱、密码等敏感信息脱敏。 + +#### Scenario: 密码存储 +- **WHEN** 用户设置或修改密码 +- **THEN** 系统仅存储不可逆哈希,绝不落明文 + +#### Scenario: 日志脱敏 +- **WHEN** 记录操作/登录日志 +- **THEN** 密码字段不落日志,手机号/邮箱部分打码