@abuhannaa/create-apptemplate 1.0.9 → 1.0.10

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/dist/index.js CHANGED
@@ -4,12 +4,669 @@
4
4
  import { intro, outro, isCancel as isCancel2 } from "@clack/prompts";
5
5
  import pc3 from "picocolors";
6
6
 
7
+ // src/types.ts
8
+ var ALL_FEATURES = [
9
+ "auth",
10
+ "userManagement",
11
+ "departments",
12
+ "fileUpload",
13
+ "auditLogs",
14
+ "notifications",
15
+ "dataExport",
16
+ "dashboard"
17
+ ];
18
+
19
+ // src/features.ts
20
+ var FEATURE_OPTIONS = [
21
+ {
22
+ value: "auth",
23
+ label: "Authentication (Login, JWT, Guards)",
24
+ hint: "Login/logout pages, JWT middleware, auth guards, profile"
25
+ },
26
+ {
27
+ value: "userManagement",
28
+ label: "User Management",
29
+ hint: "User CRUD, roles, permissions"
30
+ },
31
+ {
32
+ value: "departments",
33
+ label: "Departments",
34
+ hint: "Department CRUD module"
35
+ },
36
+ {
37
+ value: "fileUpload",
38
+ label: "File Management",
39
+ hint: "File upload, download, preview"
40
+ },
41
+ {
42
+ value: "auditLogs",
43
+ label: "Audit Logging",
44
+ hint: "Track all data changes with audit trail"
45
+ },
46
+ {
47
+ value: "notifications",
48
+ label: "Notifications",
49
+ hint: "Real-time notification system (WebSocket)"
50
+ },
51
+ {
52
+ value: "dataExport",
53
+ label: "Data Export",
54
+ hint: "CSV, Excel, PDF export"
55
+ },
56
+ {
57
+ value: "dashboard",
58
+ label: "Dashboard",
59
+ hint: "Dashboard page with statistics (Requires Users, Depts, Notifications)"
60
+ }
61
+ ];
62
+ function applyFeatureDependencies(selected) {
63
+ let result = [...selected];
64
+ if (!result.includes("auth")) {
65
+ result = result.filter((f) => f !== "userManagement" && f !== "departments");
66
+ }
67
+ if (!result.includes("userManagement")) {
68
+ result = result.filter((f) => f !== "departments");
69
+ }
70
+ if (!result.includes("userManagement") || !result.includes("departments") || !result.includes("notifications")) {
71
+ result = result.filter((f) => f !== "dashboard");
72
+ }
73
+ return result;
74
+ }
75
+ var DOTNET_CLEAN_MAP = {
76
+ auth: {
77
+ backend: [
78
+ // Application layer
79
+ "src/Core/App.Template.Application/Features/Authentication",
80
+ "src/Core/App.Template.Application/DTOs/Auth",
81
+ "src/Core/App.Template.Application/Interfaces/IJwtTokenService.cs",
82
+ "src/Core/App.Template.Application/Interfaces/IPasswordHashService.cs",
83
+ "src/Core/App.Template.Application/Interfaces/ISsoAuthService.cs",
84
+ "src/Core/App.Template.Application/Interfaces/IEmailService.cs",
85
+ // Infrastructure layer
86
+ "src/Infrastructure/App.Template.Infrastructure/Services/JwtTokenService.cs",
87
+ "src/Infrastructure/App.Template.Infrastructure/Services/PasswordHashService.cs",
88
+ "src/Infrastructure/App.Template.Infrastructure/Services/SsoAuthService.cs",
89
+ "src/Infrastructure/App.Template.Infrastructure/Services/SsoApiModels.cs",
90
+ "src/Infrastructure/App.Template.Infrastructure/Services/EmailService.cs",
91
+ // Presentation layer
92
+ "src/Presentation/App.Template.WebAPI/Controllers/AuthController.cs"
93
+ ],
94
+ frontend: []
95
+ // Frontend auth files handled by pattern below
96
+ },
97
+ userManagement: {
98
+ backend: [
99
+ "src/Core/App.Template.Application/Features/UserManagement",
100
+ "src/Core/App.Template.Application/DTOs/UserDto.cs",
101
+ "src/Presentation/App.Template.WebAPI/Controllers/UsersController.cs"
102
+ ],
103
+ frontend: []
104
+ },
105
+ departments: {
106
+ backend: [
107
+ "src/Core/App.Template.Application/Features/DepartmentManagement",
108
+ "src/Core/App.Template.Application/DTOs/DepartmentDto.cs",
109
+ "src/Core/App.Template.Application/Interfaces/IOrganizationService.cs",
110
+ "src/Infrastructure/App.Template.Infrastructure/Services/OrganizationService.cs",
111
+ "src/Presentation/App.Template.WebAPI/Controllers/DepartmentsController.cs"
112
+ ],
113
+ frontend: []
114
+ },
115
+ fileUpload: {
116
+ backend: [
117
+ "src/Core/App.Template.Application/Features/FileManagement",
118
+ "src/Core/App.Template.Application/DTOs/UploadedFileDto.cs",
119
+ "src/Core/App.Template.Application/Interfaces/IFileStorageService.cs",
120
+ "src/Infrastructure/App.Template.Infrastructure/Services/FileStorageService.cs",
121
+ "src/Presentation/App.Template.WebAPI/Controllers/FilesController.cs"
122
+ ],
123
+ frontend: []
124
+ },
125
+ auditLogs: {
126
+ backend: [
127
+ "src/Core/App.Template.Application/Features/AuditLogManagement",
128
+ "src/Core/App.Template.Application/DTOs/AuditLogDto.cs",
129
+ "src/Infrastructure/App.Template.Infrastructure/Persistence/AuditEntry.cs",
130
+ "src/Presentation/App.Template.WebAPI/Controllers/AuditLogsController.cs"
131
+ ],
132
+ frontend: []
133
+ },
134
+ notifications: {
135
+ backend: [
136
+ "src/Core/App.Template.Application/Features/NotificationManagement",
137
+ "src/Core/App.Template.Application/DTOs/NotificationDto.cs",
138
+ "src/Core/App.Template.Application/Interfaces/INotificationService.cs",
139
+ "src/Infrastructure/App.Template.Infrastructure/Services/NotificationService.cs",
140
+ "src/Infrastructure/App.Template.Infrastructure/Hubs",
141
+ "src/Infrastructure/App.Template.Infrastructure/SignalR",
142
+ "src/Presentation/App.Template.WebAPI/Controllers/NotificationsController.cs"
143
+ ],
144
+ frontend: []
145
+ },
146
+ dataExport: {
147
+ backend: [
148
+ "src/Core/App.Template.Application/Interfaces/IExportService.cs",
149
+ "src/Infrastructure/App.Template.Infrastructure/Services/ExportService.cs",
150
+ "src/Presentation/App.Template.WebAPI/Controllers/ExportController.cs"
151
+ ],
152
+ frontend: []
153
+ },
154
+ dashboard: {
155
+ backend: [],
156
+ frontend: []
157
+ }
158
+ };
159
+ var DOTNET_NLAYER_MAP = {
160
+ auth: {
161
+ backend: [
162
+ "src/App.Template.Api/Controllers/AuthController.cs",
163
+ "src/App.Template.Api/Services/AuthService.cs",
164
+ "src/App.Template.Api/Services/JwtTokenGenerator.cs",
165
+ "src/App.Template.Api/Models/Dtos/AuthDtos.cs"
166
+ ],
167
+ frontend: []
168
+ },
169
+ userManagement: {
170
+ backend: [
171
+ "src/App.Template.Api/Controllers/UsersController.cs",
172
+ "src/App.Template.Api/Services/UserService.cs",
173
+ "src/App.Template.Api/Services/IUserService.cs",
174
+ "src/App.Template.Api/Repositories/UserRepository.cs",
175
+ "src/App.Template.Api/Repositories/IUserRepository.cs",
176
+ "src/App.Template.Api/Models/Dtos/UserDtos.cs"
177
+ ],
178
+ frontend: []
179
+ },
180
+ departments: {
181
+ backend: [
182
+ "src/App.Template.Api/Controllers/DepartmentsController.cs",
183
+ "src/App.Template.Api/Models/Dtos/DepartmentDtos.cs"
184
+ ],
185
+ frontend: []
186
+ },
187
+ fileUpload: {
188
+ backend: [
189
+ "src/App.Template.Api/Controllers/FilesController.cs"
190
+ ],
191
+ frontend: []
192
+ },
193
+ auditLogs: {
194
+ backend: [],
195
+ frontend: []
196
+ },
197
+ notifications: {
198
+ backend: [
199
+ "src/App.Template.Api/Controllers/NotificationsController.cs",
200
+ "src/App.Template.Api/Infrastructure/Hubs"
201
+ ],
202
+ frontend: []
203
+ },
204
+ dataExport: {
205
+ backend: [
206
+ "src/App.Template.Api/Controllers/ExportController.cs"
207
+ ],
208
+ frontend: []
209
+ },
210
+ dashboard: {
211
+ backend: [],
212
+ frontend: []
213
+ }
214
+ };
215
+ var DOTNET_FEATURE_MAP = {
216
+ auth: {
217
+ backend: [
218
+ "src/App.Template.Api/Features/Auth"
219
+ ],
220
+ frontend: []
221
+ },
222
+ userManagement: {
223
+ backend: [
224
+ "src/App.Template.Api/Features/Users"
225
+ ],
226
+ frontend: []
227
+ },
228
+ departments: {
229
+ backend: [
230
+ "src/App.Template.Api/Features/Departments"
231
+ ],
232
+ frontend: []
233
+ },
234
+ fileUpload: {
235
+ backend: [
236
+ "src/App.Template.Api/Features/Files"
237
+ ],
238
+ frontend: []
239
+ },
240
+ auditLogs: {
241
+ backend: [],
242
+ frontend: []
243
+ },
244
+ notifications: {
245
+ backend: [
246
+ "src/App.Template.Api/Features/Notifications"
247
+ ],
248
+ frontend: []
249
+ },
250
+ dataExport: {
251
+ backend: [
252
+ "src/App.Template.Api/Features/Export"
253
+ ],
254
+ frontend: []
255
+ },
256
+ dashboard: {
257
+ backend: [],
258
+ frontend: []
259
+ }
260
+ };
261
+ var SPRING_CLEAN_MAP = {
262
+ auth: {
263
+ backend: [
264
+ "api/src/main/java/apptemplate/api/controllers/AuthController.java"
265
+ ],
266
+ frontend: []
267
+ },
268
+ userManagement: {
269
+ backend: [
270
+ "api/src/main/java/apptemplate/api/controllers/UsersController.java"
271
+ ],
272
+ frontend: []
273
+ },
274
+ departments: {
275
+ backend: [
276
+ "api/src/main/java/apptemplate/api/controllers/DepartmentsController.java"
277
+ ],
278
+ frontend: []
279
+ },
280
+ fileUpload: {
281
+ backend: [
282
+ "api/src/main/java/apptemplate/api/controllers/FilesController.java"
283
+ ],
284
+ frontend: []
285
+ },
286
+ auditLogs: {
287
+ backend: [
288
+ "api/src/main/java/apptemplate/api/controllers/AuditLogsController.java"
289
+ ],
290
+ frontend: []
291
+ },
292
+ notifications: {
293
+ backend: [
294
+ "api/src/main/java/apptemplate/api/controllers/NotificationsController.java"
295
+ ],
296
+ frontend: []
297
+ },
298
+ dataExport: {
299
+ backend: [
300
+ "api/src/main/java/apptemplate/api/controllers/ExportController.java"
301
+ ],
302
+ frontend: []
303
+ },
304
+ dashboard: {
305
+ backend: [],
306
+ frontend: []
307
+ }
308
+ };
309
+ var SPRING_NLAYER_MAP = {
310
+ auth: {
311
+ backend: [
312
+ "src/main/java/com/apptemplate/api/controller/AuthController.java"
313
+ ],
314
+ frontend: []
315
+ },
316
+ userManagement: {
317
+ backend: [
318
+ "src/main/java/com/apptemplate/api/controller/UserController.java"
319
+ ],
320
+ frontend: []
321
+ },
322
+ departments: {
323
+ backend: [
324
+ "src/main/java/com/apptemplate/api/controller/DepartmentController.java"
325
+ ],
326
+ frontend: []
327
+ },
328
+ fileUpload: {
329
+ backend: [
330
+ "src/main/java/com/apptemplate/api/controller/FileController.java"
331
+ ],
332
+ frontend: []
333
+ },
334
+ auditLogs: {
335
+ backend: [
336
+ "src/main/java/com/apptemplate/api/audit"
337
+ ],
338
+ frontend: []
339
+ },
340
+ notifications: {
341
+ backend: [
342
+ "src/main/java/com/apptemplate/api/controller/NotificationController.java"
343
+ ],
344
+ frontend: []
345
+ },
346
+ dataExport: {
347
+ backend: [
348
+ "src/main/java/com/apptemplate/api/controller/ExportController.java"
349
+ ],
350
+ frontend: []
351
+ },
352
+ dashboard: {
353
+ backend: [],
354
+ frontend: []
355
+ }
356
+ };
357
+ var SPRING_FEATURE_MAP = {
358
+ auth: {
359
+ backend: [
360
+ "src/main/java/com/apptemplate/api/features/auth"
361
+ ],
362
+ frontend: []
363
+ },
364
+ userManagement: {
365
+ backend: [
366
+ "src/main/java/com/apptemplate/api/features/users"
367
+ ],
368
+ frontend: []
369
+ },
370
+ departments: {
371
+ backend: [
372
+ "src/main/java/com/apptemplate/api/features/departments"
373
+ ],
374
+ frontend: []
375
+ },
376
+ fileUpload: {
377
+ backend: [
378
+ "src/main/java/com/apptemplate/api/features/files"
379
+ ],
380
+ frontend: []
381
+ },
382
+ auditLogs: {
383
+ backend: [
384
+ "src/main/java/com/apptemplate/api/common/audit"
385
+ ],
386
+ frontend: []
387
+ },
388
+ notifications: {
389
+ backend: [
390
+ "src/main/java/com/apptemplate/api/features/notifications"
391
+ ],
392
+ frontend: []
393
+ },
394
+ dataExport: {
395
+ backend: [
396
+ "src/main/java/com/apptemplate/api/features/export"
397
+ ],
398
+ frontend: []
399
+ },
400
+ dashboard: {
401
+ backend: [],
402
+ frontend: []
403
+ }
404
+ };
405
+ var NESTJS_CLEAN_MAP = {
406
+ auth: {
407
+ backend: [
408
+ "src/modules/auth"
409
+ ],
410
+ frontend: []
411
+ },
412
+ userManagement: {
413
+ backend: [
414
+ "src/modules/user-management"
415
+ ],
416
+ frontend: []
417
+ },
418
+ departments: {
419
+ backend: [
420
+ "src/modules/department-management"
421
+ ],
422
+ frontend: []
423
+ },
424
+ fileUpload: {
425
+ backend: [
426
+ "src/modules/file-management"
427
+ ],
428
+ frontend: []
429
+ },
430
+ auditLogs: {
431
+ backend: [
432
+ "src/modules/audit-log"
433
+ ],
434
+ frontend: []
435
+ },
436
+ notifications: {
437
+ backend: [
438
+ "src/modules/notification"
439
+ ],
440
+ frontend: []
441
+ },
442
+ dataExport: {
443
+ backend: [
444
+ "src/modules/export"
445
+ ],
446
+ frontend: []
447
+ },
448
+ dashboard: {
449
+ backend: [],
450
+ frontend: []
451
+ }
452
+ };
453
+ var NESTJS_NLAYER_MAP = {
454
+ auth: {
455
+ backend: [
456
+ "src/auth"
457
+ ],
458
+ frontend: []
459
+ },
460
+ userManagement: {
461
+ backend: [],
462
+ frontend: []
463
+ },
464
+ departments: {
465
+ backend: [
466
+ "src/modules/departments"
467
+ ],
468
+ frontend: []
469
+ },
470
+ fileUpload: {
471
+ backend: [
472
+ "src/modules/files"
473
+ ],
474
+ frontend: []
475
+ },
476
+ auditLogs: {
477
+ backend: [],
478
+ frontend: []
479
+ },
480
+ notifications: {
481
+ backend: [
482
+ "src/modules/notifications"
483
+ ],
484
+ frontend: []
485
+ },
486
+ dataExport: {
487
+ backend: [
488
+ "src/modules/export"
489
+ ],
490
+ frontend: []
491
+ },
492
+ dashboard: {
493
+ backend: [],
494
+ frontend: []
495
+ }
496
+ };
497
+ var NESTJS_FEATURE_MAP = {
498
+ auth: {
499
+ backend: [
500
+ "src/features/auth"
501
+ ],
502
+ frontend: []
503
+ },
504
+ userManagement: {
505
+ backend: [
506
+ "src/features/users"
507
+ ],
508
+ frontend: []
509
+ },
510
+ departments: {
511
+ backend: [
512
+ "src/features/departments"
513
+ ],
514
+ frontend: []
515
+ },
516
+ fileUpload: {
517
+ backend: [
518
+ "src/features/files"
519
+ ],
520
+ frontend: []
521
+ },
522
+ auditLogs: {
523
+ backend: [],
524
+ frontend: []
525
+ },
526
+ notifications: {
527
+ backend: [
528
+ "src/features/notifications"
529
+ ],
530
+ frontend: []
531
+ },
532
+ dataExport: {
533
+ backend: [
534
+ "src/features/export"
535
+ ],
536
+ frontend: []
537
+ },
538
+ dashboard: {
539
+ backend: [],
540
+ frontend: []
541
+ }
542
+ };
543
+ var VUE_FRONTEND_MAP = {
544
+ auth: [
545
+ "src/pages/login.vue",
546
+ "src/pages/forgot-password.vue",
547
+ "src/pages/reset-password.vue",
548
+ "src/pages/profile.vue",
549
+ "src/stores/auth.js",
550
+ "src/services/authApi.js"
551
+ ],
552
+ userManagement: [
553
+ "src/pages/users",
554
+ "src/stores/user.js",
555
+ "src/services/userApi.js"
556
+ ],
557
+ departments: [
558
+ "src/pages/departments",
559
+ "src/stores/department.js",
560
+ "src/services/departmentApi.js"
561
+ ],
562
+ fileUpload: [
563
+ "src/pages/files",
564
+ "src/services/fileService.js"
565
+ ],
566
+ auditLogs: [
567
+ "src/pages/audit-logs",
568
+ "src/services/auditLogService.js"
569
+ ],
570
+ notifications: [
571
+ "src/pages/notifications",
572
+ "src/stores/notification.js",
573
+ "src/stores/persistentNotification.js",
574
+ "src/services/notificationApi.js"
575
+ ],
576
+ dataExport: [
577
+ "src/services/exportService.js"
578
+ ],
579
+ dashboard: [
580
+ "src/pages/dashboard.vue"
581
+ ]
582
+ };
583
+ var REACT_FRONTEND_MAP = {
584
+ auth: [
585
+ "src/pages/Login.tsx",
586
+ "src/pages/ForgotPassword.tsx",
587
+ "src/pages/ResetPassword.tsx",
588
+ "src/pages/Profile.tsx",
589
+ "src/stores/authStore.ts",
590
+ "src/services/authApi.ts"
591
+ ],
592
+ userManagement: [
593
+ "src/pages/Users.tsx",
594
+ "src/stores/userStore.ts",
595
+ "src/services/userApi.ts"
596
+ ],
597
+ departments: [
598
+ "src/pages/Departments.tsx",
599
+ "src/stores/departmentStore.ts",
600
+ "src/services/departmentApi.ts"
601
+ ],
602
+ fileUpload: [
603
+ "src/pages/FilesPage.tsx",
604
+ "src/services/fileService.ts"
605
+ ],
606
+ auditLogs: [
607
+ "src/pages/AuditLogsPage.tsx",
608
+ "src/pages/AuditLogs.tsx",
609
+ "src/services/auditLogService.ts"
610
+ ],
611
+ notifications: [
612
+ "src/pages/Notifications.tsx",
613
+ "src/stores/notificationStore.ts",
614
+ "src/stores/persistentNotificationStore.ts",
615
+ "src/services/notificationApi.ts"
616
+ ],
617
+ dataExport: [
618
+ "src/services/exportService.ts"
619
+ ],
620
+ dashboard: [
621
+ "src/pages/Dashboard.tsx",
622
+ "src/pages/Dashboard.scss"
623
+ ]
624
+ };
625
+ function getBackendFileMap(backend, architecture) {
626
+ const key = `${backend}-${architecture}`;
627
+ switch (key) {
628
+ case "dotnet-clean":
629
+ return DOTNET_CLEAN_MAP;
630
+ case "dotnet-nlayer":
631
+ return DOTNET_NLAYER_MAP;
632
+ case "dotnet-feature":
633
+ return DOTNET_FEATURE_MAP;
634
+ case "spring-clean":
635
+ return SPRING_CLEAN_MAP;
636
+ case "spring-nlayer":
637
+ return SPRING_NLAYER_MAP;
638
+ case "spring-feature":
639
+ return SPRING_FEATURE_MAP;
640
+ case "nestjs-clean":
641
+ return NESTJS_CLEAN_MAP;
642
+ case "nestjs-nlayer":
643
+ return NESTJS_NLAYER_MAP;
644
+ case "nestjs-feature":
645
+ return NESTJS_FEATURE_MAP;
646
+ default:
647
+ return {};
648
+ }
649
+ }
650
+ function getFrontendFileMap(frontendFramework) {
651
+ return frontendFramework === "vue" ? VUE_FRONTEND_MAP : REACT_FRONTEND_MAP;
652
+ }
653
+ function getFeaturesLabel(features, allFeatures) {
654
+ if (features.length === allFeatures.length) {
655
+ return "All features";
656
+ }
657
+ if (features.length === 0) {
658
+ return "None (bare template)";
659
+ }
660
+ return features.map((f) => FEATURE_OPTIONS.find((o) => o.value === f)?.label || f).join(", ");
661
+ }
662
+
7
663
  // src/cli.ts
8
664
  var validProjectTypes = ["fullstack", "backend", "frontend"];
9
665
  var validBackends = ["dotnet", "spring", "nestjs"];
10
666
  var validArchitectures = ["clean", "nlayer", "feature"];
11
667
  var validFrontendFrameworks = ["vue", "react"];
12
668
  var validUILibraries = ["vuetify", "primevue", "primereact", "mui"];
669
+ var validFeatures = [...ALL_FEATURES];
13
670
  function parseArgs() {
14
671
  const args = process.argv.slice(2);
15
672
  const result = {};
@@ -96,6 +753,24 @@ function parseArgs() {
96
753
  i++;
97
754
  continue;
98
755
  }
756
+ if (arg === "--features" || arg === "--feat") {
757
+ const value = args[++i];
758
+ if (value) {
759
+ if (value === "all") {
760
+ result.features = [...ALL_FEATURES];
761
+ } else {
762
+ const requested = value.split(",").map((s) => s.trim());
763
+ const valid = requested.filter((f) => validFeatures.includes(f));
764
+ const invalid = requested.filter((f) => !validFeatures.includes(f));
765
+ if (invalid.length > 0) {
766
+ console.warn(`Warning: Invalid features "${invalid.join(", ")}". Valid options: ${validFeatures.join(", ")}`);
767
+ }
768
+ result.features = applyFeatureDependencies(valid);
769
+ }
770
+ }
771
+ i++;
772
+ continue;
773
+ }
99
774
  if (!arg.startsWith("-") && !result.projectPath) {
100
775
  result.projectPath = arg;
101
776
  }
@@ -276,6 +951,26 @@ async function runInteractivePrompts(cliArgs) {
276
951
  if (p.isCancel(result)) return result;
277
952
  ui = result;
278
953
  }
954
+ let features = cliArgs.features || [...ALL_FEATURES];
955
+ if (!cliArgs.features) {
956
+ const result = await p.multiselect({
957
+ message: "Which features would you like to include?",
958
+ options: FEATURE_OPTIONS.map((opt) => ({
959
+ value: opt.value,
960
+ label: opt.label,
961
+ hint: opt.hint
962
+ })),
963
+ initialValues: [...ALL_FEATURES],
964
+ required: false
965
+ });
966
+ if (p.isCancel(result)) return result;
967
+ features = applyFeatureDependencies(result);
968
+ if (features.length < result.length) {
969
+ const removed = result.filter((f) => !features.includes(f));
970
+ const removedLabels = removed.map((f) => FEATURE_OPTIONS.find((o) => o.value === f)?.label || f);
971
+ console.log(pc.yellow(` \u26A0 Auto-removed due to dependencies: ${removedLabels.join(", ")}`));
972
+ }
973
+ }
279
974
  let projectName = cliArgs.projectName;
280
975
  const needsNamespace = projectType !== "frontend" && (backend === "dotnet" || backend === "spring");
281
976
  if (needsNamespace && !projectName) {
@@ -328,6 +1023,7 @@ async function runInteractivePrompts(cliArgs) {
328
1023
  summaryLines.push(`${pc.cyan("Frontend:")} ${getFrontendLabel(frontendFramework)}`);
329
1024
  summaryLines.push(`${pc.cyan("UI Library:")} ${getUILabel(ui)}`);
330
1025
  }
1026
+ summaryLines.push(`${pc.cyan("Features:")} ${getFeaturesLabel(features, ALL_FEATURES)}`);
331
1027
  if (needsNamespace && projectName) {
332
1028
  summaryLines.push(`${pc.cyan("Namespace:")} ${projectName}`);
333
1029
  }
@@ -352,7 +1048,8 @@ async function runInteractivePrompts(cliArgs) {
352
1048
  ui,
353
1049
  projectName,
354
1050
  installDeps,
355
- placeInRoot
1051
+ placeInRoot,
1052
+ features
356
1053
  };
357
1054
  }
358
1055
  function toPascalCase(str) {
@@ -760,6 +1457,16 @@ async function generateProject(config) {
760
1457
  spinner2.stop("Download failed");
761
1458
  throw error;
762
1459
  }
1460
+ const deselectedFeatures = ALL_FEATURES.filter((f) => !config.features.includes(f));
1461
+ if (deselectedFeatures.length > 0) {
1462
+ spinner2.start("Removing deselected feature files...");
1463
+ try {
1464
+ await removeDeselectedFeatures(absolutePath, config, deselectedFeatures);
1465
+ spinner2.stop(`Removed ${deselectedFeatures.length} deselected feature(s)`);
1466
+ } catch (error) {
1467
+ spinner2.stop("Feature removal had warnings");
1468
+ }
1469
+ }
763
1470
  spinner2.start("Updating configuration files...");
764
1471
  try {
765
1472
  await updateFolderReferences(absolutePath, config);
@@ -804,6 +1511,48 @@ async function generateProject(config) {
804
1511
  await createAppSettingsFromExample(absolutePath, config);
805
1512
  }
806
1513
  }
1514
+ async function removeDeselectedFeatures(projectPath, config, deselectedFeatures) {
1515
+ if (config.projectType !== "frontend") {
1516
+ const backendMap = getBackendFileMap(config.backend, config.architecture);
1517
+ let backendDir;
1518
+ if (config.projectType === "fullstack") {
1519
+ backendDir = path5.join(projectPath, "backend");
1520
+ } else {
1521
+ backendDir = config.placeInRoot ? projectPath : path5.join(projectPath, "backend");
1522
+ }
1523
+ for (const feature of deselectedFeatures) {
1524
+ const featureMap = backendMap[feature];
1525
+ if (featureMap) {
1526
+ for (const filePath of featureMap.backend) {
1527
+ const fullPath = path5.join(backendDir, filePath);
1528
+ if (fs5.existsSync(fullPath)) {
1529
+ fs5.rmSync(fullPath, { recursive: true, force: true });
1530
+ }
1531
+ }
1532
+ }
1533
+ }
1534
+ }
1535
+ if (config.projectType !== "backend") {
1536
+ const frontendMap = getFrontendFileMap(config.frontendFramework);
1537
+ let frontendDir;
1538
+ if (config.projectType === "fullstack") {
1539
+ frontendDir = path5.join(projectPath, "frontend");
1540
+ } else {
1541
+ frontendDir = config.placeInRoot ? projectPath : path5.join(projectPath, "frontend");
1542
+ }
1543
+ for (const feature of deselectedFeatures) {
1544
+ const featurePaths = frontendMap[feature];
1545
+ if (featurePaths) {
1546
+ for (const filePath of featurePaths) {
1547
+ const fullPath = path5.join(frontendDir, filePath);
1548
+ if (fs5.existsSync(fullPath)) {
1549
+ fs5.rmSync(fullPath, { recursive: true, force: true });
1550
+ }
1551
+ }
1552
+ }
1553
+ }
1554
+ }
1555
+ }
807
1556
  function cleanupFullstackDockerFiles(projectPath) {
808
1557
  const filesToDelete = [
809
1558
  "backend/Dockerfile",
@@ -967,7 +1716,8 @@ async function main() {
967
1716
  ui: cliArgs.ui || (frontendFramework === "vue" ? "vuetify" : "mui"),
968
1717
  projectName: cliArgs.projectName,
969
1718
  installDeps: cliArgs.install || false,
970
- placeInRoot: cliArgs.root || false
1719
+ placeInRoot: cliArgs.root || false,
1720
+ features: cliArgs.features || [...ALL_FEATURES]
971
1721
  };
972
1722
  } else {
973
1723
  const result = await runInteractivePrompts(cliArgs);
@@ -1003,6 +1753,8 @@ ${pc3.bold("Options:")}
1003
1753
  ${pc3.yellow("-u, --ui")} UI library: vuetify, primevue (Vue) | mui, primereact (React)
1004
1754
  ${pc3.yellow("-n, --name")} Project namespace (Company.Project format, .NET/Spring only)
1005
1755
  ${pc3.yellow("-r, --root")} Place files in project root ${pc3.gray("(backend/frontend-only)")}
1756
+ ${pc3.yellow("--features")} Features to include (comma-separated or "all")
1757
+ Options: auth,userManagement,departments,fileUpload,auditLogs,notifications,dataExport,dashboard
1006
1758
  ${pc3.yellow("-i, --install")} Install dependencies after creation
1007
1759
  ${pc3.yellow("-h, --help")} Show this help message
1008
1760
  ${pc3.yellow("-v, --version")} Show version number