create-dp-koa 1.0.0 → 1.0.2

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 (82) hide show
  1. package/package.json +2 -2
  2. package/template/.cursor/commands/cheatsheet-backend-controller.md +45 -0
  3. package/template/.cursor/commands/implement-backend-api-controller.md +60 -0
  4. package/template/.cursor/commands/plan-backend.md +97 -0
  5. package/template/.cursor/rules/00-backend-core.skill.md +61 -0
  6. package/template/.cursor/rules/01-backend-skill-router.skill.md +57 -0
  7. package/template/.cursor/rules/10-backend-api.skill.md +55 -0
  8. package/template/.cursor/rules/11-backend-controller-recipes.skill.md +188 -0
  9. package/template/.cursor/rules/20-backend-repository.skill.md +25 -0
  10. package/template/.cursor/rules/21-backend-service.skill.md +137 -0
  11. package/template/.cursor/rules/25-backend-comments-and-doc.skill.md +98 -0
  12. package/template/.cursor/rules/30-backend-validation.skill.md +342 -0
  13. package/template/.cursor/rules/40-backend-error-logging.skill.md +21 -0
  14. package/template/.cursor/rules/50-backend-bootstrap-lifecycle.skill.md +105 -0
  15. package/template/.cursor/rules/60-backend-router-registration.skill.md +73 -0
  16. package/template/.cursor/rules/70-backend-middleware.skill.md +100 -0
  17. package/template/.cursor/rules/80-backend-utils-and-libs.skill.md +108 -0
  18. package/template/.cursor/rules/85-backend-plugins.rule.md +65 -0
  19. package/template/.cursor/rules/90-backend-testing.skill.md +29 -0
  20. package/template/.cursor/rules/README.md +49 -0
  21. package/template/.trae/skills/11-backend-controller-recipes.skill.md +91 -10
  22. package/template/scripts/sync-template.mjs +0 -1
  23. package/template/src/controllers/example/ExampleController.ts +14 -0
  24. package/template/src/entity/index.ts +1 -15
  25. package/template/src/framework/decorator/processor/AnnotationProcessor.ts +5 -1
  26. package/template/src/routers/index.ts +0 -35
  27. package/template/src/utils/testDataInitializer.ts +2 -269
  28. package/template/test/controllers/example/ExampleController.test.ts +29 -31
  29. package/template/test/framework/annotation/AnnotationDecorators.test.ts +15 -15
  30. package/template/test/framework/annotation/AnnotationExecutor.test.ts +27 -32
  31. package/template/test/framework/annotation/AnnotationProcessor.test.ts +25 -24
  32. package/template/test/framework/annotation/CustomProcessors.test.ts +15 -25
  33. package/template/test/framework/annotation/NewRouter.test.ts +9 -7
  34. package/template/test/framework/annotation/ProcessorManager.test.ts +14 -27
  35. package/template/test/framework/databaseConfig.test.ts +2 -2
  36. package/template/test/integration/integration.test.ts +15 -72
  37. package/template/src/controllers/cacheManagement.controller.ts +0 -131
  38. package/template/src/controllers/captcha.controller.ts +0 -57
  39. package/template/src/controllers/example/NewAnnotationExampleController.ts +0 -159
  40. package/template/src/controllers/example/SwaggerExampleController.ts +0 -205
  41. package/template/src/controllers/example/TransactionExample.controller.ts +0 -336
  42. package/template/src/controllers/health.controller.ts +0 -235
  43. package/template/src/controllers/home/register.controller.ts +0 -58
  44. package/template/src/controllers/home/ytGoods.controller.ts +0 -92
  45. package/template/src/controllers/home/ytShop.controller.ts +0 -135
  46. package/template/src/controllers/home/ytUser.controller.ts +0 -89
  47. package/template/src/controllers/logManagement.controller.ts +0 -396
  48. package/template/src/controllers/public/emailSend.controller.ts +0 -65
  49. package/template/src/controllers/public/ytUserAuth.controller.ts +0 -174
  50. package/template/src/controllers/testData.controller.ts +0 -253
  51. package/template/src/dto/controller/example/NewAnnotationExampleController.dto.ts +0 -73
  52. package/template/src/dto/controller/home/emailSend.controller.dto.ts +0 -40
  53. package/template/src/dto/controller/home/register.controller.dto.ts +0 -45
  54. package/template/src/dto/controller/home/ytGoods.controller.dto.ts +0 -55
  55. package/template/src/dto/controller/home/ytShop.controller.dto.ts +0 -69
  56. package/template/src/dto/controller/home/ytUser.controller.dto.ts +0 -44
  57. package/template/src/dto/controller/public/ytUserAuth.controller.dto.ts +0 -63
  58. package/template/src/dto/goods.dto.ts +0 -212
  59. package/template/src/dto/service/ytService.dto.ts +0 -13
  60. package/template/src/dto/user.dto.ts +0 -177
  61. package/template/src/entity/columnTypes.ts +0 -13
  62. package/template/src/entity/goodsImagesUnlockKey.entity.ts +0 -33
  63. package/template/src/entity/goodsUnlocker.entity.ts +0 -34
  64. package/template/src/entity/shop.entity.ts +0 -52
  65. package/template/src/entity/shopUser.entity.ts +0 -41
  66. package/template/src/entity/ytGoods.entity.ts +0 -94
  67. package/template/src/entity/ytUser.entity.ts +0 -96
  68. package/template/src/examples/SwaggerProcessorExample.ts +0 -169
  69. package/template/src/examples/TransactionManagerDemo.ts +0 -377
  70. package/template/src/framework/utils/dynamicSwagger.ts +0 -410
  71. package/template/src/repository/UserRepository.ts +0 -122
  72. package/template/src/service/paramValidateTest.service.ts +0 -139
  73. package/template/src/service/ytGoods.service.ts +0 -42
  74. package/template/src/service/ytShop.service.ts +0 -90
  75. package/template/src/service/ytUser.service.ts +0 -451
  76. package/template/src/test/swaggerParameterTest.ts +0 -90
  77. package/template/test/controllers/controllers.test.ts +0 -173
  78. package/template/test/controllers/example/NewAnnotationExampleController.test.ts +0 -200
  79. package/template/test/framework/TransactionManagerDemo.test.ts +0 -363
  80. package/template/test/service/business.test.ts +0 -87
  81. package/template/test/service/paramValidateTest.service.test.ts +0 -184
  82. package/template/test/service/ytUser.service.test.ts +0 -566
@@ -0,0 +1,105 @@
1
+ ---
2
+ alwaysApply: false
3
+ ---
4
+ # Skill:启动生命周期规范(setBeforeBootstrap / setAfterBootstrap)
5
+
6
+ ## 适用与触发(重要)
7
+ - 仅当需要修改/新增启动逻辑(`src/app.ts`)或框架启动流程(`src/framework/utils/bootstrap.ts`)时启用本 Skill。
8
+ - 触发口令建议:
9
+ - “请按 `50-backend-bootstrap-lifecycle.skill.md` 调整启动流程”
10
+
11
+ ---
12
+
13
+ ## 一、真实执行顺序(必须理解并遵守)
14
+ 以 `src/framework/utils/bootstrap.ts` 为准:
15
+
16
+ 1. `bootstrap()` 内部 **先执行** `beforeBootstraps(app)`(如果已注册)
17
+ 2. 然后框架挂载:CORS → 日志中间件 → 框架错误处理中间件 → `koaBody()`
18
+ 3. 然后挂载:`router.routes()/allowedMethods()` 并 `app.listen(...)`
19
+ 4. `listen` 成功后 **再执行** `afterBootstraps(app)`(如果已注册)
20
+
21
+ 结论:
22
+ - **before**:发生在“框架中间件/路由挂载/监听端口”之前
23
+ - **after**:发生在“监听端口成功”之后
24
+
25
+ ---
26
+
27
+ ## 二、setBeforeBootstrap(fn) 规范(必须)
28
+
29
+ ### 2.1 允许做的事情(推荐放这里)
30
+ - **注册必须最先执行的中间件**(例如静态资源 `staticMiddleware`)
31
+ - **完成路由注册/绑定**(例如调用 `Router()` 让 `bindRouter` 把 Controller 注册到 router)
32
+ - **初始化框架级系统**(例如注解系统初始化、配置系统初始化)
33
+ - **初始化数据库与依赖它的组件**
34
+ - 连接数据库(`initDb`)
35
+ - 设置 `transactionManager/migrationManager` 的 DataSource
36
+ - 生产环境迁移(如有)
37
+ - 内存库模式初始化测试数据(如有)
38
+
39
+ ### 2.1.1 环境变量文件与 `.env` 选择(对齐 `bootstrap.ts`)
40
+
41
+ - **与 `NODE_ENV` 解耦**:`bootstrap.ts` 最早加载的 `.env` 文件由 **`isDebug()`** 决定:
42
+ - `--env=debug` → `.env.development`
43
+ - 否则 → `.env.production`
44
+ - **本地开发**:`package.json` 的 `dev` 建议在 `node dist/main.js` 后追加 `--env=debug`,避免误加载生产 env。
45
+ - **生产部署**:进程**不要**带 `--env=debug`,否则迁移与脱敏等行为会按“调试口径”执行。
46
+
47
+ ### 2.1.2 数据库迁移触发时机(对齐 `app.ts`)
48
+
49
+ - 迁移执行条件以 **`!isDebug()`** 为准(非 debug 即跑迁移),与 `NODE_ENV` 解耦。
50
+ - 迁移类需**显式注册**到 DataSource(如 `src/migrations/index.ts` 导出 `APP_MIGRATIONS`),避免 webpack 单文件部署后无法按路径扫描迁移文件。
51
+
52
+ ### 2.2 必须遵守的约束
53
+ - 回调函数签名必须能接收 `app: Koa`(框架会 `beforeBootstraps(app)` 调用)
54
+ - **只注册一次**:项目当前实现中 `beforeBootstraps` 只有一个槽位,后注册会覆盖先注册
55
+ - 发生异常必须:
56
+ - 记录日志
57
+ - 抛出异常(让启动失败),避免“半初始化”状态继续运行
58
+
59
+ ### 2.3 禁止行为
60
+ - ❌ 在这里启动“永不结束的任务”阻塞启动(例如无限循环、长期 await 不返回)
61
+ - ❌ 在这里写业务逻辑(仅做启动编排/初始化)
62
+
63
+ ---
64
+
65
+ ## 三、setAfterBootstrap(fn) 规范(必须)
66
+
67
+ ### 3.1 允许做的事情(推荐放这里)
68
+ - **启动后台/周期性任务**(例如数据库连接监控 `dbMonitor.startMonitoring()`)
69
+ - **启动只依赖服务器已监听的组件**(例如需要对外暴露端口后再启动的探针/上报)
70
+ - **输出启动完成日志**、打印运行信息
71
+
72
+ ### 3.2 必须遵守的约束
73
+ - 回调函数签名必须能接收 `app: Koa`
74
+ - after 内部出错:
75
+ - 必须记录日志
76
+ - 不应静默失败(至少可观测);必要时应触发优雅退出策略(按项目约定)
77
+ - **只注册一次**:项目当前实现中 `afterBootstraps` 只有一个槽位,后注册会覆盖先注册
78
+
79
+ ### 3.3 禁止行为(强烈)
80
+ - ❌ 在 after 阶段新增路由/中间件/全局行为(会导致启动行为不可预测)
81
+ - 路由与中间件应在 before 阶段完成,保证一致性
82
+ - ❌ 在 after 阶段再做“数据库 schema 级别变更/迁移”等破坏性操作
83
+
84
+ ---
85
+
86
+ ## 四、`src/app.ts` 推荐写法(对齐范式)
87
+
88
+ ### 4.1 before 推荐结构
89
+ - 注册静态中间件(如需要最前置)
90
+ - 初始化注解系统
91
+ - 调用 `Router()` 完成 Controller→router 绑定
92
+ - 初始化数据库、迁移、测试数据、事务管理器 DataSource
93
+
94
+ ### 4.2 after 推荐结构
95
+ - 启动 dbMonitor 等后台任务
96
+ - 打印启动后日志
97
+
98
+ ---
99
+
100
+ ## 五、常见坑(必须避免)
101
+ - before/after **不是数组**,目前实现是单个槽位:多次调用会覆盖
102
+ - `Router()` 必须在 `app.use(router.routes())` 之前执行;因此应放在 before
103
+ - 若在 before 里注册中间件,其执行顺序会早于框架默认中间件(因为 before 先 `app.use`)
104
+
105
+
@@ -0,0 +1,73 @@
1
+ ---
2
+ alwaysApply: false
3
+ ---
4
+ # Skill:路由注册规范(routers/index.ts + bindRouter)
5
+
6
+ ## 适用与触发(重要)
7
+ - 仅当需要新增/修改路由绑定(`src/routers/index.ts`)或调整路由系统(`src/framework/utils/router.ts`)时启用本 Skill。
8
+ - 触发口令建议:
9
+ - “请按 `60-backend-router-registration.skill.md` 规范注册路由”
10
+
11
+ ---
12
+
13
+ ## 一、路由注册机制(必须理解)
14
+ 本项目路由注册入口:`src/routers/index.ts`
15
+ 路由绑定工具:`src/framework/utils/router.ts` 的 `bindRouter(...)`
16
+
17
+ ### 1.1 bindRouter(...) 的真实行为(以代码为准)
18
+ - 调用形式:
19
+ - `bindRouter(prefixPath, ControllerClass)`
20
+ - `bindRouter(prefixPath, middleware1, middleware2, ..., ControllerClass)`
21
+ - Controller 实例化:
22
+ - 由 `Provider<any>(ControllerClass)` 创建(依赖注入容器)
23
+ - 路由生成:
24
+ - 读取 Controller 上的 `@Get/@Post/@Put/@Del/@All` 装饰器元数据
25
+ - 将每个方法的 url 与 `prefixPath` 通过 `path.join` 拼接,并规范化为 `/`
26
+ - middleware 注入顺序:
27
+ - 传入的 middlewares 会按顺序对该 prefix 下的每个具体 `_url` 执行 `_router.use(_url, middleware)`
28
+ - 再注册对应 method 的路由处理函数(`_router.get/post/...`)
29
+ - 尾斜杠兼容:
30
+ - 若生成的 `_url` 以 `/` 结尾,会同时注册“去掉尾斜杠”的版本(避免 `/a/` 与 `/a` 不兼容)
31
+
32
+ ---
33
+
34
+ ## 二、`src/routers/index.ts` 注册规范(必须遵守)
35
+
36
+ ### 2.1 只做“路由绑定”
37
+ - `routers/index.ts` 只负责:
38
+ - 导入 Controller
39
+ - 选择是否需要 middlewares(鉴权/日志等)
40
+ - 调用 `bindRouter(prefix, ...middlewares, Controller)`
41
+ - 禁止在此文件写业务逻辑或数据库操作
42
+
43
+ ### 2.2 路由前缀命名(推荐统一)
44
+ 建议用“模块/领域 + 子模块 + 资源”的层级前缀,保持稳定:
45
+ - `"/public/..."`:公开接口(一般不加“认证/鉴权 middleware”)
46
+ - `"/home/..."`:业务接口(按需加“认证/鉴权 middleware”)
47
+ - `"/admin/..."`:管理接口(一般需要认证/鉴权;可在此基础上再加权限/审计中间件)
48
+ - `"/health"`:健康检查(通常不鉴权)
49
+ - `"/test"`:测试/调试接口(仅测试环境或内存库模式有效时暴露)
50
+
51
+ ### 2.3 middleware 使用规范(必须)
52
+ - 需要认证/鉴权的路由必须在 `bindRouter` 里显式挂“认证/鉴权 middleware”(名称不固定,以项目实际为准):
53
+ - 示例(本项目当前实现):`bindRouter("/home/user/yt_user", tokenMiddleware(), YtUserController);`
54
+ - middlewares 必须传“可执行的 koa middleware 函数”:
55
+ - 例如 `authMiddleware()` / `tokenMiddleware()`(注意是调用结果,而不是函数引用本身)
56
+ - middleware 顺序必须从“通用/鉴权”到“更具体/业务”:
57
+ - 例如:`authMiddleware()` → 其他业务中间件
58
+
59
+ ### 2.4 禁止重复绑定(必须)
60
+ - ❌ 禁止对同一个 `prefixPath + Controller` 重复调用 `bindRouter`
61
+ - 重复绑定会导致路由重复注册、重复执行中间件、行为不可预测
62
+
63
+ ### 2.5 尾斜杠(推荐)
64
+ - 推荐 `bindRouter` 的 `prefixPath` **不要以 `/` 结尾**,保持统一(除非明确需要)
65
+ - 若使用了尾斜杠,框架会额外注册无尾斜杠版本;应避免产生重复/歧义的路由
66
+
67
+ ---
68
+
69
+ ## 三、与启动流程的配合(必须)
70
+ - `Router()`(即 `src/routers/index.ts` 的默认导出函数)必须在 `app.use(router.routes())` 之前执行
71
+ - 因此通常应在 `setBeforeBootstrap(...)` 中调用(见 `50-backend-bootstrap-lifecycle.skill.md`)
72
+
73
+
@@ -0,0 +1,100 @@
1
+ ---
2
+ alwaysApply: false
3
+ ---
4
+ # Skill:中间件开发与注册规范(src/middlewares)
5
+
6
+ ## 适用与触发(重要)
7
+ - 仅当需要新增/修改中间件(`src/middlewares/*`)或调整中间件注册顺序(`src/framework/utils/bootstrap.ts`、`src/app.ts`、`src/routers/index.ts`)时启用本 Skill。
8
+ - 触发口令建议:
9
+ - “请按 `70-backend-middleware.skill.md` 新增/调整中间件”
10
+
11
+ ---
12
+
13
+ ## 一、目录与命名(必须)
14
+ - 中间件放在:`src/middlewares/`
15
+ - 文件名使用:`xxx.middleware.ts`
16
+ - 导出方式建议统一为“工厂函数返回 koa middleware”:
17
+ - `export default function xxxMiddleware(options?) { return async (ctx, next) => { ... } }`
18
+ - 或 `export const xxxMiddleware = (options?) => async (ctx, next) => { ... }`
19
+
20
+ ---
21
+
22
+ ## 二、已有中间件模式(对齐现状)
23
+ 请对齐本项目现有实现风格(不要臆造不存在的框架能力):
24
+ - `token.middleware.ts`:认证/鉴权类中间件(读取 Authorization Bearer token,验签后写入 `ctx.state.user`)
25
+ - `logging.middleware.ts`:请求链路日志/审计/性能(挂载 `ctx.logger`、`ctx.requestId`)
26
+ - `static.middleware.ts`:静态资源挂载(`koa-mount + koa-static`)
27
+ - `error.middleware.ts`:简单错误兜底(本项目框架层已有更强的 error middleware,谨慎重复)
28
+
29
+ ---
30
+
31
+ ## 三、中间件职责边界(必须)
32
+
33
+ ### 3.1 允许做的事
34
+ - **读取/设置 ctx 上下文**:如 `ctx.state.user`、`ctx.requestId`、`ctx.logger`
35
+ - **做鉴权/限流/审计/缓存/静态资源**等横切能力
36
+ - **按需提前返回**:例如鉴权失败时设置 `ctx.status` + `ctx.body` 并 `return`
37
+
38
+ ### 3.2 禁止做的事
39
+ - ❌ 在中间件里写业务逻辑(应下沉 Service/Controller)
40
+ - ❌ 在中间件里直接访问数据库(除非该中间件明确是“框架级基础设施”,且有清晰的性能与错误策略)
41
+ - ❌ 吞掉错误不抛出导致上层错误处理中间件失效(除非明确要拦截并返回标准错误响应)
42
+
43
+ ---
44
+
45
+ ## 四、错误处理规范(必须)
46
+ - 中间件必须遵循 “可观测 + 可恢复”:
47
+ - 能处理的错误:在当前中间件内返回明确的 `ctx.status`/`ctx.body`
48
+ - 不能处理的错误:记录日志后 `throw`,交给框架层错误处理中间件统一处理
49
+ - 鉴权类中间件建议:
50
+ - 缺 token:`401` + 明确 message
51
+ - token 无效/过期:`401` + 明确 message
52
+
53
+ ---
54
+
55
+ ## 五、ctx.state 与上下文规范(必须)
56
+ - 认证/鉴权类中间件必须把用户最小信息写入 `ctx.state.user`
57
+ - 推荐字段:`userId`、`type`(以项目实际 token payload 为准)
58
+ - Controller 读取用户信息应通过 `@State()` 或 `@State('user')`(由 Controller 规范约束)
59
+
60
+ ---
61
+
62
+ ## 六、注册位置与顺序(必须)
63
+
64
+ ### 6.1 全局中间件(bootstrap 阶段)
65
+ 在 `src/framework/utils/bootstrap.ts` 中,框架已注册:
66
+ - CORS
67
+ - loggingMiddleware / businessLoggingMiddleware / databaseLoggingMiddleware
68
+ - frameworkErrorMiddleware(框架级错误处理中间件)
69
+ - koaBody
70
+ - router.routes/allowedMethods
71
+
72
+ 当你需要新增“全局中间件”时:
73
+ - 只能在 **before 阶段**(`setBeforeBootstrap`)通过 `app.use(...)` 注册
74
+ - 并遵守 `50-backend-bootstrap-lifecycle.skill.md` 的 before/after 约束
75
+
76
+ ### 6.2 路由级中间件(bindRouter 阶段)
77
+ 在 `src/routers/index.ts` 中,通过:
78
+ - `bindRouter(prefix, middleware1, middleware2, Controller)`
79
+
80
+ 适用:
81
+ - 认证/鉴权(示例:当前项目为 `tokenMiddleware()`,未来名称可能变化)
82
+ - 某模块/某前缀下的专用拦截器
83
+
84
+ 顺序规则:
85
+ - 先认证/鉴权,再业务相关中间件
86
+
87
+ ---
88
+
89
+ ## 七、Swagger 中间件(当前暂不启用)
90
+ - 项目中存在 `swagger.middleware.ts`,但如果当前阶段“不需要 swagger”,不要在启动/路由中注册该中间件。
91
+
92
+ ---
93
+
94
+ ## 八、测试建议(可选但推荐)
95
+ - 单元测试优先覆盖:
96
+ - 鉴权中间件:缺 token / 无效 token / 有效 token 能写入 `ctx.state.user`
97
+ - 日志中间件:是否写入 `ctx.requestId`、是否脱敏 headers
98
+ - 静态中间件:prefix 正规化(`/static` vs `/static/`)
99
+
100
+
@@ -0,0 +1,108 @@
1
+ ---
2
+ alwaysApply: false
3
+ ---
4
+ # Skill:libs 与 utils 规划规范
5
+
6
+ ## 适用与触发(重要)
7
+ - 当需要新增/调整以下内容时启用本 Skill:
8
+ - `src/libs/**` 下的类库/适配层
9
+ - `src/utils/**` 下的工具函数
10
+ - 业务模块内部的 `xxx.utils.ts`
11
+
12
+ ---
13
+
14
+ ## 一、总体原则
15
+
16
+ - **libs**:更偏向“小框架 / 小 SDK / 第三方服务适配层”
17
+ - **utils**:更偏向“纯函数工具、小颗粒度无状态函数”
18
+ - 业务相关的工具优先放在**各自业务模块内**,而不是全局 `utils/`
19
+
20
+ ---
21
+
22
+ ## 二、`src/libs/**` 放什么(必须)
23
+
24
+ ### 2.1 适合放在 libs 的内容
25
+ - **第三方服务适配/封装**:
26
+ - 如:短信服务封装、支付网关封装、HTTP SDK 封装等
27
+ - 对外暴露一个干净的接口:如 `sendSms(phone, templateId, params)`
28
+ - **可抽成独立 npm 包的库**:
29
+ - 例如通用缓存实现、加解密库、统一重试器等
30
+ - **有内部状态或生命周期的组件**:
31
+ - 连接池包装器、复杂缓存管理器、网关客户端等
32
+
33
+ ### 2.2 不适合放在 libs 的内容
34
+ - 单一的小工具函数(字符串、日期、数字转换等)
35
+ - 强业务耦合的逻辑(如订单价格计算、业务规则判断)
36
+
37
+ ---
38
+
39
+ ## 三、`src/utils/**` 放什么(必须)
40
+
41
+ ### 3.1 适合放在 utils 的内容
42
+ - **与业务无关的纯函数工具**:
43
+ - 时间、字符串、数字处理
44
+ - 通用 Promise/重试/节流/防抖等
45
+ - **框架内的通用工具**:
46
+ - 例如:框架级测试数据初始化工具、通用校验帮助函数(若确实需要全局可见)
47
+
48
+ ### 3.2 不适合放在 utils 的内容
49
+ - 直接访问数据库的函数(应放 Service/Repository 或框架层 utils 内聚)
50
+ - 调用第三方 HTTP API 的函数(应放 libs 作为适配层)
51
+ - 仅服务单一业务模块的工具(应放在该模块内部的 `xxx.utils.ts`)
52
+
53
+ ---
54
+
55
+ ## 四、业务模块内的 utils(推荐)
56
+
57
+ - 用户模块示例:
58
+ - `src/service/user/user.utils.ts`
59
+ - 商品模块示例:
60
+ - `src/service/goods/goods.utils.ts`
61
+
62
+ 规则:
63
+ - 仅供本模块使用的业务工具函数,应优先放在模块自身的 utils 文件中
64
+ - 全局 `utils/` 仅存放 **跨模块通用** 的工具
65
+
66
+ ---
67
+
68
+ ## 五、如何决策“新代码放哪”(实用检查清单)
69
+
70
+ 新增工具/类库时,按以下顺序判断:
71
+
72
+ 1. **是否依赖第三方服务/外部系统或有复杂状态?**
73
+ - 是 → 优先放 `libs/`(适配层/小 SDK)
74
+ 2. **是否明显只服务某一个业务模块?**
75
+ - 是 → 放到该模块自己的 `xxx.utils.ts`
76
+ 3. **是否 100% 纯函数、无状态且可跨多个模块复用?**
77
+ - 是 → 放到全局 `utils/`
78
+ 4. **未来是否有机会抽为独立 npm 包?**
79
+ - 是 → 更倾向放 `libs/`
80
+
81
+ ---
82
+
83
+ ## 六、命名规范(推荐)
84
+
85
+ - `libs` 目录下:
86
+ - 文件名:`tecentSms.ts` / `mCache.ts` 等,体现“库/适配器”的语义
87
+ - 导出:优先导出类或工厂函数,如 `export class TencentSmsClient { ... }`
88
+ - `utils` 目录下:
89
+ - 文件名:`date.utils.ts` / `string.utils.ts` / `testDataInitializer.ts` 等
90
+ - 导出:纯函数 `export function xxx(...) { ... }`
91
+
92
+ ---
93
+
94
+ ## 七、框架级 `src/framework/utils/function.ts`(必须)
95
+
96
+ 本文件提供**运行环境判定**,全项目应统一使用,避免散落 `NODE_ENV === 'production'` 判断。
97
+
98
+ | API | 含义 |
99
+ |-----|------|
100
+ | `isDebug()` | `process.argv` 含 `--env=debug` 为 `true` |
101
+ | `getRuntimeEnvironmentLabel()` | `'development'`(debug)或 `'production'`(非 debug),用于日志/元数据 |
102
+
103
+ **约定**:
104
+
105
+ - **非 debug = 生产口径**(迁移、静态缓存策略、对外错误信息是否脱敏等)。
106
+ - **不要**单独用 `NODE_ENV` 替代上述判定;`NODE_ENV=test` 仅用于 Jest 等测试分支。
107
+ - 新增种子脚本若需读 `.env.development`,启动命令应带 `--env=debug`(与 `bootstrap` 一致)。
108
+
@@ -0,0 +1,65 @@
1
+ # 后端插件体系规范(dp-koa-framework 模板)
2
+
3
+ > 目标:让“独立功能体”以插件形式存在,可插拔、易维护、与宿主框架低耦合。
4
+
5
+ ---
6
+
7
+ ## 1. 插件的基本形态
8
+
9
+ - 插件统一放在 `src/plugins/<plugin-id>/` 目录下。
10
+ - 插件根目录只保留 `index.ts`(插件入口)。
11
+ - 插件入口必须导出一个 `PluginDescriptor`(见 `src/framework/plugins/types.ts`)。
12
+
13
+ 推荐目录结构:
14
+
15
+ - `src/plugins/<plugin-id>/index.ts`
16
+ - `src/plugins/<plugin-id>/core/`:类型、错误、上下文解析、纯函数工具
17
+ - `src/plugins/<plugin-id>/http/`:HTTP 路由入口(Koa Router)
18
+ - `src/plugins/<plugin-id>/entities/`:TypeORM 实体(插件自有表)
19
+ - `src/plugins/<plugin-id>/services/`:插件业务 Service
20
+ - `src/plugins/<plugin-id>/scripts/`:种子/运维脚本(可选)
21
+
22
+ ---
23
+
24
+ ## 2. 宿主与插件的依赖方向
25
+
26
+ ### 2.1 插件 → 宿主
27
+
28
+ - 插件内部业务代码应优先使用相对路径组织。
29
+ - 插件调用宿主业务能力(如用户、项目、权限)应通过 **plugin-api 门面层**(建议放在 `src/plugin-api/*`),避免直接 import 宿主 Service/Repository。
30
+
31
+ ### 2.2 宿主 → 插件
32
+
33
+ - 宿主禁止直接 import 插件 Service。
34
+ - 宿主感知插件能力应通过:
35
+ - 事件扩展点(emit + register handler)
36
+ - SPI(可替换实现:getXxxSpi + registerXxxSpi)
37
+
38
+ ---
39
+
40
+ ## 3. 插件注册与加载
41
+
42
+ - 插件注册表:`src/framework/plugins/registry.ts`
43
+ - 宿主启动接入点:`src/app.ts`
44
+ - beforeBootstrap:计算启用插件、执行插件 before hook、注册插件路由、合并插件实体后初始化 DB
45
+ - afterBootstrap:执行插件 after hook(定时任务/订阅等)
46
+
47
+ ---
48
+
49
+ ## 4. 插件数据库规范
50
+
51
+ - 插件自建表必须使用插件 ID 作为表名前缀(例如 `weboffice_files`、`weboffice_file_versions`)。
52
+ - 插件迁移原则上只操作自身前缀表,避免修改宿主核心表结构。
53
+
54
+ ---
55
+
56
+ ## 5. 示例插件:weboffice
57
+
58
+ 模板内置示例插件:`src/plugins/weboffice/`
59
+
60
+ - 通过 `WEBOFFICE_ENABLED` 环境变量控制启用(默认启用;设为 `0` 禁用)。
61
+ - 路由入口:`src/plugins/weboffice/http/routes.ts`
62
+ - 插件实体:`src/plugins/weboffice/entities/*`
63
+
64
+ > 注意:模板示例插件的 `getUsers` 为占位实现(不依赖宿主业务用户表)。真实业务接入时应改为通过 plugin-api 调宿主用户体系。
65
+
@@ -0,0 +1,29 @@
1
+ ---
2
+ alwaysApply: false
3
+ ---
4
+ # Skill:后端测试规范(Jest)
5
+
6
+ ## 一、测试基础
7
+
8
+ - 使用 Jest
9
+ - 使用 `TestDatabaseHelper` 管理测试数据库
10
+ - 使用 `Provider` 获取 Service 实例
11
+
12
+ ---
13
+
14
+ ## 二、测试要求
15
+
16
+ - 必须覆盖:
17
+ - 成功场景
18
+ - 失败场景
19
+ - 边界条件
20
+ - 测试必须相互独立
21
+ - 每个测试前重置数据
22
+
23
+ ---
24
+
25
+ ## 三、测试文件结构
26
+
27
+ - Controller:`test/controllers/**`
28
+ - Service:`test/service/**`
29
+ - Framework:`test/framework/**`
@@ -0,0 +1,49 @@
1
+ # Cursor Rules 索引(Backend Skills)
2
+
3
+ 本目录用于约束/引导 Cursor 在本项目中的后端代码生成与修改行为。
4
+
5
+ ## 使用建议(先选 Command,再选 Skill)
6
+ - **需要先规划再动手**:用 `.cursor/commands/plan-backend.md`
7
+ - **要写/改 Controller**:用 `.cursor/commands/implement-backend-api-controller.md`(并按需启用 `11-...` Recipes)
8
+ - **只想要 Controller 范式/注解速查**:用 `.cursor/commands/cheatsheet-backend-controller.md`
9
+
10
+ ## Skills 列表(按编号/作用域)
11
+
12
+ ### 00 - 核心约束(默认全局)
13
+ - **`00-backend-core.skill.md`**(alwaysApply: true)
14
+ - 分层架构(Controller/Service/Repository)
15
+ - 基类继承与统一响应结构(`BaseController.success/fail`、`CommonServiceResult`)
16
+ - **运行环境判定**:`isDebug()` / `getRuntimeEnvironmentLabel()`(与 `NODE_ENV` 解耦,详见该文件)
17
+
18
+ ### 10 - Controller / API(按需启用)
19
+ - **`10-backend-api.skill.md`**
20
+ - Controller 编排规则:DTO + Service 调用 + 统一响应映射 + try/catch
21
+ - **`11-backend-controller-recipes.skill.md`**
22
+ - Controller 推荐模板(可复制)+ 常用注解速查(@Query/@Body/@State/...)
23
+
24
+ ### 20~40 - 数据/校验/错误(按需启用)
25
+ - **`20-backend-repository.skill.md`**:Repository 使用与事务(`transactionManager.executeInTransaction`)
26
+ - **`30-backend-validation.skill.md`**:DTO 分层规范(Controller DTO / Service DTO)、命名规范、转换规范、参数校验(@ParamValidate)
27
+ - **`40-backend-error-logging.skill.md`**:错误处理与日志(try/catch、脱敏、上下文)
28
+
29
+ ### 50~70 - 启动/路由/中间件(按需启用)
30
+ - **`50-backend-bootstrap-lifecycle.skill.md`**
31
+ - `setBeforeBootstrap` / `setAfterBootstrap` 的职责与禁止项
32
+ - `.env` 选择、`isDebug()`、迁移与 webpack 显式注册迁移(`APP_MIGRATIONS`)
33
+ - **`60-backend-router-registration.skill.md`**
34
+ - `src/routers/index.ts` + `bindRouter` 的注册规范(前缀、middleware 顺序、禁止重复绑定)
35
+ - **`70-backend-middleware.skill.md`**
36
+ - `src/middlewares/*` 的中间件模式、错误处理、ctx.state 约定、注册位置与顺序
37
+
38
+ ### 80 - 工程结构(按需启用)
39
+ - **`80-backend-utils-and-libs.skill.md`**
40
+ - `src/libs` vs `src/utils` 的放置规则与决策清单
41
+ - `src/framework/utils/function.ts`:`isDebug()` / `getRuntimeEnvironmentLabel()` 约定
42
+
43
+ ### 90 - 测试(按需启用)
44
+ - **`90-backend-testing.skill.md`**
45
+ - Jest 测试结构与基本要求(配合 `TestDatabaseHelper`)
46
+
47
+
48
+
49
+
@@ -12,11 +12,91 @@ alwaysApply: false
12
12
 
13
13
  ## 一、写 Controller 的推荐范式(必须对齐)
14
14
 
15
- ### 1.1 参考样例(写代码前先对齐)
16
- - 推荐在实现前先对齐以下文件的写法(不要臆造新风格):
17
- - `src/controllers/example/NewAnnotationExampleController.ts`
18
- - `src/controllers/home/ytUser.controller.ts`
19
- - `src/controllers/base.controller.ts`
15
+ ### 1.1 内嵌参考样例(本 Skill 自包含)
16
+ 以下为从本项目常用写法整理的最小示例;**实现新接口时请先对齐本节的装饰器与类型风格**。若仓库中另有 `src/controllers/example/*` 等运行时代码,可作为补充参考,但**不必依赖**特定业务 Controller 文件是否存在。
17
+
18
+ #### 1.1.1 `BaseController` 与 `ControllerResponse`(统一响应)
19
+
20
+ ```ts
21
+ export class ControllerResponse<T> {
22
+ code = 0;
23
+ data: T | null = null;
24
+ message = '';
25
+
26
+ constructor(code: number, data: T | null, message?: string) {
27
+ this.code = code;
28
+ this.data = data;
29
+ if (message) this.message = message;
30
+ }
31
+ }
32
+
33
+ export class BaseController {
34
+ success<T>(data: T, message?: string) {
35
+ return new ControllerResponse<T>(0, data, message);
36
+ }
37
+ fail<T>(code: number, message?: string) {
38
+ return new ControllerResponse<T>(code, null, message);
39
+ }
40
+ }
41
+ ```
42
+
43
+ #### 1.1.2 `@State()`:读取整段 `ctx.state`
44
+
45
+ ```ts
46
+ import { Get, State } from '@src/framework/decorator/controller';
47
+ import { BaseController, ControllerResponse } from '@src/controllers/base.controller';
48
+
49
+ export class ExampleStateController extends BaseController {
50
+ @Get('/example/state-full')
51
+ async getWithFullState(
52
+ @State() state: { user: { userId: number; type?: number } },
53
+ ): Promise<ControllerResponse<{ userId: number }>> {
54
+ return this.success({ userId: state.user.userId });
55
+ }
56
+ }
57
+ ```
58
+
59
+ #### 1.1.3 `@State('user')`:只读 `ctx.state.user`
60
+
61
+ ```ts
62
+ import { Get, State } from '@src/framework/decorator/controller';
63
+ import { BaseController, ControllerResponse } from '@src/controllers/base.controller';
64
+
65
+ export class ExampleUserSliceController extends BaseController {
66
+ @Get('/example/state-user')
67
+ async getWithUser(
68
+ @State('user') user: { userId: number; type?: number },
69
+ ): Promise<ControllerResponse<{ ok: boolean }>> {
70
+ return this.success({ ok: user.userId > 0 });
71
+ }
72
+ }
73
+ ```
74
+
75
+ #### 1.1.4 `@ResponseValidateIf`:仅在条件成立时校验响应体
76
+
77
+ ```ts
78
+ import { Get, State, ResponseValidateIf } from '@src/framework/decorator/controller';
79
+ import { BaseController, ControllerResponse } from '@src/controllers/base.controller';
80
+
81
+ // 示例 DTO:按实际接口替换
82
+ class UserProfileResponseDto {
83
+ id!: number;
84
+ nickName!: string;
85
+ }
86
+
87
+ export class ExampleResponseValidateController extends BaseController {
88
+ @ResponseValidateIf(UserProfileResponseDto, (data) => Boolean(data && data.data))
89
+ @Get('/example/profile')
90
+ async getProfile(
91
+ @State() state: { user: { userId: number } },
92
+ ): Promise<ControllerResponse<UserProfileResponseDto | null>> {
93
+ return this.success({
94
+ id: state.user.userId,
95
+ nickName: 'demo',
96
+ });
97
+ }
98
+ }
99
+ ```
20
100
 
21
101
  ### 1.2 Controller 标准骨架(复制这个结构)
22
102
  目标:DTO 入参 → 调用 Service → 统一响应(`success/fail`)→ try/catch + logger
@@ -76,10 +156,10 @@ export class SomeController extends BaseController {
76
156
  - 读取 body 参数
77
157
  - 推荐写法:`@Body(SomeBodyDto) body: XxxBodyDto`
78
158
  - **`@State()`**:
79
- - 读取整个 `ctx.state`(样例:`ytUser.controller.ts`)
159
+ - 读取整个 `ctx.state`(样例:见 **1.1.2**)
80
160
  - 推荐写法:`@State() state: { user: { userId: number; type?: number } }`
81
161
  - **`@State('user')`**:
82
- - 读取 `ctx.state.user`(样例:`NewAnnotationExampleController.ts`)
162
+ - 读取 `ctx.state.user`(样例:见 **1.1.3**)
83
163
  - 推荐写法:`@State('user') user: { userId: number; type?: number }`
84
164
 
85
165
  禁止:
@@ -91,7 +171,7 @@ export class SomeController extends BaseController {
91
171
 
92
172
  ### 2.4 响应校验注解(进阶,按需)
93
173
  - **`@ResponseValidator(DtoClass, objectKey?)`**:对响应数据做校验
94
- - **`@ResponseValidateIf(DtoClass, fn)`**:仅当 fn 返回真时才校验(样例:`ytUser.controller.ts`)
174
+ - **`@ResponseValidateIf(DtoClass, fn)`**:仅当 fn 返回真时才校验(样例:见 **1.1.4**)
95
175
 
96
176
  ---
97
177
 
@@ -101,7 +181,8 @@ export class SomeController extends BaseController {
101
181
  - `@Get('/xxx') + @State('user')`(或 `@State()` 取整段 state)
102
182
 
103
183
  ### 3.2 带 body 的 POST 接口
104
- - `@Post('/xxx') + @Body(SomeBodyDto) body: DtSomeBodyDtoo + @ResponseCode(201)`
184
+ - `@Post('/xxx') + @Body(SomeBodyDto) body: SomeBodyDto + @ResponseCode(201)`
105
185
 
106
186
  ### 3.3 需要自定义 header
107
- - `@ResponseHeader('X-XXX', 'value')`
187
+ - `@ResponseHeader('X-XXX', 'value')`
188
+
@@ -22,7 +22,6 @@ const EXCLUDED_SEGMENTS = new Set([
22
22
  'coverage',
23
23
  '.git',
24
24
  '.DS_Store',
25
- '.cursor',
26
25
  '.idea',
27
26
  ]);
28
27