@qlover/create-app 0.7.13 → 0.7.15

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 (93) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/templates/next-app/README.en.md +131 -0
  5. package/dist/templates/next-app/README.md +115 -20
  6. package/dist/templates/next-app/config/IOCIdentifier.ts +14 -1
  7. package/dist/templates/next-app/config/Identifier/index.ts +1 -0
  8. package/dist/templates/next-app/config/Identifier/page.admin.ts +48 -0
  9. package/dist/templates/next-app/config/i18n/admin18n.ts +33 -0
  10. package/dist/templates/next-app/config/i18n/index.ts +3 -1
  11. package/dist/templates/next-app/docs/en/api.md +387 -0
  12. package/dist/templates/next-app/docs/en/component.md +544 -0
  13. package/dist/templates/next-app/docs/en/database.md +496 -0
  14. package/dist/templates/next-app/docs/en/development-guide.md +727 -0
  15. package/dist/templates/next-app/docs/en/env.md +563 -0
  16. package/dist/templates/next-app/docs/en/i18n.md +287 -0
  17. package/dist/templates/next-app/docs/en/index.md +166 -0
  18. package/dist/templates/next-app/docs/en/page.md +457 -0
  19. package/dist/templates/next-app/docs/en/project-structure.md +177 -0
  20. package/dist/templates/next-app/docs/en/router.md +427 -0
  21. package/dist/templates/next-app/docs/en/theme.md +532 -0
  22. package/dist/templates/next-app/docs/en/validator.md +478 -0
  23. package/dist/templates/next-app/docs/zh/api.md +387 -0
  24. package/dist/templates/next-app/docs/zh/component.md +544 -0
  25. package/dist/templates/next-app/docs/zh/database.md +496 -0
  26. package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
  27. package/dist/templates/next-app/docs/zh/env.md +563 -0
  28. package/dist/templates/next-app/docs/zh/i18n.md +287 -0
  29. package/dist/templates/next-app/docs/zh/index.md +166 -0
  30. package/dist/templates/next-app/docs/zh/page.md +457 -0
  31. package/dist/templates/next-app/docs/zh/project-structure.md +177 -0
  32. package/dist/templates/next-app/docs/zh/router.md +427 -0
  33. package/dist/templates/next-app/docs/zh/theme.md +532 -0
  34. package/dist/templates/next-app/docs/zh/validator.md +476 -0
  35. package/dist/templates/next-app/migrations/schema/UserSchema.ts +2 -2
  36. package/dist/templates/next-app/next.config.ts +1 -1
  37. package/dist/templates/next-app/package.json +3 -1
  38. package/dist/templates/next-app/public/locales/en.json +8 -1
  39. package/dist/templates/next-app/public/locales/zh.json +8 -1
  40. package/dist/templates/next-app/src/app/[locale]/admin/layout.tsx +1 -1
  41. package/dist/templates/next-app/src/app/[locale]/admin/page.tsx +14 -16
  42. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +10 -3
  43. package/dist/templates/next-app/src/app/[locale]/layout.tsx +1 -1
  44. package/dist/templates/next-app/src/app/[locale]/login/page.tsx +1 -1
  45. package/dist/templates/next-app/src/app/[locale]/page.tsx +2 -3
  46. package/dist/templates/next-app/src/app/[locale]/register/page.tsx +1 -1
  47. package/dist/templates/next-app/src/app/api/ai/completions/route.ts +32 -0
  48. package/dist/templates/next-app/src/base/cases/AppConfig.ts +3 -0
  49. package/dist/templates/next-app/src/base/cases/ChatAction.ts +21 -0
  50. package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +36 -0
  51. package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +1 -3
  52. package/dist/templates/next-app/src/base/services/AdminUserService.ts +1 -1
  53. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +1 -1
  54. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +23 -1
  55. package/dist/templates/next-app/src/base/services/appApi/AppUserApiBootstrap.ts +2 -2
  56. package/dist/templates/next-app/src/base/types/PageProps.ts +1 -1
  57. package/dist/templates/next-app/src/core/bootstraps/BootstrapClient.ts +1 -0
  58. package/dist/templates/next-app/src/core/bootstraps/BootstrapServer.ts +1 -0
  59. package/dist/templates/next-app/src/core/globals.ts +2 -0
  60. package/dist/templates/next-app/src/core/serverIoc/ServerIOCRegister.ts +4 -1
  61. package/dist/templates/next-app/src/{base/cases → server}/PageParams.ts +1 -1
  62. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +31 -0
  63. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +1 -1
  64. package/dist/templates/next-app/src/server/repositorys/UserRepository.ts +6 -4
  65. package/dist/templates/next-app/src/server/services/AIService.ts +43 -0
  66. package/dist/templates/next-app/src/server/services/ApiUserService.ts +1 -1
  67. package/dist/templates/next-app/src/server/{SupabaseBridge.ts → sqlBridges/SupabaseBridge.ts} +16 -11
  68. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +4 -4
  69. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +1 -1
  70. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +32 -25
  71. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +12 -26
  72. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +37 -5
  73. package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +17 -0
  74. package/dist/templates/next-app/src/uikit/components/ClientSeo.tsx +36 -0
  75. package/dist/templates/next-app/src/uikit/components/LanguageSwitcher.tsx +5 -6
  76. package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +2 -0
  77. package/dist/templates/next-app/src/uikit/components/With.tsx +17 -0
  78. package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +30 -0
  79. package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +65 -0
  80. package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +59 -0
  81. package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +28 -0
  82. package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +19 -0
  83. package/package.json +1 -1
  84. package/dist/templates/next-app/docs/env.md +0 -94
  85. package/dist/templates/next-app/src/base/port/DBBridgeInterface.ts +0 -21
  86. package/dist/templates/next-app/src/base/port/DBMigrationInterface.ts +0 -92
  87. package/dist/templates/next-app/src/base/port/MigrationApiInterface.ts +0 -3
  88. package/dist/templates/next-app/src/base/port/ServerApiResponseInterface.ts +0 -6
  89. package/dist/templates/next-app/src/base/services/migrations/MigrationsApi.ts +0 -43
  90. package/dist/templates/next-app/config/i18n/{HomeI18n .ts → HomeI18n.ts} +0 -0
  91. package/dist/templates/next-app/{build → make}/generateLocales.ts +2 -2
  92. /package/dist/templates/next-app/src/{base → server}/port/PaginationInterface.ts +0 -0
  93. /package/dist/templates/next-app/src/{base → server}/port/ParamsHandlerInterface.ts +0 -0
@@ -0,0 +1,496 @@
1
+ # 数据库开发指南
2
+
3
+ ## 目录
4
+
5
+ 1. [数据库架构概述](#数据库架构概述)
6
+ 2. [Supabase 实现](#supabase-实现)
7
+ 3. [数据库接口和抽象层](#数据库接口和抽象层)
8
+ 4. [仓库模式实现](#仓库模式实现)
9
+ 5. [MongoDB 实现示例](#mongodb-实现示例)
10
+ 6. [最佳实践和示例](#最佳实践和示例)
11
+
12
+ ## 数据库架构概述
13
+
14
+ ### 1. 整体架构
15
+
16
+ 项目采用分层的数据库架构设计:
17
+
18
+ ```
19
+ 应用层 数据访问层
20
+ ┌──────────────┐ ┌──────────────┐
21
+ │ 业务服务 │ │ 数据库接口 │
22
+ ├──────────────┤ ├──────────────┤
23
+ │ 仓库接口 │ │ 数据库桥接器 │
24
+ ├──────────────┤ ◄─────┤ │
25
+ │ 仓库实现 │ │ 具体实现 │
26
+ └──────────────┘ └──────────────┘
27
+ ```
28
+
29
+ ### 2. 核心组件
30
+
31
+ - **数据库接口**:`DBBridgeInterface`
32
+ - **数据库实现**:`SupabaseBridge`, `MongoDBBridge` 等
33
+ - **仓库接口**:`UserRepositoryInterface` 等
34
+ - **仓库实现**:`UserRepository` 等
35
+
36
+ ### 3. 数据模型
37
+
38
+ ```typescript
39
+ // 用户模型示例
40
+ interface UserSchema {
41
+ id: number;
42
+ email: string;
43
+ password: string;
44
+ role: string;
45
+ created_at: string;
46
+ updated_at: string;
47
+ email_confirmed_at?: string;
48
+ }
49
+ ```
50
+
51
+ ## Supabase 实现
52
+
53
+ ### 1. 数据库桥接器
54
+
55
+ ```typescript
56
+ @injectable()
57
+ export class SupabaseBridge implements DBBridgeInterface {
58
+ protected supabase: SupabaseClient;
59
+
60
+ constructor(
61
+ @inject(I.AppConfig) appConfig: AppConfig,
62
+ @inject(I.Logger) protected logger: LoggerInterface
63
+ ) {
64
+ // 初始化 Supabase 客户端
65
+ this.supabase = createClient(
66
+ appConfig.supabaseUrl,
67
+ appConfig.supabaseAnonKey
68
+ );
69
+ }
70
+
71
+ // 查询实现
72
+ async get(event: BridgeEvent): Promise<SupabaseBridgeResponse<unknown>> {
73
+ const { table, fields = '*', where } = event;
74
+ const selectFields = Array.isArray(fields) ? fields.join(',') : fields;
75
+ const handler = this.supabase.from(table).select(selectFields);
76
+
77
+ this.handleWhere(handler, where ?? []);
78
+
79
+ return this.catch(await handler);
80
+ }
81
+
82
+ // 分页查询实现
83
+ async pagination(event: BridgeEvent): Promise<DBBridgeResponse<unknown[]>> {
84
+ const { table, fields = '*', where, page = 1, pageSize = 10 } = event;
85
+ const selectFields = Array.isArray(fields) ? fields.join(',') : fields;
86
+
87
+ const handler = this.supabase
88
+ .from(table)
89
+ .select(selectFields, { count: 'exact' })
90
+ .range((page - 1) * pageSize, page * pageSize - 1);
91
+
92
+ this.handleWhere(handler, where ?? []);
93
+
94
+ return this.catch(await handler);
95
+ }
96
+
97
+ // WHERE 条件处理
98
+ protected handleWhere(
99
+ handler: PostgrestFilterBuilder<any, any, any>,
100
+ where: Where[]
101
+ ): void {
102
+ where.forEach(([field, operation, value]) => {
103
+ const method = whereHandlerMaps[operation];
104
+ if (method) {
105
+ handler[method](field, value);
106
+ }
107
+ });
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### 2. 查询条件映射
113
+
114
+ ```typescript
115
+ // Supabase 操作符映射
116
+ const whereHandlerMaps = {
117
+ '=': 'eq', // 等于
118
+ '!=': 'neq', // 不等于
119
+ '>': 'gt', // 大于
120
+ '<': 'lt', // 小于
121
+ '>=': 'gte', // 大于等于
122
+ '<=': 'lte' // 小于等于
123
+ };
124
+ ```
125
+
126
+ ## 数据库接口和抽象层
127
+
128
+ ### 1. 数据库桥接接口
129
+
130
+ ```typescript
131
+ export interface DBBridgeInterface {
132
+ // 基础 CRUD 操作
133
+ add(event: BridgeEvent): Promise<DBBridgeResponse<unknown>>;
134
+ update(event: BridgeEvent): Promise<DBBridgeResponse<unknown>>;
135
+ delete(event: BridgeEvent): Promise<DBBridgeResponse<unknown>>;
136
+ get(event: BridgeEvent): Promise<DBBridgeResponse<unknown>>;
137
+
138
+ // 分页查询
139
+ pagination(event: BridgeEvent): Promise<DBBridgeResponse<unknown[]>>;
140
+ }
141
+
142
+ // 查询事件定义
143
+ export interface BridgeEvent {
144
+ table: string;
145
+ fields?: string | string[];
146
+ where?: Where[];
147
+ data?: unknown;
148
+ page?: number;
149
+ pageSize?: number;
150
+ }
151
+
152
+ // 统一响应格式
153
+ export interface DBBridgeResponse<T> {
154
+ error?: unknown;
155
+ data: T;
156
+ pagination?: PaginationInfo;
157
+ }
158
+ ```
159
+
160
+ ### 2. 查询条件类型
161
+
162
+ ```typescript
163
+ // 操作符类型
164
+ export type WhereOperation = '=' | '!=' | '>' | '<' | '>=' | '<=';
165
+
166
+ // 查询条件类型
167
+ export type Where = [string, WhereOperation, string | number];
168
+
169
+ // 分页信息
170
+ export interface PaginationInfo {
171
+ total: number;
172
+ page: number;
173
+ pageSize: number;
174
+ }
175
+ ```
176
+
177
+ ## 仓库模式实现
178
+
179
+ ### 1. 用户仓库接口
180
+
181
+ ```typescript
182
+ export interface UserRepositoryInterface {
183
+ // 获取所有用户
184
+ getAll(): Promise<unknown>;
185
+
186
+ // 通过邮箱查询用户
187
+ getUserByEmail(email: string): Promise<UserSchema | null>;
188
+
189
+ // 添加用户
190
+ add(params: {
191
+ email: string;
192
+ password: string;
193
+ }): Promise<UserSchema[] | null>;
194
+
195
+ // 更新用户
196
+ updateById(
197
+ id: number,
198
+ params: Partial<Omit<UserSchema, 'id' | 'created_at'>>
199
+ ): Promise<void>;
200
+
201
+ // 分页查询
202
+ pagination<UserSchema>(params: {
203
+ page: number;
204
+ pageSize: number;
205
+ }): Promise<PaginationInterface<UserSchema>>;
206
+ }
207
+ ```
208
+
209
+ ### 2. 用户仓库实现
210
+
211
+ ```typescript
212
+ @injectable()
213
+ export class UserRepository implements UserRepositoryInterface {
214
+ readonly name = 'fe_users';
215
+
216
+ // 安全字段列表(排除敏感信息)
217
+ protected safeFields = [
218
+ 'created_at',
219
+ 'email',
220
+ 'email_confirmed_at',
221
+ 'id',
222
+ 'role',
223
+ 'updated_at'
224
+ ];
225
+
226
+ constructor(
227
+ @inject(I.DBBridgeInterface) protected dbBridge: DBBridgeInterface
228
+ ) {}
229
+
230
+ async getUserByEmail(email: string): Promise<UserSchema | null> {
231
+ const result = await this.dbBridge.get({
232
+ table: this.name,
233
+ where: [['email', '=', email]]
234
+ });
235
+
236
+ return isEmpty(result.data) ? null : last(result.data as UserSchema[]);
237
+ }
238
+
239
+ async pagination<UserSchema>(
240
+ params: PaginationParams
241
+ ): Promise<PaginationResult> {
242
+ const result = await this.dbBridge.pagination({
243
+ table: this.name,
244
+ page: params.page,
245
+ pageSize: params.pageSize,
246
+ fields: this.safeFields // 只返回安全字段
247
+ });
248
+
249
+ return {
250
+ list: result.data as UserSchema[],
251
+ total: result.count ?? 0,
252
+ page: params.page,
253
+ pageSize: params.pageSize
254
+ };
255
+ }
256
+ }
257
+ ```
258
+
259
+ ## MongoDB 实现示例
260
+
261
+ ### 1. MongoDB 桥接器
262
+
263
+ ```typescript
264
+ @injectable()
265
+ export class MongoDBBridge implements DBBridgeInterface {
266
+ protected client: MongoClient;
267
+ protected db: Db;
268
+
269
+ constructor(
270
+ @inject(I.AppConfig) appConfig: AppConfig,
271
+ @inject(I.Logger) protected logger: LoggerInterface
272
+ ) {
273
+ this.client = new MongoClient(appConfig.mongodbUrl);
274
+ this.db = this.client.db(appConfig.mongodbDatabase);
275
+ }
276
+
277
+ async get(event: BridgeEvent): Promise<DBBridgeResponse<unknown>> {
278
+ const { table, where } = event;
279
+ const collection = this.db.collection(table);
280
+
281
+ const query = this.buildQuery(where ?? []);
282
+ const data = await collection.find(query).toArray();
283
+
284
+ return { data };
285
+ }
286
+
287
+ async pagination(event: BridgeEvent): Promise<DBBridgeResponse<unknown[]>> {
288
+ const { table, where, page = 1, pageSize = 10 } = event;
289
+ const collection = this.db.collection(table);
290
+
291
+ const query = this.buildQuery(where ?? []);
292
+ const total = await collection.countDocuments(query);
293
+ const data = await collection
294
+ .find(query)
295
+ .skip((page - 1) * pageSize)
296
+ .limit(pageSize)
297
+ .toArray();
298
+
299
+ return {
300
+ data,
301
+ pagination: { total, page, pageSize }
302
+ };
303
+ }
304
+
305
+ protected buildQuery(where: Where[]): Document {
306
+ return where.reduce((query, [field, operation, value]) => {
307
+ switch (operation) {
308
+ case '=':
309
+ return { ...query, [field]: value };
310
+ case '!=':
311
+ return { ...query, [field]: { $ne: value } };
312
+ case '>':
313
+ return { ...query, [field]: { $gt: value } };
314
+ case '<':
315
+ return { ...query, [field]: { $lt: value } };
316
+ case '>=':
317
+ return { ...query, [field]: { $gte: value } };
318
+ case '<=':
319
+ return { ...query, [field]: { $lte: value } };
320
+ default:
321
+ return query;
322
+ }
323
+ }, {});
324
+ }
325
+ }
326
+ ```
327
+
328
+ ### 2. MongoDB 配置
329
+
330
+ ```typescript
331
+ // 在 AppConfig 中添加 MongoDB 配置
332
+ export class AppConfig implements EnvConfigInterface {
333
+ readonly mongodbUrl: string = process.env.MONGODB_URL!;
334
+ readonly mongodbDatabase: string = process.env.MONGODB_DATABASE!;
335
+ }
336
+
337
+ // 注册 MongoDB 桥接器
338
+ export class ServerIOCRegister {
339
+ protected registerImplement(ioc: IOCContainerInterface): void {
340
+ // 使用 MongoDB 实现
341
+ ioc.bind(I.DBBridgeInterface, ioc.get(MongoDBBridge));
342
+ // 或使用 Supabase 实现
343
+ // ioc.bind(I.DBBridgeInterface, ioc.get(SupabaseBridge));
344
+ }
345
+ }
346
+ ```
347
+
348
+ ## 最佳实践和示例
349
+
350
+ ### 1. 仓库模式使用
351
+
352
+ ```typescript
353
+ @injectable()
354
+ export class UserService {
355
+ constructor(
356
+ @inject(I.UserRepository)
357
+ private userRepository: UserRepositoryInterface
358
+ ) {}
359
+
360
+ async getUserProfile(email: string): Promise<UserProfile | null> {
361
+ const user = await this.userRepository.getUserByEmail(email);
362
+ if (!user) return null;
363
+
364
+ // 转换为业务模型
365
+ return this.mapToUserProfile(user);
366
+ }
367
+
368
+ async listUsers(
369
+ params: PaginationParams
370
+ ): Promise<PaginationResult<UserProfile>> {
371
+ const result = await this.userRepository.pagination(params);
372
+
373
+ return {
374
+ ...result,
375
+ list: result.list.map(this.mapToUserProfile)
376
+ };
377
+ }
378
+ }
379
+ ```
380
+
381
+ ### 2. 事务处理
382
+
383
+ ```typescript
384
+ @injectable()
385
+ export class TransactionManager {
386
+ async withTransaction<T>(
387
+ callback: (transaction: Transaction) => Promise<T>
388
+ ): Promise<T> {
389
+ const transaction = await this.dbBridge.startTransaction();
390
+
391
+ try {
392
+ const result = await callback(transaction);
393
+ await transaction.commit();
394
+ return result;
395
+ } catch (error) {
396
+ await transaction.rollback();
397
+ throw error;
398
+ }
399
+ }
400
+ }
401
+
402
+ // 使用事务
403
+ async createUserWithProfile(data: UserData): Promise<User> {
404
+ return this.transactionManager.withTransaction(async (transaction) => {
405
+ const user = await this.userRepository.add(data, transaction);
406
+ await this.profileRepository.add(data.profile, transaction);
407
+ return user;
408
+ });
409
+ }
410
+ ```
411
+
412
+ ### 3. 查询优化
413
+
414
+ ```typescript
415
+ @injectable()
416
+ export class OptimizedUserRepository extends UserRepository {
417
+ // 使用字段选择优化查询
418
+ async getUserProfile(id: number): Promise<UserProfile> {
419
+ const result = await this.dbBridge.get({
420
+ table: this.name,
421
+ fields: this.safeFields, // 只选择需要的字段
422
+ where: [['id', '=', id]]
423
+ });
424
+ return this.mapToProfile(result.data);
425
+ }
426
+
427
+ // 使用索引优化查询
428
+ async searchUsers(query: string): Promise<User[]> {
429
+ const result = await this.dbBridge.get({
430
+ table: this.name,
431
+ where: [
432
+ ['email', '=', query], // 假设 email 字段有索引
433
+ ['role', '=', 'user']
434
+ ]
435
+ });
436
+ return result.data as User[];
437
+ }
438
+ }
439
+ ```
440
+
441
+ ### 4. 缓存策略
442
+
443
+ ```typescript
444
+ @injectable()
445
+ export class CachedUserRepository extends UserRepository {
446
+ constructor(
447
+ @inject(I.DBBridgeInterface) dbBridge: DBBridgeInterface,
448
+ @inject(I.CacheManager) private cache: CacheManager
449
+ ) {
450
+ super(dbBridge);
451
+ }
452
+
453
+ async getUserByEmail(email: string): Promise<UserSchema | null> {
454
+ // 先查缓存
455
+ const cached = await this.cache.get(`user:${email}`);
456
+ if (cached) return cached;
457
+
458
+ // 缓存未命中,查数据库
459
+ const user = await super.getUserByEmail(email);
460
+ if (user) {
461
+ await this.cache.set(`user:${email}`, user, '1h');
462
+ }
463
+
464
+ return user;
465
+ }
466
+ }
467
+ ```
468
+
469
+ ## 总结
470
+
471
+ 项目的数据库设计遵循以下原则:
472
+
473
+ 1. **抽象分层**:
474
+ - 清晰的接口定义
475
+ - 数据库实现可替换
476
+ - 仓库模式封装业务逻辑
477
+
478
+ 2. **类型安全**:
479
+ - 完整的 TypeScript 类型定义
480
+ - 查询条件类型检查
481
+ - 响应数据类型验证
482
+
483
+ 3. **安全性**:
484
+ - 字段级别的访问控制
485
+ - 参数化查询防注入
486
+ - 敏感数据过滤
487
+
488
+ 4. **可扩展性**:
489
+ - 支持多种数据库实现
490
+ - 插件化的功能扩展
491
+ - 统一的查询接口
492
+
493
+ 5. **性能优化**:
494
+ - 字段选择优化
495
+ - 查询条件优化
496
+ - 缓存策略支持