@wneng/create-keel 0.3.6 → 0.4.1

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.
Files changed (89) hide show
  1. package/dist/index.js +206 -13
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/src/templates/ci-gitee/files/PULL_REQUEST_TEMPLATE.md +15 -2
  5. package/src/templates/ci-gitee/files/pipeline.yml +62 -0
  6. package/src/templates/ci-github/files/PULL_REQUEST_TEMPLATE.md +15 -2
  7. package/src/templates/ci-github/files/ci.yml +160 -0
  8. package/src/templates/db-go-elasticsearch/files/Makefile +18 -0
  9. package/src/templates/db-go-elasticsearch/files/apply_templates.go +80 -0
  10. package/src/templates/db-go-elasticsearch/files/db-README.md +57 -0
  11. package/src/templates/db-go-elasticsearch/files/go.mod +7 -0
  12. package/src/templates/db-go-elasticsearch/files/index-template-init.json +25 -0
  13. package/src/templates/db-go-elasticsearch/fragment.yaml +22 -0
  14. package/src/templates/db-go-migrate-mysql/files/000001_init.down.sql +3 -0
  15. package/src/templates/db-go-migrate-mysql/files/000001_init.up.sql +35 -0
  16. package/src/templates/db-go-migrate-mysql/files/Makefile +33 -0
  17. package/src/templates/db-go-migrate-mysql/files/db-README.md +77 -0
  18. package/src/templates/db-go-migrate-mysql/files/go.mod +8 -0
  19. package/src/templates/db-go-migrate-mysql/fragment.yaml +22 -0
  20. package/src/templates/db-go-migrate-postgres/files/000001_init.down.sql +3 -0
  21. package/src/templates/db-go-migrate-postgres/files/000001_init.up.sql +32 -0
  22. package/src/templates/db-go-migrate-postgres/files/Makefile +31 -0
  23. package/src/templates/db-go-migrate-postgres/files/db-README.md +71 -0
  24. package/src/templates/db-go-migrate-postgres/files/go.mod +8 -0
  25. package/src/templates/db-go-migrate-postgres/fragment.yaml +22 -0
  26. package/src/templates/db-java-elasticsearch/files/EsTemplateApplier.java +86 -0
  27. package/src/templates/db-java-elasticsearch/files/db-README.md +63 -0
  28. package/src/templates/db-java-elasticsearch/files/index-template-init.json +25 -0
  29. package/src/templates/db-java-elasticsearch/files/pom.xml +134 -0
  30. package/src/templates/db-java-elasticsearch/fragment.yaml +19 -0
  31. package/src/templates/db-java-flyway-mysql/files/V1__init.sql +44 -0
  32. package/src/templates/db-java-flyway-mysql/files/application.yaml +39 -0
  33. package/src/templates/db-java-flyway-mysql/files/db-README.md +102 -0
  34. package/src/templates/db-java-flyway-mysql/files/pom.xml +172 -0
  35. package/src/templates/db-java-flyway-mysql/fragment.yaml +19 -0
  36. package/src/templates/db-java-flyway-postgres/files/V1__init.sql +40 -0
  37. package/src/templates/db-java-flyway-postgres/files/application.yaml +37 -0
  38. package/src/templates/db-java-flyway-postgres/files/db-README.md +75 -0
  39. package/src/templates/db-java-flyway-postgres/files/pom.xml +166 -0
  40. package/src/templates/db-java-flyway-postgres/fragment.yaml +19 -0
  41. package/src/templates/db-node-elasticsearch/files/apply-templates.cjs +60 -0
  42. package/src/templates/db-node-elasticsearch/files/db-README.md +76 -0
  43. package/src/templates/db-node-elasticsearch/files/index-template-init.json +26 -0
  44. package/src/templates/db-node-elasticsearch/files/package.json +26 -0
  45. package/src/templates/db-node-elasticsearch/fragment.yaml +19 -0
  46. package/src/templates/db-node-knex-mysql/files/db-README.md +90 -0
  47. package/src/templates/db-node-knex-mysql/files/knexfile.cjs +72 -0
  48. package/src/templates/db-node-knex-mysql/files/migrations-init.cjs +42 -0
  49. package/src/templates/db-node-knex-mysql/files/package.json +31 -0
  50. package/src/templates/db-node-knex-mysql/files/seeds-dev-fixtures.cjs +38 -0
  51. package/src/templates/db-node-knex-mysql/files/seeds-prod-dictionaries.cjs +25 -0
  52. package/src/templates/db-node-knex-mysql/fragment.yaml +25 -0
  53. package/src/templates/db-node-knex-postgres/files/db-README.md +81 -0
  54. package/src/templates/db-node-knex-postgres/files/knexfile.cjs +67 -0
  55. package/src/templates/db-node-knex-postgres/files/migrations-init.cjs +42 -0
  56. package/src/templates/db-node-knex-postgres/files/package.json +31 -0
  57. package/src/templates/db-node-knex-postgres/files/seeds-dev-fixtures.cjs +36 -0
  58. package/src/templates/db-node-knex-postgres/files/seeds-prod-dictionaries.cjs +26 -0
  59. package/src/templates/db-node-knex-postgres/fragment.yaml +25 -0
  60. package/src/templates/db-python-alembic-mysql/files/0001_init.py +70 -0
  61. package/src/templates/db-python-alembic-mysql/files/alembic.ini +47 -0
  62. package/src/templates/db-python-alembic-mysql/files/db-README.md +87 -0
  63. package/src/templates/db-python-alembic-mysql/files/env.py +71 -0
  64. package/src/templates/db-python-alembic-mysql/files/pyproject.toml +52 -0
  65. package/src/templates/db-python-alembic-mysql/files/script.py.mako +26 -0
  66. package/src/templates/db-python-alembic-mysql/fragment.yaml +25 -0
  67. package/src/templates/db-python-alembic-postgres/files/0001_init.py +62 -0
  68. package/src/templates/db-python-alembic-postgres/files/alembic.ini +45 -0
  69. package/src/templates/db-python-alembic-postgres/files/db-README.md +70 -0
  70. package/src/templates/db-python-alembic-postgres/files/env.py +62 -0
  71. package/src/templates/db-python-alembic-postgres/files/pyproject.toml +52 -0
  72. package/src/templates/db-python-alembic-postgres/files/script.py.mako +25 -0
  73. package/src/templates/db-python-alembic-postgres/fragment.yaml +25 -0
  74. package/src/templates/db-python-elasticsearch/files/apply_templates.py +55 -0
  75. package/src/templates/db-python-elasticsearch/files/db-README.md +57 -0
  76. package/src/templates/db-python-elasticsearch/files/index-template-init.json +25 -0
  77. package/src/templates/db-python-elasticsearch/files/pyproject.toml +50 -0
  78. package/src/templates/db-python-elasticsearch/fragment.yaml +19 -0
  79. package/src/templates/docs-skeleton/files/governance-change-tiers.md +135 -76
  80. package/src/templates/docs-skeleton/files/governance-database.md +150 -0
  81. package/src/templates/docs-skeleton/fragment.yaml +3 -0
  82. package/src/templates/root-files/files/AGENTS.md +35 -17
  83. package/src/templates/server-python/files/README.md +75 -2
  84. package/src/templates/server-python/files/app-init.py +11 -1
  85. package/src/templates/server-python/files/config.py +40 -0
  86. package/src/templates/server-python/files/main.py +62 -0
  87. package/src/templates/server-python/files/pyproject.toml +14 -1
  88. package/src/templates/server-python/files/test_healthz.py +36 -0
  89. package/src/templates/server-python/fragment.yaml +10 -1
@@ -1,133 +1,192 @@
1
1
  ---
2
- last-reviewed: 2026-05-16
2
+ last-reviewed: 2026-05-17
3
3
  ---
4
4
 
5
5
  # 变更分级(Change Tiers)
6
6
 
7
7
  > AGENTS.md §6 的细则。澄清"先文档先契约再 code"在不同场景下应该有多厚。
8
8
 
9
- ## 0. 为什么需要分级
9
+ ## 0. 两件正交的事,不要绑死
10
10
 
11
- `AGENTS.md` §2 的"Contract First"和 §6 的"先补契约和文档,再补实现"在小改动场景下容易被 AI 过度解读。常见误读:
11
+ `AGENTS.md` §2 的 Contract First §6 的"变更分级"要拆成**两件独立的事**:
12
12
 
13
- - 改一个 typo 想去补 PRD
14
- - 修一个不涉及 API 的 bug → 想去更新 OpenAPI
15
- - 加一行配置 想去写 ADR
13
+ | 维度 | 是什么 | 谁定 |
14
+ |---|---|---|
15
+ | **Tier**(变更影响面) | 改动客观属性:动了哪些层、是否破坏性、有几个团队耦合 | AI 按决策树自动判定 |
16
+ | **Doc Weight**(文档投入) | 团队 / 项目 / 这次 PR 想花多少笔墨在 markdown 上 | AI 给默认建议;PR 作者最终决定 |
16
17
 
17
- 这浪费时间、噪声 PR、让团队反感框架本身。
18
+ 它们是 **and**,不是 **=**。
18
19
 
19
- **正确的理解**:
20
- - **A. 方案讨论必须有书面结论**(载体可大可小)—— 总成立
21
- - **B. 契约必须在 code 之前冻结**—— 仅当变更触及契约时成立
20
+ 20 人银行项目和 2 人工具型 startup 改同一个 API 字段,Tier 都是 3,但前者会写后端设计 + 前端联动说明(Doc Weight = standard),后者只在 PR 描述里写一段(Doc Weight = lite)。框架不强行统一两者。
22
21
 
23
- A + B 不是绑死的。改一个不动 API 的 bug,B 不触发;改一个 typo,A 也只需要 PR title + 一行描述。
22
+ ## 1. 六档 Tier(变更影响面)
24
23
 
25
- ## 1. 六档 Tier
24
+ | Tier | 名称 | 典型场景 | 是否动契约 |
25
+ |---|---|---|---|
26
+ | **0** | trivial | 拼写、注释、格式化、补测试、依赖 patch 升级 | 不动 |
27
+ | **1** | bugfix | 修 NPE、错误的 SQL、UI 显示错位(无新行为,行为符合既有契约) | 不动 |
28
+ | **2** | small change | 加按钮 / 排序 / 导出列、调文案、加配置项 | 通常不动 |
29
+ | **3** | contract change | 加 API / 字段 / 错误码 / 事件 / 状态(兼容新增) | **必须**先冻结契约 + CHANGELOG |
30
+ | **4** | architecture / breaking | 跨服务、鉴权变化、删字段、改类型、新依赖、数据迁移 | **必须** ADR + 契约 + 迁移说明 |
31
+ | **5** | spike | 探索性、方案未明 | 在 `spike/*` 分支自由探索;合入 `main` 前补到对应 tier |
26
32
 
27
- | Tier | 名称 | 典型场景 | A:方案记录的最小载体 | B:是否动契约 |
28
- |---|---|---|---|---|
29
- | **0** | trivial | 拼写、注释、格式化、补测试、依赖 patch 升级 | PR title + 1-2 行描述 | 不动 |
30
- | **1** | bugfix | 修 NPE、错误的 SQL、UI 显示错位(无新行为) | PR 描述:**重现 + 根因 + 修复点 + 回归测试** | 不动 |
31
- | **2** | small change | 加按钮 / 排序 / 导出列、调文案、加配置项 | PR 描述(含动机 + 方案 + 影响面),或 1 页 markdown 进 `docs/过程文档/drafts/` | 通常不动 |
32
- | **3** | contract change | 加 API / 字段 / 错误码 / 事件 / 状态 | 简短设计章节(写在 `docs/04` 或 `docs/05` 的对应模块里)+ contracts 更新 + CHANGELOG | **必须**先冻结契约 |
33
- | **4** | architecture / breaking | 新模块、跨服务、数据迁移、鉴权模型变化、删除字段 | PRD(若来自需求)→ ADR → 详细设计 → 契约 → code | **必须** ADR + 契约 + 迁移说明 |
34
- | **5** | spike | 探索性、方案未明 | 在 `spike/*` 分支自由探索 | 合入 `main` 前补齐到对应 tier |
33
+ ## 2. Tier 判定决策树
35
34
 
36
- ## 2. 判定决策树
35
+ 按从严到宽问自己:
37
36
 
38
- 按从严到宽顺序问自己:
37
+ 1. 改了 `contracts/` 任何文件? → 至少 **Tier 3**
38
+ 2. 改动会改变 API / DB schema / 事件 / 鉴权 / 安全语义?(即使现在 contracts 还没收录) → **Tier 3 或 4**,先补契约再继续
39
+ 3. 删除或不兼容地修改了已有契约字段? → **Tier 4** 必须 ADR
40
+ 4. 跨服务、跨模块边界、跨执行环境(server↔web↔mobile)? → **Tier 4**
41
+ 5. 影响 ops/ 或 deploy/ 实际拓扑(新加 service / 新开端口 / 改加密策略)? → **Tier 4**
42
+ 6. 探索 / 调研,方案不清楚? → **Tier 5**(`spike/*` 分支)
43
+ 7. 以上都不是,纯局部、可逆的改动? → 按体量定 **Tier 0/1/2**
39
44
 
40
- 1. **改动改了 `contracts/` 任何文件?** → 至少 Tier 3
41
- 2. **改动会改变 API / DB schema / 事件 / 鉴权 / 安全语义?**(即使现在 contracts 还没收录)→ Tier 3 或 4,**先把契约补上再继续**
42
- 3. **删除或不兼容地修改了已有契约字段?** → Tier 4,**必须** ADR
43
- 4. **跨服务、跨模块边界、跨执行环境(server↔web↔mobile)?** → Tier 4
44
- 5. **会影响 ops/ 或 deploy/ 实际拓扑(新加一个 service / 新开一个端口 / 改加密策略)?** → Tier 4
45
- 6. **是探索 / 调研,方案还不清楚?** → Tier 5(用 `spike/*` 分支)
46
- 7. **以上都不是,纯局部、可逆的改动?** → 按体量定 Tier 0/1/2
45
+ ## 3. 三档 Doc Weight(文档投入)
47
46
 
48
- ## 3. 反例(避免过度反应)
47
+ > **默认值**:每个 Tier 的"AI 推荐 doc weight"如下,PR 作者可在 PR 模板里覆盖。
49
48
 
50
- 下面这些情况 **不要** 升级 tier:
49
+ | Tier | AI 默认推荐 | lite 时只要 | standard 时再加 | full 时再加 |
50
+ |---|---|---|---|---|
51
+ | **0** trivial | **lite**(除非异常) | PR 描述 1-2 行 | — | — |
52
+ | **1** bugfix | **lite** | PR 描述:重现 + 根因 + 修复 + 回归测试 | — | — |
53
+ | **2** small change | **lite** | PR 描述:动机 + 方案 + 影响面 | 1 页 markdown 进 `docs/过程文档/drafts/` | — |
54
+ | **3** contract change | **lite**(关键!) | PR 描述 + 契约 diff + CHANGELOG + 契约锚点 | 简短后端 / 前端设计章节进 `docs/04` 或 `docs/05`,每份 2-3 段 | + PRD(`docs/01/prd-<slug>.md`) |
55
+ | **4** arch / breaking | **standard** | PR 描述 + 契约 diff + CHANGELOG + ADR | 简化 04 / 05 详细设计 + 迁移 / 回滚预案 | + PRD + UI 设计稿(如涉及前端) |
56
+ | **5** spike | **lite**(探索期不需要文档) | spike 分支自由实验;合入 `main` 时按目标 tier 补齐 | — | — |
51
57
 
52
- | 情形 | 正确 tier | 错误反应 |
53
- |---|---|---|
54
- | 修 `web/src/utils/format-date.ts` 的 typo 注释 | 0 | 写 PRD |
55
- | `GET /users/{id}` 的实现里漏判 null,500 改 404 | 1(行为符合契约) | 改 OpenAPI |
56
- | 给已有列表加"最近 7 天"筛选选项(前端筛选,后端无变化) | 2 | 写 ADR |
57
- | `package.json` 里 `lodash 4.17.20 → 4.17.21`(patch) | 0 | 走完整升级流程 |
58
- | 改 README 一段错别字 | 0 | 同步多份治理文件 |
59
- | 重构一个内部 helper 函数(不导出) | 0 或 1 | 写详细设计 |
60
- | 加测试覆盖既有功能 | 0 | 写 PRD |
58
+ **关键修正**(相对 0.4.0):**Tier 3 默认 doc weight lite,不是 standard**。理由:契约 diff 本身就是设计真值;额外的中文设计文档反而和契约漂移。只在业务复杂度高到契约说不清时(复杂状态机、多模块交互、跨团队协作),作者主动升 standard / full。
61
59
 
62
- 下面这些情况 **必须** 升级 tier:
60
+ ### 3.1 lite 的最小载体
63
61
 
64
- | 情形 | 正确 tier | 误判风险 |
65
- |---|---|---|
66
- | 给 `GET /users/{id}` 加返回字段 `lastLoginAt` | 3 | 想成 Tier 2 / 文档"顺手补" |
67
- | 给已有 List API 加 `?status=` 查询参数 | 3 | 想成 Tier 2 |
68
- | 把鉴权从 cookie 改为 Bearer token | 4 | 想成 Tier 3 |
69
- | 把 RBAC 从扁平改为支持继承 | 4 | 想成 Tier 3 |
70
- | 引入新的消息队列 / 缓存层 / 第三方支付 | 4 | 想成 Tier 3 |
71
- | 删除 `User.email` 字段 | 4 | 想成 Tier 3(删除 ≠ 兼容新增) |
72
- | 升级 Spring Boot major 版本(3.x → 4.x) | 4 | 想成 Tier 0(只是版本号) |
62
+ **lite 没文档**。PR 描述本身就是文档;契约本身就是真值。lite 只是不再要求**额外的 markdown 文件**。
73
63
 
74
- ## 4. PR 模板里的 Tier 框
64
+ PR 描述至少包含:
75
65
 
76
- PR 模板顶部要求作者明示 tier。Reviewer 第一眼看到 tier 后:
66
+ - **What**:改了什么
67
+ - **Why**:为什么(业务动机 / 用户痛点 / 技术债)
68
+ - **影响面**:哪些路径 / 服务 / 团队会被影响
69
+ - 如有契约 diff:契约锚点(`contracts/openapi/api.yaml#/paths/~1users/post`)
70
+ - 如是 Tier 1 bugfix:重现步骤 + 根因 + 修复点 + 回归测试
77
71
 
78
- - **Tier 0/1/2**:着重看代码 / 测试 / 描述完整性,不要求 ADR / 契约改动
79
- - **Tier 3**:必须看到 contracts 同步、CHANGELOG 同步、契约锚点引用
80
- - **Tier 4**:必须看到 ADR 存在或新增、详细设计文档、迁移 / 回滚预案
81
- - **Tier 5**:分支必须是 `spike/*`;如果想合入 `main`,作者必须在合入 PR 中标明落地到了哪个 tier
72
+ ### 3.2 何时升 standard / full
82
73
 
83
- CI 不强制校验 tier 标签(语义判定是 reviewer 的责任);但 CI **会**校验:
74
+ AI 在以下信号下**主动建议**升级 doc weight,并在 PR 描述里写一句理由:
84
75
 
85
- - 改了 `contracts/` PR 必须同改 `contracts/CHANGELOG.md`(已有规则)
86
- - `spike/*` 分支不能直接合入 `main`(PR 模板 + CODEOWNERS)
76
+ | 信号 | 建议 |
77
+ |---|---|
78
+ | 契约 diff > 5 个 endpoint / schema 变化 | standard |
79
+ | 引入新状态机或改既有状态机的状态数 | standard |
80
+ | 跨服务联动(server 改 + web 改 + 第三方 webhook 改) | standard |
81
+ | 删字段 / 改类型 / 改鉴权(即 Tier 4) | standard 或 full |
82
+ | 业务规则复杂到契约的 description 字段写不下 | standard |
83
+ | 来源是产品同学的需求文档(PRD 是上游产物) | full(PRD 落到 `docs/01/`) |
84
+ | 跨多团队 / 多季度的项目 | full |
85
+
86
+ PR 作者也可主动**降级**:如果 AI 推荐 standard 但作者认为契约自身已说清楚,可以 lite 通过;reviewer 不应仅因"没写设计文档"而打回。
87
+
88
+ ## 4. 反例
89
+
90
+ 下面这些情况 **不要** 升级 tier 或 doc weight:
91
+
92
+ | 情形 | 正确 Tier | 推荐 Doc Weight | 错误反应 |
93
+ |---|---|---|---|
94
+ | 修 `web/src/utils/format-date.ts` 的 typo 注释 | 0 | lite | 写 PRD |
95
+ | `GET /users/{id}` 实现里漏判 null,500 改 404 | 1 | lite | 改 OpenAPI |
96
+ | 加"最近 7 天"前端筛选选项(后端无变化) | 2 | lite | 写 ADR |
97
+ | `lodash 4.17.20 → 4.17.21`(patch) | 0 | lite | 走完整升级流程 |
98
+ | 改 README 错别字 | 0 | lite | 同步多份治理文件 |
99
+ | 重构一个内部 helper 函数(不导出) | 0 或 1 | lite | 写详细设计 |
100
+ | 加测试覆盖既有功能 | 0 | lite | 写 PRD |
101
+ | **给 `GET /users/{id}` 加返回字段 `lastLoginAt`**(兼容新增) | **3** | **lite**(只改契约 + CHANGELOG) | 想成必须写 04 后端设计 |
102
+ | **给已有 List API 加 `?status=` 查询参数** | **3** | **lite** | 想成 Tier 2 / 必须写 PRD |
103
+
104
+ 下面这些情况 **必须** 升级 tier:
87
105
 
88
- ## 5. AI PR 描述中的引用义务
106
+ | 情形 | 正确 Tier | 推荐 Doc Weight |
107
+ |---|---|---|
108
+ | 把鉴权从 cookie 改为 Bearer token | 4 | standard 或 full |
109
+ | 把 RBAC 从扁平改为支持继承 | 4 | full(PRD + ADR + 详细设计) |
110
+ | 引入新消息队列 / 缓存层 / 第三方支付 | 4 | full |
111
+ | 删除 `User.email` 字段 | 4 | standard(迁移预案 + ADR) |
112
+ | 升级 Spring Boot major 版本(3.x → 4.x) | 4 | standard(兼容性扫描 + 测试矩阵) |
113
+
114
+ ## 5. PR 模板里的两个框
115
+
116
+ PR 作者填两件事:
117
+
118
+ ```
119
+ ## Tier(影响面,AI 自动判)
120
+ - [ ] 0 trivial
121
+ - [ ] 1 bugfix
122
+ - [x] 2 small change ← AI 建议
123
+ - [ ] 3 contract change
124
+ - [ ] 4 architecture / breaking
125
+ - [ ] 5 spike
126
+
127
+ ## Doc Weight(文档投入,AI 推荐 + 作者覆盖)
128
+ - [x] lite ← AI 推荐:PR 描述足够,不需额外文档
129
+ - [ ] standard
130
+ - [ ] full
131
+ ```
132
+
133
+ Reviewer 看到 Tier + Doc Weight 后:
134
+
135
+ - **Tier 0/1/2 + lite**:着重看代码 / 测试 / 描述完整性
136
+ - **Tier 3 + lite**:看契约 diff + CHANGELOG + 契约锚点;不要求 04/05 markdown
137
+ - **Tier 3 + standard**:以上 + 简短后端 / 前端设计章节(2-3 段就够)
138
+ - **Tier 3 + full**:以上 + PRD(如有产品需求来源)
139
+ - **Tier 4 + standard**:必须 ADR + 详细设计 + 迁移预案
140
+ - **Tier 4 + full**:以上 + PRD + UI 稿(如涉及)
141
+
142
+ CI 不强制 doc weight 与 tier 的对应关系(reviewer 责任);但 CI **会**校验:
143
+
144
+ - 改了 `contracts/` 必须同改 `contracts/CHANGELOG.md`(已有规则)
145
+ - `spike/*` 分支不能直接合入 `main`(PR 模板 + CODEOWNERS)
89
146
 
90
- tier 升级:
147
+ ## 6. AI 引用义务(按 Tier,doc weight 无关)
91
148
 
92
149
  | Tier | 引用义务 |
93
150
  |---|---|
94
- | 0/1/2 | 不强制;PR 描述本身就是方案记录 |
95
- | 3 | 必须引用契约锚点(如 `contracts/openapi/api.yaml#/paths/~1users/post`) |
96
- | 4 | 必须引用 ADR / 详细设计文档;契约锚点也必须 |
97
- | 5 | 必须标明 spike 分支与最终目标 tier |
151
+ | 0/1/2 | 不强制 |
152
+ | 3 | 必须引用契约锚点(lite 也要) |
153
+ | 4 | 必须引用 ADR + 契约锚点;详细设计在 standard / full 时引用 |
154
+ | 5 | 必须标明 spike 分支与目标 tier |
98
155
 
99
- AI 不要在 Tier 0/1/2 主动制造文档噪音;reviewer 也不要因"AI 没引用契约"而打回 Tier 0/1/2 的 PR。
156
+ AI Tier 0/1/2 不要主动制造文档噪音;reviewer 不要因"AI 没引用契约"打回 Tier 0/1/2 的 PR。
100
157
 
101
- ## 6. 与 spike 的关系
158
+ ## 7. 与 spike 的关系
102
159
 
103
- `spike/*` 分支是 Tier 5 的载体。它允许 AI 与开发者**暂时**绕过 Contract First:
160
+ `spike/*` 分支是 Tier 5 的载体,**doc weight 默认 lite**:
104
161
 
105
162
  1. 创建 `spike/<topic>` 分支
106
163
  2. 自由写代码、跑实验、改方向
107
164
  3. 结论清楚后:
108
165
  - 不采纳 → 文档进 `docs/过程文档/spike-investigations/`,分支保留备查
109
- - 采纳 → 反向走完 Tier 1-4 该补的内容(PRD / ADR / 详细设计 / 契约),再合入 `main`
166
+ - 采纳 → 反向按目标 Tier Doc Weight 补齐对应内容,再合入 `main`
110
167
 
111
- Spike 不是"绕过框架的永久后门"。`spike/*` 不能直接合入 `main`;合入 PR 必须用 `feat(...)` / `feat(ai)(...)` 等正式 type 重写。
168
+ Spike 不是"绕过框架的永久后门"。`spike/*` 不能直接合入 `main`。
112
169
 
113
- ## 7. 何时升级 / 降级
170
+ ## 8. 何时升级 / 降级
114
171
 
115
- 升级(向上):开发过程中发现影响面比预想大 → 立即升 tier,停下补对应文档 / 契约。
172
+ **Tier 升级**:开发过程中发现影响面比预想大 → 立即升 tier,停下补对应契约 / 文档。
173
+ **Tier 降级**:通常**不允许**。一旦你声明 Tier 3+ 并写了契约 / ADR / 设计,就保留它(除非改动被裁掉变成 Tier 2)。
116
174
 
117
- 降级(向下):通常**不允许**。一旦你声明 Tier 3+ 并写了契约 / ADR / 设计,就保留它。降级只在明确的"改动被裁掉了"场景下成立(例如:本来要加一个字段,最后发现可以用既有字段实现),此时把 tier 改成实际生效的层级,并在 PR 描述里写明。
175
+ **Doc Weight 升级**:欢迎随时升级(写更多文档不是错)。
176
+ **Doc Weight 降级**:作者可在 PR 评审中说明降级理由("契约已自解释"),reviewer 同意即可。
118
177
 
119
- ## 8. 与契约 SemVer 的关系
178
+ ## 9. 与契约 SemVer 的关系
120
179
 
121
180
  | Tier | 契约动作 | SemVer 影响 |
122
181
  |---|---|---|
123
182
  | 0/1/2 | 不动 | 无 |
124
183
  | 3(兼容新增) | `MINOR` bump | `0.x.y → 0.(x+1).0`(pre-1.0)/ `x.y.z → x.(y+1).0`(≥1.0) |
125
- | 3(破坏性,但还在 0.x) | `MINOR` bump + CHANGELOG 标 BREAKING | 同上(pre-1.0 允许) |
184
+ | 3(破坏性,但 0.x) | `MINOR` bump + CHANGELOG 标 BREAKING | 同上(pre-1.0 允许) |
126
185
  | 4(破坏性,≥1.0) | `MAJOR` bump | `x.y.z → (x+1).0.0` |
127
186
 
128
187
  完整版本策略 → [`../../contracts/README.md`](../../contracts/README.md)。
129
188
 
130
- ## 9. 关联文档
189
+ ## 10. 关联文档
131
190
 
132
191
  - [`../../AGENTS.md`](../../AGENTS.md) §6(变更分级摘要)
133
192
  - [`git-workflow.md`](git-workflow.md)(PR 模板与 CODEOWNERS 完整规则)
@@ -0,0 +1,150 @@
1
+ ---
2
+ last-reviewed: 2026-05-16
3
+ ---
4
+
5
+ # 数据库治理
6
+
7
+ > 本文件统一回答:"SQL / 索引 / 迁移 / 种子数据放哪个目录、与 `contracts/` 如何对齐"。
8
+ >
9
+ > 工具与命令的细节(哪个项目用 Knex / Flyway / Alembic / golang-migrate / ES applier)见各项目的 `server/db/README.md`,本文件不重复。
10
+ >
11
+ > 工具决策与 mongodb / sqlite 排除理由见 [`../02-系统方案与架构/adr-0005-database-conventions.md`](../02-系统方案与架构/adr-0005-database-conventions.md)。
12
+
13
+ ## 1. 五类 SQL 文件的归属
14
+
15
+ 数据库相关的产物分五类,每类只有一个合法位置:
16
+
17
+ | 类型 | 例子 | 归属 | 与契约关系 |
18
+ |---|---|---|---|
19
+ | **schema migration**(DDL,版本化) | `V1__create_users.sql` / `0001_init.py` / `000001_init.up.sql` | `server/db/migrations/`(Java 走 `src/main/resources/db/migration/`) | 与 `contracts/openapi/` 中的字段对齐 |
20
+ | **生产种子数据**(字典 / 码表) | 角色码表、状态枚举、错误码 lookup | `server/db/seeds/prod/`(Knex)/ 写入迁移文件(Flyway / Alembic / golang-migrate) | **真值在 `contracts/dictionaries/`**;当前手动同步 |
21
+ | **开发种子数据**(fixture) | 样例用户、demo 商品、调试数据 | `server/db/seeds/dev/` | 与契约无关;不进生产 |
22
+ | **存储过程 / 函数 / 视图 / 触发器** | `usp_calculate_amount.sql`、物化视图 | `server/db/procedures/` | 写入迁移文件,与代码同等对待 |
23
+ | **运维脚本**(一次性) | 数据回填、重建索引、清理过期数据 | `scripts/db/<date>-<topic>.sql` | 与契约无关;不进生产迁移历史 |
24
+ | **报表 / 分析 query**(BI 看板) | 仪表板背后的 SQL、临时调研 query | `docs/09-数据与埋点/`(启用 data 角色) | 与契约无关;与数据资产对齐 |
25
+
26
+ > Elasticsearch 的"migration"指**幂等的 index-template apply**,不在上述 RDBMS 表里;其归属规则:JSON template 在 `server/db/index-templates/`(Java 走 `src/main/resources/index-templates/`),applier 脚本在 `server/db/`。详见各项目 `server/db/README.md`。
27
+
28
+ ## 2. 三类特殊场景
29
+
30
+ ### 2.1 跨 service 共享同一个 DB(微服务但 DB 没拆)
31
+
32
+ DB schema 升格为契约:
33
+
34
+ ```
35
+ contracts/schemas/db/
36
+ ├── README.md # 谁是 schema 拥有者("owner service")
37
+ ├── ddl/ # 真值;其他 service 视为 read-only
38
+ │ ├── core_tables.sql
39
+ │ └── views.sql
40
+ └── CHANGELOG.md # 改 schema 必须 bump SemVer
41
+ server/apps/owner/db/migrations/ # 唯一执行迁移的 service
42
+ server/apps/consumer/db/ # 不存 DDL,只存 ORM 映射
43
+ ```
44
+
45
+ 只有 owner service 的 PR 能改 `contracts/schemas/db/ddl/`;consumer service 改 → CI 拒(按 contracts/ 现有规则)。
46
+
47
+ ### 2.2 多租户 schema-per-tenant
48
+
49
+ ```
50
+ server/db/migrations/
51
+ ├── shared/ # 公共 schema(账户、租户元数据)
52
+ └── tenant/ # 应用到每个租户 schema 的迁移
53
+ ```
54
+
55
+ 文档说清楚"新租户 onboarding 要跑哪些 migrations"。
56
+
57
+ ### 2.3 多 database per service
58
+
59
+ 例如:postgres 主库 + elasticsearch 用作搜索。
60
+
61
+ - 选第二个 fragment:手动从对应 `db-<backend>-<other>` 复制配置
62
+ - 在 `server/db/README.md` 里说明双库各管什么
63
+ - CI 起两个 service container
64
+
65
+ scaffolder 0.4.0 不自动支持双库;用户合并两个 fragment 的内容。
66
+
67
+ ## 3. 与 `contracts/` 的同步规则
68
+
69
+ ### 3.1 字典数据 → 生产种子
70
+
71
+ `contracts/dictionaries/enums.yaml` 是字典(角色 / 错误码 / 状态枚举)的真值。改字典的 PR 必须**同步**:
72
+
73
+ - 加字典项 → 同 PR 在迁移文件中加 INSERT IGNORE / ON CONFLICT DO NOTHING
74
+ - 改字典项的 name / description → 写新迁移更新对应行(不要改既有迁移)
75
+ - 删字典项 → Tier 4,需 ADR
76
+
77
+ > 当前是**手动同步**。自动派生(codegen)留给后续 `contract-derived-seeds` 特性。
78
+
79
+ ### 3.2 OpenAPI 字段 → DB 列
80
+
81
+ OpenAPI 中的实体字段与 DB 表的列**应当**对齐(同名、同类型映射)。手动维护;governance-lint 不强制(语义 diff 太复杂)。
82
+
83
+ ### 3.3 AsyncAPI 事件 → ES index template
84
+
85
+ `contracts/asyncapi/asyncapi.yaml` 中的事件 schema 与 `server/db/index-templates/` 中的 mapping **应当**对齐。当前手动同步。
86
+
87
+ ## 4. 改动分级(参见 `change-tiers.md`)
88
+
89
+ | 改动 | Tier | 备注 |
90
+ |---|---|---|
91
+ | 新增 migration 加表 / 加字段 | 3 | 同 PR 改 `contracts/CHANGELOG.md`(如果字段进契约) |
92
+ | 修改既有 migration 文件 | **不允许** | 写新 migration 代替;Flyway / Alembic / golang-migrate 都拒绝 |
93
+ | 删字段 / 改类型(破坏性) | 4 | ADR + 详细设计 + 数据迁移预案 |
94
+ | 改 dev seed | 1/2 | 不需要同步契约 |
95
+ | 改 prod seed(字典数据) | 3 | 同 PR 改 `contracts/dictionaries/` |
96
+ | 改 ES index-template 的 mapping | 4 | 破坏性 - 可能需要 reindex |
97
+ | 改 ES index-template 的 priority / settings | 2 | 局部行为调整 |
98
+ | 升级 Knex / Flyway / Alembic / golang-migrate / ES SDK | 2 | 同 PR 改 `tech-stack-server.md` 钉版本 |
99
+
100
+ ## 5. CI 行为
101
+
102
+ 每个 (backend, database) 组合的 CI 都跑 **migrate up + migrate down** smoke test:
103
+
104
+ - RDBMS:`db-migrate-smoke` job 起 service container,跑 `npm run db:migrate && npm run db:rollback`(或对应工具命令)
105
+ - ES:`db-es-template-apply` job 起 ES service container,跑 applier 脚本一次
106
+
107
+ CI **不**校验:
108
+ - schema 内容(用 DBA tool)
109
+ - 与 `contracts/` 字段对齐(语义 diff 太复杂)
110
+ - 数据回填脚本的正确性(一次性脚本不进 CI)
111
+
112
+ ## 6. 目录布局速查(非 multi-app 模式)
113
+
114
+ ```
115
+ server/
116
+ ├── db/
117
+ │ ├── README.md # 工具与命令(按 backend 不同)
118
+ │ ├── migrations/ # Knex / Alembic / golang-migrate 路径
119
+ │ │ └── <ts/N>_<description>.<ext>
120
+ │ ├── index-templates/ # ES applier 模式
121
+ │ │ └── <ts>_<description>.json
122
+ │ ├── seeds/
123
+ │ │ ├── prod/ # 字典数据;与 contracts/dictionaries 对齐
124
+ │ │ └── dev/ # 仅本地 / 测试
125
+ │ └── apply-templates.{cjs,py,go} # ES applier(按 backend)
126
+ ├── src/main/resources/db/migration/ # ← Java + Flyway 的迁移路径(与 server/db/ 分离)
127
+ └── src/main/resources/index-templates/ # ← Java + ES applier 的 template 路径
128
+
129
+ contracts/
130
+ ├── dictionaries/enums.yaml # 字典真值(→ prod seed 派生)
131
+ ├── openapi/api.yaml # API 字段(→ DB 列对齐)
132
+ └── asyncapi/asyncapi.yaml # 事件 schema(→ ES mapping 对齐)
133
+
134
+ scripts/db/ # 一次性运维(数据回填等)
135
+ └── 2026-05-backfill-tenants.sql
136
+
137
+ ops/db/ # DB 实例 / 权限 / 备份(IaC)
138
+ └── grants/
139
+ ```
140
+
141
+ ## 7. multi-app 模式
142
+
143
+ 每个 `server/apps/<app>/` 自己一份 `db/`。共享 schema 时(多 app 同 DB)schema 真值进 `contracts/schemas/db/`,由 owner app 唯一执行迁移。完整规则与示例见 §2.1。
144
+
145
+ ## 8. 不在本特性范围内的(推到下次 spec)
146
+
147
+ - mongodb 支持(详见 ADR-0005)
148
+ - sqlite 支持(详见 ADR-0005)
149
+ - contracts/dictionaries → seed migration 自动派生
150
+ - web/mobile/miniapp 本地数据库(IndexedDB / SQLite / Realm)
@@ -117,6 +117,9 @@ files:
117
117
  - from: files/governance-change-tiers.md
118
118
  to: docs/governance/change-tiers.md
119
119
  render: false
120
+ - from: files/governance-database.md
121
+ to: docs/governance/database.md
122
+ render: false
120
123
  - from: files/governance-checklists.md
121
124
  to: docs/governance/checklists.md
122
125
  render: true
@@ -45,7 +45,9 @@
45
45
  | `.claude/` | AI | Claude Code slash-commands |
46
46
  <% } %>
47
47
 
48
- ### 1.1 单应用 vs 多应用模式
48
+ <% if (it.options.database !== 'none') { %>> **数据库相关产物**(已启用 `database=<%= it.options.database %>`):`server/db/`(迁移、种子<% if (it.options.database === 'elasticsearch') { %>、ES index template<% } %>、运维脚本入口)的归属规则见 [`docs/governance/database.md`](docs/governance/database.md)。<% if (it.options.backend === 'java') { %> Java + <%= it.options.database === 'elasticsearch' ? 'spring-data-elasticsearch' : 'Flyway' %> 因 Spring Boot classpath 约定,<%= it.options.database === 'elasticsearch' ? 'index template' : '迁移' %>文件实际在 `server/src/main/resources/<%= it.options.database === 'elasticsearch' ? 'index-templates/' : 'db/migration/' %>`。<% } %>
49
+
50
+ <% } %>### 1.1 单应用 vs 多应用模式
49
51
 
50
52
  每个执行环境目录(`server/` `web/` `mobile/` `miniapp/` `agent/`)默认处于**单应用模式**。需要容纳第二个应用时切换到**多应用模式**:
51
53
 
@@ -138,31 +140,45 @@
138
140
  - 完整规则 → [`docs/governance/integrations.md`](docs/governance/integrations.md)
139
141
  <% } %>
140
142
 
141
- ## 6. 核心协作规则(变更分级)
143
+ ## 6. 核心协作规则(变更分级 + 文档投入)
144
+
145
+ 变更走**两个独立维度**:**Tier**(影响面,AI 自动判)+ **Doc Weight**(文档投入,AI 推荐 + 作者覆盖)。完整判定决策树、反例、与 SemVer 关系 → [`docs/governance/change-tiers.md`](docs/governance/change-tiers.md)。
142
146
 
143
- 变更分**六档**,文档与契约的"厚度"匹配影响面。完整判定决策树、反例、与 SemVer 关系 → [`docs/governance/change-tiers.md`](docs/governance/change-tiers.md)。
147
+ **Tier(影响面)**
144
148
 
145
- | Tier | 典型 | 文档要求 | 契约动作 |
146
- |---|---|---|---|
147
- | 0 trivial | typo / 格式化 / patch 升级 / 补测试 | PR title + 1-2 行描述 | 不动 |
148
- | 1 bugfix | 修 NPE / SQL / UI 错位(无新行为) | PR 描述:重现 + 根因 + 修复 + 回归测试 | 不动 |
149
- | 2 small | 加按钮 / 排序 / 文案 / 配置项 | PR 描述(动机 + 方案 + 影响面) | 通常不动 |
150
- | 3 contract | 加 API / 字段 / 错误码 / 事件 / 状态 | 简短设计章节进 `docs/04` 或 `docs/05` | **必须**先冻结契约 + CHANGELOG |
151
- | 4 arch | 跨服务 / 鉴权变化 / 删字段 / breaking | PRD(如来自需求)→ ADR → 详细设计 → 契约 → code | **必须** ADR + 契约 + 迁移说明 |
152
- | 5 spike | 探索 / 方案未明 | `spike/*` 分支自由探索 | 合入 `main` 前补到对应 tier |
149
+ | Tier | 典型 | 是否动契约 |
150
+ |---|---|---|
151
+ | 0 trivial | typo / 格式化 / patch 升级 / 补测试 | 不动 |
152
+ | 1 bugfix | 修 NPE / SQL / UI 错位(无新行为) | 不动 |
153
+ | 2 small | 加按钮 / 排序 / 文案 / 配置项 | 通常不动 |
154
+ | 3 contract | 加 API / 字段 / 错误码 / 事件 / 状态 | **必须**先冻结契约 + CHANGELOG |
155
+ | 4 arch | 跨服务 / 鉴权变化 / 删字段 / breaking | **必须** ADR + 契约 + 迁移说明 |
156
+ | 5 spike | 探索 / 方案未明 | `spike/*` 分支自由探索;合入前补到对应 tier |
153
157
 
154
158
  **判定**:改 `contracts/` → 至少 Tier 3;改鉴权 / 跨服务 / 删字段 → Tier 4;纯局部 → 0/1/2;探索 → 5。
155
159
 
156
- **AI 引用义务**(按 tier 升级):
157
- - Tier 0/1/2:PR 描述自身即方案记录,**不强制**引用契约或 ADR
158
- - Tier 3+:必须显式引用契约锚点(如 `contracts/openapi/api.yaml#/paths/~1users/post`)
159
- - Tier 4:必须引用 ADR / 详细设计文档
160
+ **Doc Weight(文档投入,AI 推荐 + 作者覆盖)**
161
+
162
+ | Tier | AI 默认推荐 | lite 时 | standard 加 | full 加 |
163
+ |---|---|---|---|---|
164
+ | 0/1/2 | **lite** | PR 描述(含动机 / 方案 / 影响面) | — | — |
165
+ | 3 contract | **lite**(关键) | PR 描述 + 契约 diff + CHANGELOG + 锚点 | 简短 04 / 05 设计(2-3 段) | + PRD(`docs/01/prd-<slug>.md`) |
166
+ | 4 arch | **standard** | PR 描述 + 契约 + ADR | 简化 04 / 05 + 迁移 / 回滚预案 | + PRD + UI 稿 |
167
+ | 5 spike | **lite** | spike 分支自由实验 | — | — |
168
+
169
+ > **关键**:Tier 3 的默认 doc weight 是 **lite**——契约 diff 本身就是设计真值,额外的中文设计文档反而易和契约漂移。复杂度高时(多状态机、跨服务、跨团队)作者主动升 standard / full。
170
+
171
+ **AI 引用义务**(按 Tier,与 Doc Weight 无关):
172
+ - Tier 0/1/2:PR 描述自身即方案记录,**不强制**引用契约 / ADR
173
+ - Tier 3+:commit / PR 必须显式引用契约锚点(如 `contracts/openapi/api.yaml#/paths/~1users/post`)
174
+ - Tier 4:必须引用 ADR;详细设计在 standard / full 时引用
160
175
 
161
176
  其他:
162
- - `spike/*` 分支允许暂时跳过契约(即 Tier 5);合入 `main` 前必须补齐到对应 tier
177
+ - `spike/*` 分支允许暂时跳过契约(即 Tier 5);合入 `main` 前必须补到对应 tier
163
178
  - 完整 PR 模板与 CODEOWNERS → [`docs/governance/git-workflow.md`](docs/governance/git-workflow.md)
164
179
  - 契约 SemVer / CHANGELOG / 废弃流程 → [`contracts/README.md`](contracts/README.md)
165
180
 
181
+
166
182
  ## 7. 按需加载索引
167
183
 
168
184
  ### 7.1 路径触发表
@@ -176,7 +192,8 @@
176
192
  | `docs/assets/**` 或根 `.gitattributes` | `docs/governance/assets.md` |
177
193
  | `ops/**` 或 `deploy/**` | `docs/governance/deploy-ops.md`、`docs/governance/security.md` |
178
194
  | `tools/**` 或 `scripts/**` | `docs/governance/tools-scripts.md` |
179
- <% if (it.options.ci === 'gitee') { %>| `.gitee/**` | `docs/governance/ci.md`、`docs/governance/security.md` |
195
+ <% if (it.options.database !== 'none') { %>| `server/db/**`(迁移 / 种子 / ES template / applier) | `docs/governance/database.md`、`contracts/dictionaries/`(如改字典 seed) |
196
+ <% } %><% if (it.options.ci === 'gitee') { %>| `.gitee/**` | `docs/governance/ci.md`、`docs/governance/security.md` |
180
197
  <% } else { %>| `.github/**` | `docs/governance/ci.md`、`docs/governance/security.md` |
181
198
  <% } %>
182
199
 
@@ -205,6 +222,7 @@
205
222
  | ops / deploy 完整规则 | [`docs/governance/deploy-ops.md`](docs/governance/deploy-ops.md) |
206
223
  | tools / scripts 完整规则 | [`docs/governance/tools-scripts.md`](docs/governance/tools-scripts.md) |
207
224
  | 变更分级(六档 Tier) | [`docs/governance/change-tiers.md`](docs/governance/change-tiers.md) |
225
+ | 数据库目录 / 迁移工具 / SQL 归属 | [`docs/governance/database.md`](docs/governance/database.md) |
208
226
  | 完整 checklist | [`docs/governance/checklists.md`](docs/governance/checklists.md) |
209
227
  | 治理细则索引 | [`docs/governance/README.md`](docs/governance/README.md) |
210
228
 
@@ -1,4 +1,77 @@
1
1
  # server/
2
2
 
3
- Python backend for **<%= it.options.projectName %>**. Contract-first; see
4
- `contracts/openapi/api.yaml` for the authoritative API definition.
3
+ Python backend for **<%= it.options.projectName %>**, built on **FastAPI**.
4
+
5
+ > Contract First:路由 / 请求体 / 响应体应当与 [`../contracts/openapi/api.yaml`](../contracts/openapi/api.yaml) 对齐。新增端点的工作流见根 `AGENTS.md` §6(变更分级)+ `docs/governance/change-tiers.md`:端点新增 / 字段新增是 Tier 3,必须先冻结 contracts 再写实现。
6
+
7
+ ## 目录布局
8
+
9
+ ```
10
+ server/
11
+ ├── pyproject.toml # 依赖钉版本、ruff / mypy / pytest 配置
12
+ ├── app/
13
+ │ ├── __init__.py # re-export `app` 给 `python -m app`
14
+ │ ├── main.py # FastAPI 实例 + /healthz + CORS
15
+ │ └── config.py # pydantic-settings;从环境 / .env 读配置
16
+ └── tests/
17
+ └── test_healthz.py # ASGI smoke test
18
+ ```
19
+
20
+ ## 工具与版本
21
+
22
+ | 项 | 值 |
23
+ |---|---|
24
+ | Python | 3.11+ |
25
+ | Framework | FastAPI `0.115.5` |
26
+ | ASGI server | uvicorn `0.32.0` |
27
+ | Validation | pydantic `2.9.2` + pydantic-settings `2.6.1` |
28
+ | Lint / format | ruff `0.6.8+` |
29
+ | Type check | mypy `1.11.0+`(strict-ish) |
30
+ | Test | pytest `8.3.0+` + pytest-asyncio + httpx |
31
+
32
+ 版本钉死见 `pyproject.toml`,并镜像到 `docs/03-工程规范与研发基础设施/tech-stack-server.md`。governance-lint 检测两边漂移并阻断 PR。
33
+
34
+ ## 常用命令
35
+
36
+ ```bash
37
+ # 创建虚拟环境 + 装依赖
38
+ python -m venv .venv && source .venv/bin/activate
39
+ pip install -e ".[dev]"
40
+
41
+ # 本地开发(热加载)
42
+ uvicorn app.main:app --reload --port 8000
43
+ # 浏览自动生成的 OpenAPI UI:http://127.0.0.1:8000/docs
44
+
45
+ # 测试 / lint / format / typecheck
46
+ pytest -q
47
+ ruff check .
48
+ ruff format --check .
49
+ mypy .
50
+
51
+ # 安全扫描
52
+ pip-audit
53
+ ```
54
+
55
+ ## 配置
56
+
57
+ 环境变量优先级:CLI / 容器注入 > `.env` 文件 > `app/config.py` 默认值。
58
+
59
+ | 变量 | 默认 | 说明 |
60
+ |---|---|---|
61
+ | `APP_NAME` | `<projectName>-server` | 显示在 OpenAPI title |
62
+ | `APP_VERSION` | `0.1.0` | 显示在 OpenAPI version |
63
+ | `CORS_ALLOW_ORIGINS` | `["http://localhost:5173","http://localhost:3000"]` | 逗号分隔;生产环境收紧 |
64
+
65
+ ## 部署
66
+
67
+ 打包 / 镜像 / 流水线归 `deploy/` 与 `ops/`,详见 [`../docs/governance/deploy-ops.md`](../docs/governance/deploy-ops.md)。最小生产命令示例:
68
+
69
+ ```bash
70
+ uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
71
+ ```
72
+
73
+ ## 与契约的同步
74
+
75
+ - API 端点:`contracts/openapi/api.yaml` → `app/main.py` 路由;改契约同 PR 改实现
76
+ - 字典 / 枚举:`contracts/dictionaries/enums.yaml`(如启用)→ Pydantic Enum
77
+ - 错误码:`contracts/errors/error-codes.yaml` → Exception → HTTP status 映射
@@ -1 +1,11 @@
1
- """Package marker. Implement per contracts/openapi/api.yaml."""
1
+ """<%= it.options.projectName %>-server.
2
+
3
+ Application package. Entry point: app.main:app
4
+ Run locally: `uvicorn app.main:app --reload`
5
+
6
+ Contract First:路由实现见 contracts/openapi/api.yaml;新端点先改契约再写代码。
7
+ """
8
+
9
+ from .main import app
10
+
11
+ __all__ = ["app"]