147 lines
7.7 KiB
Markdown
147 lines
7.7 KiB
Markdown
# 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(按 SH-AC 契约验收)
|
||
│ └── 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 无后缀) |
|
||
|
||
**顺序(读取即构建顺序)**:
|
||
1. 层序:`SH` → `FE` → `BE`
|
||
2. FE 内端序:`AD`(将来加 `FE` 用户端时排 `AD` 之后)
|
||
3. 域序按 §9 核心域顺序;块序 `.01` → `.02` …
|
||
|
||
**目录命名**:功能块目录带序号,如 `specs/frontend/AD/<页面>/03-<功能块>/`。
|
||
|
||
**例子**:`SH-DM`(数据模型,最前)· `FE-AD-<页面>.<块>`(前端功能块)· `BE-<域码>`(后端域)
|
||
|
||
## 6. 铁律
|
||
|
||
1. **单一事实源 = `openspec/specs/`**(无 PRD 权威);冲突以 `shared/data-model` / `shared/api-contract` 为准。
|
||
2. **数据库 schema 是字段一致性的唯一锚点**:`data-model` 字段字典先行,前后端引用同一字段名,禁止各自命名。
|
||
3. **契约先行,联调走真实 API**:前后端各自按 `SH-AC` 契约实现,完成后直接联调,不另造 Mock。
|
||
4. **字段/接口变更先改 `shared/`,再改对应 spec。**
|
||
5. **多租户**:业务实体一律带 `tenant_id`,查询统一按租户过滤(见 §9.2-1)。
|
||
6. **资源表统一授权**:菜单/按钮/接口统一为「资源」表,RBAC 授权锚点(见 §9.2-2)。
|
||
7. **数据权限**:行级可见性由 `ROLE.data_scope` 控制(见 §9.2-3)。
|
||
|
||
## 7. 构建顺序(Phase)
|
||
|
||
- **Phase 0 地基**:`sources/` 脚手架 + `shared/` 三层 spec(含 DB 设计)
|
||
- **Phase 1 前端**:管理后台按 `SH-AC` 契约实现
|
||
- **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 三大设计决策
|
||
|
||
1. **多租户**:单租户式简单实现——所有业务实体带 `tenant_id`,后端统一租户过滤切面;
|
||
登录时按账号/租户域识别当前租户。**不做**按量付费、套餐、租户配额。
|
||
2. **资源表(RES)**:菜单与权限合一为「资源」表,`type ∈ {菜单 MENU, 按钮 BUTTON, 接口 API}`;
|
||
「目录」不设独立类型,由「菜单节点是否拥有菜单子节点」推导。
|
||
- 后端鉴权三级:公开接口无需 token → 未登记接口仅校验登录 → 登记为「接口」资源的接口校验 token + 权限标识。
|
||
- **约定**:写操作/敏感查询一律登记为「接口」资源,仅真正公开的留白。
|
||
3. **数据权限**:`ROLE.data_scope ∈ {全部 / 本部门 / 本部门及以下 / 本人 / 自定义}`;
|
||
自定义时经 `role_org`(角色-部门)关联表;后端列表查询统一按可见部门过滤。
|