@qlover/create-app 0.7.14 → 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 (31) hide show
  1. package/CHANGELOG.md +23 -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/docs/en/api.md +387 -0
  7. package/dist/templates/next-app/docs/en/component.md +544 -0
  8. package/dist/templates/next-app/docs/en/database.md +496 -0
  9. package/dist/templates/next-app/docs/en/development-guide.md +727 -0
  10. package/dist/templates/next-app/docs/en/env.md +563 -0
  11. package/dist/templates/next-app/docs/en/i18n.md +287 -0
  12. package/dist/templates/next-app/docs/en/index.md +166 -0
  13. package/dist/templates/next-app/docs/en/page.md +457 -0
  14. package/dist/templates/next-app/docs/en/project-structure.md +177 -0
  15. package/dist/templates/next-app/docs/en/router.md +427 -0
  16. package/dist/templates/next-app/docs/en/theme.md +532 -0
  17. package/dist/templates/next-app/docs/en/validator.md +478 -0
  18. package/dist/templates/next-app/docs/zh/api.md +387 -0
  19. package/dist/templates/next-app/docs/zh/component.md +544 -0
  20. package/dist/templates/next-app/docs/zh/database.md +496 -0
  21. package/dist/templates/next-app/docs/zh/development-guide.md +727 -0
  22. package/dist/templates/next-app/docs/zh/env.md +563 -0
  23. package/dist/templates/next-app/docs/zh/i18n.md +287 -0
  24. package/dist/templates/next-app/docs/zh/index.md +166 -0
  25. package/dist/templates/next-app/docs/zh/page.md +457 -0
  26. package/dist/templates/next-app/docs/zh/project-structure.md +177 -0
  27. package/dist/templates/next-app/docs/zh/router.md +427 -0
  28. package/dist/templates/next-app/docs/zh/theme.md +532 -0
  29. package/dist/templates/next-app/docs/zh/validator.md +476 -0
  30. package/package.json +1 -1
  31. package/dist/templates/next-app/docs/env.md +0 -94
@@ -0,0 +1,563 @@
1
+ # Next.js Environment Variable Configuration Guide
2
+
3
+ ## What are Environment Variables?
4
+
5
+ Environment variables are a way to configure application behavior across different environments (development, testing, production). In Next.js, environment variables have special characteristics, particularly in how they are handled on the client and server sides.
6
+
7
+ **Key Features**:
8
+
9
+ - Client-side environment variables must start with `NEXT_PUBLIC_`
10
+ - Server-side environment variables can be used directly without special prefix
11
+ - Supports multi-environment configuration and local overrides
12
+
13
+ ## Environment Variable Loading Priority
14
+
15
+ Next.js loads environment variables in the following priority order:
16
+
17
+ ```
18
+ .env.local → .env.development/.env.production → .env
19
+ ```
20
+
21
+ ## File Structure
22
+
23
+ ```
24
+ project-root/
25
+ ├── .env # Default environment variables
26
+ ├── .env.local # Local environment variables (git ignored)
27
+ ├── .env.development # Development environment variables
28
+ ├── .env.production # Production environment variables
29
+ ├── .env.test # Test environment variables
30
+ └── src/
31
+ └── base/
32
+ └── cases/
33
+ └── AppConfig.ts # Application configuration class
34
+ ```
35
+
36
+ ## Environment Variable Files
37
+
38
+ ### 1. Environment Variable File Examples
39
+
40
+ ```bash
41
+ # .env (default configuration)
42
+ # Client-accessible environment variables (starting with NEXT_PUBLIC_)
43
+ NEXT_PUBLIC_APP_NAME=MyApp
44
+ NEXT_PUBLIC_API_BASE_URL=http://api.example.com
45
+ NEXT_PUBLIC_ENABLE_ANALYTICS=false
46
+
47
+ # Server-side only environment variables
48
+ DATABASE_URL=postgres://user:pass@localhost:5432/db
49
+ JWT_SECRET=your-secret-key
50
+ API_TOKEN=server-side-token
51
+
52
+ # .env.development (development environment)
53
+ NEXT_PUBLIC_API_BASE_URL=http://localhost:3000/api
54
+ NEXT_PUBLIC_DEBUG=true
55
+ DATABASE_URL=postgres://dev:pass@localhost:5432/dev_db
56
+
57
+ # .env.production (production environment)
58
+ NEXT_PUBLIC_API_BASE_URL=https://api.production.com
59
+ NEXT_PUBLIC_DEBUG=false
60
+ DATABASE_URL=postgres://prod:pass@production:5432/prod_db
61
+
62
+ # .env.local (local override, not committed to git)
63
+ NEXT_PUBLIC_FEATURE_FLAG=true
64
+ DATABASE_URL=postgres://local:pass@localhost:5432/local_db
65
+ ```
66
+
67
+ ### 2. Environment Variable Usage Guidelines
68
+
69
+ #### Client-Side Environment Variables
70
+
71
+ - Must start with `NEXT_PUBLIC_`
72
+ - Will be bundled into client-side code
73
+ - Suitable for public configuration information
74
+
75
+ ```bash
76
+ # ✅ Correct client-side environment variables
77
+ NEXT_PUBLIC_API_URL=https://api.example.com
78
+ NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=UA-XXXXX
79
+ NEXT_PUBLIC_FEATURE_FLAGS={"newUI":true}
80
+
81
+ # ❌ Incorrect client-side environment variables (missing NEXT_PUBLIC_ prefix)
82
+ API_URL=https://api.example.com # Client cannot access
83
+ ```
84
+
85
+ #### Server-Side Environment Variables
86
+
87
+ - No special prefix needed
88
+ - Only available on server-side
89
+ - Suitable for sensitive information
90
+
91
+ ```bash
92
+ # ✅ Correct server-side environment variables
93
+ DATABASE_URL=postgres://user:pass@localhost:5432/db
94
+ JWT_SECRET=your-secret-key
95
+ API_TOKEN=your-api-token
96
+
97
+ # ❌ Server-side sensitive information should not start with NEXT_PUBLIC_
98
+ NEXT_PUBLIC_DATABASE_URL=postgres://user:pass@localhost:5432/db # Security risk!
99
+ ```
100
+
101
+ ## Implementation in Project
102
+
103
+ ### 1. Application Configuration Class
104
+
105
+ ```typescript
106
+ // src/base/cases/AppConfig.ts
107
+ export class AppConfig implements EnvConfigInterface {
108
+ /**
109
+ * Application name
110
+ * @description Retrieved from NEXT_PUBLIC_APP_NAME environment variable
111
+ */
112
+ readonly appName = process.env.NEXT_PUBLIC_APP_NAME || '';
113
+
114
+ /**
115
+ * API base URL
116
+ * @description Retrieved from NEXT_PUBLIC_API_BASE_URL environment variable
117
+ */
118
+ readonly apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL || '';
119
+
120
+ /**
121
+ * Whether in development environment
122
+ */
123
+ readonly isDevelopment = process.env.NODE_ENV === 'development';
124
+
125
+ /**
126
+ * Whether in production environment
127
+ */
128
+ readonly isProduction = process.env.NODE_ENV === 'production';
129
+
130
+ /**
131
+ * Database connection URL (server-side only)
132
+ */
133
+ readonly databaseUrl = process.env.DATABASE_URL;
134
+
135
+ /**
136
+ * JWT secret (server-side only)
137
+ */
138
+ readonly jwtSecret = process.env.JWT_SECRET;
139
+
140
+ // ... more configuration items
141
+ }
142
+ ```
143
+
144
+ ### 2. Using Configuration in Client
145
+
146
+ ```typescript
147
+ // Using in components
148
+ function Analytics() {
149
+ // ✅ Correct: Get configuration object through IOC
150
+ const appConfig = IOC(IOCIdentifier.AppConfig);
151
+
152
+ useEffect(() => {
153
+ if (appConfig.analyticsId) {
154
+ // Initialize analytics
155
+ }
156
+ }, [appConfig.analyticsId]);
157
+
158
+ return appConfig.debug ? <DebugInfo /> : null;
159
+ }
160
+ ```
161
+
162
+ ### 3. Using Configuration in Server
163
+
164
+ ```typescript
165
+ // app/api/auth/[...nextauth]/route.ts
166
+ import { NextResponse } from 'next/server';
167
+
168
+ export async function GET() {
169
+ // ✅ Correct: Get configuration object through IOC
170
+ const appConfig = IOC(IOCIdentifier.AppConfig);
171
+
172
+ if (!appConfig.databaseUrl || !appConfig.jwtSecret) {
173
+ return NextResponse.json(
174
+ { error: 'Server configuration error' },
175
+ { status: 500 }
176
+ );
177
+ }
178
+
179
+ // Use configuration...
180
+ }
181
+ ```
182
+
183
+ ### 4. Using Configuration in Services
184
+
185
+ ```typescript
186
+ // Define service class
187
+ @injectable()
188
+ export class AdminService {
189
+ constructor(
190
+ @inject(IOCIdentifier.AppConfig)
191
+ private appConfig: AppConfig
192
+ ) {}
193
+
194
+ async fetchAdminData() {
195
+ const response = await fetch('https://api.example.com/admin', {
196
+ headers: {
197
+ Authorization: `Bearer ${this.appConfig.apiToken}`
198
+ }
199
+ });
200
+ return response.json();
201
+ }
202
+ }
203
+ ```
204
+
205
+ ## Best Practices
206
+
207
+ ### 1. Environment Variable Naming Conventions
208
+
209
+ ```bash
210
+ # ✅ Good naming
211
+ NEXT_PUBLIC_APP_NAME=MyApp
212
+ NEXT_PUBLIC_API_URL=https://api.example.com
213
+ NEXT_PUBLIC_FEATURE_FLAGS={"darkMode":true}
214
+
215
+ # ❌ Bad naming
216
+ next_public_app_name=MyApp # Should use uppercase
217
+ NEXT_PUBLIC_SECRET_KEY=xxx # Sensitive info shouldn't use NEXT_PUBLIC_
218
+ ```
219
+
220
+ ### 2. Configuration Class Implementation
221
+
222
+ ```typescript
223
+ // Define configuration interface
224
+ interface EnvConfigInterface {
225
+ readonly env: string;
226
+ readonly appName: string;
227
+ readonly appVersion: string;
228
+ // ... other configuration items
229
+ }
230
+
231
+ // Implement configuration class
232
+ @injectable()
233
+ export class AppConfig implements EnvConfigInterface {
234
+ /**
235
+ * Current environment mode
236
+ * @description Automatically set based on current .env file
237
+ */
238
+ readonly env: string = process.env.APP_ENV!;
239
+
240
+ /**
241
+ * Application name
242
+ */
243
+ readonly appName: string = name;
244
+
245
+ /**
246
+ * Application version
247
+ */
248
+ readonly appVersion: string = version;
249
+
250
+ /**
251
+ * User token storage key
252
+ */
253
+ readonly userTokenKey: string = '_user_token';
254
+
255
+ /**
256
+ * Database connection URL (server-side only)
257
+ */
258
+ readonly supabaseUrl: string = process.env.SUPABASE_URL!;
259
+
260
+ /**
261
+ * Database anonymous key (server-side only)
262
+ */
263
+ readonly supabaseAnonKey: string = process.env.SUPABASE_ANON_KEY!;
264
+
265
+ /**
266
+ * JWT secret (server-side only)
267
+ */
268
+ readonly jwtSecret: string = process.env.JWT_SECRET!;
269
+
270
+ /**
271
+ * JWT expiration time
272
+ * @example '30 days'
273
+ * @example '1 year'
274
+ */
275
+ readonly jwtExpiresIn: StringValue = '30 days';
276
+
277
+ /**
278
+ * OpenAI API configuration (server-side only)
279
+ */
280
+ readonly openaiBaseUrl: string = process.env.CEREBRAS_BASE_URL!;
281
+ readonly openaiApiKey: string = process.env.CEREBRAS_API_KEY!;
282
+ }
283
+ ```
284
+
285
+ ### 3. Configuration Validation
286
+
287
+ ```typescript
288
+ // Define configuration validator
289
+ @injectable()
290
+ export class ConfigValidator {
291
+ constructor(
292
+ @inject(IOCIdentifier.AppConfig)
293
+ private appConfig: AppConfig,
294
+ @inject(IOCIdentifier.Logger)
295
+ private logger: LoggerInterface
296
+ ) {}
297
+
298
+ /**
299
+ * Validate all required configuration items
300
+ * @throws {Error} When required configuration items are missing
301
+ */
302
+ validateRequiredConfig(): void {
303
+ // Validate basic configuration
304
+ this.validateBasicConfig();
305
+
306
+ // Validate different configurations based on runtime environment
307
+ if (typeof window === 'undefined') {
308
+ this.validateServerConfig();
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Validate basic configuration items
314
+ */
315
+ private validateBasicConfig(): void {
316
+ const requiredConfigs: Array<keyof AppConfig> = [
317
+ 'env',
318
+ 'appName',
319
+ 'appVersion',
320
+ 'userTokenKey'
321
+ ];
322
+
323
+ for (const key of requiredConfigs) {
324
+ if (!this.appConfig[key]) {
325
+ throw new Error(`Missing required config: ${key}`);
326
+ }
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Validate server-side configuration items
332
+ */
333
+ private validateServerConfig(): void {
334
+ const requiredServerConfigs: Array<keyof AppConfig> = [
335
+ 'supabaseUrl',
336
+ 'supabaseAnonKey',
337
+ 'jwtSecret',
338
+ 'openaiBaseUrl',
339
+ 'openaiApiKey'
340
+ ];
341
+
342
+ for (const key of requiredServerConfigs) {
343
+ if (!this.appConfig[key]) {
344
+ throw new Error(`Missing required server config: ${key}`);
345
+ }
346
+ }
347
+ }
348
+
349
+ /**
350
+ * Validate configuration value formats
351
+ */
352
+ validateConfigFormat(): void {
353
+ // Validate URL format
354
+ if (!this.isValidUrl(this.appConfig.supabaseUrl)) {
355
+ throw new Error('Invalid supabaseUrl format');
356
+ }
357
+
358
+ // Validate JWT expiration time format
359
+ if (!this.isValidDuration(this.appConfig.jwtExpiresIn)) {
360
+ throw new Error('Invalid jwtExpiresIn format');
361
+ }
362
+
363
+ this.logger.info('All config formats validated successfully');
364
+ }
365
+
366
+ private isValidUrl(url: string): boolean {
367
+ try {
368
+ new URL(url);
369
+ return true;
370
+ } catch {
371
+ return false;
372
+ }
373
+ }
374
+
375
+ private isValidDuration(duration: string): boolean {
376
+ // Implement duration format validation logic
377
+ return /^\d+\s+(days?|weeks?|months?|years?)$/.test(duration);
378
+ }
379
+ }
380
+ ```
381
+
382
+ ### 4. Handling Sensitive Information
383
+
384
+ ```bash
385
+ # .env.local (not committed to git)
386
+ DATABASE_URL=postgres://user:pass@localhost:5432/db
387
+ JWT_SECRET=your-secret-key
388
+ API_TOKEN=your-api-token
389
+
390
+ # .env.template (committed to git, as template)
391
+ DATABASE_URL=postgres://user:password@localhost:5432/dbname
392
+ JWT_SECRET=your-jwt-secret-here
393
+ API_TOKEN=your-api-token-here
394
+ ```
395
+
396
+ ## Debugging and Troubleshooting
397
+
398
+ ### 1. Configuration Debug Tool
399
+
400
+ ```typescript
401
+ @injectable()
402
+ export class ConfigDebugger {
403
+ constructor(
404
+ @inject(IOCIdentifier.AppConfig)
405
+ private appConfig: AppConfig,
406
+ @inject(IOCIdentifier.Logger)
407
+ private logger: LoggerInterface
408
+ ) {}
409
+
410
+ /**
411
+ * Print configuration information
412
+ */
413
+ logConfig(): void {
414
+ this.logger.group('Configuration Debug Info');
415
+
416
+ // Basic configuration
417
+ this.logger.info('Basic Config:', {
418
+ env: this.appConfig.env,
419
+ appName: this.appConfig.appName,
420
+ appVersion: this.appConfig.appVersion
421
+ });
422
+
423
+ // If on server-side, print server configuration
424
+ if (typeof window === 'undefined') {
425
+ this.logger.info('Server Config:', {
426
+ supabaseUrl: this.maskSensitiveInfo(this.appConfig.supabaseUrl),
427
+ jwtExpiresIn: this.appConfig.jwtExpiresIn
428
+ });
429
+ }
430
+
431
+ this.logger.groupEnd();
432
+ }
433
+
434
+ /**
435
+ * Validate configuration health status
436
+ */
437
+ async checkConfigHealth(): Promise<void> {
438
+ try {
439
+ // Validate database connection
440
+ if (typeof window === 'undefined') {
441
+ await this.checkDatabaseConnection();
442
+ }
443
+
444
+ // Validate other configuration items
445
+ this.validateConfigValues();
446
+
447
+ this.logger.info('Configuration health check passed');
448
+ } catch (error) {
449
+ this.logger.error('Configuration health check failed:', error);
450
+ throw error;
451
+ }
452
+ }
453
+
454
+ private async checkDatabaseConnection(): Promise<void> {
455
+ // Implement database connection check logic
456
+ }
457
+
458
+ private validateConfigValues(): void {
459
+ // Implement configuration value validation logic
460
+ }
461
+
462
+ private maskSensitiveInfo(value: string): string {
463
+ return value.replace(/^(https?:\/\/[^:]+:)([^@]+)(@.*)$/, '$1****$3');
464
+ }
465
+ }
466
+ ```
467
+
468
+ ### 2. Common Issues Handling
469
+
470
+ **Issue 1: Configuration Not Properly Injected**
471
+
472
+ ```typescript
473
+ // ❌ Wrong: Using environment variables directly
474
+ class UserService {
475
+ private apiUrl = process.env.NEXT_PUBLIC_API_URL;
476
+ }
477
+
478
+ // ✅ Correct: Get through configuration class
479
+ @injectable()
480
+ class UserService {
481
+ constructor(
482
+ @inject(IOCIdentifier.AppConfig)
483
+ private appConfig: AppConfig
484
+ ) {}
485
+ }
486
+ ```
487
+
488
+ **Issue 2: Configuration Validation Failed**
489
+
490
+ ```typescript
491
+ // ❌ Wrong: No configuration validation
492
+ @injectable()
493
+ class ApiService {
494
+ constructor(
495
+ @inject(IOCIdentifier.AppConfig)
496
+ private appConfig: AppConfig
497
+ ) {}
498
+ }
499
+
500
+ // ✅ Correct: Include configuration validation
501
+ @injectable()
502
+ class ApiService {
503
+ constructor(
504
+ @inject(IOCIdentifier.AppConfig)
505
+ private appConfig: AppConfig,
506
+ @inject(IOCIdentifier.ConfigValidator)
507
+ private configValidator: ConfigValidator
508
+ ) {
509
+ this.configValidator.validateRequiredConfig();
510
+ }
511
+ }
512
+ ```
513
+
514
+ **Issue 3: Configuration Type Handling**
515
+
516
+ ```typescript
517
+ // ❌ Wrong: Manual type conversion
518
+ class FeatureService {
519
+ private isDebug = process.env.NEXT_PUBLIC_DEBUG === 'true';
520
+ }
521
+
522
+ // ✅ Correct: Handle type conversion in configuration class
523
+ @injectable()
524
+ export class AppConfig implements EnvConfigInterface {
525
+ readonly debug: boolean = this.parseBoolean(process.env.NEXT_PUBLIC_DEBUG);
526
+
527
+ private parseBoolean(value: string | undefined): boolean {
528
+ return value?.toLowerCase() === 'true';
529
+ }
530
+ }
531
+ ```
532
+
533
+ ## Summary
534
+
535
+ The object-oriented configuration management system provides:
536
+
537
+ 1. **Configuration Encapsulation**:
538
+ - Unified management of all configurations through `AppConfig` class
539
+ - Implement `EnvConfigInterface` interface to ensure configuration completeness
540
+ - Use dependency injection to achieve configuration decoupling
541
+
542
+ 2. **Type Safety**:
543
+ - Handle type conversion in configuration class
544
+ - TypeScript interface definitions ensure type correctness
545
+ - Compile-time type checking
546
+
547
+ 3. **Configuration Validation**:
548
+ - Dedicated `ConfigValidator` class handles configuration validation
549
+ - Runtime configuration completeness check
550
+ - Configuration format validation
551
+
552
+ 4. **Best Practices**:
553
+ - Dependency injection for configuration management
554
+ - Configuration validation and debugging tools
555
+ - Sensitive information protection
556
+ - Type-safe handling
557
+
558
+ Through object-oriented configuration management, we can:
559
+
560
+ - Improve code maintainability and testability
561
+ - Ensure configuration type safety and completeness
562
+ - Easily perform configuration validation and debugging
563
+ - Better manage configuration dependencies