create-dp-koa 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/.cursor/rules/00-backend-core.skill.md +1 -1
- package/template/.cursor/rules/01-backend-skill-router.skill.md +8 -2
- package/template/.cursor/rules/10-backend-api.skill.md +8 -0
- package/template/.cursor/rules/11-backend-controller-recipes.skill.md +12 -9
- package/template/.cursor/rules/21-backend-service.skill.md +14 -0
- package/template/.cursor/rules/30-backend-validation.skill.md +1 -1
- package/template/.cursor/rules/40-backend-error-logging.skill.md +9 -5
- package/template/.cursor/rules/50-backend-bootstrap-lifecycle.skill.md +4 -4
- package/template/.cursor/rules/60-backend-router-registration.skill.md +16 -6
- package/template/.cursor/rules/70-backend-middleware.skill.md +2 -2
- package/template/.cursor/rules/80-backend-utils-and-libs.skill.md +71 -14
- package/template/.cursor/rules/85-backend-plugins.rule.md +4 -4
- package/template/.cursor/rules/90-backend-testing.skill.md +26 -0
- package/template/.cursor/rules/README.md +2 -2
- package/template/.trae/skills/11-backend-controller-recipes.skill.md +12 -9
- package/template/.trae/skills/21-backend-service.skill.md +15 -1
- package/template/.trae/skills/40-backend-error-logging.skill.md +9 -5
- package/template/.trae/skills/80-backend-utils-and-libs.skill.md +77 -8
- package/template/.trae/skills/90-backend-testing.skill.md +26 -0
- package/template/scripts/sync-template.mjs +20 -0
- package/template/src/app.ts +1 -2
- package/template/src/{framework/plugins → plugins}/registry.ts +2 -2
- package/template/src/plugins/weboffice/http/routes.ts +1 -1
- package/template/src/plugins/weboffice/index.ts +3 -3
- package/template/src/plugins/weboffice/services/webofficeCallback.service.ts +3 -4
- package/template/src/types/ctxState.ts +9 -0
- package/template/src/utils/testDataInitializer.ts +1 -1
- package/template/tsconfig.json +6 -0
- package/template/src/annotations/decorators/ConfigManagement.ts +0 -9
- package/template/src/annotations/decorators/DistributedTracing.ts +0 -9
- package/template/src/annotations/decorators/EnterprisePerformance.ts +0 -9
- package/template/src/annotations/decorators/PerformanceMonitor.ts +0 -32
- package/template/src/annotations/decorators/SecurityAudit.ts +0 -9
- package/template/src/annotations/index.ts +0 -50
- package/template/src/annotations/processors/ConfigManagementProcessor.ts +0 -369
- package/template/src/annotations/processors/DistributedTracingProcessor.ts +0 -288
- package/template/src/annotations/processors/EnterprisePerformanceProcessor.ts +0 -189
- package/template/src/annotations/processors/PerformanceMonitorProcessor.ts +0 -101
- package/template/src/annotations/processors/SecurityAuditProcessor.ts +0 -345
- package/template/src/annotations/processors/SwaggerProcessor.ts +0 -612
- package/template/src/annotations/processors/index.ts +0 -10
- package/template/src/examples/InterceptorExampleRunner.ts +0 -284
- package/template/src/examples/ServiceInterceptorExample.ts +0 -214
- package/template/src/examples/cacheExamples.ts +0 -155
- package/template/src/framework/decorator/controller.ts +0 -311
- package/template/src/framework/decorator/processor/AnnotationDecorators.ts +0 -100
- package/template/src/framework/decorator/processor/AnnotationProcessor.ts +0 -160
- package/template/src/framework/decorator/processor/AnnotationProcessorConfig.ts +0 -45
- package/template/src/framework/decorator/processor/AnnotationRegistry.ts +0 -117
- package/template/src/framework/decorator/processor/AnnotationSystemInitializer.ts +0 -95
- package/template/src/framework/decorator/processor/ProcessorManager.ts +0 -76
- package/template/src/framework/decorator/processor/processors/CustomProcessors.ts +0 -126
- package/template/src/framework/decorator/processor/processors/DefaultProcessors.ts +0 -207
- package/template/src/framework/decorator/refactored/DecoratorFactory.ts +0 -99
- package/template/src/framework/decorator/refactored/DecoratorMetadataManager.ts +0 -125
- package/template/src/framework/decorator/refactored/DecoratorValidator.ts +0 -128
- package/template/src/framework/decorator/refactored/TypeSafeDecorators.ts +0 -139
- package/template/src/framework/decorator/refactored/index.ts +0 -98
- package/template/src/framework/decorator/swagger.ts +0 -150
- package/template/src/framework/interceptors/AdvancedServiceCallInterceptor.ts +0 -375
- package/template/src/framework/interceptors/ServiceCallInterceptor.ts +0 -348
- package/template/src/framework/interceptors/index.ts +0 -19
- package/template/src/framework/plugins/types.ts +0 -15
- package/template/src/framework/types/ServiceResult.ts +0 -151
- package/template/src/framework/types/index.ts +0 -16
- package/template/src/framework/utils/CacheManager.ts +0 -430
- package/template/src/framework/utils/CacheService.ts +0 -248
- package/template/src/framework/utils/DtoValidator.ts +0 -164
- package/template/src/framework/utils/MigrationHelper.ts +0 -179
- package/template/src/framework/utils/MigrationManager.ts +0 -256
- package/template/src/framework/utils/NewRouter.ts +0 -207
- package/template/src/framework/utils/TransactionManager.ts +0 -172
- package/template/src/framework/utils/bootstrap.ts +0 -445
- package/template/src/framework/utils/cache.ts +0 -269
- package/template/src/framework/utils/databaseConfig.ts +0 -148
- package/template/src/framework/utils/db.ts +0 -39
- package/template/src/framework/utils/dbMonitor.ts +0 -106
- package/template/src/framework/utils/function.ts +0 -61
- package/template/src/framework/utils/gracefulShutdown.ts +0 -131
- package/template/src/framework/utils/logger.ts +0 -388
- package/template/src/framework/utils/metrics.ts +0 -182
- package/template/src/framework/utils/router.ts +0 -417
- package/template/src/framework/utils/swagger.ts +0 -184
- package/template/src/framework/utils/testDb.ts +0 -19
- package/template/src/framework/utils/token.ts +0 -23
- package/template/src/framework/utils/transform.ts +0 -17
- package/template/src/libs/aokEmailSender.ts +0 -42
- package/template/src/libs/captcha.ts +0 -37
- package/template/src/libs/cos.ts +0 -45
- package/template/src/libs/mCache.ts +0 -7
- package/template/src/libs/serviceValidate.ts +0 -3
- package/template/src/libs/tecentSms.ts +0 -51
- package/template/src/middlewares/a.middleware.ts +0 -6
- package/template/src/middlewares/error.middleware.ts +0 -14
- package/template/src/middlewares/logging.middleware.ts +0 -187
- package/template/src/middlewares/static.middleware.ts +0 -79
- package/template/src/middlewares/swagger.middleware.ts +0 -70
- package/template/src/middlewares/token.middleware.ts +0 -32
- package/template/src/migrations/1700000000000-InitialDatabaseStructure.ts +0 -172
- package/template/src/migrations/index.ts +0 -6
- package/template/src/repository/base/BaseRepository.ts +0 -124
- package/template/src/repository/interfaces/IBaseRepository.ts +0 -67
- package/template/src/service/base.service.ts +0 -116
|
@@ -43,13 +43,14 @@ export class BaseController {
|
|
|
43
43
|
#### 1.1.2 `@State()`:读取整段 `ctx.state`
|
|
44
44
|
|
|
45
45
|
```ts
|
|
46
|
-
import { Get, State } from '
|
|
46
|
+
import { Get, State } from 'dp-koa-framework-core';
|
|
47
47
|
import { BaseController, ControllerResponse } from '@src/controllers/base.controller';
|
|
48
|
+
import type { AppCtxState } from '@src/types/ctxState';
|
|
48
49
|
|
|
49
50
|
export class ExampleStateController extends BaseController {
|
|
50
51
|
@Get('/example/state-full')
|
|
51
52
|
async getWithFullState(
|
|
52
|
-
@State() state:
|
|
53
|
+
@State() state: AppCtxState,
|
|
53
54
|
): Promise<ControllerResponse<{ userId: number }>> {
|
|
54
55
|
return this.success({ userId: state.user.userId });
|
|
55
56
|
}
|
|
@@ -59,13 +60,14 @@ export class ExampleStateController extends BaseController {
|
|
|
59
60
|
#### 1.1.3 `@State('user')`:只读 `ctx.state.user`
|
|
60
61
|
|
|
61
62
|
```ts
|
|
62
|
-
import { Get, State } from '
|
|
63
|
+
import { Get, State } from 'dp-koa-framework-core';
|
|
63
64
|
import { BaseController, ControllerResponse } from '@src/controllers/base.controller';
|
|
65
|
+
import type { UserState } from '@src/types/ctxState';
|
|
64
66
|
|
|
65
67
|
export class ExampleUserSliceController extends BaseController {
|
|
66
68
|
@Get('/example/state-user')
|
|
67
69
|
async getWithUser(
|
|
68
|
-
@State('user') user:
|
|
70
|
+
@State('user') user: UserState,
|
|
69
71
|
): Promise<ControllerResponse<{ ok: boolean }>> {
|
|
70
72
|
return this.success({ ok: user.userId > 0 });
|
|
71
73
|
}
|
|
@@ -75,8 +77,9 @@ export class ExampleUserSliceController extends BaseController {
|
|
|
75
77
|
#### 1.1.4 `@ResponseValidateIf`:仅在条件成立时校验响应体
|
|
76
78
|
|
|
77
79
|
```ts
|
|
78
|
-
import { Get, State, ResponseValidateIf } from '
|
|
80
|
+
import { Get, State, ResponseValidateIf } from 'dp-koa-framework-core';
|
|
79
81
|
import { BaseController, ControllerResponse } from '@src/controllers/base.controller';
|
|
82
|
+
import type { AppCtxState } from '@src/types/ctxState';
|
|
80
83
|
|
|
81
84
|
// 示例 DTO:按实际接口替换
|
|
82
85
|
class UserProfileResponseDto {
|
|
@@ -88,7 +91,7 @@ export class ExampleResponseValidateController extends BaseController {
|
|
|
88
91
|
@ResponseValidateIf(UserProfileResponseDto, (data) => Boolean(data && data.data))
|
|
89
92
|
@Get('/example/profile')
|
|
90
93
|
async getProfile(
|
|
91
|
-
@State() state:
|
|
94
|
+
@State() state: AppCtxState,
|
|
92
95
|
): Promise<ControllerResponse<UserProfileResponseDto | null>> {
|
|
93
96
|
return this.success({
|
|
94
97
|
id: state.user.userId,
|
|
@@ -102,13 +105,13 @@ export class ExampleResponseValidateController extends BaseController {
|
|
|
102
105
|
目标:DTO 入参 → 调用 Service → 统一响应(`success/fail`)→ try/catch + logger
|
|
103
106
|
|
|
104
107
|
```ts
|
|
105
|
-
import { Get, Post, Query, Body, State, ResponseCode, ResponseHeader } from '
|
|
108
|
+
import { Get, Post, Query, Body, State, ResponseCode, ResponseHeader } from 'dp-koa-framework-core';
|
|
106
109
|
import { BaseController, ControllerResponse } from '@src/controllers/base.controller';
|
|
107
110
|
import { Inject } from 'dp-ioc2';
|
|
108
|
-
import { logger } from '
|
|
111
|
+
import { logger } from 'dp-koa-framework-core';
|
|
109
112
|
import { SomeService } from '@src/service/some.service';
|
|
110
113
|
import { SomeQueryDto, SomeBodyDto } from '@src/dto/controller/xxx/some.controller.dto';
|
|
111
|
-
import { CommonServiceResultCode } from '
|
|
114
|
+
import { CommonServiceResultCode } from 'dp-koa-framework-core';
|
|
112
115
|
|
|
113
116
|
export class SomeController extends BaseController {
|
|
114
117
|
@Inject(SomeService)
|
|
@@ -132,4 +132,18 @@ alwaysApply: false
|
|
|
132
132
|
## 六、调用关系约束(必须)
|
|
133
133
|
- Controller 只能调用 Service 的公开方法,不应调用 Repository
|
|
134
134
|
- Service 不应调用 Controller,也不应依赖 Koa `Context`
|
|
135
|
-
- Service 之间如需调用,应通过依赖注入(`@Inject(OtherService)`),避免静态调用/循环依赖
|
|
135
|
+
- Service 之间如需调用,应通过依赖注入(`@Inject(OtherService)`),避免静态调用/循环依赖
|
|
136
|
+
- 禁止在 Service 内手动创建实例:
|
|
137
|
+
- ❌ 禁止 `new OtherService()` / `new XxxService()`(包括在方法内部临时 new)
|
|
138
|
+
- ❌ 禁止通过手写单例/缓存实例绕过 IoC 容器
|
|
139
|
+
- ✅ 必须依赖 dp-ioc2 在运行期注入(例如字段注入或构造注入)
|
|
140
|
+
- 推荐写法(字段注入示例):
|
|
141
|
+
```ts
|
|
142
|
+
import { Inject } from "dp-ioc2";
|
|
143
|
+
import { OtherService } from "./other.service";
|
|
144
|
+
|
|
145
|
+
export class MyService extends BaseService {
|
|
146
|
+
@Inject(OtherService)
|
|
147
|
+
private otherService!: OtherService;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
@@ -6,11 +6,15 @@ alwaysApply: false
|
|
|
6
6
|
## 一、错误处理
|
|
7
7
|
|
|
8
8
|
- 所有 async 方法必须 try/catch
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
-
|
|
9
|
+
- 业务错误(可预期、可分类):
|
|
10
|
+
- 主要在 **Service 层 catch 中**处理
|
|
11
|
+
- 返回 `CommonServiceResult.fail()/validationError/notFound/...`(由 Service 统一封装)
|
|
12
|
+
- 系统错误(不可预期、疑似异常):
|
|
13
|
+
- **必须记录日志(logger.error)**
|
|
14
|
+
- Service 层返回通用失败的 `CommonServiceResult.error(...)`
|
|
15
|
+
- 映射到 Controller:
|
|
16
|
+
- Controller 不应直接返回 `CommonServiceResult`
|
|
17
|
+
- Controller 必须把 Service 的 `CommonServiceResult` 通过 `this.success()/this.fail()` 映射为 `ControllerResponse`
|
|
14
18
|
|
|
15
19
|
---
|
|
16
20
|
|
|
@@ -5,7 +5,7 @@ alwaysApply: false
|
|
|
5
5
|
|
|
6
6
|
## 适用与触发(重要)
|
|
7
7
|
- 当需要新增/调整以下内容时启用本 Skill:
|
|
8
|
-
- `
|
|
8
|
+
- 共享适配/可抽包的代码(优先使用 `dp-koa-framework-libs`;仅临时代码可放业务模块内)
|
|
9
9
|
- `src/utils/**` 下的工具函数
|
|
10
10
|
- 业务模块内部的 `xxx.utils.ts`
|
|
11
11
|
|
|
@@ -19,9 +19,9 @@ alwaysApply: false
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## 二、共享适配/可抽包代码放什么(必须)
|
|
23
23
|
|
|
24
|
-
### 2.1
|
|
24
|
+
### 2.1 适合的内容
|
|
25
25
|
- **第三方服务适配/封装**:
|
|
26
26
|
- 如:短信服务封装、支付网关封装、HTTP SDK 封装等
|
|
27
27
|
- 对外暴露一个干净的接口:如 `sendSms(phone, templateId, params)`
|
|
@@ -30,15 +30,67 @@ alwaysApply: false
|
|
|
30
30
|
- **有内部状态或生命周期的组件**:
|
|
31
31
|
- 连接池包装器、复杂缓存管理器、网关客户端等
|
|
32
32
|
|
|
33
|
-
### 2.2
|
|
33
|
+
### 2.2 不适合放到共享适配层的内容
|
|
34
34
|
- 单一的小工具函数(字符串、日期、数字转换等)
|
|
35
35
|
- 强业务耦合的逻辑(如订单价格计算、业务规则判断)
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
### 2.3 框架库内置工具(缓存/短信/验证码等)(重点)
|
|
40
|
+
当你需要使用“框架已经内置好的工具”,优先直接从 `dp-koa-framework-libs` 导入稳定导出;其中**缓存**建议按业务通过 `createCache + CacheType` 创建你的“业务缓存”对象。
|
|
41
|
+
|
|
42
|
+
#### 2.3.1 缓存工具:用 `createCache` + `CacheType` 构建你的缓存
|
|
43
|
+
- 核心提供缓存工厂:`createCache(name, type, customConfig?)`(配合 `CacheType`)
|
|
44
|
+
- 你可以完全参考 `dp-koa-framework-libs/src/libs/mCache.ts`(1-8 行)的写法,在你自己的 `libs/` 里创建“业务自定义缓存对象”
|
|
45
|
+
- 注意:`name` 作为全局缓存标识,同名会复用已有缓存实例(避免重复创建)
|
|
46
|
+
- `CacheType` 用于选择默认 TTL/容量策略(来自 `dp-koa-framework-core` 缓存模块默认配置):
|
|
47
|
+
- `CacheType.USER`:用户缓存(默认 `stdTTL=1800` 秒,`maxKeys=500`)
|
|
48
|
+
- `CacheType.CONTROLLER`:控制器结果缓存(默认 `stdTTL=60` 秒,`maxKeys=2000`)
|
|
49
|
+
- `CacheType.SESSION`:会话缓存(默认 `stdTTL=3600` 秒,`maxKeys=1000`)
|
|
50
|
+
- `CacheType.CAPTCHA`:验证码缓存(默认 `stdTTL=300` 秒,`maxKeys=100`)
|
|
51
|
+
- `CacheType.TEMP`:临时缓存(默认 `stdTTL=60` 秒,`maxKeys=100`)
|
|
52
|
+
- `customConfig` 的行为:会在“默认配置(DEFAULT_CACHE_CONFIG)+ CacheType 配置”基础上进行合并,从而覆盖 `stdTTL/maxKeys/checkperiod/...` 等参数
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { createCache, CacheType } from "dp-koa-framework-core";
|
|
56
|
+
|
|
57
|
+
// 例:给当前业务域创建一个“用户缓存”
|
|
58
|
+
export const myUserCache = createCache("my-user", CacheType.USER, {
|
|
59
|
+
stdTTL: 600, // 10分钟过期(秒)
|
|
60
|
+
maxKeys: 500, // 用户缓存最大条目数
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
使用方式示例(以 `node-cache` 风格的 `get/set` 为准):
|
|
65
|
+
```ts
|
|
66
|
+
import { myUserCache } from "@src/libs/myUserCache"; // 示例:把 myUserCache 放到你的 libs 文件并导出
|
|
67
|
+
|
|
68
|
+
const cached = myUserCache.get(String(userId));
|
|
69
|
+
if (!cached) {
|
|
70
|
+
const value = await buildValue();
|
|
71
|
+
myUserCache.set(String(userId), value); // TTL 由 createCache 配置决定
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### 2.3.2 其它常用内置工具(快速导入)
|
|
76
|
+
- 验证码:`CaptchaGenerator`
|
|
77
|
+
- 短信:
|
|
78
|
+
- `TencentSms`(类)
|
|
79
|
+
- `tencentSms`(函数/实例)
|
|
80
|
+
- 邮件:`AokEmailSender`
|
|
81
|
+
- COS/文件:
|
|
82
|
+
- `isCosConfigured`
|
|
83
|
+
- `uploadToCos`
|
|
84
|
+
- `getFilePublicUrl`
|
|
85
|
+
- `webofficeCosKey`
|
|
86
|
+
- 通用业务校验:`ServiceValidate`
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 三、`src/utils/`** 放什么(必须)
|
|
40
91
|
|
|
41
92
|
### 3.1 适合放在 utils 的内容
|
|
93
|
+
|
|
42
94
|
- **与业务无关的纯函数工具**:
|
|
43
95
|
- 时间、字符串、数字处理
|
|
44
96
|
- 通用 Promise/重试/节流/防抖等
|
|
@@ -70,13 +122,13 @@ alwaysApply: false
|
|
|
70
122
|
新增工具/类库时,按以下顺序判断:
|
|
71
123
|
|
|
72
124
|
1. **是否依赖第三方服务/外部系统或有复杂状态?**
|
|
73
|
-
- 是 →
|
|
125
|
+
- 是 → 优先放共享适配层(`dp-koa-framework-libs` 或独立 npm 包)
|
|
74
126
|
2. **是否明显只服务某一个业务模块?**
|
|
75
127
|
- 是 → 放到该模块自己的 `xxx.utils.ts`
|
|
76
128
|
3. **是否 100% 纯函数、无状态且可跨多个模块复用?**
|
|
77
129
|
- 是 → 放到全局 `utils/`
|
|
78
130
|
4. **未来是否有机会抽为独立 npm 包?**
|
|
79
|
-
- 是 →
|
|
131
|
+
- 是 → 更倾向放共享适配层(`dp-koa-framework-libs` 或独立 npm 包)
|
|
80
132
|
|
|
81
133
|
---
|
|
82
134
|
|
|
@@ -87,4 +139,21 @@ alwaysApply: false
|
|
|
87
139
|
- 导出:优先导出类或工厂函数,如 `export class TencentSmsClient { ... }`
|
|
88
140
|
- `utils` 目录下:
|
|
89
141
|
- 文件名:`date.utils.ts` / `string.utils.ts` / `testDataInitializer.ts` 等
|
|
90
|
-
- 导出:纯函数 `export function xxx(...) { ... }`
|
|
142
|
+
- 导出:纯函数 `export function xxx(...) { ... }`
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 七、运行环境判定(必须)
|
|
147
|
+
|
|
148
|
+
应统一使用 `dp-koa-framework-core` 导出的**运行环境判定** API,避免散落 `NODE_ENV === 'production'` 判断。
|
|
149
|
+
|
|
150
|
+
| API | 含义 |
|
|
151
|
+
| ------------------------------ | -------------------------------------------------------- |
|
|
152
|
+
| `isDebug()` | `process.argv` 含 `--env=debug` 为 `true` |
|
|
153
|
+
| `getRuntimeEnvironmentLabel()` | `'development'`(debug)或 `'production'`(非 debug),用于日志/元数据 |
|
|
154
|
+
|
|
155
|
+
**约定**:
|
|
156
|
+
|
|
157
|
+
- **非 debug = 生产口径**(迁移、静态缓存策略、对外错误信息是否脱敏等)。
|
|
158
|
+
- **不要**单独用 `NODE_ENV` 替代上述判定;`NODE_ENV=test` 仅用于 Jest 等测试分支。
|
|
159
|
+
- 新增种子脚本若需读 `.env.development`,启动命令应带 `--env=debug`(与 `bootstrap` 一致)。
|
|
@@ -20,6 +20,32 @@ alwaysApply: false
|
|
|
20
20
|
- 测试必须相互独立
|
|
21
21
|
- 每个测试前重置数据
|
|
22
22
|
|
|
23
|
+
## 二.2 涉及数据库读写的 Service 测试:必须使用内存数据库
|
|
24
|
+
|
|
25
|
+
- 如果测试中调用的 Service(或其依赖)会发生数据库读写(查询/插入/更新/删除、事务、迁移/初始化等):
|
|
26
|
+
- 必须启用内存数据库模式:通过 `TestDatabaseHelper.initTestDatabase(...)` 初始化测试用 `DataSource`
|
|
27
|
+
- 必须在测试结束后清理:调用 `TestDatabaseHelper.cleanupTestDatabase()`(确保释放资源,并清理缓存)
|
|
28
|
+
- 禁止为了“方便”而只模拟数据:
|
|
29
|
+
- 不允许用简单对象/假 Repository 来替代数据库读写(会掩盖 SQL/实体映射/事务边界问题)
|
|
30
|
+
- 允许 mock 的范围:仅限非数据库行为(如外部 HTTP 调用、消息发送、第三方 SDK 等)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 二.1 测试是否发“真实 HTTP”(需要理解)
|
|
35
|
+
|
|
36
|
+
- `test/controllers/**`:Controller 单元测试
|
|
37
|
+
- 通常是 `new Controller()` 后直接调用 controller 方法
|
|
38
|
+
- 不会触发真实的 `app.listen` 端口监听
|
|
39
|
+
- 这是在验证“编排/返回结构/装饰器效果(mock 情况)”的正确性
|
|
40
|
+
|
|
41
|
+
- `test/plugins/**` / `test/integration/**`:路由/插件集成测试
|
|
42
|
+
- 会创建 `Koa` + `router`
|
|
43
|
+
- 通过 `supertest` 调用 `request(app.callback()).get/post/...`
|
|
44
|
+
- 走完整 Koa 路由链路,但仍是“in-memory callback”,**不需要也不建议**真实 `app.listen`
|
|
45
|
+
|
|
46
|
+
原则:
|
|
47
|
+
- 测试环境不要 `app.listen` 开端口(避免端口占用、慢、难复现)
|
|
48
|
+
|
|
23
49
|
---
|
|
24
50
|
|
|
25
51
|
## 三、测试文件结构
|
|
@@ -28,6 +28,21 @@ const EXCLUDED_SEGMENTS = new Set([
|
|
|
28
28
|
/** 仓库根下整目录排除 */
|
|
29
29
|
const EXCLUDED_TOP_LEVEL = new Set(['packages']);
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* 不同步到模板的相对路径前缀(相对仓库根)
|
|
33
|
+
* 目标:让脚手架模板不再携带框架实现快照(framework/libs 等),改为依赖 npm 包。
|
|
34
|
+
*/
|
|
35
|
+
const EXCLUDED_RELATIVE_PREFIXES = [
|
|
36
|
+
'src/framework/',
|
|
37
|
+
'src/libs/',
|
|
38
|
+
'src/annotations/',
|
|
39
|
+
'src/middlewares/',
|
|
40
|
+
'src/examples/',
|
|
41
|
+
'src/repository/',
|
|
42
|
+
'src/migrations/',
|
|
43
|
+
'src/service/',
|
|
44
|
+
];
|
|
45
|
+
|
|
31
46
|
// template 内部“必须保留”的文件(防止后续 sync-template 直接覆盖回旧实现)
|
|
32
47
|
// 相对路径以 DEST 为基准。
|
|
33
48
|
const PRESERVE_RELATIVE_PATHS = [
|
|
@@ -39,11 +54,16 @@ const PRESERVE_RELATIVE_PATHS = [
|
|
|
39
54
|
'src/controllers/example/ExampleController.ts',
|
|
40
55
|
'src/controllers/example/EnterpriseExampleController.ts',
|
|
41
56
|
'src/plugins/weboffice/http/routes.ts',
|
|
57
|
+
'src/plugins/registry.ts',
|
|
42
58
|
];
|
|
43
59
|
|
|
44
60
|
function shouldCopySource(absSrc, baseRoot) {
|
|
45
61
|
const rel = relative(baseRoot, absSrc);
|
|
46
62
|
if (!rel || rel === '.') return true;
|
|
63
|
+
const normalized = rel.replace(/\\/g, '/');
|
|
64
|
+
for (const prefix of EXCLUDED_RELATIVE_PREFIXES) {
|
|
65
|
+
if (normalized === prefix.slice(0, -1) || normalized.startsWith(prefix)) return false;
|
|
66
|
+
}
|
|
47
67
|
const parts = rel.split(/[/\\]/);
|
|
48
68
|
for (const p of parts) {
|
|
49
69
|
if (EXCLUDED_SEGMENTS.has(p)) return false;
|
package/template/src/app.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { DataSourceOptions } from "typeorm";
|
|
2
1
|
import {
|
|
3
2
|
bootstrap,
|
|
4
3
|
setAfterBootstrap,
|
|
@@ -30,7 +29,7 @@ import {
|
|
|
30
29
|
registerPluginRoutes,
|
|
31
30
|
runAfterBootstrapHooks,
|
|
32
31
|
runBeforeBootstrapHooks,
|
|
33
|
-
} from "@src/
|
|
32
|
+
} from "@src/plugins/registry";
|
|
34
33
|
import Koa from "koa";
|
|
35
34
|
import path from "path";
|
|
36
35
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type Koa from "koa";
|
|
2
2
|
import type Router from "koa-router";
|
|
3
|
-
import type { PluginDescriptor } from "
|
|
4
|
-
import { logger } from "
|
|
3
|
+
import type { PluginDescriptor } from "dp-koa-framework-core";
|
|
4
|
+
import { logger } from "dp-koa-framework-core";
|
|
5
5
|
|
|
6
6
|
// 示例插件(可按需添加/移除)
|
|
7
7
|
import { plugin as webofficePlugin } from "@src/plugins/weboffice";
|
|
@@ -3,7 +3,7 @@ import { Provider } from "dp-ioc2";
|
|
|
3
3
|
import { WebofficeCallbackService } from "../services/webofficeCallback.service";
|
|
4
4
|
import { parseWebOfficeContext } from "../core/context";
|
|
5
5
|
import { OK, WebOfficeError, ErrInvalidArguments } from "../core/errors";
|
|
6
|
-
import { logger } from "
|
|
6
|
+
import { logger } from "dp-koa-framework-core";
|
|
7
7
|
import path from "path";
|
|
8
8
|
import fs from "fs";
|
|
9
9
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type Router from "koa-router";
|
|
2
2
|
import type Koa from "koa";
|
|
3
|
-
import type { PluginDescriptor } from "
|
|
3
|
+
import type { PluginDescriptor } from "dp-koa-framework-core";
|
|
4
4
|
import { registerWebOfficeRoutes } from "./http/routes";
|
|
5
5
|
import { WebofficeFileEntity, WebofficeFileVersionEntity } from "./entities";
|
|
6
|
-
import { logger } from "
|
|
6
|
+
import { logger } from "dp-koa-framework-core";
|
|
7
7
|
|
|
8
8
|
export const plugin: PluginDescriptor = {
|
|
9
9
|
id: "weboffice",
|
|
10
10
|
displayName: "WPS WebOffice 示例插件",
|
|
11
|
-
enabled: (env) => env.WEBOFFICE_ENABLED !== "0",
|
|
11
|
+
enabled: (env: NodeJS.ProcessEnv) => env.WEBOFFICE_ENABLED !== "0",
|
|
12
12
|
|
|
13
13
|
onBeforeBootstrap(_app: Koa) {
|
|
14
14
|
logger.info('Plugin "weboffice" before bootstrap');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Injectable } from "dp-ioc2";
|
|
2
|
-
import { BaseService } from "
|
|
2
|
+
import { BaseService, logger } from "dp-koa-framework-core";
|
|
3
3
|
import { WebofficeFileEntity } from "../entities/webofficeFile.entity";
|
|
4
4
|
import { WebofficeFileVersionEntity } from "../entities/webofficeFileVersion.entity";
|
|
5
5
|
import {
|
|
@@ -18,8 +18,7 @@ import {
|
|
|
18
18
|
ErrInternalError,
|
|
19
19
|
} from "../core/errors";
|
|
20
20
|
import { normalizeWpsUserId } from "../core/utils";
|
|
21
|
-
import { getFilePublicUrl, isCosConfigured, uploadToCos, webofficeCosKey } from "
|
|
22
|
-
import { logger } from "@src/framework/utils/logger";
|
|
21
|
+
import { getFilePublicUrl, isCosConfigured, uploadToCos, webofficeCosKey } from "dp-koa-framework-libs";
|
|
23
22
|
import fs from "fs";
|
|
24
23
|
import { v4 as uuidv4 } from "uuid";
|
|
25
24
|
|
|
@@ -229,7 +228,7 @@ export class WebofficeCallbackService extends BaseService {
|
|
|
229
228
|
skip: offset,
|
|
230
229
|
take: limit,
|
|
231
230
|
});
|
|
232
|
-
return versions.map((v) => this.toGetFileReply(pair.file, v));
|
|
231
|
+
return versions.map((v: WebofficeFileVersionEntity) => this.toGetFileReply(pair.file, v));
|
|
233
232
|
}
|
|
234
233
|
|
|
235
234
|
async getFileVersion(
|
package/template/tsconfig.json
CHANGED
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
"@src/*": [
|
|
16
16
|
"./src/*"
|
|
17
17
|
],
|
|
18
|
+
"dp-koa-framework-core": [
|
|
19
|
+
"../../dp-koa-framework-core/dist/index.d.ts"
|
|
20
|
+
],
|
|
21
|
+
"dp-koa-framework-libs": [
|
|
22
|
+
"../../dp-koa-framework-libs/dist/index.d.ts"
|
|
23
|
+
]
|
|
18
24
|
},
|
|
19
25
|
"strictPropertyInitialization": false
|
|
20
26
|
},
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 企业级配置管理装饰器
|
|
3
|
-
*/
|
|
4
|
-
import { createAnnotationDecorator } from '@src/framework/decorator/processor/AnnotationDecorators';
|
|
5
|
-
import { ConfigManagementConfig } from '@src/annotations/processors/ConfigManagementProcessor';
|
|
6
|
-
|
|
7
|
-
export function ConfigManagement(config?: ConfigManagementConfig) {
|
|
8
|
-
return createAnnotationDecorator('ConfigManagement')(config);
|
|
9
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 企业级分布式追踪装饰器
|
|
3
|
-
*/
|
|
4
|
-
import { createAnnotationDecorator } from '@src/framework/decorator/processor/AnnotationDecorators';
|
|
5
|
-
import { TracingConfig } from '@src/annotations/processors/DistributedTracingProcessor';
|
|
6
|
-
|
|
7
|
-
export function DistributedTracing(config?: TracingConfig) {
|
|
8
|
-
return createAnnotationDecorator('DistributedTracing')(config);
|
|
9
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 企业级性能监控装饰器
|
|
3
|
-
*/
|
|
4
|
-
import { createAnnotationDecorator } from '@src/framework/decorator/processor/AnnotationDecorators';
|
|
5
|
-
import { PerformanceConfig } from '@src/annotations/processors/EnterprisePerformanceProcessor';
|
|
6
|
-
|
|
7
|
-
export function EnterprisePerformance(config?: PerformanceConfig) {
|
|
8
|
-
return createAnnotationDecorator('EnterprisePerformance')(config);
|
|
9
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { createAnnotationDecorator } from '@src/framework/decorator/processor/AnnotationDecorators';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 性能监控注解配置接口
|
|
5
|
-
*/
|
|
6
|
-
export interface PerformanceMonitorConfig {
|
|
7
|
-
/** 最大执行时间(毫秒) */
|
|
8
|
-
maxExecutionTime?: number;
|
|
9
|
-
/** 最大内存使用变化(MB) */
|
|
10
|
-
maxMemoryUsage?: number;
|
|
11
|
-
/** 是否启用详细日志 */
|
|
12
|
-
verbose?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 性能监控注解
|
|
17
|
-
* 用于监控方法执行性能,包括执行时间和内存使用
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* @PerformanceMonitor()
|
|
22
|
-
* async getData() {
|
|
23
|
-
* return { data: 'example' };
|
|
24
|
-
* }
|
|
25
|
-
*
|
|
26
|
-
* @PerformanceMonitor({ maxExecutionTime: 1000, maxMemoryUsage: 10 })
|
|
27
|
-
* async heavyOperation() {
|
|
28
|
-
* // 执行耗时操作
|
|
29
|
-
* }
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export const PerformanceMonitor = createAnnotationDecorator('PerformanceMonitor');
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 企业级安全审计装饰器
|
|
3
|
-
*/
|
|
4
|
-
import { createAnnotationDecorator } from '@src/framework/decorator/processor/AnnotationDecorators';
|
|
5
|
-
import { SecurityAuditConfig } from '@src/annotations/processors/SecurityAuditProcessor';
|
|
6
|
-
|
|
7
|
-
export function SecurityAudit(config?: SecurityAuditConfig) {
|
|
8
|
-
return createAnnotationDecorator('SecurityAudit')(config);
|
|
9
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 企业级业务层注解导出文件
|
|
3
|
-
* 统一导出所有自定义注解处理器和装饰器
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// 导出基础注解处理器
|
|
7
|
-
export { PerformanceMonitorProcessor } from './processors/PerformanceMonitorProcessor';
|
|
8
|
-
|
|
9
|
-
// 导出企业级注解处理器
|
|
10
|
-
export { EnterprisePerformanceProcessor } from './processors/EnterprisePerformanceProcessor';
|
|
11
|
-
export { SecurityAuditProcessor } from './processors/SecurityAuditProcessor';
|
|
12
|
-
export { DistributedTracingProcessor } from './processors/DistributedTracingProcessor';
|
|
13
|
-
export { ConfigManagementProcessor } from './processors/ConfigManagementProcessor';
|
|
14
|
-
|
|
15
|
-
// 导出基础注解装饰器
|
|
16
|
-
export { PerformanceMonitor, type PerformanceMonitorConfig } from './decorators/PerformanceMonitor';
|
|
17
|
-
|
|
18
|
-
// 导出企业级注解装饰器
|
|
19
|
-
export { EnterprisePerformance } from './decorators/EnterprisePerformance';
|
|
20
|
-
export { SecurityAudit } from './decorators/SecurityAudit';
|
|
21
|
-
export { DistributedTracing } from './decorators/DistributedTracing';
|
|
22
|
-
export { ConfigManagement } from './decorators/ConfigManagement';
|
|
23
|
-
|
|
24
|
-
// 导出类型定义
|
|
25
|
-
export type { PerformanceConfig } from './processors/EnterprisePerformanceProcessor';
|
|
26
|
-
export type { SecurityAuditConfig } from './processors/SecurityAuditProcessor';
|
|
27
|
-
export type { TracingConfig } from './processors/DistributedTracingProcessor';
|
|
28
|
-
export type { ConfigManagementConfig } from './processors/ConfigManagementProcessor';
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 获取所有业务层注解处理器
|
|
32
|
-
* 用于在注解系统初始化时注册
|
|
33
|
-
*/
|
|
34
|
-
export function getBusinessAnnotationProcessors() {
|
|
35
|
-
const {
|
|
36
|
-
PerformanceMonitorProcessor,
|
|
37
|
-
EnterprisePerformanceProcessor,
|
|
38
|
-
SecurityAuditProcessor,
|
|
39
|
-
DistributedTracingProcessor,
|
|
40
|
-
ConfigManagementProcessor
|
|
41
|
-
} = require('@src/annotations/processors');
|
|
42
|
-
|
|
43
|
-
return [
|
|
44
|
-
new PerformanceMonitorProcessor(),
|
|
45
|
-
new EnterprisePerformanceProcessor(),
|
|
46
|
-
new SecurityAuditProcessor(),
|
|
47
|
-
new DistributedTracingProcessor(),
|
|
48
|
-
new ConfigManagementProcessor()
|
|
49
|
-
];
|
|
50
|
-
}
|