@abuhannaa/create-apptemplate 1.0.12 → 1.1.0

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