@deepstorm/cli 0.11.0 → 0.11.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 (123) hide show
  1. package/README.md +8 -8
  2. package/dist/build-registry.js +11 -5
  3. package/dist/cli.js +839 -585
  4. package/dist/mcp/code-hosting/github.json +14 -1
  5. package/dist/mcp/docs-reference/context7.json +1 -10
  6. package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-read/SKILL.md +8 -5
  7. package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-write/SKILL.md +10 -8
  8. package/dist/mcp-skills/deepstorm-mcp-figma-read/SKILL.md +21 -20
  9. package/dist/mcp-skills/deepstorm-mcp-github-read/SKILL.md +17 -17
  10. package/dist/mcp-skills/deepstorm-mcp-github-write/SKILL.md +20 -20
  11. package/dist/mcp-skills/deepstorm-mcp-jira-read/SKILL.md +8 -8
  12. package/dist/mcp-skills/deepstorm-mcp-jira-write/SKILL.md +13 -12
  13. package/dist/mcp-skills/deepstorm-mcp-playwright-read/SKILL.md +10 -10
  14. package/dist/skills/atoll-ops/SKILL.md +4 -0
  15. package/dist/skills/reef-commit/SKILL.md +9 -5
  16. package/dist/skills/reef-commit/scripts/branch-check.mjs +5 -11
  17. package/dist/skills/reef-commit/scripts/check-openspec-status.mjs +6 -12
  18. package/dist/skills/reef-commit/scripts/collect-git-context.mjs +13 -11
  19. package/dist/skills/reef-gen-backend/variants/java/steps.md +7 -7
  20. package/dist/skills/reef-gen-backend/variants/nodejs/steps.md +7 -7
  21. package/dist/skills/reef-gen-backend/variants/python/steps.md +7 -7
  22. package/dist/skills/reef-gen-frontend/variants/angular/steps.md +5 -5
  23. package/dist/skills/reef-gen-frontend/variants/react/steps.md +6 -6
  24. package/dist/skills/reef-gen-frontend/variants/vue/steps.md +6 -6
  25. package/dist/skills/reef-harden/EXAMPLES.md +12 -10
  26. package/dist/skills/reef-harden/SKILL.md +6 -0
  27. package/dist/skills/reef-harden/scripts/find-change-dir.mjs +13 -13
  28. package/dist/skills/reef-pr/SKILL.md +7 -0
  29. package/dist/skills/reef-pr/scripts/create-pr.mjs +31 -29
  30. package/dist/skills/reef-scope/SKILL.md +6 -6
  31. package/dist/skills/reef-start/references/jira-start-subagent.md +7 -7
  32. package/dist/skills/reef-start/references/risk-routing-card.md +28 -25
  33. package/dist/skills/reef-start/references/stage-4-implementation.md +33 -21
  34. package/dist/skills/reef-start/references/superpowers-gate.md +9 -9
  35. package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/structured-output.md +2 -2
  36. package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/quick-reference.md +11 -0
  37. package/dist/skills/reef-style-backend/fragments/java/api-spec/jackson-polymorphism.md +36 -40
  38. package/dist/skills/reef-style-backend/fragments/java/api-spec/quick-reference.md +11 -10
  39. package/dist/skills/reef-style-backend/fragments/java/db-migration/liquibase/examples/database-migration.md +7 -7
  40. package/dist/skills/reef-style-backend/fragments/java/dependency-management/quick-reference.md +24 -21
  41. package/dist/skills/reef-style-backend/fragments/java/exception-handling/examples/error-code-enum.md +7 -7
  42. package/dist/skills/reef-style-backend/fragments/java/exception-handling/quick-reference.md +10 -8
  43. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/dto-mapper.md +2 -2
  44. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/service-entity.md +5 -5
  45. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/testing.md +1 -0
  46. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/quick-reference.md +12 -12
  47. package/dist/skills/reef-style-backend/fragments/java/orm/hibernate/quick-reference.md +13 -12
  48. package/dist/skills/reef-style-backend/fragments/java/security-redlines/quick-reference.md +11 -9
  49. package/dist/skills/reef-style-backend/fragments/java/test/data-jpa-test/quick-reference.md +7 -7
  50. package/dist/skills/reef-style-backend/fragments/java/test/junit5/quick-reference.md +6 -6
  51. package/dist/skills/reef-style-backend/fragments/java/test/spring-mvc-test/quick-reference.md +8 -8
  52. package/dist/skills/reef-style-backend/fragments/java/test/spring-service-test/quick-reference.md +8 -7
  53. package/dist/skills/reef-style-backend/fragments/nodejs/eslint-config.json +1 -4
  54. package/dist/skills/reef-style-backend/fragments/nodejs/nestjs-structure.md +9 -9
  55. package/dist/skills/reef-style-backend/fragments/python/alembic-migration/quick-reference.md +2 -1
  56. package/dist/skills/reef-style-backend/fragments/python/api-spec/quick-reference.md +10 -10
  57. package/dist/skills/reef-style-backend/fragments/python/dependency-management/quick-reference.md +24 -22
  58. package/dist/skills/reef-style-backend/fragments/python/exception-handling/quick-reference.md +10 -9
  59. package/dist/skills/reef-style-backend/fragments/python/fastapi-quick-reference/quick-reference.md +3 -0
  60. package/dist/skills/reef-style-backend/fragments/python/langchain/quick-reference.md +10 -7
  61. package/dist/skills/reef-style-backend/fragments/python/pytest-testing/quick-reference.md +2 -0
  62. package/dist/skills/reef-style-backend/fragments/python/ruff-mypy-toolchain/quick-reference.md +2 -0
  63. package/dist/skills/reef-style-backend/fragments/python/security-redlines/quick-reference.md +11 -9
  64. package/dist/skills/reef-style-backend/fragments/python/sqlalchemy-orm/quick-reference.md +3 -0
  65. package/dist/skills/reef-style-backend/variants/java/examples/code-wrapping.md +3 -4
  66. package/dist/skills/reef-style-backend/variants/java/quick-reference.md +31 -29
  67. package/dist/skills/reef-style-backend/variants/nodejs/examples/module-example.md +2 -8
  68. package/dist/skills/reef-style-backend/variants/nodejs/quick-reference.md +35 -36
  69. package/dist/skills/reef-style-backend/variants/python/quick-reference.md +32 -31
  70. package/dist/skills/reef-style-frontend/fragments/css/tailwind/quick-reference.md +9 -7
  71. package/dist/skills/reef-style-frontend/fragments/test/vitest/examples/testing.md +9 -4
  72. package/dist/skills/reef-style-frontend/fragments/test/vitest/quick-reference.md +4 -4
  73. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/examples/testing.md +135 -140
  74. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/quick-reference.md +32 -32
  75. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/examples/testing.md +161 -162
  76. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/quick-reference.md +42 -42
  77. package/dist/skills/reef-style-frontend/fragments/ts-config/strict/quick-reference.md +16 -10
  78. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/examples/ui-components.md +72 -87
  79. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/quick-reference.md +14 -10
  80. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/examples/ui-components.md +93 -111
  81. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/quick-reference.md +29 -33
  82. package/dist/skills/reef-style-frontend/fragments/ui-lib/primeng/examples/ui-components.md +14 -23
  83. package/dist/skills/reef-style-frontend/variants/angular/examples/code-wrapping.md +15 -17
  84. package/dist/skills/reef-style-frontend/variants/angular/examples/component-types-pipes.md +22 -5
  85. package/dist/skills/reef-style-frontend/variants/angular/examples/entity-types.md +52 -22
  86. package/dist/skills/reef-style-frontend/variants/angular/examples/forms-layer.md +17 -20
  87. package/dist/skills/reef-style-frontend/variants/angular/examples/service-routing.md +8 -11
  88. package/dist/skills/reef-style-frontend/variants/angular/quick-reference.md +27 -27
  89. package/dist/skills/reef-style-frontend/variants/react/examples/code-wrapping.md +14 -27
  90. package/dist/skills/reef-style-frontend/variants/react/examples/component-types-pipes.md +45 -52
  91. package/dist/skills/reef-style-frontend/variants/react/examples/entity-types.md +44 -44
  92. package/dist/skills/reef-style-frontend/variants/react/examples/forms-layer.md +56 -85
  93. package/dist/skills/reef-style-frontend/variants/react/examples/service-routing.md +114 -88
  94. package/dist/skills/reef-style-frontend/variants/react/quick-reference.md +48 -42
  95. package/dist/skills/reef-style-frontend/variants/vue/examples/code-wrapping.md +24 -43
  96. package/dist/skills/reef-style-frontend/variants/vue/examples/component-types-pipes.md +48 -49
  97. package/dist/skills/reef-style-frontend/variants/vue/examples/entity-types.md +45 -45
  98. package/dist/skills/reef-style-frontend/variants/vue/examples/forms-layer.md +64 -68
  99. package/dist/skills/reef-style-frontend/variants/vue/examples/service-routing.md +85 -84
  100. package/dist/skills/reef-style-frontend/variants/vue/quick-reference.md +46 -51
  101. package/dist/skills/reef-testcase/SKILL.md +19 -19
  102. package/dist/skills/reef-testcase/references/coverage-dimensions.md +8 -0
  103. package/dist/skills/reef-testcase/references/test-case-template.md +16 -16
  104. package/dist/skills/sweep-explore/SKILL.md +129 -100
  105. package/dist/skills/sweep-explore/references/explore-flow-template.md +9 -9
  106. package/dist/skills/sweep-init/SKILL.md +4 -0
  107. package/dist/skills/sweep-init/scripts/flow-selector.mjs +6 -11
  108. package/dist/skills/sweep-init/scripts/init-project.mjs +68 -51
  109. package/dist/skills/sweep-plan/references/test-flow-template.md +12 -6
  110. package/dist/skills/sweep-record/SKILL.md +38 -15
  111. package/dist/skills/sweep-run/SKILL.md +59 -50
  112. package/dist/skills/sweep-run/scripts/env-manager.mjs +4 -5
  113. package/dist/skills/sweep-run/scripts/flow-parser.mjs +7 -6
  114. package/dist/skills/sweep-run/scripts/flow-selector.mjs +4 -15
  115. package/dist/skills/sweep-run/scripts/generate-report.mjs +1 -2
  116. package/dist/skills/sweep-run/scripts/mcp-manager.mjs +107 -14
  117. package/dist/skills/sweep-run/scripts/spec-compiler.mjs +19 -9
  118. package/dist/skills/tide-discuss/references/checklists.md +32 -32
  119. package/dist/skills/tide-discuss/references/data-format.md +85 -77
  120. package/dist/skills/tide-discuss/references/prd-template.md +21 -19
  121. package/dist/skills/tide-discuss/references/publish-flow.md +30 -11
  122. package/dist/skills/tide-discuss/references/role-prompts.md +5 -5
  123. package/package.json +4 -3
@@ -6,19 +6,19 @@
6
6
 
7
7
  ## 速查
8
8
 
9
- | 场景 | 决策 |
10
- | --- | --- |
9
+ | 场景 | 决策 |
10
+ | --------------- | ---------------------------------------------------------------------------------------------- |
11
11
  | 新建 Controller | `@RestController` + `@RequestMapping("/api/v1/apps/{appId}/...")` + `@RequiredArgsConstructor` |
12
- | 新建 Service | `@Service` + `@Transactional` + `@RequiredArgsConstructor`,字段 `private final` |
13
- | 新建 Repository | 继承 `JpaRepository<Entity, Long>` |
14
- | 新建立方 DTO | 继承 `AbstractDto` 等基类或使用 `@Value` |
15
- | 新建写请求 | 独立 `record CreateRequest` / `UpdateRequest` |
16
- | 对象映射 | MapStruct `@Mapper(config = MapStructConfig.class)` |
17
- | 异常处理 | 使用项目自定义异常(`NotFoundException` 等) |
18
- | 多租户查询 | 禁止裸 `findById`,使用 `findByIdAndAppId`;禁止 `createNativeQuery` |
19
- | Controller 权限 | 写操作接口加 `@PreAuthorize("hasAuthority('...')")` |
20
- | 密码存储 | `BCryptPasswordEncoder` |
21
- | 弃用 API | 编译警告中的 `@Deprecated` API 在同一次 PR 中替换为新 API |
12
+ | 新建 Service | `@Service` + `@Transactional` + `@RequiredArgsConstructor`,字段 `private final` |
13
+ | 新建 Repository | 继承 `JpaRepository<Entity, Long>` |
14
+ | 新建立方 DTO | 继承 `AbstractDto` 等基类或使用 `@Value` |
15
+ | 新建写请求 | 独立 `record CreateRequest` / `UpdateRequest` |
16
+ | 对象映射 | MapStruct `@Mapper(config = MapStructConfig.class)` |
17
+ | 异常处理 | 使用项目自定义异常(`NotFoundException` 等) |
18
+ | 多租户查询 | 禁止裸 `findById`,使用 `findByIdAndAppId`;禁止 `createNativeQuery` |
19
+ | Controller 权限 | 写操作接口加 `@PreAuthorize("hasAuthority('...')")` |
20
+ | 密码存储 | `BCryptPasswordEncoder` |
21
+ | 弃用 API | 编译警告中的 `@Deprecated` API 在同一次 PR 中替换为新 API |
22
22
 
23
23
  ## 核心规范
24
24
 
@@ -4,13 +4,13 @@
4
4
 
5
5
  ## 速查
6
6
 
7
- | 场景 | 决策 |
8
- | --- | --- |
9
- | 新建实体 | 继承 `AbstractTenantAwareEntity` 或 `AbstractTenantAwareAuditable` |
10
- | 实体 `@Table` 命名 | 小写蛇形复数,如 `app_forms` |
11
- | 审计字段 | `createdById` 由 `AuditingEntityListener` 自动填充 |
12
- | 日志实体 | 继承 `LogEntry`(SINGLE_TABLE),不直接继承基类 |
13
- | `open-in-view` | 设为 `false` |
7
+ | 场景 | 决策 |
8
+ | ------------------ | ------------------------------------------------------------------ |
9
+ | 新建实体 | 继承 `AbstractTenantAwareEntity` 或 `AbstractTenantAwareAuditable` |
10
+ | 实体 `@Table` 命名 | 小写蛇形复数,如 `app_forms` |
11
+ | 审计字段 | `createdById` 由 `AuditingEntityListener` 自动填充 |
12
+ | 日志实体 | 继承 `LogEntry`(SINGLE_TABLE),不直接继承基类 |
13
+ | `open-in-view` | 设为 `false` |
14
14
 
15
15
  ## 概述
16
16
 
@@ -46,6 +46,7 @@ public class User extends AbstractAuditable {
46
46
  ```
47
47
 
48
48
  **规则:**
49
+
49
50
  - 继承正确的基类(参见「实体/DTO 层次」章节)
50
51
  - 三件套:`@Entity` + `@NoArgsConstructor(access = PROTECTED)`(final 字段加 `force = true`),`@Getter` 类级别或字段级别,`@SuperBuilder` 按需使用
51
52
  - `@Table(name = "...")` 命名:小写蛇形,复数
@@ -99,11 +100,11 @@ classDiagram
99
100
 
100
101
  ## 关系映射
101
102
 
102
- | 关系 | 注解 | Fetch 策略 | 使用场景 |
103
- |------|------|-----------|---------|
104
- | 多对一 | `@ManyToOne` | LAZY (默认) | 子→父引用 |
105
- | 一对多 | `@OneToMany` | LAZY (默认) | 父→子集合 |
106
- | 一对一 | `@OneToOne` | LAZY (显式) | 用户→档案 |
103
+ | 关系 | 注解 | Fetch 策略 | 使用场景 |
104
+ | ------ | ------------- | ----------- | --------- |
105
+ | 多对一 | `@ManyToOne` | LAZY (默认) | 子→父引用 |
106
+ | 一对多 | `@OneToMany` | LAZY (默认) | 父→子集合 |
107
+ | 一对一 | `@OneToOne` | LAZY (显式) | 用户→档案 |
107
108
  | 多对多 | `@ManyToMany` | LAZY (显式) | 用户→角色 |
108
109
 
109
110
  ## 查询
@@ -2,15 +2,15 @@
2
2
 
3
3
  ## 🔴 红线速查
4
4
 
5
- | 红线 | 禁止行为 | 正确做法 | 违反后果 |
6
- |------|---------|---------|---------|
7
- | 密码存储 | 明文存储密码 | `BCryptPasswordEncoder`(Spring Security) | P0 — 安全漏洞 |
8
- | SQL 拼接 | 字符串拼接 SQL | JPA `@Query` + 命名参数,或 QueryDSL/JPA Criteria | P0 — SQL 注入 |
9
- | 危险初始化 | `@PostConstruct` 中触发写操作 | 延迟到首次调用或独立 `@EventListener(ApplicationReadyEvent.class)` | P1 — 非预期行为 |
10
- | 硬编码密钥 | 代码中硬编码 API Key / Secret | 环境变量或 `application-{profile}.yml`(.env 不提交) | P0 — 凭据泄露 |
11
- | 敏感信息打印 | `System.out.println` 敏感数据 | 用 SLF4J,生产日志级别过滤敏感字段 | P1 — 信息泄露 |
12
- | 文件上传验证 | 无限制的文件上传 | 限制类型 + 大小 + 重命名 + 非 webroot 存储 | P1 — 任意文件上传 |
13
- | 不安全的反序列化 | 信任外部反序列化数据 | 验证输入类型 + 数字签名 + 白名单 | P1 — 远程代码执行 |
5
+ | 红线 | 禁止行为 | 正确做法 | 违反后果 |
6
+ | ---------------- | ----------------------------- | ------------------------------------------------------------------ | ----------------- |
7
+ | 密码存储 | 明文存储密码 | `BCryptPasswordEncoder`(Spring Security) | P0 — 安全漏洞 |
8
+ | SQL 拼接 | 字符串拼接 SQL | JPA `@Query` + 命名参数,或 QueryDSL/JPA Criteria | P0 — SQL 注入 |
9
+ | 危险初始化 | `@PostConstruct` 中触发写操作 | 延迟到首次调用或独立 `@EventListener(ApplicationReadyEvent.class)` | P1 — 非预期行为 |
10
+ | 硬编码密钥 | 代码中硬编码 API Key / Secret | 环境变量或 `application-{profile}.yml`(.env 不提交) | P0 — 凭据泄露 |
11
+ | 敏感信息打印 | `System.out.println` 敏感数据 | 用 SLF4J,生产日志级别过滤敏感字段 | P1 — 信息泄露 |
12
+ | 文件上传验证 | 无限制的文件上传 | 限制类型 + 大小 + 重命名 + 非 webroot 存储 | P1 — 任意文件上传 |
13
+ | 不安全的反序列化 | 信任外部反序列化数据 | 验证输入类型 + 数字签名 + 白名单 | P1 — 远程代码执行 |
14
14
 
15
15
  ## 🔴 红线详情
16
16
 
@@ -60,6 +60,7 @@ List<User> findByRawSQL(@Param("name") String name);
60
60
  ```
61
61
 
62
62
  **红线规则:**
63
+
63
64
  - Repository 中禁止使用 `+ name +` 拼接查询条件
64
65
  - 禁止 `createNativeQuery`(也绕过多租户过滤)
65
66
  - `@Query` 必须使用命名参数 `:paramName`,禁止使用 `?1` 位置参数
@@ -158,6 +159,7 @@ public static String maskPhone(String phone) {
158
159
  ```
159
160
 
160
161
  **红线规则:**
162
+
161
163
  - 禁止打印密码、Token、完整手机号、完整身份证号
162
164
  - DTO 中密码字段加 `@JsonIgnore` 或从响应 DTO 中排除
163
165
  - 禁止 `System.out.println` — 必须通过 SLF4J 日志框架
@@ -92,10 +92,10 @@ void should_findByEmail() {
92
92
 
93
93
  ## 关键规则
94
94
 
95
- | 场景 | 做法 |
96
- |------|------|
97
- | Repository 测试 | `@DataJpaTest` |
98
- | 测试数据库 | Testcontainers + `@ServiceConnection` |
99
- | 数据准备 | `entityManager.persistAndFlush()` 或 `@Sql` |
100
- | 多租户 | `findByIdAndAppId(id, appId)` **禁止裸 `findById`** |
101
- | 写操作 | `@Modifying` + 验证 `int updated` 返回值 |
95
+ | 场景 | 做法 |
96
+ | --------------- | --------------------------------------------------- |
97
+ | Repository 测试 | `@DataJpaTest` |
98
+ | 测试数据库 | Testcontainers + `@ServiceConnection` |
99
+ | 数据准备 | `entityManager.persistAndFlush()` 或 `@Sql` |
100
+ | 多租户 | `findByIdAndAppId(id, appId)` **禁止裸 `findById`** |
101
+ | 写操作 | `@Modifying` + 验证 `int updated` 返回值 |
@@ -9,13 +9,13 @@
9
9
 
10
10
  ## 基本注解
11
11
 
12
- | 注解 | 用途 |
13
- |------|------|
14
- | `@Test` | 标记测试方法,每个方法一个独立场景 |
12
+ | 注解 | 用途 |
13
+ | ------------- | ----------------------------------- |
14
+ | `@Test` | 标记测试方法,每个方法一个独立场景 |
15
15
  | `@BeforeEach` | 每个测试前执行(初始化、Mock 设置) |
16
- | `@AfterEach` | 每个测试后执行(清理资源) |
17
- | `@BeforeAll` | 所有测试前(static) |
18
- | `@AfterAll` | 所有测试后(static) |
16
+ | `@AfterEach` | 每个测试后执行(清理资源) |
17
+ | `@BeforeAll` | 所有测试前(static) |
18
+ | `@AfterAll` | 所有测试后(static) |
19
19
 
20
20
  ## AAA 模式
21
21
 
@@ -75,11 +75,11 @@ void should_return400_when_invalidInput() throws Exception {
75
75
 
76
76
  ## 关键规则
77
77
 
78
- | 场景 | 做法 |
79
- |------|------|
80
- | Controller 测试 | `@WebMvcTest` + `MockMvc` |
81
- | Service Mock | `@MockitoBean` |
82
- | 权限测试 | `@WithMockUser` + `authorities` |
83
- | JSON 验证 | `jsonPath("$.field").value(...)` |
84
- | 请求体 | `objectMapper.writeValueAsString(dto)` |
85
- | 异常路径 | Service 抛出异常,验证状态码 + message |
78
+ | 场景 | 做法 |
79
+ | --------------- | -------------------------------------- |
80
+ | Controller 测试 | `@WebMvcTest` + `MockMvc` |
81
+ | Service Mock | `@MockitoBean` |
82
+ | 权限测试 | `@WithMockUser` + `authorities` |
83
+ | JSON 验证 | `jsonPath("$.field").value(...)` |
84
+ | 请求体 | `objectMapper.writeValueAsString(dto)` |
85
+ | 异常路径 | Service 抛出异常,验证状态码 + message |
@@ -15,6 +15,7 @@ class UserServiceTest {
15
15
  ```
16
16
 
17
17
  > **⚠️ 何时用 `@SpringBootTest` vs `@ExtendWith(MockitoExtension.class)`**
18
+ >
18
19
  > - **数据库交互**(Repository / 事务)→ `@SpringBootTest`
19
20
  > - **纯业务逻辑**(计算、校验、映射)→ `MockitoExtension`(更快)
20
21
 
@@ -72,12 +73,12 @@ void should_rollback_on_failure() {
72
73
 
73
74
  ## 关键规则
74
75
 
75
- | 场景 | 做法 |
76
- |------|------|
77
- | 需要数据库交互 | `@SpringBootTest` + `TestEntityManager` |
78
- | 纯业务逻辑 | `@ExtendWith(MockitoExtension.class)` |
79
- | 测试隔离 | `@Transactional`(自动回滚) |
80
- | 测试配置 | `@ActiveProfiles("test")` |
81
- | 数据准备 | `entityManager.persistAndFlush()` 或 `@Sql` |
76
+ | 场景 | 做法 |
77
+ | -------------- | ------------------------------------------- |
78
+ | 需要数据库交互 | `@SpringBootTest` + `TestEntityManager` |
79
+ | 纯业务逻辑 | `@ExtendWith(MockitoExtension.class)` |
80
+ | 测试隔离 | `@Transactional`(自动回滚) |
81
+ | 测试配置 | `@ActiveProfiles("test")` |
82
+ | 数据准备 | `entityManager.persistAndFlush()` 或 `@Sql` |
82
83
 
83
84
  > **注意:** `@Transactional` 不回滚 `@PostConstruct` 和异步操作(`@Async`)中的操作。
@@ -10,10 +10,7 @@
10
10
  "sourceType": "module"
11
11
  },
12
12
  "plugins": ["@typescript-eslint/eslint-plugin"],
13
- "extends": [
14
- "plugin:@typescript-eslint/recommended",
15
- "plugin:prettier/recommended"
16
- ],
13
+ "extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
17
14
  "rules": {
18
15
  "@typescript-eslint/no-explicit-any": "error",
19
16
  "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
@@ -47,12 +47,12 @@ src/
47
47
 
48
48
  ## 命名规范
49
49
 
50
- | 类型 | 命名规则 | 示例 |
51
- |------|---------|------|
52
- | Module 类 | PascalCase + Module | `UsersModule` |
53
- | Controller 类 | PascalCase + Controller | `UsersController` |
54
- | Service 类 | PascalCase + Service | `UsersService` |
55
- | DTO 类 | PascalCase + Dto | `CreateUserDto` |
56
- | Module 目录 | kebab-case | `src/modules/user-roles/` |
57
- | DTO 文件 | kebab-case | `create-user-role.dto.ts` |
58
- | 配置键 | UPPER_SNAKE_CASE | `DATABASE_URL` |
50
+ | 类型 | 命名规则 | 示例 |
51
+ | ------------- | ----------------------- | ------------------------- |
52
+ | Module 类 | PascalCase + Module | `UsersModule` |
53
+ | Controller 类 | PascalCase + Controller | `UsersController` |
54
+ | Service 类 | PascalCase + Service | `UsersService` |
55
+ | DTO 类 | PascalCase + Dto | `CreateUserDto` |
56
+ | Module 目录 | kebab-case | `src/modules/user-roles/` |
57
+ | DTO 文件 | kebab-case | `create-user-role.dto.ts` |
58
+ | 配置键 | UPPER_SNAKE_CASE | `DATABASE_URL` |
@@ -45,7 +45,7 @@ alembic current
45
45
  """add user table
46
46
 
47
47
  Revision ID: abc123
48
- Revises:
48
+ Revises:
49
49
  Create Date: 2026-06-25 10:00:00
50
50
  """
51
51
  from alembic import op
@@ -71,6 +71,7 @@ def downgrade() -> None:
71
71
  ```
72
72
 
73
73
  **规范:**
74
+
74
75
  - 每个迁移文件只做**一件事**(一个表或一个字段变更)
75
76
  - `upgrade()` 和 `downgrade()` 必须互逆
76
77
  - `down_revision` 必须正确指向前一个迁移
@@ -2,17 +2,17 @@
2
2
 
3
3
  ## 速查
4
4
 
5
- | 场景 | 决策 |
6
- | --- | --- |
7
- | 资源路径 | 英文复数 kebab-case:`/api/v1/user-roles`,不用 camelCase |
8
- | 路径变量 | snake_case:`/api/v1/users/{user_id}` |
5
+ | 场景 | 决策 |
6
+ | ---------- | ------------------------------------------------------------------- |
7
+ | 资源路径 | 英文复数 kebab-case:`/api/v1/user-roles`,不用 camelCase |
8
+ | 路径变量 | snake_case:`/api/v1/users/{user_id}` |
9
9
  | 自定义动作 | 遵循 REST 语义;无法用标准 CRUD 时用 `@router.post("/{id}:action")` |
10
- | 查询参数 | snake_case:`?status=active&page=1&page_size=20` |
11
- | 统一响应体 | `response_model` + `ApiResponse[T]` / `PageResponse[T]` 包装 |
12
- | 版本策略 | URL path 前缀 `/api/v1/` |
13
- | 错误响应 | 统一 JSON:`{"code": "USER_001", "message": "...", "detail": {}}` |
14
- | OpenAPI | FastAPI 自动生成,配合 `summary` / `description` / `tags` |
15
- | 分页 | `page`(1-based) + `page_size`(默认 20,最大 100) |
10
+ | 查询参数 | snake_case:`?status=active&page=1&page_size=20` |
11
+ | 统一响应体 | `response_model` + `ApiResponse[T]` / `PageResponse[T]` 包装 |
12
+ | 版本策略 | URL path 前缀 `/api/v1/` |
13
+ | 错误响应 | 统一 JSON:`{"code": "USER_001", "message": "...", "detail": {}}` |
14
+ | OpenAPI | FastAPI 自动生成,配合 `summary` / `description` / `tags` |
15
+ | 分页 | `page`(1-based) + `page_size`(默认 20,最大 100) |
16
16
 
17
17
  ## 核心规范
18
18
 
@@ -2,17 +2,17 @@
2
2
 
3
3
  ## 速查
4
4
 
5
- | 场景 | 决策 |
6
- | --- | --- |
7
- | 包管理器 | `uv`(统一管理和运行) |
8
- | 声明依赖 | `uv add {package}` 或直接在 `pyproject.toml` 中声明 |
9
- | 版本声明 | 在 `pyproject.toml` 中指定主版本范围:`>=1.0,<2.0` |
10
- | 禁止通配符版本 | 禁止 `*` 或 `>=0.0.0` |
11
- | 禁止硬编码 | 禁止 `pip install package==1.0.0`(不可复现) |
12
- | 依赖分组 | `[project.dependencies]`(运行)+ `[project.optional-dependencies]`(dev) |
13
- | 锁定文件 | `uv.lock` — 提交到 Git |
14
- | CVE 检查 | `uv audit` 扫描已知漏洞 |
15
- | 版本升级 | 手动升级后运行 `uv lock` 更新锁定文件 |
5
+ | 场景 | 决策 |
6
+ | -------------- | -------------------------------------------------------------------------- |
7
+ | 包管理器 | `uv`(统一管理和运行) |
8
+ | 声明依赖 | `uv add {package}` 或直接在 `pyproject.toml` 中声明 |
9
+ | 版本声明 | 在 `pyproject.toml` 中指定主版本范围:`>=1.0,<2.0` |
10
+ | 禁止通配符版本 | 禁止 `*` 或 `>=0.0.0` |
11
+ | 禁止硬编码 | 禁止 `pip install package==1.0.0`(不可复现) |
12
+ | 依赖分组 | `[project.dependencies]`(运行)+ `[project.optional-dependencies]`(dev) |
13
+ | 锁定文件 | `uv.lock` — 提交到 Git |
14
+ | CVE 检查 | `uv audit` 扫描已知漏洞 |
15
+ | 版本升级 | 手动升级后运行 `uv lock` 更新锁定文件 |
16
16
 
17
17
  ## 核心规范
18
18
 
@@ -50,6 +50,7 @@ dev = [
50
50
  ```
51
51
 
52
52
  **规范:**
53
+
53
54
  - 运行依赖在 `[project.dependencies]` 中声明
54
55
  - 开发/测试依赖在 `[project.optional-dependencies]` 中分组
55
56
  - 每组使用语义化版本范围:`>=min,<max`
@@ -106,11 +107,11 @@ uv add fastapi
106
107
 
107
108
  ### 版本升级规则
108
109
 
109
- | 升级类型 | 操作 | 验证 |
110
- |---------|------|------|
111
- | Major 升级 | 手动升级,独立 PR | 需检查 breaking changes + API 兼容性 |
112
- | Minor 升级 | `uv lock --upgrade-package {pkg}` | 运行完整测试套件 |
113
- | Patch 升级 | `uv lock --upgrade-package {pkg}` | 运行测试 + lint |
110
+ | 升级类型 | 操作 | 验证 |
111
+ | ---------- | --------------------------------- | ------------------------------------ |
112
+ | Major 升级 | 手动升级,独立 PR | 需检查 breaking changes + API 兼容性 |
113
+ | Minor 升级 | `uv lock --upgrade-package {pkg}` | 运行完整测试套件 |
114
+ | Patch 升级 | `uv lock --upgrade-package {pkg}` | 运行测试 + lint |
114
115
 
115
116
  ### 安全审计
116
117
 
@@ -125,15 +126,16 @@ uv audit
125
126
  ```
126
127
 
127
128
  **规范:**
129
+
128
130
  - 每次 CI 中运行 `uv audit`
129
131
  - 紧急 CVE(CVSS >= 7.0):1 天内升级并验证
130
132
  - 无法立即升级时,加备注和缓解措施文档
131
133
 
132
134
  ### 已知 CVE 常见的 Python 包
133
135
 
134
- | 包 | 受影响版本 | 最低安全版本 |
135
- |---|----------|------------|
136
- | urllib3 | < 2.2.3 | >= 2.2.3 |
137
- | requests | < 2.32.0 | >= 2.32.0 |
138
- | Jinja2 | < 3.1.5 | >= 3.1.5 |
139
- | cryptography | < 43.0.1 | >= 43.0.1 |
136
+ | 包 | 受影响版本 | 最低安全版本 |
137
+ | ------------ | ---------- | ------------ |
138
+ | urllib3 | < 2.2.3 | >= 2.2.3 |
139
+ | requests | < 2.32.0 | >= 2.32.0 |
140
+ | Jinja2 | < 3.1.5 | >= 3.1.5 |
141
+ | cryptography | < 43.0.1 | >= 43.0.1 |
@@ -2,15 +2,15 @@
2
2
 
3
3
  ## 速查
4
4
 
5
- | 场景 | 决策 |
6
- | --- | --- |
7
- | 业务异常 | 继承 `AppError(HTTPException)`,含 `code` + `status_code` + `detail` |
8
- | 全局捕获 | `@app.exception_handler(AppError)` 统一处理 |
9
- | 错误响应 | `{"code": "USER_001", "message": "...", "detail": {}}` |
10
- | 错误码 | `{MODULE}_{NNN}` 枚举 |
11
- | 参数校验失败 | FastAPI 自动处理 `RequestValidationError` |
12
- | 未知异常 | 兜底 500 — `GENERIC_001`,记录完整 traceback |
13
- | Service 层异常 | 抛出 `AppError` 子类,不在 Router 中 try-catch |
5
+ | 场景 | 决策 |
6
+ | -------------- | -------------------------------------------------------------------- |
7
+ | 业务异常 | 继承 `AppError(HTTPException)`,含 `code` + `status_code` + `detail` |
8
+ | 全局捕获 | `@app.exception_handler(AppError)` 统一处理 |
9
+ | 错误响应 | `{"code": "USER_001", "message": "...", "detail": {}}` |
10
+ | 错误码 | `{MODULE}_{NNN}` 枚举 |
11
+ | 参数校验失败 | FastAPI 自动处理 `RequestValidationError` |
12
+ | 未知异常 | 兜底 500 — `GENERIC_001`,记录完整 traceback |
13
+ | Service 层异常 | 抛出 `AppError` 子类,不在 Router 中 try-catch |
14
14
 
15
15
  ## 核心规范
16
16
 
@@ -146,6 +146,7 @@ async def unexpected_error_handler(request: Request, exc: Exception):
146
146
  ```
147
147
 
148
148
  **规范:**
149
+
149
150
  - 不要在 Router 函数中写 try-except 包裹业务逻辑
150
151
  - 不要吞异常后返回 `None` 或空字典
151
152
  - 兜底 handler 必须 `logger.error(..., exc_info=True)`
@@ -17,6 +17,7 @@ async def list_users(
17
17
  ```
18
18
 
19
19
  **规范:**
20
+
20
21
  - 每个模块一个 `APIRouter`,在 `app/api/v1/__init__.py` 中 `include_router`
21
22
  - 路径用 kebab-case:`/api/v1/user-roles`,不用 `/api/v1/userRoles`
22
23
  - 路径变量用 snake_case:`/api/v1/users/{user_id}`
@@ -41,6 +42,7 @@ async def get_user(user_id: int): # ← 没有依赖注入
41
42
  ```
42
43
 
43
44
  **规范:**
45
+
44
46
  - Service 类使用 `__init__` 接收依赖,注册为 `Depends()`
45
47
  - 不要用全局单例模式
46
48
  - DAO / Repository 也通过 `Depends()` 注入到 Service
@@ -65,6 +67,7 @@ class UserResponse(BaseModel):
65
67
  ```
66
68
 
67
69
  **规范:**
70
+
68
71
  - Request Schema 用 `BaseModel`,加输入约束
69
72
  - Response Schema 用 `ConfigDict(from_attributes=True)` 以支持 ORM 序列化
70
73
  - CRUD 接口用 `Create*Request` / `Update*Request` / `*Response` 命名
@@ -7,6 +7,7 @@ LangChain 是 Python 生态中的 AI 集成框架,提供统一的 API 来调
7
7
  ## 核心概念
8
8
 
9
9
  ### ChatModel
10
+
10
11
  LangChain 的中央 API,用于与大语言模型交互。
11
12
 
12
13
  ```python
@@ -25,6 +26,7 @@ print(response.content)
25
26
  ```
26
27
 
27
28
  **最佳实践:**
29
+
28
30
  - `ChatOpenAI` / `ChatAnthropic` 在应用初始化时创建一次,通过依赖注入传递
29
31
  - 不要在每个请求中重新创建 LLM 实例
30
32
  - `temperature=0` 用于确定性结果,`temperature>0` 用于创意场景
@@ -65,6 +67,7 @@ llm_with_tools = llm.bind_tools([get_user_order])
65
67
  ```
66
68
 
67
69
  **最佳实践:**
70
+
68
71
  - `@tool` 的 docstring 会被模型理解,写清楚参数含义和返回值格式
69
72
  - 工具函数内部调用 Service 层,不在工具内写业务逻辑
70
73
  - `bind_tools([])` 传工具数组,不逐个 `.bind()` 调用
@@ -126,10 +129,10 @@ uv add chromadb tiktoken
126
129
 
127
130
  ## 常见坑
128
131
 
129
- | 场景 | 问题 | 正确做法 |
130
- |------|------|---------|
131
- | API Key 管理 | 硬编码在代码中 | 从 `os.getenv("OPENAI_API_KEY")` 读取 |
132
- | 每次请求新建 LLM | 性能差、连接池耗尽 | 应用启动时创建单例,通过 DI 注入 |
133
- | 工具函数逻辑过重 | 工具内包含全部业务逻辑 | 工具只做参数解析 + 调用 Service |
134
- | 忽略 `async` 支持 | LCEL 链中调同步 IO | 使用 `ainvoke()` 和 async retriever |
135
- | prompt 不设 system message | 模型行为不可控 | 始终设置 system message 定义角色和约束 |
132
+ | 场景 | 问题 | 正确做法 |
133
+ | -------------------------- | ---------------------- | -------------------------------------- |
134
+ | API Key 管理 | 硬编码在代码中 | 从 `os.getenv("OPENAI_API_KEY")` 读取 |
135
+ | 每次请求新建 LLM | 性能差、连接池耗尽 | 应用启动时创建单例,通过 DI 注入 |
136
+ | 工具函数逻辑过重 | 工具内包含全部业务逻辑 | 工具只做参数解析 + 调用 Service |
137
+ | 忽略 `async` 支持 | LCEL 链中调同步 IO | 使用 `ainvoke()` 和 async retriever |
138
+ | prompt 不设 system message | 模型行为不可控 | 始终设置 system message 定义角色和约束 |
@@ -14,6 +14,7 @@ tests/
14
14
  ```
15
15
 
16
16
  **规范:**
17
+
17
18
  - `tests/unit/` — 不依赖外部服务的纯逻辑测试
18
19
  - `tests/integration/` — 依赖数据库、HTTP 调用的测试
19
20
  - 测试文件以 `test_` 开头,函数以 `test_` 开头
@@ -40,6 +41,7 @@ async def user_service(db_session: AsyncSession):
40
41
  ```
41
42
 
42
43
  **规范:**
44
+
43
45
  - 测试用 `pytest-asyncio` 支持异步 fixture 和 test
44
46
  - fixture 只在 `conftest.py` 中定义,不在测试文件中
45
47
  - fixture 范围默认 `function`,仅共享资源用 `session` / `module`
@@ -31,6 +31,7 @@ line-ending = "lf"
31
31
  ```
32
32
 
33
33
  **规范:**
34
+
34
35
  - ruff 负责 lint(`ruff check`)和 format(`ruff format`)双重职责
35
36
  - 启用 `F` + `E` + `W` + `I` + `N` + `UP` + `B` 规则组
36
37
  - 行长度检查(`E501`)交给 black / ruff format,不在 lint 中重复
@@ -59,6 +60,7 @@ disallow_untyped_defs = false
59
60
  ```
60
61
 
61
62
  **规范:**
63
+
62
64
  - 生产代码使用 `strict = true`
63
65
  - 所有函数必须有类型注释
64
66
  - 测试文件放宽类型要求
@@ -2,15 +2,15 @@
2
2
 
3
3
  ## 🔴 红线速查
4
4
 
5
- | 红线 | 禁止行为 | 正确做法 | 违反后果 |
6
- |------|---------|---------|---------|
7
- | 密码存储 | 明文存储密码 | `hashlib` / `bcrypt` / `passlib` 哈希后存储 | P0 — 安全漏洞 |
8
- | SQL 拼接 | f-string / format 拼接 SQL | SQLAlchemy ORM 或 参数化查询 | P0 — SQL 注入 |
9
- | 硬编码密钥 | 代码中硬编码 Secret / Token | 环境变量 `os.getenv()` 或 `pydantic-settings` | P0 — 凭据泄露 |
10
- | 敏感信息打印 | `print()` 敏感数据 | `logging` + 脱敏 + 生产级别过滤 | P1 — 信息泄露 |
11
- | 输入验证缺失 | 不验证用户输入 | Pydantic model + 严格约束 | P1 — 注入/越权 |
12
- | 不安全的 CORS | `allow_origins=["*"]` | 明确指定允许源列表 | P1 — CORS 安全 |
13
- | 调试接口 | 生产暴露 `/docs` / 调试路由 | 根据环境变量控制开启 | P1 — 信息泄露 |
5
+ | 红线 | 禁止行为 | 正确做法 | 违反后果 |
6
+ | ------------- | --------------------------- | --------------------------------------------- | -------------- |
7
+ | 密码存储 | 明文存储密码 | `hashlib` / `bcrypt` / `passlib` 哈希后存储 | P0 — 安全漏洞 |
8
+ | SQL 拼接 | f-string / format 拼接 SQL | SQLAlchemy ORM 或 参数化查询 | P0 — SQL 注入 |
9
+ | 硬编码密钥 | 代码中硬编码 Secret / Token | 环境变量 `os.getenv()` 或 `pydantic-settings` | P0 — 凭据泄露 |
10
+ | 敏感信息打印 | `print()` 敏感数据 | `logging` + 脱敏 + 生产级别过滤 | P1 — 信息泄露 |
11
+ | 输入验证缺失 | 不验证用户输入 | Pydantic model + 严格约束 | P1 — 注入/越权 |
12
+ | 不安全的 CORS | `allow_origins=["*"]` | 明确指定允许源列表 | P1 — CORS 安全 |
13
+ | 调试接口 | 生产暴露 `/docs` / 调试路由 | 根据环境变量控制开启 | P1 — 信息泄露 |
14
14
 
15
15
  ## 🔴 红线详情
16
16
 
@@ -62,6 +62,7 @@ cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
62
62
  ```
63
63
 
64
64
  **红线规则:**
65
+
65
66
  - 禁止在 SQL 中使用 `f"..."` 或 `"".format()` 拼接用户输入
66
67
  - 优先使用 SQLAlchemy ORM 的查询构建器
67
68
  - 必须使用原生 SQL 时,必须使用参数化查询(`:name` 或 `%s`)
@@ -133,6 +134,7 @@ logger.info(f"User [id={user_id}] logged in")
133
134
  ```
134
135
 
135
136
  **红线规则:**
137
+
136
138
  - 禁止打印密码、Token、完整手机号、完整身份证号
137
139
  - 响应体中密码字段不输出(Pydantic `model_config` 排除或 response schema 中忽略)
138
140
  - 禁止 `print()` — 必须使用 `logging` 模块
@@ -27,6 +27,7 @@ class UserService:
27
27
  ```
28
28
 
29
29
  **规范:**
30
+
30
31
  - **强制**使用 `AsyncSession` + `async_sessionmaker`
31
32
  - 禁止同步 `Session` 或 `scoped_session`
32
33
  - `expire_on_commit=False` 避免 commit 后属性不可访问
@@ -52,6 +53,7 @@ class User(Base):
52
53
  ```
53
54
 
54
55
  **规范:**
56
+
55
57
  - **强制**使用 `Mapped` + `mapped_column`(v2.0 style)
56
58
  - 禁止旧版 `Column`(name, Type) 写法
57
59
  - 所有模型继承共享 `Base`
@@ -71,6 +73,7 @@ stmt = select(Post).options(joinedload(Post.author)).where(Post.id == post_id)
71
73
  ```
72
74
 
73
75
  **规范:**
76
+
74
77
  - 批量列表查询用 `selectinload()`(发出额外 IN 查询,对列表友好)
75
78
  - 单条查询用 `joinedload()`(JOIN 一次)
76
79
  - **禁止**在循环中逐条访问关联属性
@@ -185,7 +185,7 @@ Java 15+ 的 Text Block 用于嵌入 JSON / SQL / XML / 模板等 DSL。缩进
185
185
  ```java
186
186
  // ✅ opening """ 后直接换行,内容相对 opening 行缩进 4 格
187
187
  // ✅ closing """ 决定 stripIndent() 的公共缩进基线
188
- var json =
188
+ var json =
189
189
  """
190
190
  {
191
191
  "name": "example",
@@ -195,7 +195,7 @@ var json =
195
195
  """;
196
196
 
197
197
  // ✅ 嵌入 SQL:closing """ 与 SQL 内容的公共缩进最左列对齐
198
- var sql =
198
+ var sql =
199
199
  """
200
200
  SELECT u.id, u.name, r.role_name
201
201
  FROM users u
@@ -211,7 +211,7 @@ var message = """
211
211
  """.formatted(userName, orderId);
212
212
 
213
213
  // ✅ 空行可用 \s 占位避免 stripIndent 清空:
214
- var json =
214
+ var json =
215
215
  """
216
216
  {
217
217
  "title": "test",
@@ -228,4 +228,3 @@ var json =
228
228
  - 禁止 text block 与 `+` 拼接混用;需要变量替换统一用 `formatted()`
229
229
  - 短字符串(≤ 100 列单行)不使用 text block,直接使用普通字符串
230
230
  - `\s` 用于显式保留 text block 中的空行(避免 `stripIndent()` 把空行清空)
231
-