@fastcar/cli 0.1.1 → 0.1.3

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.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: fastcar-framework
3
- description: FastCar 是一个基于 TypeScript 的 Node.js 企业级应用开发框架,采用 IoC(控制反转)设计思想,提供模块化、可扩展的架构支持。Use when working with FastCar framework for: (1) Creating IoC-based Node.js applications, (2) Using dependency injection with decorators (@Component, @Service, @Autowired), (3) Building web APIs with @fastcar/koa, (4) Database operations with MySQL/MongoDB/Redis, (5) Setting up scheduled tasks or worker pools, (6) Managing application lifecycle and configuration, (7) Selecting and configuring project templates (web, rpc, cos, static, microservices), (8) Writing application.yml for different templates.
3
+ description: FastCar 是一个基于 TypeScript 的 Node.js 企业级应用开发框架,采用 IoC(控制反转)设计思想。Use when working with FastCar framework for: (1) Creating IoC-based Node.js applications, (2) Using dependency injection with decorators (@Component, @Service, @Autowired), (3) Building web APIs with @fastcar/koa, (4) Database operations with MySQL/MongoDB/Redis, (5) Setting up scheduled tasks or worker pools, (6) Managing application lifecycle and configuration.
4
4
  ---
5
5
 
6
6
  # FastCar Framework
7
7
 
8
- FastCar 是基于 TypeScript 的 Node.js 企业级应用开发框架,灵感来源于 Spring Boot,采用 IoC(控制反转)设计思想。
8
+ FastCar 是基于 TypeScript 的 Node.js 企业级应用开发框架,采用 IoC(控制反转)设计思想。
9
9
 
10
10
  ## 核心概念
11
11
 
@@ -15,32 +15,41 @@ FastCar 是基于 TypeScript 的 Node.js 企业级应用开发框架,灵感来
15
15
  |--------|------|------|
16
16
  | `@Application` | 入口应用类 | `@Application class App {}` |
17
17
  | `@Component` | 通用组件 | `@Component class UtilService {}` |
18
- | `@Service` | 服务层 | `@Service class UserService {}` |
19
- | `@Controller` | 控制器层 | `@Controller class UserController {}` |
20
- | `@Repository` | 数据访问层 | `@Repository class UserRepository {}` |
21
- | `@Autowired` | 依赖注入 | `@Autowired private userService!: UserService;` |
18
+ | `@Service` | 服务层 | `@Service class BizService {}` |
19
+ | `@Controller` | 控制器层 | `@Controller class ApiController {}` |
20
+ | `@Repository` | 数据访问层 | `@Repository class DataRepository {}` |
21
+ | `@Autowired` | 依赖注入 | `@Autowired private service!: BizService;` |
22
22
 
23
23
  ### 基础应用结构
24
24
 
25
25
  ```typescript
26
26
  import { FastCarApplication } from "@fastcar/core";
27
- import { Application, Autowired, Component, Service } from "@fastcar/core/annotation";
27
+ import { Application, Autowired, Component, Service, Controller } from "@fastcar/core/annotation";
28
28
 
29
29
  @Service
30
- class UserService {
31
- getUsers() { return [{ id: 1, name: "Alice" }]; }
30
+ class BizService {
31
+ getData() {
32
+ return [{ id: 1, name: "示例" }];
33
+ }
32
34
  }
33
35
 
34
36
  @Controller
35
- class UserController {
36
- @Autowired private userService!: UserService;
37
- getUsers() { return this.userService.getUsers(); }
37
+ class ApiController {
38
+ @Autowired
39
+ private service!: BizService;
40
+
41
+ getData() {
42
+ return this.service.getData();
43
+ }
38
44
  }
39
45
 
40
46
  @Application
41
47
  class App {
42
48
  app!: FastCarApplication;
43
- async start() { console.log("应用启动成功!"); }
49
+
50
+ async start() {
51
+ console.log("应用启动成功!");
52
+ }
44
53
  }
45
54
 
46
55
  const app = new App();
@@ -51,44 +60,167 @@ app.start();
51
60
 
52
61
  ### Web 开发 (@fastcar/koa)
53
62
 
63
+ **路由装饰器使用方式:**
64
+
54
65
  ```typescript
55
- import { GET, POST, REQUEST, Body, Param } from "@fastcar/koa/annotation";
66
+ import { GET, POST, REQUEST } from "@fastcar/koa/annotation";
56
67
 
57
- @Controller @REQUEST("/api/users")
58
- class UserController {
59
- @GET async list() { return { data: [] }; }
60
- @GET("/:id") async getById(@Param("id") id: string) { return { id }; }
61
- @POST async create(@Body user: UserDTO) { return { created: true }; }
68
+ @Controller
69
+ @REQUEST("/api/items")
70
+ class ItemController {
71
+ // GET 请求 - 无路径参数时必须有括号
72
+ @GET()
73
+ async list() {
74
+ return { data: [] };
75
+ }
76
+
77
+ // GET 请求 - 有路径参数
78
+ @GET("/:id")
79
+ async getById(id: string) {
80
+ return { id };
81
+ }
82
+
83
+ // POST 请求
84
+ @POST()
85
+ async create(body: ItemDTO) {
86
+ return { created: true };
87
+ }
62
88
  }
63
89
  ```
64
90
 
91
+ **⚠️ 重要:FastCar 没有 `@Body`, `@Param`, `@Query` 装饰器**
92
+
93
+ - 请求参数直接作为方法参数传入
94
+ - GET 请求参数通过方法参数直接获取
95
+ - POST 请求体通过 `body` 参数获取
96
+ - 路径参数通过方法参数直接获取
97
+
65
98
  ### 数据库 (@fastcar/mysql)
66
99
 
67
- ```typescript
68
- import { Repository, Table, Field, PrimaryKey, SqlSession } from "@fastcar/mysql/annotation";
100
+ **实体定义:**
69
101
 
70
- @Table("users")
71
- class User {
72
- @PrimaryKey @Field("id") id!: number;
73
- @Field("name") name!: string;
102
+ ```typescript
103
+ import { Table, Field, DBType, PrimaryKey, NotNull, Size } from "@fastcar/core/annotation";
104
+
105
+ @Table("entities")
106
+ class Entity {
107
+ @Field("id")
108
+ @DBType("int")
109
+ @PrimaryKey
110
+ id!: number;
111
+
112
+ @Field("name")
113
+ @DBType("varchar")
114
+ @NotNull
115
+ @Size({ maxSize: 50 })
116
+ name!: string;
74
117
  }
118
+ ```
119
+
120
+ **Mapper 定义:**
121
+
122
+ ```typescript
123
+ import { Entity, Repository } from "@fastcar/core/annotation";
124
+ import { MysqlMapper } from "@fastcar/mysql";
75
125
 
126
+ @Entity(Entity)
76
127
  @Repository
77
- class UserRepository {
78
- @SqlSession private session!: SqlSession;
79
- async findById(id: number) { return this.session.findById(User, id); }
128
+ class EntityMapper extends MysqlMapper<Entity> {}
129
+ export default EntityMapper;
130
+ ```
131
+
132
+ **Service 中使用:**
133
+
134
+ ```typescript
135
+ import { Service, Autowired } from "@fastcar/core/annotation";
136
+ import { OrderEnum } from "@fastcar/core/db";
137
+ import EntityMapper from "./EntityMapper";
138
+
139
+ @Service
140
+ class EntityService {
141
+ @Autowired
142
+ private mapper!: EntityMapper;
143
+
144
+ async getList() {
145
+ return this.mapper.select({
146
+ where: { status: 1 },
147
+ orders: { createTime: OrderEnum.desc },
148
+ limit: 10
149
+ });
150
+ }
151
+
152
+ async getOne(id: number) {
153
+ return this.mapper.selectOne({ where: { id } });
154
+ }
155
+
156
+ async create(data: Entity) {
157
+ return this.mapper.saveOne(data);
158
+ }
159
+
160
+ async update(id: number, data: Partial<Entity>) {
161
+ return this.mapper.update({ where: { id }, row: data });
162
+ }
163
+
164
+ async delete(id: number) {
165
+ return this.mapper.delete({ where: { id } });
166
+ }
167
+ }
168
+ ```
169
+
170
+ ### 表单验证 (@fastcar/core)
171
+
172
+ ```typescript
173
+ import { ValidForm, NotNull, Size, Rule } from "@fastcar/core/annotation";
174
+
175
+ class ItemDTO {
176
+ @NotNull
177
+ name!: string;
178
+
179
+ @Size({ minSize: 1, maxSize: 150 })
180
+ value!: number;
181
+ }
182
+
183
+ @Controller
184
+ @REQUEST("/api/items")
185
+ class ItemController {
186
+ @GET()
187
+ async list(page: number = 1, pageSize: number = 10) {
188
+ return { page, pageSize, data: [] };
189
+ }
190
+
191
+ @ValidForm
192
+ @POST()
193
+ async create(@Rule() body: ItemDTO) {
194
+ const { name, value } = body;
195
+ return this.service.create({ name, value });
196
+ }
80
197
  }
81
198
  ```
82
199
 
200
+ **表单验证规则:**
201
+
202
+ | 装饰器 | 用途 | 示例 |
203
+ |--------|------|------|
204
+ | `@ValidForm` | 开启方法参数校验 | 放在方法上 |
205
+ | `@Rule()` | 标记校验对象 | 放在 DTO 参数前 |
206
+ | `@NotNull` | 参数不能为空 | 放在 DTO 字段上 |
207
+ | `@Size({min, max})` | 大小限制 | 放在 DTO 字段上 |
208
+
83
209
  ### Redis (@fastcar/redis)
84
210
 
85
211
  ```typescript
212
+ import { Service, Autowired } from "@fastcar/core/annotation";
86
213
  import { RedisClient } from "@fastcar/redis/annotation";
87
214
 
88
215
  @Service
89
216
  class CacheService {
90
- @RedisClient private redis!: RedisClient;
91
- async get(key: string) { return this.redis.get(key); }
217
+ @RedisClient
218
+ private redis!: RedisClient;
219
+
220
+ async get(key: string) {
221
+ return this.redis.get(key);
222
+ }
223
+
92
224
  async set(key: string, value: string, ttl?: number) {
93
225
  await this.redis.set(key, value, ttl);
94
226
  }
@@ -97,13 +229,24 @@ class CacheService {
97
229
 
98
230
  ### 定时任务 (@fastcar/timer)
99
231
 
232
+ > **推荐使用 `@fastcar/timer/scheduling2` 模块**
233
+
100
234
  ```typescript
101
- import { Scheduled, Cron } from "@fastcar/timer/annotation";
235
+ import { ScheduledInterval, ScheduledCron } from "@fastcar/timer/scheduling2";
102
236
 
103
237
  @Component
104
238
  class TaskService {
105
- @Scheduled(60000) async intervalTask() { console.log("每分钟执行"); }
106
- @Cron("0 0 * * * *") async hourlyTask() { console.log("每小时执行"); }
239
+ // 间隔执行(毫秒)
240
+ @ScheduledInterval({ fixedRate: 60000 })
241
+ async intervalTask() {
242
+ console.log("每分钟执行");
243
+ }
244
+
245
+ // Cron 表达式
246
+ @ScheduledCron("0 0 * * * *")
247
+ async hourlyTask() {
248
+ console.log("每小时执行");
249
+ }
107
250
  }
108
251
  ```
109
252
 
@@ -114,7 +257,9 @@ import { WorkerPool, WorkerTask } from "@fastcar/workerpool/annotation";
114
257
 
115
258
  @Component
116
259
  class ComputeService {
117
- @WorkerPool({ minWorkers: 2, maxWorkers: 4 }) private pool!: WorkerPool;
260
+ @WorkerPool({ minWorkers: 2, maxWorkers: 4 })
261
+ private pool!: WorkerPool;
262
+
118
263
  @WorkerTask
119
264
  heavyComputation(data: number[]): number {
120
265
  return data.reduce((a, b) => a + b, 0);
@@ -124,42 +269,31 @@ class ComputeService {
124
269
 
125
270
  ## 项目模板速查
126
271
 
127
- ### 模板选择指南
272
+ FastCar CLI 提供 5 种项目模板:
128
273
 
129
274
  | 模板 | 适用场景 | 核心依赖 | 关键注解 |
130
275
  |------|---------|---------|---------|
131
276
  | web | RESTful API 服务 | @fastcar/koa, @fastcar/server | @EnableKoa |
132
277
  | static | 静态资源服务器 | @fastcar/koa, @fastcar/server | @EnableKoa + KoaStatic |
133
278
  | rpc | RPC 微服务通信 | @fastcar/rpc, @fastcar/server | @EnableRPC |
134
- | cos | 对象存储/文件上传/直播转码 | @fastcar/koa, @fastcar/cossdk, @fastcar/server | @EnableKoa |
135
- | microservices | 分布式多服务架构 | @fastcar/koa, @fastcar/rpc, @fastcar/server, @fastcar/timer | @EnableKoa / @EnableRPC(按服务模块) |
279
+ | cos | 对象存储/文件上传 | @fastcar/koa, @fastcar/cossdk, @fastcar/server | @EnableKoa |
280
+ | microservices | 分布式多服务架构 | @fastcar/koa, @fastcar/rpc, @fastcar/server, @fastcar/timer | @EnableKoa / @EnableRPC |
136
281
 
137
282
  ### 各模板入口示例
138
283
 
139
284
  **Web 模板**
140
285
  ```typescript
141
- import { FastCarApplication } from "@fastcar/core";
142
286
  import { Application } from "@fastcar/core/annotation";
143
287
  import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
144
288
  import { ExceptionGlobalHandler, KoaBodyParser } from "@fastcar/koa";
145
289
 
146
- @Application @EnableKoa
290
+ @Application
291
+ @EnableKoa
147
292
  @KoaMiddleware(ExceptionGlobalHandler)
148
293
  @KoaMiddleware(KoaBodyParser)
149
- class APP { app!: FastCarApplication; }
150
- export default new APP();
151
- ```
152
-
153
- **Static 模板**
154
- ```typescript
155
- import { Application } from "@fastcar/core/annotation";
156
- import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
157
- import { ExceptionGlobalHandler, KoaStatic } from "@fastcar/koa";
158
-
159
- @Application @EnableKoa
160
- @KoaMiddleware(ExceptionGlobalHandler)
161
- @KoaMiddleware(KoaStatic)
162
- class APP { app!: any; }
294
+ class APP {
295
+ app!: FastCarApplication;
296
+ }
163
297
  export default new APP();
164
298
  ```
165
299
 
@@ -168,68 +302,27 @@ export default new APP();
168
302
  import { Application } from "@fastcar/core/annotation";
169
303
  import { EnableRPC } from "@fastcar/rpc/annotation";
170
304
 
171
- @Application @EnableRPC
172
- class APP {}
173
- export default new APP();
174
- ```
175
-
176
- **COS 模板**
177
- ```typescript
178
- import { Application } from "@fastcar/core/annotation";
179
- import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
180
- import { ExceptionGlobalHandler, KoaBody, KoaBodyParser, KoaCors } from "@fastcar/koa";
181
-
182
- @Application @EnableKoa
183
- @KoaMiddleware(ExceptionGlobalHandler, KoaBody, KoaBodyParser, KoaCors)
305
+ @Application
306
+ @EnableRPC
184
307
  class APP {}
185
308
  export default new APP();
186
309
  ```
187
310
 
188
311
  **Microservices 模板**
189
- 微服务模板采用多服务架构,包含 `app-node.ts`(子进程启动多服务)和 `app-pm2.ts`(PM2 启动入口)。服务模块分为:
190
- - **center**:服务中心,提供服务注册与发现
191
- - **connector**:连接器服务,处理客户端连接
192
- - **chat**:聊天服务,处理实时消息
193
- - **web**:Web 服务,提供 HTTP 接口
194
- - **base**:基础服务,提供公共功能
195
-
196
- 各服务模块内部根据职责使用 `@EnableKoa` 或 `@EnableRPC`。
312
+ 微服务模板包含多服务架构:center(服务中心)、connector(连接器)、message(消息服务)、web(Web服务)、base(基础服务)。
197
313
 
198
314
  ### 项目结构示例
199
315
 
200
- **Web / Static / RPC / COS 模板**
201
316
  ```
202
317
  template/
203
318
  ├── src/
204
319
  │ ├── controller/ # 控制器(web/cos)
205
- │ ├── middleware/ # 中间件(web/cos)
320
+ │ ├── dto/ # DTO 类(表单验证)
321
+ │ ├── service/ # 服务层
206
322
  │ ├── model/ # 数据模型
207
323
  │ └── app.ts # 应用入口
208
324
  ├── resource/
209
325
  │ └── application.yml # 配置文件
210
- ├── target/ # 编译输出
211
- ├── package.json
212
- ├── tsconfig.json
213
- └── ecosystem.config.yml
214
- ```
215
-
216
- **Microservices 模板**
217
- ```
218
- template/
219
- ├── src/
220
- │ ├── annotation/ # 注解定义
221
- │ ├── common/ # 公共代码
222
- │ ├── middleware/ # 中间件
223
- │ ├── servers/ # 服务目录(base/center/chat/connector/web)
224
- │ ├── types/ # 类型定义
225
- │ ├── utils/ # 工具函数
226
- │ ├── app-node.ts # 单节点入口
227
- │ └── app-pm2.ts # PM2 入口
228
- ├── resource/
229
- │ ├── application.yml
230
- │ ├── application-dev.yml
231
- │ └── ecosystem.config.yml
232
- ├── test/
233
326
  ├── package.json
234
327
  └── tsconfig.json
235
328
  ```
@@ -252,7 +345,7 @@ npm i @fastcar/core @fastcar/koa @fastcar/rpc @fastcar/server @fastcar/timer
252
345
 
253
346
  ## 配置管理
254
347
 
255
- 配置文件放在 `resource/application.yml`。FastCar 支持按 `env` 加载多文件,例如 `application-dev.yml` 会与主配置合并。
348
+ 配置文件放在 `resource/application.yml`。支持按 `env` 加载多文件,例如 `application-dev.yml` 会与主配置合并。
256
349
 
257
350
  ### 基础配置示例
258
351
 
@@ -281,14 +374,15 @@ import { Configure, Value } from "@fastcar/core/annotation";
281
374
 
282
375
  @Configure
283
376
  class AppConfig {
284
- @Value("server.port") port!: number;
285
- @Value("mysql.host") dbHost!: string;
377
+ @Value("server.port")
378
+ port!: number;
379
+
380
+ @Value("mysql.host")
381
+ dbHost!: string;
286
382
  }
287
383
  ```
288
384
 
289
- ### 各模板 application.yml 配置
290
-
291
- #### Web / Static / COS 通用配置
385
+ ### Web 模板 application.yml
292
386
 
293
387
  ```yaml
294
388
  application:
@@ -298,18 +392,13 @@ settings:
298
392
  koa:
299
393
  server:
300
394
  - { port: 8080, host: "0.0.0.0" }
301
- # HTTPS: { port: 443, host: "0.0.0.0", protocol: https, ssl: { key: "./ssl/server.key", cert: "./ssl/server.pem" } }
302
- koaStatic: { "public": "public" } # 静态资源映射
395
+ koaStatic:
396
+ { "public": "public" }
303
397
  koaBodyParser:
304
398
  enableTypes: ["json", "form", "text"]
305
- extendTypes: { text: ["text/xml", "application/xml"] }
306
399
  ```
307
400
 
308
- - `settings.koa.server`:服务器监听配置数组,支持 `http`/`https`/`http2`
309
- - `settings.koa.koaStatic`:静态资源访问映射,格式 `{ "别名": "路径" }`
310
- - `settings.koa.koaBodyParser`:请求体解析配置
311
-
312
- #### RPC 模板配置
401
+ ### RPC 模板配置
313
402
 
314
403
  ```yaml
315
404
  application:
@@ -319,54 +408,38 @@ settings:
319
408
  rpc:
320
409
  list:
321
410
  - id: "server-1"
322
- type: "ws" # 协议:ws / http / grpc / mqtt
411
+ type: "ws"
323
412
  server: { port: 1235 }
324
- serviceType: "base" # 服务类型分类
325
- secure: { username: "user", password: "123456" }
413
+ serviceType: "base"
414
+ secure:
415
+ username: "user"
416
+ password: "password"
326
417
  ```
327
418
 
328
- - `settings.rpc.list`:RPC 服务端点数组
329
- - `type`:通信协议;`serviceType`:服务分组;`secure`:安全认证
330
-
331
- #### Microservices 模板配置
332
-
333
- 主配置声明环境,详细集群配置放在 `application-dev.yml`:
419
+ ### Microservices 模板配置
334
420
 
335
421
  ```yaml
336
422
  settings:
337
- hotterSysConfig: true # 监听配置变更
338
423
  microservices:
339
- center: # 服务中心
340
- token: "xxx"
424
+ center:
425
+ token: "your-token-here"
341
426
  servers:
342
427
  - host: "localhost"
343
- clusters: 1 # 实例数
428
+ clusters: 1
344
429
  list:
345
430
  - type: "ws"
346
431
  server: { port: 60000 }
347
- timeout: 0
348
- connectionLimit: 1
349
- retry: { retryCount: 3, retryInterval: 3000 }
350
-
351
- connector: # 连接器服务
352
- token: "xxx"
432
+ connector:
433
+ token: "your-token-here"
353
434
  servers:
354
435
  - host: "localhost"
355
436
  clusters: 1
356
437
  list:
357
- - front: true # 面向客户端的前置节点
438
+ - front: true
358
439
  type: "ws"
359
440
  server: { port: 60100 }
360
-
361
- chat: { ... } # 聊天服务
362
- web: { ... } # Web 服务(支持 http/ws 混合)
363
441
  ```
364
442
 
365
- - `settings.microservices.<服务名>`:各微服务模块配置
366
- - `token`:服务间通信鉴权令牌;`clusters`:集群实例数(自动递增端口号)
367
- - `front: true`:标记为面向客户端的前置节点
368
- - `retry`:消息重试策略(retryCount/retryInterval/timeout/maxMsgNum/increase)
369
-
370
443
  ## 生命周期钩子
371
444
 
372
445
  ```typescript
@@ -374,27 +447,19 @@ import { ApplicationStart, ApplicationStop, ApplicationInit } from "@fastcar/cor
374
447
 
375
448
  @Component
376
449
  class LifecycleService {
377
- @ApplicationStart async onStart() { console.log("应用启动"); }
378
- @ApplicationStop async onStop() { console.log("应用停止"); }
379
- @ApplicationInit async init() { console.log("初始化完成"); }
380
- }
381
- ```
382
-
383
- ## 表单验证
384
-
385
- ```typescript
386
- import { ValidForm, NotNull, Size, Rule } from "@fastcar/core/annotation";
387
-
388
- class UserDTO {
389
- @NotNull name!: string;
390
- @Size({ minSize: 1, maxSize: 150 }) age!: number;
391
- }
392
-
393
- @Controller
394
- class UserController {
395
- @ValidForm
396
- createUser(@Rule() @NotNull user: UserDTO) {
397
- return this.userService.create(user);
450
+ @ApplicationStart
451
+ async onStart() {
452
+ console.log("应用启动");
453
+ }
454
+
455
+ @ApplicationStop
456
+ async onStop() {
457
+ console.log("应用停止");
458
+ }
459
+
460
+ @ApplicationInit
461
+ async init() {
462
+ console.log("初始化完成");
398
463
  }
399
464
  }
400
465
  ```
@@ -446,39 +511,66 @@ TypeUtil.isClass(MyClass); // true
446
511
  ```bash
447
512
  # Web 项目
448
513
  mkdir my-web-app && cd my-web-app
449
- fastcar-cli init web && npm install && npm run debug
450
-
451
- # Static 项目
452
- mkdir my-static-app && cd my-static-app
453
- fastcar-cli init static && npm install && npm run debug
514
+ fastcar-cli init web
515
+ npm install
516
+ npm run debug
454
517
 
455
518
  # RPC 项目
456
519
  mkdir my-rpc-app && cd my-rpc-app
457
- fastcar-cli init rpc && npm install && npm run debug
458
-
459
- # COS 项目
460
- mkdir my-cos-app && cd my-cos-app
461
- fastcar-cli init cos && npm install && npm run debug
520
+ fastcar-cli init rpc
521
+ npm install
522
+ npm run debug
462
523
 
463
524
  # Microservices 项目
464
525
  mkdir my-ms-app && cd my-ms-app
465
- fastcar-cli init microservices && npm install
466
- npm run start-node # 单节点模式
467
- # 或 npm run start-pm2 # PM2 模式
526
+ fastcar-cli init microservices
527
+ npm install
528
+ npm run start-node
468
529
  ```
469
530
 
470
- ### 手动创建项目
531
+ ## 常见错误与注意事项
471
532
 
472
- ```bash
473
- mkdir my-fastcar-app && cd my-fastcar-app
474
- npm init -y
475
- npm i @fastcar/core @fastcar/koa @fastcar/server
476
- npm i -D typescript ts-node @types/node
477
- npx tsc --init
478
- # 启用装饰器(tsconfig.json): experimentalDecorators, emitDecoratorMetadata
533
+ ### 1. 路由装饰器必须有括号
534
+
535
+ **错误:**
536
+ ```typescript
537
+ @GET
538
+ async list() { }
479
539
  ```
480
540
 
481
- ## 参考资源
541
+ **正确:**
542
+ ```typescript
543
+ @GET()
544
+ async list() { }
545
+ ```
546
+
547
+ ### 2. 不要使用不存在的装饰器
548
+
549
+ ❌ **错误:**
550
+ ```typescript
551
+ import { Body, Param, Query } from "@fastcar/koa/annotation";
482
552
 
483
- - 详细 API 文档:[references/api-reference.md](references/api-reference.md)
484
- - 项目模板:[assets/project-template/](assets/project-template/)
553
+ @GET("/:id")
554
+ async getById(@Param("id") id: string) { }
555
+ ```
556
+
557
+ ✅ **正确:**
558
+ ```typescript
559
+ @GET("/:id")
560
+ async getById(id: string) { }
561
+ ```
562
+
563
+ ### 3. 表单验证使用 @ValidForm + @Rule
564
+
565
+ ❌ **错误:**
566
+ ```typescript
567
+ @POST()
568
+ async create(@Body body: ItemDTO) { }
569
+ ```
570
+
571
+ ✅ **正确:**
572
+ ```typescript
573
+ @ValidForm
574
+ @POST()
575
+ async create(@Rule() body: ItemDTO) { }
576
+ ```