@abuhannaa/create-apptemplate 1.0.9 → 1.0.11

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