- spec 约定/模块清单/设计决策统一由 docs/spec-conventions.md 维护 - 丢弃 PRD 唯一权威,单一事实源改为 openspec/specs/ - 填充技术栈(NestJS 12 / Vue 3 / Node 22.23.1 / pnpm 12.10.1) - 资源表 RES 命名 + 多租户/数据权限设计决策 - CLAUDE.md/README/config.yaml 改为引用,AGENTS.md 保持 symlink Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.6 KiB
7.6 KiB
Spec 约定(Spec Conventions)
通用系统管理脚手架 openspec spec 的组织、粒度、编号、模块划分唯一权威。 新会话、新 change 必须遵守,违反即返工。
本文是 spec 相关约定的唯一事实源;
CLAUDE.md/AGENTS.md/openspec/config.yaml只引用本文、不重复本文内容。改 spec 约定只改这里。
1. 事实源
- 本项目是脚手架,无外部 PRD;单一事实源 =
openspec/specs/,其中shared/data-model(字段字典)是字段一致性唯一锚点,shared/api-contract(接口契约) 是前后端联调唯一锚点。 - 功能文档边实现边补,存
docs/requirements/(模块说明/产品方案),仅作说明,不凌驾于 spec。 - 原型仅作视觉参考。
2. 技术栈
| 端 | 工程 | 栈 |
|---|---|---|
| 后端 | sources/sysmgr-nest |
NestJS 12 · TypeScript · Vitest |
| 管理后台前端 | sources/sysmgr-admin |
Vue 3 · Vite · TypeScript · Pinia · UnoCSS |
- 运行时 Node 22.23.1,包管理 pnpm 12.10.1(以
engines/packageManager/.nvmrc为准)。 - 前后端工程以 Git submodule 形式纳入主仓管理。
3. spec 三层结构
specs/
├── shared/ ← 跨前后端公共契约(粘合剂)
│ ├── platform/ 全局规范(设计令牌/文案/URL 契约/隐私红线)
│ ├── data-model/ 数据模型(实体 + 枚举 + 状态机 = 字段字典)
│ └── api-contract/ API 契约(endpoint + 请求/响应 shape)
├── frontend/ ← 前端 spec(Mock 独立验收)
│ └── AD/ 管理后台(当前唯一前端端)
└── backend/ ← 后端 spec(API 独立验收)
└── <域>/ 按 §9 域码清单
4. 粒度规则
- 前端:细到「功能块」级。一个 spec = 一个可独立验收的功能单元。每页保留一个薄
「页面级 spec」作容器(定位/导航/布局/流转)。
- 判断标准:这个块能不能独立验收、独立打勾。能就拆,不能就合;简单页不强拆。
- 同一页面 PC 与移动可合并为同一 spec(布局差异写在 spec 内部)。
- 后端:按实体/域(见 §9 域码清单)。
- 共享:platform / data-model / api-contract 三个。
5. 编号规则
格式:<层>-<端/域>-<页面/实体>[.<功能块>]
| 段 | 取值 |
|---|---|
| 层 | SH shared / FE frontend / BE backend |
| 端(FE) | AD 管理后台(当前唯一;将来用户端为 FE) |
| 域(BE) | 见 §9 域码清单 |
| 域(SH) | PLT platform / DM data-model / AC api-contract |
| 页面(FE) | 功能页英文 kebab-case(如 user、role、resource) |
| 功能块 | .01 .02 …(页面级 spec 无后缀) |
顺序(读取即构建顺序):
- 层序:
SH→FE→BE - FE 内端序:
AD(将来加FE用户端时排AD之后) - 域序按 §9 核心域顺序;块序
.01→.02…
目录命名:功能块目录带序号,如 specs/frontend/AD/<页面>/03-<功能块>/。
例子:SH-DM(数据模型,最前)· FE-AD-<页面>.<块>(前端功能块)· BE-<域码>(后端域)
6. 铁律
- 单一事实源 =
openspec/specs/(无 PRD 权威);冲突以shared/data-model/shared/api-contract为准。 - 数据库 schema 是字段一致性的唯一锚点:
data-model字段字典先行,前后端引用同一字段名,禁止各自命名。 - 前端先行 + Mock:前端对 Mock 验收,后端对
SH-AC契约实现。 - 字段/接口变更先改
shared/,再改对应 spec。 - 多租户:业务实体一律带
tenant_id,查询统一按租户过滤(见 §9.2-1)。 - 资源表统一授权:菜单/按钮/接口统一为「资源」表,RBAC 授权锚点(见 §9.2-2)。
- 数据权限:行级可见性由
ROLE.data_scope控制(见 §9.2-3)。
7. 构建顺序(Phase)
- Phase 0 地基:
sources/脚手架 +shared/三层 spec(含 DB 设计)+ Mock - Phase 1 前端:管理后台按 Mock 驱动实现
- Phase 2 后端:按
SH-AC契约实现 - Phase 3 联调与上线:切真实 API → 端到端验证 → 上线
8. spec 文档结构(四段式,每个 spec 必含)
每个 spec 是独立开发单元:可独立开发、独立测试、独立交付。文档必须含以下四段:
① 模块边界(Scope)
- 包含什么功能 / 不包含什么功能(明确列出「非目标」,防范围蔓延)
- 依赖声明:本 spec 引用哪些
SH-*(字段名 → data-model、接口 → api-contract、全局规则 → platform)
② 核心场景(Scenarios)
- 用 WHEN / THEN / AND 格式,覆盖正常路径 + 异常路径
- 与 openspec 原生
#### Scenario:格式对齐
③ 数据结构(Data)
按层适配:
| 层 | 数据结构内容 |
|---|---|
| 前端 FE | 组件 Props(props 名 / 类型 / 必填 / 默认值 / 约束)+ 页面状态 |
| 后端 BE | 实体字段 + DTO(请求/响应字段、类型、校验约束)+ 状态机 |
| 共享 SH | data-model = 字段字典(实体/枚举/状态机);api-contract = 接口 shape |
④ 验收标准(Acceptance)
- ACCEPTANCE Checklist,可勾选(
- [ ]形式) - 每条对应一个可验证行为,锚定
SH-AC契约或功能点编号
9. 模块清单与设计决策
9.1 域码清单(后端 spec 按此拆分)
| 层 | 域码 | 模块 | 说明 |
|---|---|---|---|
| 核心 | TENANT |
租户 | 仅 tenant_id 隔离,不做计费/SaaS 复杂化 |
| 核心 | AUTH |
认证 | 登录/登出、token、验证码、密码策略(横切:落 SH-AC + 守卫) |
| 核心 | USER |
用户 | CRUD、启停/锁定、密码重置、头像、关联角色/部门 |
| 核心 | ROLE |
角色 | 授权(资源)+ 数据权限范围 |
| 核心 | RES |
资源 | 菜单/按钮/接口统一资源表,RBAC 授权锚点 |
| 核心 | ORG |
组织 | 部门树、层级、负责人 |
| 核心 | DICT |
字典 | 类型 + 项,运行时 lookup |
| 建议 | CONFIG |
参数配置 | 系统键值参数 |
| 建议 | AUDIT |
操作日志 | 审计:谁/何时/对什么/做了什么 |
| 建议 | LOGIN |
登录日志 | 登录成功/失败、IP、UA |
| 建议 | SESSION |
在线会话 | 活跃会话、强退 |
| 扩展 | POST |
岗位 | 比「角色」更细的职位维度 |
| 扩展 | NOTICE |
通知公告 | 站内公告 |
| 扩展 | JOB |
定时任务 | 任务调度 |
| 扩展 | FILE |
文件存储 | 附件/OSS |
| 扩展 | MSG |
消息通知 | 邮件/短信/推送 |
9.2 三大设计决策
- 多租户:单租户式简单实现——所有业务实体带
tenant_id,后端统一租户过滤切面; 登录时按账号/租户域识别当前租户。不做按量付费、套餐、租户配额。 - 资源表(RES):菜单与权限合一为「资源」表,
type ∈ {菜单 MENU, 按钮 BUTTON, 接口 API}; 「目录」不设独立类型,由「菜单节点是否拥有菜单子节点」推导。- 后端鉴权三级:公开接口无需 token → 未登记接口仅校验登录 → 登记为「接口」资源的接口校验 token + 权限标识。
- 约定:写操作/敏感查询一律登记为「接口」资源,仅真正公开的留白。
- 数据权限:
ROLE.data_scope ∈ {全部 / 本部门 / 本部门及以下 / 本人 / 自定义}; 自定义时经role_org(角色-部门)关联表;后端列表查询统一按可见部门过滤。