@wneng/create-keel 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +74 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/standards/templates/tech-stack-server.md.eta +34 -2
- package/src/templates/contracts-base/files/dictionaries/event-types.yaml +16 -0
- package/src/templates/contracts-base/files/dictionaries/locales.yaml +12 -0
- package/src/templates/contracts-base/files/dictionaries/roles.yaml +12 -0
- package/src/templates/contracts-base/files/dictionaries/status.yaml +16 -0
- package/src/templates/contracts-base/files/errors/common-errors.yaml +40 -0
- package/src/templates/contracts-base/files/errors/server-errors.yaml +16 -0
- package/src/templates/contracts-base/files/events/audit-event.schema.json +47 -0
- package/src/templates/contracts-base/fragment.yaml +22 -10
- package/src/templates/contracts-rest/fragment.yaml +2 -1
- package/src/templates/contracts-rest-by-audience/files/_components-README.md +32 -0
- package/src/templates/contracts-rest-by-audience/files/_components-schemas.yaml +78 -0
- package/src/templates/contracts-rest-by-audience/files/admin-api.yaml +37 -0
- package/src/templates/contracts-rest-by-audience/files/agent-api.yaml +37 -0
- package/src/templates/contracts-rest-by-audience/files/user-api.yaml +33 -0
- package/src/templates/contracts-rest-by-audience/fragment.yaml +22 -0
- package/src/templates/contracts-rest-events/fragment.yaml +2 -1
- package/src/templates/contracts-rest-events-by-audience/files/_components-README.md +32 -0
- package/src/templates/contracts-rest-events-by-audience/files/_components-schemas.yaml +78 -0
- package/src/templates/contracts-rest-events-by-audience/files/admin-api.yaml +37 -0
- package/src/templates/contracts-rest-events-by-audience/files/agent-api.yaml +37 -0
- package/src/templates/contracts-rest-events-by-audience/files/asyncapi.yaml +8 -0
- package/src/templates/contracts-rest-events-by-audience/files/user-api.yaml +33 -0
- package/src/templates/contracts-rest-events-by-audience/fragment.yaml +25 -0
- package/src/templates/docs-skeleton/files/governance-contracts-layout.md +172 -0
- package/src/templates/docs-skeleton/fragment.yaml +3 -0
- package/src/templates/root-files/files/AGENTS.md +2 -0
- package/src/templates/contracts-base/files/dictionaries/domain-models.yaml +0 -3
- package/src/templates/contracts-base/files/dictionaries/enums.yaml +0 -3
- package/src/templates/contracts-base/files/errors/error-codes.yaml +0 -6
- package/src/templates/contracts-base/files/events-gitkeep +0 -0
package/package.json
CHANGED
|
@@ -4,7 +4,8 @@ language: <%= it.standards.language %>
|
|
|
4
4
|
packageManager: <%= it.standards.packageManager %>
|
|
5
5
|
manifestPath: <%= it.standards.manifestPath %>
|
|
6
6
|
lastReviewed: <%= it.standards.lastReviewed %>
|
|
7
|
-
|
|
7
|
+
<% if (it.standards.ormConvention && it.standards.ormConvention !== 'none') { %>ormConvention: <%= it.standards.ormConvention %>
|
|
8
|
+
<% } %>dependencies:
|
|
8
9
|
<% for (const dep of it.standards.dependencies) { %> - name: "<%= dep.name %>"
|
|
9
10
|
version: "<%= dep.version %>"
|
|
10
11
|
policy: <%= dep.policy %>
|
|
@@ -12,7 +13,7 @@ dependencies:
|
|
|
12
13
|
|
|
13
14
|
# 后端技术栈钉版本表
|
|
14
15
|
|
|
15
|
-
> 这个文件的 **frontmatter 是机器真值**:CI 中的 `governance-lint` 会把上面 `dependencies` 数组与 `<%= it.standards.manifestPath %>`
|
|
16
|
+
> 这个文件的 **frontmatter 是机器真值**:CI 中的 `governance-lint` 会把上面 `dependencies` 数组与 `<%= it.standards.manifestPath %>` 的实际版本逐条对比<% if (it.standards.ormConvention && it.standards.ormConvention !== 'none') { %>,并扫描 `server/src` 是否违反 `ormConvention: <%= it.standards.ormConvention %>` 约束<% } %>。
|
|
16
17
|
>
|
|
17
18
|
> 本文件正文是**为什么**这样选 + **如何调整**。机器无法回答这两个问题。
|
|
18
19
|
|
|
@@ -42,6 +43,37 @@ dependencies:
|
|
|
42
43
|
- 仅开发期使用的 lint / format / 测试工具:可以放在 `devDependencies` 但**不**进本表
|
|
43
44
|
- 容器基础镜像版本:在 `deploy/Dockerfile` 里钉,本表不重复
|
|
44
45
|
- 系统包(apt / yum):交给运行时镜像维护者
|
|
46
|
+
<% if (it.standards.ormConvention && it.standards.ormConvention !== 'none') { %>
|
|
47
|
+
## ORM 约定(`ormConvention: <%= it.standards.ormConvention %>`)
|
|
48
|
+
|
|
49
|
+
frontmatter 的 `ormConvention` 字段把"用什么方式访问数据库"作为**项目级硬约束**写入契约。governance-lint 在每次 PR 中扫描 `server/src` 验证是否违反。
|
|
50
|
+
|
|
51
|
+
当前约定:**`<%= it.standards.ormConvention %>`**。
|
|
52
|
+
|
|
53
|
+
<% if (it.standards.ormConvention === 'mybatis-plus-only') { %>**含义**:
|
|
54
|
+
|
|
55
|
+
- 业务持久化统一使用 MyBatis-Plus 的 `entity / mapper` 方式
|
|
56
|
+
- CRUD、单表条件查询、条件更新、逻辑删除优先用 `BaseMapper` + `LambdaQueryWrapper` / `LambdaUpdateWrapper`
|
|
57
|
+
- 复杂联表分页、聚合、跨表投影:写 mapper 层 `@Select` / `@Update` 或 XML SQL;**不内联在 service / controller**
|
|
58
|
+
- **禁止**新增 `JdbcTemplate` / `NamedParameterJdbcTemplate` 作为 CRUD / 查询实现
|
|
59
|
+
- 历史 `JdbcTemplate` 代码改动时应迁移到 mapper 方式
|
|
60
|
+
- `JdbcTemplate` 仅允许保留在测试夹具、迁移工具、一次性运维脚本、基础设施适配中
|
|
61
|
+
|
|
62
|
+
**lint 阻断条件**:`server/src/main/java/**/*.java` 中出现 `import org.springframework.jdbc.core.JdbcTemplate` 或 `import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate`(被 governance-lint 标 warning)。
|
|
63
|
+
<% } else if (it.standards.ormConvention === 'jpa-only') { %>**含义**:业务持久化统一使用 Spring Data JPA / Hibernate;禁止在业务代码中使用 JdbcTemplate / 原生 SQL。
|
|
64
|
+
<% } else if (it.standards.ormConvention === 'sqlalchemy-orm-only') { %>**含义**:业务持久化统一使用 SQLAlchemy ORM(`Session` + 模型);禁止在业务代码里用 raw `text()` SQL(迁移文件除外)。
|
|
65
|
+
<% } else if (it.standards.ormConvention === 'knex-only') { %>**含义**:业务持久化统一使用 Knex query builder;禁止在业务代码里用 `db.raw()`(迁移与 seed 除外)。
|
|
66
|
+
<% } else if (it.standards.ormConvention === 'prisma-only') { %>**含义**:业务持久化统一使用 Prisma Client;禁止在业务代码里用 `$queryRaw`(迁移除外)。
|
|
67
|
+
<% } else if (it.standards.ormConvention === 'gorm-only') { %>**含义**:业务持久化统一使用 GORM;禁止在业务代码里用 `db.Raw()`。
|
|
68
|
+
<% } else if (it.standards.ormConvention === 'sqlx-only') { %>**含义**:业务持久化统一使用 sqlx;禁止散用 `database/sql` 直接 driver 调用。
|
|
69
|
+
<% } %>
|
|
70
|
+
|
|
71
|
+
**调整流程**:
|
|
72
|
+
|
|
73
|
+
1. 改 frontmatter 的 `ormConvention` 字段属于 **Tier 4** 决策(参见 `docs/governance/change-tiers.md`),需要 ADR
|
|
74
|
+
2. 取值 `none` 关闭 lint(不推荐,意味着团队接受混用)
|
|
75
|
+
3. 升级或更换 ORM 是**仓库级**变更,不是单个 PR 范围内的事
|
|
76
|
+
<% } %>
|
|
45
77
|
|
|
46
78
|
## 关联
|
|
47
79
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
name: event-types
|
|
3
|
+
description: 平台事件类型字典。事件 envelope schema 在 contracts/events/,本文件统一登记 type 字符串。
|
|
4
|
+
items:
|
|
5
|
+
- code: user.created
|
|
6
|
+
domain: user
|
|
7
|
+
source: server
|
|
8
|
+
description: 新用户注册成功。
|
|
9
|
+
- code: user.deleted
|
|
10
|
+
domain: user
|
|
11
|
+
source: server
|
|
12
|
+
description: 用户被软删除。
|
|
13
|
+
- code: audit.event.ingested
|
|
14
|
+
domain: audit
|
|
15
|
+
source: server
|
|
16
|
+
description: 审计事件已被平台接收并归档。
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
name: roles
|
|
3
|
+
description: 用户 / 终端 / API caller 的角色码表。新增时改这里 + 同 PR 加迁移文件 / seed。
|
|
4
|
+
items:
|
|
5
|
+
- code: admin
|
|
6
|
+
label: 系统管理员
|
|
7
|
+
order: 10
|
|
8
|
+
description: 可执行所有管理操作(账号、配置、审计)。
|
|
9
|
+
- code: user
|
|
10
|
+
label: 普通用户
|
|
11
|
+
order: 20
|
|
12
|
+
description: 默认注册角色;只能访问自己的资源。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
name: status
|
|
3
|
+
description: 通用状态枚举(活跃 / 停用 / 删除等),跨多个实体复用。
|
|
4
|
+
items:
|
|
5
|
+
- code: active
|
|
6
|
+
label: 活跃
|
|
7
|
+
order: 10
|
|
8
|
+
description: 资源处于正常使用状态。
|
|
9
|
+
- code: disabled
|
|
10
|
+
label: 已停用
|
|
11
|
+
order: 20
|
|
12
|
+
description: 资源被管理员手动停用,可恢复。
|
|
13
|
+
- code: deleted
|
|
14
|
+
label: 已删除
|
|
15
|
+
order: 30
|
|
16
|
+
description: 资源被软删除(保留 deleted_at),仅审计可见。
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
namespace: common
|
|
3
|
+
description: 跨服务通用错误码(鉴权、参数校验、限流等)。各业务错误码请新建 <namespace>-errors.yaml 文件。
|
|
4
|
+
errors:
|
|
5
|
+
- code: COMMON-VALIDATION-FAILED
|
|
6
|
+
http_status: 422
|
|
7
|
+
category: validation
|
|
8
|
+
message: 请求参数校验失败
|
|
9
|
+
retryable: false
|
|
10
|
+
description: 字段缺失、类型错误或值越界。详细信息见 response 的 details 数组。
|
|
11
|
+
- code: COMMON-UNAUTHORIZED
|
|
12
|
+
http_status: 401
|
|
13
|
+
category: auth
|
|
14
|
+
message: 未登录或登录已过期
|
|
15
|
+
retryable: false
|
|
16
|
+
description: 调用需要鉴权的端点但未提供有效 token;客户端应跳转登录。
|
|
17
|
+
- code: COMMON-FORBIDDEN
|
|
18
|
+
http_status: 403
|
|
19
|
+
category: auth
|
|
20
|
+
message: 当前账号无权访问该资源
|
|
21
|
+
retryable: false
|
|
22
|
+
description: 已登录但角色 / 权限不足;不要在错误信息里泄露资源是否存在。
|
|
23
|
+
- code: COMMON-NOT-FOUND
|
|
24
|
+
http_status: 404
|
|
25
|
+
category: resource
|
|
26
|
+
message: 资源不存在
|
|
27
|
+
retryable: false
|
|
28
|
+
description: ID 错误或资源已被删除。
|
|
29
|
+
- code: COMMON-RATE-LIMITED
|
|
30
|
+
http_status: 429
|
|
31
|
+
category: throttle
|
|
32
|
+
message: 请求过于频繁
|
|
33
|
+
retryable: true
|
|
34
|
+
description: 客户端应根据 Retry-After 头退避后重试。
|
|
35
|
+
- code: COMMON-INTERNAL-ERROR
|
|
36
|
+
http_status: 500
|
|
37
|
+
category: server
|
|
38
|
+
message: 系统繁忙,请稍后重试
|
|
39
|
+
retryable: true
|
|
40
|
+
description: 兜底错误码;具体原因写入 server log + tracing,不暴露给客户端。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
namespace: server
|
|
3
|
+
description: 后端业务错误码示例。新增按业务域拆分(如 admin-errors.yaml / iam-errors.yaml / billing-errors.yaml)。
|
|
4
|
+
errors:
|
|
5
|
+
- code: SERVER-USER-NOT-FOUND
|
|
6
|
+
http_status: 404
|
|
7
|
+
category: resource
|
|
8
|
+
message: 用户不存在
|
|
9
|
+
retryable: false
|
|
10
|
+
description: 通过 ID / email 查找用户失败。
|
|
11
|
+
- code: SERVER-USER-EMAIL-CONFLICT
|
|
12
|
+
http_status: 409
|
|
13
|
+
category: resource
|
|
14
|
+
message: 邮箱已被占用
|
|
15
|
+
retryable: false
|
|
16
|
+
description: 注册或更新邮箱时检测到唯一约束冲突。
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://contracts.<%= it.options.projectName %>.local/events/audit-event.schema.json",
|
|
4
|
+
"title": "Audit Event Envelope",
|
|
5
|
+
"description": "审计事件统一信封;type 字段对应 contracts/dictionaries/event-types.yaml 中的 code。",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["eventId", "type", "occurredAt", "source", "payload"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"eventId": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"format": "uuid",
|
|
13
|
+
"description": "事件唯一 ID。"
|
|
14
|
+
},
|
|
15
|
+
"type": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "事件类型,例如 user.created。须存在于 contracts/dictionaries/event-types.yaml。"
|
|
18
|
+
},
|
|
19
|
+
"occurredAt": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"format": "date-time",
|
|
22
|
+
"description": "事件发生时间(UTC,毫秒精度 ISO 8601)。"
|
|
23
|
+
},
|
|
24
|
+
"source": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "事件来源服务或模块。"
|
|
27
|
+
},
|
|
28
|
+
"userId": {
|
|
29
|
+
"type": ["string", "null"],
|
|
30
|
+
"description": "触发该事件的用户 ID(系统事件可为 null)。"
|
|
31
|
+
},
|
|
32
|
+
"traceId": {
|
|
33
|
+
"type": ["string", "null"],
|
|
34
|
+
"description": "贯穿请求链路的 trace ID。"
|
|
35
|
+
},
|
|
36
|
+
"result": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"enum": ["success", "failure"],
|
|
39
|
+
"description": "事件处理结果。"
|
|
40
|
+
},
|
|
41
|
+
"payload": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"description": "事件业务载荷。各事件类型的 payload 形态在事件类型自身的 schema 中收紧约束。",
|
|
44
|
+
"additionalProperties": true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name: contracts-base
|
|
2
|
-
version: 1.
|
|
2
|
+
version: 1.2.0
|
|
3
3
|
appliesWhen: {}
|
|
4
4
|
priority: 10
|
|
5
5
|
files:
|
|
@@ -15,18 +15,33 @@ files:
|
|
|
15
15
|
- from: files/_spectral.yaml
|
|
16
16
|
to: contracts/.spectral.yaml
|
|
17
17
|
render: false
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# 字典:每个域一份独立 yaml;新增不要回头合并
|
|
19
|
+
- from: files/dictionaries/roles.yaml
|
|
20
|
+
to: contracts/dictionaries/roles.yaml
|
|
20
21
|
render: false
|
|
21
|
-
- from: files/dictionaries/
|
|
22
|
-
to: contracts/dictionaries/
|
|
22
|
+
- from: files/dictionaries/status.yaml
|
|
23
|
+
to: contracts/dictionaries/status.yaml
|
|
23
24
|
render: false
|
|
24
|
-
- from: files/
|
|
25
|
-
to: contracts/
|
|
25
|
+
- from: files/dictionaries/locales.yaml
|
|
26
|
+
to: contracts/dictionaries/locales.yaml
|
|
27
|
+
render: false
|
|
28
|
+
- from: files/dictionaries/event-types.yaml
|
|
29
|
+
to: contracts/dictionaries/event-types.yaml
|
|
30
|
+
render: false
|
|
31
|
+
# 错误码:通用 + 业务域拆开
|
|
32
|
+
- from: files/errors/common-errors.yaml
|
|
33
|
+
to: contracts/errors/common-errors.yaml
|
|
34
|
+
render: false
|
|
35
|
+
- from: files/errors/server-errors.yaml
|
|
36
|
+
to: contracts/errors/server-errors.yaml
|
|
26
37
|
render: false
|
|
27
38
|
- from: files/errors/error-response.schema.json
|
|
28
39
|
to: contracts/errors/error-response.schema.json
|
|
29
40
|
render: false
|
|
41
|
+
# 事件:每个事件域一份 schema;通过 dictionaries/event-types.yaml 索引
|
|
42
|
+
- from: files/events/audit-event.schema.json
|
|
43
|
+
to: contracts/events/audit-event.schema.json
|
|
44
|
+
render: true
|
|
30
45
|
- from: files/environment/.env.example
|
|
31
46
|
to: contracts/environment/.env.example
|
|
32
47
|
render: false
|
|
@@ -36,9 +51,6 @@ files:
|
|
|
36
51
|
- from: files/states-gitkeep
|
|
37
52
|
to: contracts/states/.gitkeep
|
|
38
53
|
render: false
|
|
39
|
-
- from: files/events-gitkeep
|
|
40
|
-
to: contracts/events/.gitkeep
|
|
41
|
-
render: false
|
|
42
54
|
- from: files/resources-examples-gitkeep
|
|
43
55
|
to: contracts/resources/examples/.gitkeep
|
|
44
56
|
render: false
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# `_components/` — 跨 audience 共享的 OpenAPI 类型
|
|
2
|
+
|
|
3
|
+
本目录的 `schemas.yaml` 是 `admin-api.yaml` / `user-api.yaml` / `agent-api.yaml` 共享的类型库。
|
|
4
|
+
|
|
5
|
+
## 引用方式
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
$ref: '_components/schemas.yaml#/components/schemas/User'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 何时改这里
|
|
12
|
+
|
|
13
|
+
- 添加跨 audience 的实体(User / Order / ErrorResponse 等)
|
|
14
|
+
- 修改既有共享类型的字段(**Tier 3**,必须同步 `contracts/CHANGELOG.md`)
|
|
15
|
+
- 删字段或改类型(**Tier 4**,破坏性,需要 ADR)
|
|
16
|
+
|
|
17
|
+
## 何时**不**改这里
|
|
18
|
+
|
|
19
|
+
- 单个 audience 私有的 DTO(例如管理员后台的 `AdminUserListItem`)
|
|
20
|
+
写在对应 API 文件自己的 `components/schemas` 里,并用 audience 前缀命名
|
|
21
|
+
|
|
22
|
+
## 工具兼容性
|
|
23
|
+
|
|
24
|
+
Spectral / openapi-generator-cli / Redoc / Postman 都原生支持跨文件 `$ref`,不需要任何配置:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx --yes @stoplight/spectral-cli lint contracts/openapi/admin-api.yaml
|
|
28
|
+
npx --yes @stoplight/spectral-cli lint contracts/openapi/user-api.yaml
|
|
29
|
+
npx --yes @stoplight/spectral-cli lint contracts/openapi/agent-api.yaml
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> Spectral 会自动 follow `$ref` 进入 `_components/schemas.yaml` 校验。
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# 跨 audience 共享的 schemas / parameters / responses。
|
|
2
|
+
#
|
|
3
|
+
# 引用方式:
|
|
4
|
+
# $ref: '_components/schemas.yaml#/components/schemas/User'
|
|
5
|
+
#
|
|
6
|
+
# 不要在 admin-api.yaml / user-api.yaml / agent-api.yaml 各自重复定义同名实体;
|
|
7
|
+
# 添加新共享类型时改这里,并在对应 API 文件用 $ref 引入。
|
|
8
|
+
#
|
|
9
|
+
# 仅 audience 私有的类型(例如 admin 后台特定 DTO)可以放在自己 API 文件的
|
|
10
|
+
# components/schemas 里,但要在 schema 名字加 audience 前缀以避免误用,
|
|
11
|
+
# 例如 AdminUserListItem。
|
|
12
|
+
|
|
13
|
+
openapi: 3.1.0
|
|
14
|
+
info:
|
|
15
|
+
title: Shared components
|
|
16
|
+
version: 0.1.0
|
|
17
|
+
paths: {}
|
|
18
|
+
components:
|
|
19
|
+
schemas:
|
|
20
|
+
User:
|
|
21
|
+
type: object
|
|
22
|
+
required: [id, email, displayName]
|
|
23
|
+
properties:
|
|
24
|
+
id:
|
|
25
|
+
type: string
|
|
26
|
+
format: uuid
|
|
27
|
+
description: 用户 ID。
|
|
28
|
+
email:
|
|
29
|
+
type: string
|
|
30
|
+
format: email
|
|
31
|
+
displayName:
|
|
32
|
+
type: string
|
|
33
|
+
maxLength: 128
|
|
34
|
+
createdAt:
|
|
35
|
+
type: string
|
|
36
|
+
format: date-time
|
|
37
|
+
AgentRegistration:
|
|
38
|
+
type: object
|
|
39
|
+
required: [terminalId, hostname, osVersion]
|
|
40
|
+
properties:
|
|
41
|
+
terminalId:
|
|
42
|
+
type: string
|
|
43
|
+
description: 终端唯一 ID(首次注册由客户端生成 UUID)。
|
|
44
|
+
hostname:
|
|
45
|
+
type: string
|
|
46
|
+
osVersion:
|
|
47
|
+
type: string
|
|
48
|
+
AgentRegistrationResult:
|
|
49
|
+
type: object
|
|
50
|
+
required: [terminalId, agentToken, expiresAt]
|
|
51
|
+
properties:
|
|
52
|
+
terminalId:
|
|
53
|
+
type: string
|
|
54
|
+
agentToken:
|
|
55
|
+
type: string
|
|
56
|
+
description: 后续调用所有 /api/agent/v1/* 端点时携带于 Authorization header。
|
|
57
|
+
expiresAt:
|
|
58
|
+
type: string
|
|
59
|
+
format: date-time
|
|
60
|
+
ErrorResponse:
|
|
61
|
+
type: object
|
|
62
|
+
required: [code, message]
|
|
63
|
+
properties:
|
|
64
|
+
code:
|
|
65
|
+
type: string
|
|
66
|
+
description: 错误码,对应 contracts/errors/*.yaml 中的 code 字段。
|
|
67
|
+
message:
|
|
68
|
+
type: string
|
|
69
|
+
details:
|
|
70
|
+
type: array
|
|
71
|
+
items: { type: object }
|
|
72
|
+
responses:
|
|
73
|
+
Unauthorized:
|
|
74
|
+
description: 未登录或登录已过期
|
|
75
|
+
content:
|
|
76
|
+
application/json:
|
|
77
|
+
schema:
|
|
78
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
openapi: 3.1.0
|
|
2
|
+
info:
|
|
3
|
+
title: <%= it.options.projectName %> Admin API
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
description: |
|
|
6
|
+
管理员后台 API。
|
|
7
|
+
|
|
8
|
+
路径前缀统一为 `/api/admin/v1/`;调用方限定为内部管理员前端 + 管理工具。
|
|
9
|
+
schemas 通过 $ref 引用 `_components/schemas.yaml`,避免在多个 audience 文件之间重复。
|
|
10
|
+
contact:
|
|
11
|
+
name: Backend Team
|
|
12
|
+
servers:
|
|
13
|
+
- url: https://api.example.com
|
|
14
|
+
description: 生产环境
|
|
15
|
+
- url: http://127.0.0.1:8080
|
|
16
|
+
description: 本地开发
|
|
17
|
+
tags:
|
|
18
|
+
- name: users
|
|
19
|
+
description: 用户管理
|
|
20
|
+
paths:
|
|
21
|
+
/api/admin/v1/users:
|
|
22
|
+
get:
|
|
23
|
+
tags: [users]
|
|
24
|
+
summary: 列出所有用户(管理员)
|
|
25
|
+
operationId: adminListUsers
|
|
26
|
+
responses:
|
|
27
|
+
'200':
|
|
28
|
+
description: 用户列表
|
|
29
|
+
content:
|
|
30
|
+
application/json:
|
|
31
|
+
schema:
|
|
32
|
+
type: array
|
|
33
|
+
items:
|
|
34
|
+
$ref: '_components/schemas.yaml#/components/schemas/User'
|
|
35
|
+
'401':
|
|
36
|
+
$ref: '_components/schemas.yaml#/components/responses/Unauthorized'
|
|
37
|
+
components: {}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
openapi: 3.1.0
|
|
2
|
+
info:
|
|
3
|
+
title: <%= it.options.projectName %> Agent API
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
description: |
|
|
6
|
+
Agent 公共接入 API。
|
|
7
|
+
|
|
8
|
+
路径前缀统一为 `/api/agent/v1/`;调用方限定为终端常驻 agent / 桌面 / CLI 客户端。
|
|
9
|
+
与管理员 API 完全隔离:agent 不能调用 admin 端点,反之亦然。
|
|
10
|
+
servers:
|
|
11
|
+
- url: https://api.example.com
|
|
12
|
+
description: 生产环境
|
|
13
|
+
- url: http://127.0.0.1:8080
|
|
14
|
+
description: 本地开发
|
|
15
|
+
tags:
|
|
16
|
+
- name: registration
|
|
17
|
+
description: 终端注册
|
|
18
|
+
paths:
|
|
19
|
+
/api/agent/v1/register:
|
|
20
|
+
post:
|
|
21
|
+
tags: [registration]
|
|
22
|
+
summary: 终端首次注册
|
|
23
|
+
operationId: agentRegister
|
|
24
|
+
requestBody:
|
|
25
|
+
required: true
|
|
26
|
+
content:
|
|
27
|
+
application/json:
|
|
28
|
+
schema:
|
|
29
|
+
$ref: '_components/schemas.yaml#/components/schemas/AgentRegistration'
|
|
30
|
+
responses:
|
|
31
|
+
'200':
|
|
32
|
+
description: 注册成功
|
|
33
|
+
content:
|
|
34
|
+
application/json:
|
|
35
|
+
schema:
|
|
36
|
+
$ref: '_components/schemas.yaml#/components/schemas/AgentRegistrationResult'
|
|
37
|
+
components: {}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
openapi: 3.1.0
|
|
2
|
+
info:
|
|
3
|
+
title: <%= it.options.projectName %> User API
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
description: |
|
|
6
|
+
用户自助 API。
|
|
7
|
+
|
|
8
|
+
路径前缀统一为 `/api/user/v1/`;调用方限定为终端用户的前端 / 移动端。
|
|
9
|
+
所有端点必须遵守"用户只能看到自己资源"的约束。
|
|
10
|
+
servers:
|
|
11
|
+
- url: https://api.example.com
|
|
12
|
+
description: 生产环境
|
|
13
|
+
- url: http://127.0.0.1:8080
|
|
14
|
+
description: 本地开发
|
|
15
|
+
tags:
|
|
16
|
+
- name: profile
|
|
17
|
+
description: 当前用户资料
|
|
18
|
+
paths:
|
|
19
|
+
/api/user/v1/profile:
|
|
20
|
+
get:
|
|
21
|
+
tags: [profile]
|
|
22
|
+
summary: 获取当前用户资料
|
|
23
|
+
operationId: userGetProfile
|
|
24
|
+
responses:
|
|
25
|
+
'200':
|
|
26
|
+
description: 当前用户资料
|
|
27
|
+
content:
|
|
28
|
+
application/json:
|
|
29
|
+
schema:
|
|
30
|
+
$ref: '_components/schemas.yaml#/components/schemas/User'
|
|
31
|
+
'401':
|
|
32
|
+
$ref: '_components/schemas.yaml#/components/responses/Unauthorized'
|
|
33
|
+
components: {}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: contracts-rest-by-audience
|
|
2
|
+
version: 1.0.0
|
|
3
|
+
appliesWhen:
|
|
4
|
+
contract: rest
|
|
5
|
+
openapiLayout: by-audience
|
|
6
|
+
priority: 20
|
|
7
|
+
files:
|
|
8
|
+
- from: files/admin-api.yaml
|
|
9
|
+
to: contracts/openapi/admin-api.yaml
|
|
10
|
+
render: true
|
|
11
|
+
- from: files/user-api.yaml
|
|
12
|
+
to: contracts/openapi/user-api.yaml
|
|
13
|
+
render: true
|
|
14
|
+
- from: files/agent-api.yaml
|
|
15
|
+
to: contracts/openapi/agent-api.yaml
|
|
16
|
+
render: true
|
|
17
|
+
- from: files/_components-schemas.yaml
|
|
18
|
+
to: contracts/openapi/_components/schemas.yaml
|
|
19
|
+
render: true
|
|
20
|
+
- from: files/_components-README.md
|
|
21
|
+
to: contracts/openapi/_components/README.md
|
|
22
|
+
render: true
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# `_components/` — 跨 audience 共享的 OpenAPI 类型
|
|
2
|
+
|
|
3
|
+
本目录的 `schemas.yaml` 是 `admin-api.yaml` / `user-api.yaml` / `agent-api.yaml` 共享的类型库。
|
|
4
|
+
|
|
5
|
+
## 引用方式
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
$ref: '_components/schemas.yaml#/components/schemas/User'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 何时改这里
|
|
12
|
+
|
|
13
|
+
- 添加跨 audience 的实体(User / Order / ErrorResponse 等)
|
|
14
|
+
- 修改既有共享类型的字段(**Tier 3**,必须同步 `contracts/CHANGELOG.md`)
|
|
15
|
+
- 删字段或改类型(**Tier 4**,破坏性,需要 ADR)
|
|
16
|
+
|
|
17
|
+
## 何时**不**改这里
|
|
18
|
+
|
|
19
|
+
- 单个 audience 私有的 DTO(例如管理员后台的 `AdminUserListItem`)
|
|
20
|
+
写在对应 API 文件自己的 `components/schemas` 里,并用 audience 前缀命名
|
|
21
|
+
|
|
22
|
+
## 工具兼容性
|
|
23
|
+
|
|
24
|
+
Spectral / openapi-generator-cli / Redoc / Postman 都原生支持跨文件 `$ref`,不需要任何配置:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx --yes @stoplight/spectral-cli lint contracts/openapi/admin-api.yaml
|
|
28
|
+
npx --yes @stoplight/spectral-cli lint contracts/openapi/user-api.yaml
|
|
29
|
+
npx --yes @stoplight/spectral-cli lint contracts/openapi/agent-api.yaml
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> Spectral 会自动 follow `$ref` 进入 `_components/schemas.yaml` 校验。
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# 跨 audience 共享的 schemas / parameters / responses。
|
|
2
|
+
#
|
|
3
|
+
# 引用方式:
|
|
4
|
+
# $ref: '_components/schemas.yaml#/components/schemas/User'
|
|
5
|
+
#
|
|
6
|
+
# 不要在 admin-api.yaml / user-api.yaml / agent-api.yaml 各自重复定义同名实体;
|
|
7
|
+
# 添加新共享类型时改这里,并在对应 API 文件用 $ref 引入。
|
|
8
|
+
#
|
|
9
|
+
# 仅 audience 私有的类型(例如 admin 后台特定 DTO)可以放在自己 API 文件的
|
|
10
|
+
# components/schemas 里,但要在 schema 名字加 audience 前缀以避免误用,
|
|
11
|
+
# 例如 AdminUserListItem。
|
|
12
|
+
|
|
13
|
+
openapi: 3.1.0
|
|
14
|
+
info:
|
|
15
|
+
title: Shared components
|
|
16
|
+
version: 0.1.0
|
|
17
|
+
paths: {}
|
|
18
|
+
components:
|
|
19
|
+
schemas:
|
|
20
|
+
User:
|
|
21
|
+
type: object
|
|
22
|
+
required: [id, email, displayName]
|
|
23
|
+
properties:
|
|
24
|
+
id:
|
|
25
|
+
type: string
|
|
26
|
+
format: uuid
|
|
27
|
+
description: 用户 ID。
|
|
28
|
+
email:
|
|
29
|
+
type: string
|
|
30
|
+
format: email
|
|
31
|
+
displayName:
|
|
32
|
+
type: string
|
|
33
|
+
maxLength: 128
|
|
34
|
+
createdAt:
|
|
35
|
+
type: string
|
|
36
|
+
format: date-time
|
|
37
|
+
AgentRegistration:
|
|
38
|
+
type: object
|
|
39
|
+
required: [terminalId, hostname, osVersion]
|
|
40
|
+
properties:
|
|
41
|
+
terminalId:
|
|
42
|
+
type: string
|
|
43
|
+
description: 终端唯一 ID(首次注册由客户端生成 UUID)。
|
|
44
|
+
hostname:
|
|
45
|
+
type: string
|
|
46
|
+
osVersion:
|
|
47
|
+
type: string
|
|
48
|
+
AgentRegistrationResult:
|
|
49
|
+
type: object
|
|
50
|
+
required: [terminalId, agentToken, expiresAt]
|
|
51
|
+
properties:
|
|
52
|
+
terminalId:
|
|
53
|
+
type: string
|
|
54
|
+
agentToken:
|
|
55
|
+
type: string
|
|
56
|
+
description: 后续调用所有 /api/agent/v1/* 端点时携带于 Authorization header。
|
|
57
|
+
expiresAt:
|
|
58
|
+
type: string
|
|
59
|
+
format: date-time
|
|
60
|
+
ErrorResponse:
|
|
61
|
+
type: object
|
|
62
|
+
required: [code, message]
|
|
63
|
+
properties:
|
|
64
|
+
code:
|
|
65
|
+
type: string
|
|
66
|
+
description: 错误码,对应 contracts/errors/*.yaml 中的 code 字段。
|
|
67
|
+
message:
|
|
68
|
+
type: string
|
|
69
|
+
details:
|
|
70
|
+
type: array
|
|
71
|
+
items: { type: object }
|
|
72
|
+
responses:
|
|
73
|
+
Unauthorized:
|
|
74
|
+
description: 未登录或登录已过期
|
|
75
|
+
content:
|
|
76
|
+
application/json:
|
|
77
|
+
schema:
|
|
78
|
+
$ref: '#/components/schemas/ErrorResponse'
|