@mandujs/core 0.12.1 → 0.13.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.
Files changed (177) hide show
  1. package/README.ko.md +304 -304
  2. package/README.md +653 -653
  3. package/package.json +8 -8
  4. package/src/brain/architecture/analyzer.ts +28 -26
  5. package/src/brain/doctor/analyzer.ts +1 -1
  6. package/src/bundler/build.ts +91 -91
  7. package/src/bundler/css.ts +302 -302
  8. package/src/bundler/dev.ts +0 -1
  9. package/src/change/history.ts +3 -3
  10. package/src/change/snapshot.ts +10 -9
  11. package/src/change/transaction.ts +2 -2
  12. package/src/client/Link.tsx +227 -227
  13. package/src/client/globals.ts +44 -44
  14. package/src/client/hooks.ts +267 -267
  15. package/src/client/index.ts +5 -5
  16. package/src/client/island.ts +8 -8
  17. package/src/client/router.ts +435 -435
  18. package/src/client/runtime.ts +23 -23
  19. package/src/client/serialize.ts +404 -404
  20. package/src/client/window-state.ts +101 -101
  21. package/src/config/mandu.ts +94 -96
  22. package/src/config/validate.ts +213 -215
  23. package/src/config/watcher.ts +311 -311
  24. package/src/constants.ts +40 -40
  25. package/src/content/content-layer.ts +314 -314
  26. package/src/content/content.test.ts +433 -433
  27. package/src/content/data-store.ts +245 -245
  28. package/src/content/digest.ts +133 -133
  29. package/src/content/index.ts +164 -164
  30. package/src/content/loader-context.ts +172 -172
  31. package/src/content/loaders/api.ts +216 -216
  32. package/src/content/loaders/file.ts +169 -169
  33. package/src/content/loaders/glob.ts +252 -252
  34. package/src/content/loaders/index.ts +34 -34
  35. package/src/content/loaders/types.ts +137 -137
  36. package/src/content/meta-store.ts +209 -209
  37. package/src/content/types.ts +282 -282
  38. package/src/content/watcher.ts +135 -135
  39. package/src/contract/client-safe.test.ts +42 -42
  40. package/src/contract/client-safe.ts +114 -114
  41. package/src/contract/client.ts +16 -16
  42. package/src/contract/define.ts +459 -459
  43. package/src/contract/handler.ts +10 -10
  44. package/src/contract/normalize.test.ts +276 -276
  45. package/src/contract/normalize.ts +404 -404
  46. package/src/contract/registry.test.ts +206 -206
  47. package/src/contract/registry.ts +568 -568
  48. package/src/contract/schema.ts +48 -48
  49. package/src/contract/types.ts +58 -58
  50. package/src/contract/validator.ts +32 -32
  51. package/src/devtools/ai/context-builder.ts +375 -375
  52. package/src/devtools/ai/index.ts +25 -25
  53. package/src/devtools/ai/mcp-connector.ts +465 -465
  54. package/src/devtools/client/catchers/error-catcher.ts +327 -327
  55. package/src/devtools/client/catchers/index.ts +18 -18
  56. package/src/devtools/client/catchers/network-proxy.ts +363 -363
  57. package/src/devtools/client/components/index.ts +39 -39
  58. package/src/devtools/client/components/kitchen-root.tsx +362 -362
  59. package/src/devtools/client/components/mandu-character.tsx +241 -241
  60. package/src/devtools/client/components/overlay.tsx +368 -368
  61. package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
  62. package/src/devtools/client/components/panel/guard-panel.tsx +244 -244
  63. package/src/devtools/client/components/panel/index.ts +32 -32
  64. package/src/devtools/client/components/panel/islands-panel.tsx +304 -304
  65. package/src/devtools/client/components/panel/network-panel.tsx +292 -292
  66. package/src/devtools/client/components/panel/panel-container.tsx +259 -259
  67. package/src/devtools/client/filters/context-filters.ts +282 -282
  68. package/src/devtools/client/filters/index.ts +16 -16
  69. package/src/devtools/client/index.ts +63 -63
  70. package/src/devtools/client/persistence.ts +335 -335
  71. package/src/devtools/client/state-manager.ts +478 -478
  72. package/src/devtools/design-tokens.ts +263 -263
  73. package/src/devtools/hook/create-hook.ts +207 -207
  74. package/src/devtools/hook/index.ts +13 -13
  75. package/src/devtools/index.ts +439 -439
  76. package/src/devtools/init.ts +266 -266
  77. package/src/devtools/protocol.ts +237 -237
  78. package/src/devtools/server/index.ts +17 -17
  79. package/src/devtools/server/source-context.ts +444 -444
  80. package/src/devtools/types.ts +319 -319
  81. package/src/devtools/worker/index.ts +25 -25
  82. package/src/devtools/worker/redaction-worker.ts +222 -222
  83. package/src/devtools/worker/worker-manager.ts +409 -409
  84. package/src/error/classifier.ts +2 -2
  85. package/src/error/domains.ts +265 -265
  86. package/src/error/formatter.ts +32 -32
  87. package/src/error/result.ts +46 -46
  88. package/src/error/stack-analyzer.ts +5 -0
  89. package/src/error/types.ts +6 -6
  90. package/src/errors/extractor.ts +409 -409
  91. package/src/errors/index.ts +19 -19
  92. package/src/filling/auth.ts +308 -308
  93. package/src/filling/context.ts +569 -569
  94. package/src/filling/deps.ts +238 -238
  95. package/src/generator/contract-glue.ts +2 -1
  96. package/src/generator/generate.ts +12 -10
  97. package/src/generator/index.ts +3 -3
  98. package/src/generator/templates.ts +80 -79
  99. package/src/guard/analyzer.ts +360 -360
  100. package/src/guard/ast-analyzer.ts +806 -806
  101. package/src/guard/auto-correct.ts +1 -1
  102. package/src/guard/check.ts +128 -128
  103. package/src/guard/contract-guard.ts +9 -9
  104. package/src/guard/file-type.test.ts +24 -24
  105. package/src/guard/healing.ts +2 -0
  106. package/src/guard/index.ts +2 -0
  107. package/src/guard/negotiation.ts +430 -4
  108. package/src/guard/presets/atomic.ts +70 -70
  109. package/src/guard/presets/clean.ts +77 -77
  110. package/src/guard/presets/cqrs.test.ts +175 -0
  111. package/src/guard/presets/cqrs.ts +107 -0
  112. package/src/guard/presets/fsd.ts +79 -79
  113. package/src/guard/presets/hexagonal.ts +68 -68
  114. package/src/guard/presets/index.ts +291 -288
  115. package/src/guard/reporter.ts +445 -445
  116. package/src/guard/rules.ts +12 -12
  117. package/src/guard/statistics.ts +578 -578
  118. package/src/guard/suggestions.ts +358 -352
  119. package/src/guard/types.ts +348 -347
  120. package/src/guard/validator.ts +834 -834
  121. package/src/guard/watcher.ts +404 -404
  122. package/src/index.ts +1 -0
  123. package/src/intent/index.ts +310 -310
  124. package/src/island/index.ts +304 -304
  125. package/src/logging/index.ts +22 -22
  126. package/src/logging/transports.ts +365 -365
  127. package/src/paths.test.ts +47 -0
  128. package/src/paths.ts +47 -0
  129. package/src/plugins/index.ts +38 -38
  130. package/src/plugins/registry.ts +377 -377
  131. package/src/plugins/types.ts +363 -363
  132. package/src/report/build.ts +1 -1
  133. package/src/report/index.ts +1 -1
  134. package/src/router/fs-patterns.ts +387 -387
  135. package/src/router/fs-routes.ts +344 -401
  136. package/src/router/fs-scanner.ts +497 -497
  137. package/src/router/fs-types.ts +270 -278
  138. package/src/router/index.ts +81 -81
  139. package/src/runtime/boundary.tsx +232 -232
  140. package/src/runtime/compose.ts +222 -222
  141. package/src/runtime/lifecycle.ts +381 -381
  142. package/src/runtime/logger.test.ts +345 -345
  143. package/src/runtime/logger.ts +677 -677
  144. package/src/runtime/router.test.ts +476 -476
  145. package/src/runtime/router.ts +105 -105
  146. package/src/runtime/security.ts +155 -155
  147. package/src/runtime/server.ts +24 -24
  148. package/src/runtime/session-key.ts +328 -328
  149. package/src/runtime/ssr.ts +367 -367
  150. package/src/runtime/streaming-ssr.ts +1245 -1245
  151. package/src/runtime/trace.ts +144 -144
  152. package/src/seo/index.ts +214 -214
  153. package/src/seo/integration/ssr.ts +307 -307
  154. package/src/seo/render/basic.ts +427 -427
  155. package/src/seo/render/index.ts +143 -143
  156. package/src/seo/render/jsonld.ts +539 -539
  157. package/src/seo/render/opengraph.ts +191 -191
  158. package/src/seo/render/robots.ts +116 -116
  159. package/src/seo/render/sitemap.ts +137 -137
  160. package/src/seo/render/twitter.ts +126 -126
  161. package/src/seo/resolve/index.ts +353 -353
  162. package/src/seo/resolve/opengraph.ts +143 -143
  163. package/src/seo/resolve/robots.ts +73 -73
  164. package/src/seo/resolve/title.ts +94 -94
  165. package/src/seo/resolve/twitter.ts +73 -73
  166. package/src/seo/resolve/url.ts +97 -97
  167. package/src/seo/routes/index.ts +290 -290
  168. package/src/seo/types.ts +575 -575
  169. package/src/slot/validator.ts +39 -39
  170. package/src/spec/index.ts +3 -3
  171. package/src/spec/load.ts +76 -76
  172. package/src/spec/lock.ts +56 -56
  173. package/src/utils/bun.ts +8 -8
  174. package/src/utils/lru-cache.ts +75 -75
  175. package/src/utils/safe-io.ts +188 -188
  176. package/src/utils/string-safe.ts +298 -298
  177. package/src/watcher/rules.ts +5 -5
@@ -118,7 +118,11 @@ export type FileTemplate =
118
118
  | "util"
119
119
  | "type"
120
120
  | "test"
121
- | "slot";
121
+ | "slot"
122
+ | "command"
123
+ | "query"
124
+ | "event"
125
+ | "dto";
122
126
 
123
127
  /**
124
128
  * 협상 응답
@@ -438,6 +442,341 @@ const STRUCTURE_TEMPLATES: Record<FeatureCategory, (featureName: string) => Dire
438
442
  ],
439
443
  };
440
444
 
445
+ // ═══════════════════════════════════════════════════════════════════════════
446
+ // CQRS Structure Templates
447
+ // ═══════════════════════════════════════════════════════════════════════════
448
+
449
+ /**
450
+ * CQRS 프리셋 전용 구조 템플릿
451
+ *
452
+ * application 레이어를 commands/queries/dto/events/mappers로 세분화
453
+ */
454
+ const CQRS_STRUCTURE_TEMPLATES: Record<FeatureCategory, (featureName: string) => DirectoryProposal[]> = {
455
+ auth: (name) => [
456
+ {
457
+ path: `src/domain/${name}`,
458
+ purpose: `${name} 도메인 모델`,
459
+ layer: "domain",
460
+ files: [
461
+ { name: `${name}.entity.ts`, purpose: "사용자/인증 엔티티", template: "type" },
462
+ { name: `${name}.service.ts`, purpose: "도메인 서비스 인터페이스", template: "service" },
463
+ { name: `${name}.repository.ts`, purpose: "Repository 인터페이스", template: "repository" },
464
+ ],
465
+ },
466
+ {
467
+ path: `src/application/commands/${name}`,
468
+ purpose: `${name} 쓰기 경로`,
469
+ layer: "application/commands",
470
+ files: [
471
+ { name: `login.command.ts`, purpose: "로그인 커맨드 핸들러", template: "command" },
472
+ { name: `logout.command.ts`, purpose: "로그아웃 커맨드 핸들러", template: "command" },
473
+ { name: `refresh-token.command.ts`, purpose: "토큰 갱신 커맨드 핸들러", template: "command" },
474
+ ],
475
+ },
476
+ {
477
+ path: `src/application/queries/${name}`,
478
+ purpose: `${name} 읽기 경로`,
479
+ layer: "application/queries",
480
+ files: [
481
+ { name: `get-session.query.ts`, purpose: "세션 조회 쿼리 핸들러", template: "query" },
482
+ { name: `verify-token.query.ts`, purpose: "토큰 검증 쿼리 핸들러", template: "query" },
483
+ ],
484
+ },
485
+ {
486
+ path: `src/application/dto/${name}`,
487
+ purpose: `${name} DTO`,
488
+ layer: "application/dto",
489
+ files: [
490
+ { name: `login.dto.ts`, purpose: "로그인 요청/응답 DTO", template: "dto" },
491
+ { name: `token.dto.ts`, purpose: "토큰 DTO", template: "dto" },
492
+ ],
493
+ },
494
+ {
495
+ path: `src/application/events/${name}`,
496
+ purpose: `${name} 도메인 이벤트`,
497
+ layer: "application/events",
498
+ files: [
499
+ { name: `user-logged-in.event.ts`, purpose: "로그인 성공 이벤트", template: "event" },
500
+ { name: `user-logged-out.event.ts`, purpose: "로그아웃 이벤트", template: "event" },
501
+ ],
502
+ },
503
+ {
504
+ path: `src/infra/${name}`,
505
+ purpose: `${name} 인프라 어댑터`,
506
+ layer: "infrastructure",
507
+ files: [
508
+ { name: `token.provider.ts`, purpose: "토큰 생성/검증 구현", template: "service" },
509
+ { name: `session.repository.ts`, purpose: "세션 저장소 구현", template: "repository" },
510
+ ],
511
+ },
512
+ {
513
+ path: `src/api/${name}`,
514
+ purpose: `${name} API 라우트`,
515
+ layer: "api",
516
+ files: [
517
+ { name: `login/route.ts`, purpose: "로그인 API → LoginCommand 디스패치", template: "route", isSlot: true },
518
+ { name: `logout/route.ts`, purpose: "로그아웃 API → LogoutCommand 디스패치", template: "route", isSlot: true },
519
+ { name: `refresh/route.ts`, purpose: "토큰 갱신 API → RefreshTokenCommand 디스패치", template: "route", isSlot: true },
520
+ { name: `session/route.ts`, purpose: "세션 조회 API → GetSessionQuery 디스패치", template: "route", isSlot: true },
521
+ ],
522
+ },
523
+ ],
524
+
525
+ crud: (name) => [
526
+ {
527
+ path: `src/domain/${name}`,
528
+ purpose: `${name} 도메인`,
529
+ layer: "domain",
530
+ files: [
531
+ { name: `${name}.entity.ts`, purpose: "엔티티 정의", template: "type" },
532
+ { name: `${name}.repository.ts`, purpose: "Repository 인터페이스", template: "repository" },
533
+ ],
534
+ },
535
+ {
536
+ path: `src/application/commands/${name}`,
537
+ purpose: `${name} 쓰기 커맨드`,
538
+ layer: "application/commands",
539
+ files: [
540
+ { name: `create-${name}.command.ts`, purpose: "생성 커맨드 핸들러", template: "command" },
541
+ { name: `update-${name}.command.ts`, purpose: "수정 커맨드 핸들러", template: "command" },
542
+ { name: `delete-${name}.command.ts`, purpose: "삭제 커맨드 핸들러", template: "command" },
543
+ ],
544
+ },
545
+ {
546
+ path: `src/application/queries/${name}`,
547
+ purpose: `${name} 읽기 쿼리`,
548
+ layer: "application/queries",
549
+ files: [
550
+ { name: `get-${name}.query.ts`, purpose: "단건 조회 쿼리 핸들러", template: "query" },
551
+ { name: `list-${name}.query.ts`, purpose: "목록 조회 쿼리 핸들러", template: "query" },
552
+ ],
553
+ },
554
+ {
555
+ path: `src/application/dto/${name}`,
556
+ purpose: `${name} DTO`,
557
+ layer: "application/dto",
558
+ files: [
559
+ { name: `create-${name}.dto.ts`, purpose: "생성 요청 DTO", template: "dto" },
560
+ { name: `update-${name}.dto.ts`, purpose: "수정 요청 DTO", template: "dto" },
561
+ { name: `${name}-response.dto.ts`, purpose: "응답 DTO", template: "dto" },
562
+ ],
563
+ },
564
+ {
565
+ path: `src/infra/${name}`,
566
+ purpose: `${name} Repository 구현`,
567
+ layer: "infrastructure",
568
+ files: [
569
+ { name: `${name}.repository-impl.ts`, purpose: "Repository 구현체", template: "repository" },
570
+ ],
571
+ },
572
+ {
573
+ path: `src/api/${name}`,
574
+ purpose: `${name} API`,
575
+ layer: "api",
576
+ files: [
577
+ { name: `route.ts`, purpose: "목록/생성 API (GET→ListQuery, POST→CreateCommand)", template: "route", isSlot: true },
578
+ { name: `[id]/route.ts`, purpose: "상세/수정/삭제 API (GET→GetQuery, PUT→UpdateCommand, DELETE→DeleteCommand)", template: "route", isSlot: true },
579
+ ],
580
+ },
581
+ ],
582
+
583
+ api: (name) => [
584
+ {
585
+ path: `src/domain/${name}`,
586
+ purpose: `${name} 도메인`,
587
+ layer: "domain",
588
+ files: [
589
+ { name: `${name}.service.ts`, purpose: "도메인 서비스", template: "service" },
590
+ { name: `${name}.types.ts`, purpose: "타입 정의", template: "type" },
591
+ ],
592
+ },
593
+ {
594
+ path: `src/application/commands/${name}`,
595
+ purpose: `${name} 커맨드`,
596
+ layer: "application/commands",
597
+ files: [
598
+ { name: `${name}.command.ts`, purpose: "커맨드 핸들러", template: "command" },
599
+ ],
600
+ },
601
+ {
602
+ path: `src/application/queries/${name}`,
603
+ purpose: `${name} 쿼리`,
604
+ layer: "application/queries",
605
+ files: [
606
+ { name: `${name}.query.ts`, purpose: "쿼리 핸들러", template: "query" },
607
+ ],
608
+ },
609
+ {
610
+ path: `src/api/${name}`,
611
+ purpose: `${name} API 엔드포인트`,
612
+ layer: "api",
613
+ files: [
614
+ { name: `route.ts`, purpose: "API 핸들러 → Command/Query 디스패치", template: "route", isSlot: true },
615
+ ],
616
+ },
617
+ ],
618
+
619
+ ui: (name) => [
620
+ {
621
+ path: `src/application/queries/${name}`,
622
+ purpose: `${name} 데이터 조회`,
623
+ layer: "application/queries",
624
+ files: [
625
+ { name: `get-${name}.query.ts`, purpose: "UI용 데이터 조회 쿼리", template: "query" },
626
+ ],
627
+ },
628
+ {
629
+ path: `src/application/dto/${name}`,
630
+ purpose: `${name} DTO`,
631
+ layer: "application/dto",
632
+ files: [
633
+ { name: `${name}-view.dto.ts`, purpose: "뷰 모델 DTO", template: "dto" },
634
+ ],
635
+ },
636
+ {
637
+ path: `src/api/${name}`,
638
+ purpose: `${name} API`,
639
+ layer: "api",
640
+ files: [
641
+ { name: `route.ts`, purpose: "UI 데이터 API", template: "route", isSlot: true },
642
+ ],
643
+ },
644
+ ],
645
+
646
+ integration: (name) => [
647
+ {
648
+ path: `src/domain/${name}`,
649
+ purpose: `${name} 도메인 포트`,
650
+ layer: "domain",
651
+ files: [
652
+ { name: `${name}.port.ts`, purpose: "포트 인터페이스", template: "type" },
653
+ ],
654
+ },
655
+ {
656
+ path: `src/application/commands/${name}`,
657
+ purpose: `${name} 동기화 커맨드`,
658
+ layer: "application/commands",
659
+ files: [
660
+ { name: `sync-${name}.command.ts`, purpose: "외부 서비스 동기화 커맨드", template: "command" },
661
+ ],
662
+ },
663
+ {
664
+ path: `src/application/events/${name}`,
665
+ purpose: `${name} 연동 이벤트`,
666
+ layer: "application/events",
667
+ files: [
668
+ { name: `${name}-synced.event.ts`, purpose: "동기화 완료 이벤트", template: "event" },
669
+ ],
670
+ },
671
+ {
672
+ path: `src/infra/${name}`,
673
+ purpose: `${name} 외부 서비스 어댑터`,
674
+ layer: "infrastructure",
675
+ files: [
676
+ { name: `${name}.client.ts`, purpose: "외부 API 클라이언트", template: "service" },
677
+ { name: `${name}.config.ts`, purpose: "연동 설정", template: "util" },
678
+ ],
679
+ },
680
+ {
681
+ path: `src/api/webhooks/${name}`,
682
+ purpose: `${name} 웹훅`,
683
+ layer: "api",
684
+ files: [
685
+ { name: `route.ts`, purpose: "웹훅 핸들러", template: "route", isSlot: true },
686
+ ],
687
+ },
688
+ ],
689
+
690
+ data: (name) => [
691
+ {
692
+ path: `src/domain/${name}`,
693
+ purpose: `${name} 데이터 처리 도메인`,
694
+ layer: "domain",
695
+ files: [
696
+ { name: `${name}.types.ts`, purpose: "타입 정의", template: "type" },
697
+ ],
698
+ },
699
+ {
700
+ path: `src/application/commands/${name}`,
701
+ purpose: `${name} 데이터 처리 커맨드`,
702
+ layer: "application/commands",
703
+ files: [
704
+ { name: `import-${name}.command.ts`, purpose: "데이터 임포트 커맨드", template: "command" },
705
+ { name: `transform-${name}.command.ts`, purpose: "데이터 변환 커맨드", template: "command" },
706
+ ],
707
+ },
708
+ {
709
+ path: `src/application/queries/${name}`,
710
+ purpose: `${name} 데이터 조회`,
711
+ layer: "application/queries",
712
+ files: [
713
+ { name: `export-${name}.query.ts`, purpose: "데이터 익스포트 쿼리", template: "query" },
714
+ ],
715
+ },
716
+ {
717
+ path: `src/application/dto/${name}`,
718
+ purpose: `${name} DTO`,
719
+ layer: "application/dto",
720
+ files: [
721
+ { name: `${name}-import.dto.ts`, purpose: "임포트 DTO", template: "dto" },
722
+ ],
723
+ },
724
+ ],
725
+
726
+ util: (name) => [
727
+ {
728
+ path: `src/shared/${name}`,
729
+ purpose: `${name} 유틸리티`,
730
+ layer: "shared",
731
+ files: [
732
+ { name: `${name}.ts`, purpose: "유틸리티 함수", template: "util" },
733
+ { name: `${name}.test.ts`, purpose: "테스트", template: "test" },
734
+ { name: `index.ts`, purpose: "Public API", template: "util" },
735
+ ],
736
+ },
737
+ ],
738
+
739
+ config: (name) => [
740
+ {
741
+ path: `src/shared/config`,
742
+ purpose: "설정 관리",
743
+ layer: "shared",
744
+ files: [
745
+ { name: `${name}.config.ts`, purpose: `${name} 설정`, template: "util" },
746
+ { name: `${name}.schema.ts`, purpose: "설정 스키마 (Zod)", template: "type" },
747
+ ],
748
+ },
749
+ ],
750
+
751
+ other: (name) => [
752
+ {
753
+ path: `src/domain/${name}`,
754
+ purpose: `${name} 도메인`,
755
+ layer: "domain",
756
+ files: [
757
+ { name: `${name}.service.ts`, purpose: "도메인 서비스", template: "service" },
758
+ { name: `${name}.types.ts`, purpose: "타입 정의", template: "type" },
759
+ ],
760
+ },
761
+ {
762
+ path: `src/application/commands/${name}`,
763
+ purpose: `${name} 커맨드`,
764
+ layer: "application/commands",
765
+ files: [
766
+ { name: `${name}.command.ts`, purpose: "커맨드 핸들러", template: "command" },
767
+ ],
768
+ },
769
+ {
770
+ path: `src/application/queries/${name}`,
771
+ purpose: `${name} 쿼리`,
772
+ layer: "application/queries",
773
+ files: [
774
+ { name: `${name}.query.ts`, purpose: "쿼리 핸들러", template: "query" },
775
+ ],
776
+ },
777
+ ],
778
+ };
779
+
441
780
  // ═══════════════════════════════════════════════════════════════════════════
442
781
  // File Templates
443
782
  // ═══════════════════════════════════════════════════════════════════════════
@@ -557,6 +896,91 @@ describe("${name}", () => {
557
896
  expect(true).toBe(true);
558
897
  });
559
898
  });
899
+ `;
900
+
901
+ case "command":
902
+ return `/**
903
+ * ${purpose}
904
+ *
905
+ * Command Handler - 쓰기 경로
906
+ */
907
+
908
+ export interface ${toPascalCase(name)}Command {
909
+ // TODO: Define command payload
910
+ }
911
+
912
+ export interface ${toPascalCase(name)}Result {
913
+ // TODO: Define command result
914
+ }
915
+
916
+ export class ${toPascalCase(name)}Handler {
917
+ async execute(command: ${toPascalCase(name)}Command): Promise<${toPascalCase(name)}Result> {
918
+ // TODO: Implement command handler
919
+ throw new Error("Not implemented");
920
+ }
921
+ }
922
+ `;
923
+
924
+ case "query":
925
+ return `/**
926
+ * ${purpose}
927
+ *
928
+ * Query Handler - 읽기 경로
929
+ */
930
+
931
+ export interface ${toPascalCase(name)}Query {
932
+ // TODO: Define query parameters
933
+ }
934
+
935
+ export interface ${toPascalCase(name)}Result {
936
+ // TODO: Define query result
937
+ }
938
+
939
+ export class ${toPascalCase(name)}Handler {
940
+ async execute(query: ${toPascalCase(name)}Query): Promise<${toPascalCase(name)}Result> {
941
+ // TODO: Implement query handler
942
+ throw new Error("Not implemented");
943
+ }
944
+ }
945
+ `;
946
+
947
+ case "event":
948
+ return `/**
949
+ * ${purpose}
950
+ *
951
+ * Domain Event
952
+ */
953
+
954
+ export interface ${toPascalCase(name)}Event {
955
+ readonly type: "${name}";
956
+ readonly occurredAt: Date;
957
+ // TODO: Define event payload
958
+ }
959
+
960
+ export function create${toPascalCase(name)}Event(
961
+ // TODO: Define factory parameters
962
+ ): ${toPascalCase(name)}Event {
963
+ return {
964
+ type: "${name}",
965
+ occurredAt: new Date(),
966
+ };
967
+ }
968
+ `;
969
+
970
+ case "dto":
971
+ return `/**
972
+ * ${purpose}
973
+ *
974
+ * Data Transfer Object
975
+ */
976
+
977
+ export interface ${toPascalCase(name)}Dto {
978
+ // TODO: Define DTO fields
979
+ }
980
+
981
+ export interface ${toPascalCase(name)}ResponseDto {
982
+ // TODO: Define response DTO fields
983
+ }
560
984
  `;
561
985
 
562
986
  case "util":
@@ -659,6 +1083,7 @@ function adjustStructureForPreset(
659
1083
  "shared": "src/utils",
660
1084
  "app/api": "src/api",
661
1085
  },
1086
+ cqrs: {}, // CQRS 전용 템플릿이 자체 경로 사용
662
1087
  mandu: {}, // 기본값, 매핑 불필요
663
1088
  };
664
1089
 
@@ -716,11 +1141,12 @@ export async function negotiate(
716
1141
 
717
1142
  // 4. 프리셋 정의 로드 및 구조 템플릿 선택
718
1143
  const presetDef = getPreset(preset);
719
- const templateFn = STRUCTURE_TEMPLATES[category] || STRUCTURE_TEMPLATES.other;
1144
+ const templates = preset === "cqrs" ? CQRS_STRUCTURE_TEMPLATES : STRUCTURE_TEMPLATES;
1145
+ const templateFn = templates[category] || templates.other;
720
1146
  let structure = templateFn(featureName);
721
1147
 
722
- // 5. 프리셋에 따른 구조 조정
723
- if (presetDef && preset !== "mandu") {
1148
+ // 5. 프리셋에 따른 구조 조정 (cqrs, mandu는 자체 경로 사용)
1149
+ if (presetDef && preset !== "mandu" && preset !== "cqrs") {
724
1150
  structure = adjustStructureForPreset(structure, presetDef, preset);
725
1151
  }
726
1152
 
@@ -1,70 +1,70 @@
1
- /**
2
- * Atomic Design Preset
3
- *
4
- * UI 컴포넌트 아키텍처
5
- *
6
- * @see https://bradfrost.com/blog/post/atomic-web-design/
7
- */
8
-
9
- import type { PresetDefinition } from "../types";
10
-
11
- /**
12
- * Atomic Design 레이어 계층 구조 (복잡 → 단순)
13
- */
14
- export const ATOMIC_HIERARCHY = [
15
- "pages",
16
- "templates",
17
- "organisms",
18
- "molecules",
19
- "atoms",
20
- ] as const;
21
-
22
- /**
23
- * Atomic Design 프리셋 정의
24
- */
25
- export const atomicPreset: PresetDefinition = {
26
- name: "atomic",
27
- description: "Atomic Design - UI 컴포넌트 아키텍처",
28
-
29
- hierarchy: [...ATOMIC_HIERARCHY],
30
-
31
- layers: [
32
- {
33
- name: "pages",
34
- pattern: "src/components/pages/**",
35
- canImport: ["templates", "organisms", "molecules", "atoms"],
36
- description: "페이지 컴포넌트 (특정 콘텐츠가 있는 템플릿)",
37
- },
38
- {
39
- name: "templates",
40
- pattern: "src/components/templates/**",
41
- canImport: ["organisms", "molecules", "atoms"],
42
- description: "페이지 템플릿 (레이아웃 구조)",
43
- },
44
- {
45
- name: "organisms",
46
- pattern: "src/components/organisms/**",
47
- canImport: ["molecules", "atoms"],
48
- description: "복잡한 UI 블록 (Header, Footer, Form)",
49
- },
50
- {
51
- name: "molecules",
52
- pattern: "src/components/molecules/**",
53
- canImport: ["atoms"],
54
- description: "조합된 컴포넌트 (SearchInput, Card)",
55
- },
56
- {
57
- name: "atoms",
58
- pattern: "src/components/atoms/**",
59
- canImport: [],
60
- description: "기본 요소 (Button, Input, Text)",
61
- },
62
- ],
63
-
64
- defaultSeverity: {
65
- layerViolation: "error",
66
- circularDependency: "warn",
67
- crossSliceDependency: "info",
68
- deepNesting: "info",
69
- },
70
- };
1
+ /**
2
+ * Atomic Design Preset
3
+ *
4
+ * UI 컴포넌트 아키텍처
5
+ *
6
+ * @see https://bradfrost.com/blog/post/atomic-web-design/
7
+ */
8
+
9
+ import type { PresetDefinition } from "../types";
10
+
11
+ /**
12
+ * Atomic Design 레이어 계층 구조 (복잡 → 단순)
13
+ */
14
+ export const ATOMIC_HIERARCHY = [
15
+ "pages",
16
+ "templates",
17
+ "organisms",
18
+ "molecules",
19
+ "atoms",
20
+ ] as const;
21
+
22
+ /**
23
+ * Atomic Design 프리셋 정의
24
+ */
25
+ export const atomicPreset: PresetDefinition = {
26
+ name: "atomic",
27
+ description: "Atomic Design - UI 컴포넌트 아키텍처",
28
+
29
+ hierarchy: [...ATOMIC_HIERARCHY],
30
+
31
+ layers: [
32
+ {
33
+ name: "pages",
34
+ pattern: "src/components/pages/**",
35
+ canImport: ["templates", "organisms", "molecules", "atoms"],
36
+ description: "페이지 컴포넌트 (특정 콘텐츠가 있는 템플릿)",
37
+ },
38
+ {
39
+ name: "templates",
40
+ pattern: "src/components/templates/**",
41
+ canImport: ["organisms", "molecules", "atoms"],
42
+ description: "페이지 템플릿 (레이아웃 구조)",
43
+ },
44
+ {
45
+ name: "organisms",
46
+ pattern: "src/components/organisms/**",
47
+ canImport: ["molecules", "atoms"],
48
+ description: "복잡한 UI 블록 (Header, Footer, Form)",
49
+ },
50
+ {
51
+ name: "molecules",
52
+ pattern: "src/components/molecules/**",
53
+ canImport: ["atoms"],
54
+ description: "조합된 컴포넌트 (SearchInput, Card)",
55
+ },
56
+ {
57
+ name: "atoms",
58
+ pattern: "src/components/atoms/**",
59
+ canImport: [],
60
+ description: "기본 요소 (Button, Input, Text)",
61
+ },
62
+ ],
63
+
64
+ defaultSeverity: {
65
+ layerViolation: "error",
66
+ circularDependency: "warn",
67
+ crossSliceDependency: "info",
68
+ deepNesting: "info",
69
+ },
70
+ };