moai-adk 0.34.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
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.
- moai_adk/__main__.py +136 -5
- moai_adk/astgrep/__init__.py +37 -0
- moai_adk/astgrep/analyzer.py +522 -0
- moai_adk/astgrep/models.py +124 -0
- moai_adk/astgrep/rules.py +179 -0
- moai_adk/cli/commands/analyze.py +11 -2
- moai_adk/cli/commands/doctor.py +7 -1
- moai_adk/cli/commands/init.py +321 -11
- moai_adk/cli/commands/language.py +7 -1
- moai_adk/cli/commands/rank.py +449 -0
- moai_adk/cli/commands/status.py +7 -1
- moai_adk/cli/commands/switch.py +325 -0
- moai_adk/cli/commands/update.py +296 -23
- moai_adk/cli/prompts/init_prompts.py +362 -66
- moai_adk/cli/prompts/translations/__init__.py +573 -0
- moai_adk/cli/ui/prompts.py +61 -2
- moai_adk/cli/worktree/cli.py +106 -1
- moai_adk/cli/worktree/manager.py +155 -0
- moai_adk/core/config/unified.py +244 -63
- moai_adk/core/credentials.py +264 -0
- moai_adk/core/error_recovery_system.py +22 -4
- moai_adk/core/git/conflict_detector.py +10 -1
- moai_adk/core/git/event_detector.py +16 -5
- moai_adk/core/integration/engine.py +2 -2
- moai_adk/core/integration/integration_tester.py +5 -5
- moai_adk/core/language_config_resolver.py +9 -3
- moai_adk/core/merge/analyzer.py +509 -324
- moai_adk/core/migration/alfred_to_moai_migrator.py +7 -1
- moai_adk/core/migration/backup_manager.py +54 -4
- moai_adk/core/migration/file_migrator.py +174 -2
- moai_adk/core/migration/interactive_checkbox_ui.py +42 -31
- moai_adk/core/migration/version_detector.py +123 -19
- moai_adk/core/migration/version_migrator.py +44 -9
- moai_adk/core/model_allocator.py +241 -0
- moai_adk/core/project/backup_utils.py +12 -2
- moai_adk/core/project/initializer.py +44 -87
- moai_adk/core/project/phase_executor.py +95 -33
- moai_adk/core/project/validator.py +16 -1
- moai_adk/core/quality/trust_checker.py +30 -10
- moai_adk/core/rollback_manager.py +60 -25
- moai_adk/core/template/backup.py +88 -6
- moai_adk/core/template/config.py +33 -9
- moai_adk/core/template/merger.py +34 -8
- moai_adk/core/template/processor.py +334 -11
- moai_adk/core/template_engine.py +10 -1
- moai_adk/core/template_variable_synchronizer.py +16 -2
- moai_adk/core/version_sync.py +54 -6
- moai_adk/foundation/__init__.py +1 -20
- moai_adk/foundation/testing.py +1 -1
- moai_adk/loop/__init__.py +54 -0
- moai_adk/loop/controller.py +305 -0
- moai_adk/loop/feedback.py +230 -0
- moai_adk/loop/state.py +209 -0
- moai_adk/loop/storage.py +220 -0
- moai_adk/lsp/__init__.py +70 -0
- moai_adk/lsp/client.py +320 -0
- moai_adk/lsp/models.py +261 -0
- moai_adk/lsp/protocol.py +404 -0
- moai_adk/lsp/server_manager.py +248 -0
- moai_adk/project/configuration.py +8 -1
- moai_adk/py.typed +0 -0
- moai_adk/ralph/__init__.py +37 -0
- moai_adk/ralph/engine.py +307 -0
- moai_adk/rank/__init__.py +21 -0
- moai_adk/rank/auth.py +425 -0
- moai_adk/rank/client.py +557 -0
- moai_adk/rank/config.py +147 -0
- moai_adk/rank/hook.py +1503 -0
- moai_adk/rank/py.typed +0 -0
- moai_adk/statusline/__init__.py +3 -0
- moai_adk/statusline/enhanced_output_style_detector.py +5 -5
- moai_adk/statusline/main.py +20 -1
- moai_adk/statusline/memory_collector.py +268 -0
- moai_adk/statusline/renderer.py +54 -38
- moai_adk/tag_system/__init__.py +48 -0
- moai_adk/tag_system/atomic_ops.py +117 -0
- moai_adk/tag_system/linkage.py +335 -0
- moai_adk/tag_system/parser.py +176 -0
- moai_adk/tag_system/validator.py +200 -0
- moai_adk/templates/.claude/agents/moai/builder-agent.md +19 -3
- moai_adk/templates/.claude/agents/moai/builder-command.md +62 -16
- moai_adk/templates/.claude/agents/moai/builder-plugin.md +763 -0
- moai_adk/templates/.claude/agents/moai/builder-skill.md +21 -5
- moai_adk/templates/.claude/agents/moai/expert-backend.md +103 -39
- moai_adk/templates/.claude/agents/moai/expert-debug.md +9 -3
- moai_adk/templates/.claude/agents/moai/expert-devops.md +16 -14
- moai_adk/templates/.claude/agents/moai/expert-frontend.md +45 -31
- moai_adk/templates/.claude/agents/moai/expert-performance.md +13 -9
- moai_adk/templates/.claude/agents/moai/expert-refactoring.md +228 -0
- moai_adk/templates/.claude/agents/moai/expert-security.md +19 -3
- moai_adk/templates/.claude/agents/moai/expert-testing.md +13 -9
- moai_adk/templates/.claude/agents/moai/manager-claude-code.md +8 -2
- moai_adk/templates/.claude/agents/moai/manager-docs.md +10 -5
- moai_adk/templates/.claude/agents/moai/manager-git.md +99 -27
- moai_adk/templates/.claude/agents/moai/manager-project.md +87 -7
- moai_adk/templates/.claude/agents/moai/manager-quality.md +22 -5
- moai_adk/templates/.claude/agents/moai/manager-spec.md +8 -2
- moai_adk/templates/.claude/agents/moai/manager-strategy.md +45 -14
- moai_adk/templates/.claude/agents/moai/manager-tdd.md +16 -3
- moai_adk/templates/.claude/commands/moai/0-project.md +239 -1185
- moai_adk/templates/.claude/commands/moai/1-plan.md +383 -363
- moai_adk/templates/.claude/commands/moai/2-run.md +254 -347
- moai_adk/templates/.claude/commands/moai/3-sync.md +174 -100
- moai_adk/templates/.claude/commands/moai/9-feedback.md +49 -33
- moai_adk/templates/.claude/commands/moai/alfred.md +339 -0
- moai_adk/templates/.claude/commands/moai/cancel-loop.md +163 -0
- moai_adk/templates/.claude/commands/moai/fix.md +264 -0
- moai_adk/templates/.claude/commands/moai/loop.md +363 -0
- moai_adk/templates/.claude/hooks/moai/lib/README.md +143 -0
- moai_adk/templates/.claude/hooks/moai/lib/__init__.py +37 -81
- moai_adk/templates/.claude/hooks/moai/lib/alfred_detector.py +105 -0
- moai_adk/templates/.claude/hooks/moai/lib/atomic_write.py +122 -0
- moai_adk/templates/.claude/hooks/moai/lib/checkpoint.py +4 -1
- moai_adk/templates/.claude/hooks/moai/lib/common.py +35 -5
- moai_adk/templates/.claude/hooks/moai/lib/config.py +376 -0
- moai_adk/templates/.claude/hooks/moai/lib/config_manager.py +24 -28
- moai_adk/templates/.claude/hooks/moai/lib/config_validator.py +14 -14
- moai_adk/templates/.claude/hooks/moai/lib/enhanced_output_style_detector.py +372 -0
- moai_adk/templates/.claude/hooks/moai/lib/exceptions.py +171 -0
- moai_adk/templates/.claude/hooks/moai/lib/file_utils.py +95 -0
- moai_adk/templates/.claude/hooks/moai/lib/git_collector.py +190 -0
- moai_adk/templates/.claude/hooks/moai/lib/git_operations_manager.py +15 -13
- moai_adk/templates/.claude/hooks/moai/lib/language_detector.py +298 -0
- moai_adk/templates/.claude/hooks/moai/lib/language_validator.py +125 -25
- moai_adk/templates/.claude/hooks/moai/lib/main.py +341 -0
- moai_adk/templates/.claude/hooks/moai/lib/memory_collector.py +268 -0
- moai_adk/templates/.claude/hooks/moai/lib/metrics_tracker.py +78 -0
- moai_adk/templates/.claude/hooks/moai/lib/models.py +9 -7
- moai_adk/templates/.claude/hooks/moai/lib/path_utils.py +204 -13
- moai_adk/templates/.claude/hooks/moai/lib/project.py +23 -14
- moai_adk/templates/.claude/hooks/moai/lib/renderer.py +359 -0
- moai_adk/templates/.claude/hooks/moai/lib/tag_linkage.py +333 -0
- moai_adk/templates/.claude/hooks/moai/lib/tag_parser.py +176 -0
- moai_adk/templates/.claude/hooks/moai/lib/tag_validator.py +200 -0
- moai_adk/templates/.claude/hooks/moai/lib/timeout.py +5 -5
- moai_adk/templates/.claude/hooks/moai/lib/tool_registry.py +896 -0
- moai_adk/templates/.claude/hooks/moai/lib/unified_timeout_manager.py +30 -18
- moai_adk/templates/.claude/hooks/moai/lib/update_checker.py +129 -0
- moai_adk/templates/.claude/hooks/moai/lib/version_reader.py +741 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__ast_grep_scan.py +276 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__code_formatter.py +255 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__coverage_guard.py +325 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__linter.py +315 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__lsp_diagnostic.py +508 -0
- moai_adk/templates/.claude/hooks/moai/pre_commit__tag_validator.py +287 -0
- moai_adk/templates/.claude/hooks/moai/pre_tool__security_guard.py +268 -0
- moai_adk/templates/.claude/hooks/moai/pre_tool__tdd_enforcer.py +208 -0
- moai_adk/templates/.claude/hooks/moai/session_end__auto_cleanup.py +93 -61
- moai_adk/templates/.claude/hooks/moai/session_end__rank_submit.py +69 -0
- moai_adk/templates/.claude/hooks/moai/session_start__show_project_info.py +165 -70
- moai_adk/templates/.claude/hooks/moai/shared/utils/announcement_translator.py +206 -0
- moai_adk/templates/.claude/hooks/moai/stop__loop_controller.py +621 -0
- moai_adk/templates/.claude/output-styles/moai/alfred.md +758 -0
- moai_adk/templates/.claude/output-styles/moai/r2d2.md +86 -3
- moai_adk/templates/.claude/output-styles/moai/yoda.md +2 -2
- moai_adk/templates/.claude/settings.json +154 -77
- moai_adk/templates/.claude/skills/moai-docs-generation/SKILL.md +252 -198
- moai_adk/templates/.claude/skills/moai-docs-generation/examples.md +169 -323
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/README.md +39 -27
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/api-documentation.md +115 -125
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/code-documentation.md +150 -150
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/multi-format-output.md +182 -175
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/user-guides.md +198 -138
- moai_adk/templates/.claude/skills/moai-docs-generation/reference.md +226 -320
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +43 -222
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +75 -219
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +103 -463
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/component-architecture.md +723 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/nextjs16-patterns.md +713 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/performance-optimization.md +694 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/react19-patterns.md +591 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/state-management.md +680 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/vue35-patterns.md +802 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/SKILL.md +118 -339
- moai_adk/templates/.claude/skills/moai-formats-data/SKILL.md +74 -377
- moai_adk/templates/.claude/skills/moai-formats-data/modules/README.md +299 -70
- moai_adk/templates/.claude/skills/moai-foundation-claude/SKILL.md +205 -182
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/advanced-agent-patterns.md +370 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-cli-reference-official.md +420 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-custom-slash-commands-official.md +32 -22
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-devcontainers-official.md +381 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-discover-plugins-official.md +379 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-headless-official.md +378 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-hooks-official.md +110 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-plugin-marketplaces-official.md +308 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-plugins-official.md +640 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sandboxing-official.md +282 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-skills-official.md +425 -71
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-statusline-official.md +293 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sub-agents-official.md +325 -143
- moai_adk/templates/.claude/skills/moai-foundation-context/SKILL.md +96 -316
- moai_adk/templates/.claude/skills/moai-foundation-core/SKILL.md +116 -294
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-advanced.md +279 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-implementation.md +267 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-patterns.md +121 -650
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/patterns.md +22 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-ears-format.md +200 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-first-tdd.md +37 -730
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-tdd-implementation.md +275 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-framework.md +77 -819
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-implementation.md +244 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-validation.md +219 -0
- moai_adk/templates/.claude/skills/moai-foundation-philosopher/SKILL.md +14 -18
- moai_adk/templates/.claude/skills/moai-foundation-quality/SKILL.md +86 -270
- moai_adk/templates/.claude/skills/moai-framework-electron/SKILL.md +288 -0
- moai_adk/templates/.claude/skills/moai-framework-electron/examples.md +2082 -0
- moai_adk/templates/.claude/skills/moai-framework-electron/reference.md +1649 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +76 -582
- moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +1239 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/modules/advanced-patterns.md +401 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +1136 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +82 -436
- moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +585 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/aspnet-core.md +627 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/blazor-components.md +767 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/cqrs-validation.md +626 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/csharp12-features.md +580 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/efcore-patterns.md +622 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +403 -0
- moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +65 -542
- moai_adk/templates/.claude/skills/moai-lang-elixir/examples.md +1171 -0
- moai_adk/templates/.claude/skills/moai-lang-elixir/modules/advanced-patterns.md +531 -0
- moai_adk/templates/.claude/skills/moai-lang-elixir/reference.md +889 -0
- moai_adk/templates/.claude/skills/moai-lang-flutter/SKILL.md +32 -405
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +114 -293
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +83 -307
- moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +179 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +973 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +1543 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +42 -279
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +94 -556
- moai_adk/templates/.claude/skills/moai-lang-php/examples.md +1608 -0
- moai_adk/templates/.claude/skills/moai-lang-php/modules/advanced-patterns.md +538 -0
- moai_adk/templates/.claude/skills/moai-lang-php/reference.md +1323 -0
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +108 -358
- moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +84 -482
- moai_adk/templates/.claude/skills/moai-lang-r/examples.md +1154 -0
- moai_adk/templates/.claude/skills/moai-lang-r/modules/advanced-patterns.md +489 -0
- moai_adk/templates/.claude/skills/moai-lang-r/reference.md +1087 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +106 -610
- moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +1106 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/modules/advanced-patterns.md +309 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/modules/testing-patterns.md +306 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +1024 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +51 -265
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +106 -442
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/akka-actors.md +479 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/cats-effect.md +489 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/functional-programming.md +460 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/spark-data.md +498 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/zio-patterns.md +541 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +88 -457
- moai_adk/templates/.claude/skills/moai-lang-swift/modules/combine-reactive.md +256 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/modules/concurrency.md +270 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/modules/swift6-features.md +265 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/modules/swiftui-patterns.md +314 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +75 -283
- moai_adk/templates/.claude/skills/moai-library-mermaid/SKILL.md +97 -252
- moai_adk/templates/.claude/skills/moai-library-nextra/SKILL.md +64 -240
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-patterns.md +331 -12
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/configuration.md +330 -37
- moai_adk/templates/.claude/skills/moai-library-shadcn/SKILL.md +90 -287
- moai_adk/templates/.claude/skills/moai-platform-auth0/SKILL.md +200 -206
- moai_adk/templates/.claude/skills/moai-platform-auth0/examples.md +2446 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/adaptive-mfa.md +233 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/akamai-integration.md +214 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/application-credentials.md +280 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/attack-protection-log-events.md +224 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/attack-protection-overview.md +140 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/bot-detection.md +144 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/breached-password-detection.md +187 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/brute-force-protection.md +189 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/certifications.md +282 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/compliance-overview.md +263 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/continuous-session-protection.md +307 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/customize-mfa.md +177 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/dpop-implementation.md +283 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/fapi-implementation.md +259 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/gdpr-compliance.md +313 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/guardian-configuration.md +269 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/highly-regulated-identity.md +272 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/jwt-fundamentals.md +248 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mdl-verification.md +210 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-api-management.md +278 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-factors.md +226 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-overview.md +174 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mtls-sender-constraining.md +316 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/ropg-flow-mfa.md +216 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/security-center.md +325 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/security-guidance.md +277 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/state-parameters.md +177 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/step-up-authentication.md +251 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/suspicious-ip-throttling.md +240 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/tenant-access-control.md +179 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/webauthn-fido.md +235 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/reference.md +224 -0
- moai_adk/templates/.claude/skills/moai-platform-clerk/SKILL.md +75 -330
- moai_adk/templates/.claude/skills/moai-platform-clerk/examples.md +1426 -0
- moai_adk/templates/.claude/skills/moai-platform-clerk/modules/advanced-patterns.md +417 -0
- moai_adk/templates/.claude/skills/moai-platform-clerk/reference.md +273 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/SKILL.md +100 -340
- moai_adk/templates/.claude/skills/moai-platform-convex/examples.md +506 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/modules/auth-integration.md +421 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/modules/file-storage.md +474 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/modules/reactive-queries.md +302 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/modules/server-functions.md +452 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/reference.md +385 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/SKILL.md +113 -326
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/examples.md +514 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/custom-claims.md +374 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/phone-auth.md +372 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/social-auth.md +339 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/reference.md +382 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/SKILL.md +71 -302
- moai_adk/templates/.claude/skills/moai-platform-firestore/examples.md +445 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/modules/offline-cache.md +392 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/modules/realtime-listeners.md +441 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/modules/security-rules.md +352 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/modules/transactions.md +452 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/reference.md +322 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/SKILL.md +101 -412
- moai_adk/templates/.claude/skills/moai-platform-neon/examples.md +470 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/modules/auto-scaling.md +349 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/modules/branching-workflows.md +354 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/modules/connection-pooling.md +412 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/modules/pitr-backups.md +458 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/reference.md +272 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/SKILL.md +96 -327
- moai_adk/templates/.claude/skills/moai-platform-railway/examples.md +539 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/modules/docker-deployment.md +261 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/modules/multi-service.md +291 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/modules/networking-domains.md +338 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/modules/volumes-storage.md +353 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/reference.md +374 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/SKILL.md +103 -428
- moai_adk/templates/.claude/skills/moai-platform-supabase/examples.md +502 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/auth-integration.md +384 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/edge-functions.md +371 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/postgresql-pgvector.md +231 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/realtime-presence.md +354 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/row-level-security.md +286 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/storage-cdn.md +319 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/typescript-patterns.md +453 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/reference.md +284 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/SKILL.md +96 -446
- moai_adk/templates/.claude/skills/moai-platform-vercel/examples.md +502 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/analytics-speed.md +348 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/deployment-config.md +344 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/edge-functions.md +222 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/isr-caching.md +306 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/kv-storage.md +399 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/reference.md +360 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/SKILL.md +193 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/examples.md +1099 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/language-specific.md +307 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/pattern-syntax.md +237 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/refactoring-patterns.md +260 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/security-rules.md +239 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/reference.md +288 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/go.yml +90 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/python.yml +101 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/typescript.yml +83 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/quality/complexity-check.yml +94 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/quality/deprecated-apis.yml +84 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/secrets-detection.yml +89 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/sql-injection.yml +45 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/xss-prevention.yml +50 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/sgconfig.yml +54 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/SKILL.md +225 -423
- moai_adk/templates/.claude/skills/moai-workflow-loop/SKILL.md +197 -0
- moai_adk/templates/.claude/skills/moai-workflow-loop/examples.md +1063 -0
- moai_adk/templates/.claude/skills/moai-workflow-loop/reference.md +1414 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/SKILL.md +211 -314
- moai_adk/templates/.claude/skills/moai-workflow-project/schemas/tab_schema.json +15 -43
- moai_adk/templates/.claude/skills/moai-workflow-spec/SKILL.md +119 -316
- moai_adk/templates/.claude/skills/moai-workflow-spec/modules/advanced-patterns.md +237 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/SKILL.md +96 -203
- moai_adk/templates/.claude/skills/moai-workflow-testing/SKILL.md +201 -388
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/README.md +52 -3
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/ai-debugging.md +263 -806
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/context7-integration.md +286 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/review-workflows.md +500 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/relevance-analysis.md +154 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/safety-analysis.md +148 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/scoring-algorithms.md +196 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/timeliness-analysis.md +168 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/truthfulness-analysis.md +136 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/usability-analysis.md +153 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework.md +257 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review.md +191 -1344
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/analysis-patterns.md +340 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/core-classes.md +299 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/tool-integration.md +380 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/debugging/debugging-workflows.md +451 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/debugging/error-analysis.md +442 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance/optimization-patterns.md +473 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance/profiling-techniques.md +481 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/ai-optimization.md +241 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/bottleneck-detection.md +397 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/optimization-plan.md +315 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/profiler-core.md +277 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/real-time-monitoring.md +187 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization.md +287 -1194
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/quality-metrics.md +415 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/refactoring/ai-workflows.md +620 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/refactoring/patterns.md +692 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/security-analysis.md +429 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/smart-refactoring.md +262 -1192
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/static-analysis.md +438 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd/core-classes.md +397 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/advanced-features.md +494 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/red-green-refactor.md +316 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/test-generation.md +471 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/test-patterns.md +371 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7.md +227 -1222
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/trust5-validation.md +428 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/SKILL.md +228 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/integration-patterns.md +149 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/moai-adk-integration.md +245 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-advanced.md +310 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-development.md +202 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-workflows.md +302 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/registry-architecture.md +271 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/resource-optimization.md +300 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/tools-integration.md +280 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/troubleshooting.md +397 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/worktree-commands.md +296 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/worktree-management.md +217 -0
- moai_adk/templates/.git-hooks/pre-push +162 -59
- moai_adk/templates/.github/workflows/ci-universal.yml +934 -133
- moai_adk/templates/.gitignore +65 -107
- moai_adk/templates/.lsp.json +152 -0
- moai_adk/templates/.mcp.json +2 -20
- moai_adk/templates/.moai/announcements/en.json +18 -0
- moai_adk/templates/.moai/announcements/ja.json +18 -0
- moai_adk/templates/.moai/announcements/ko.json +18 -0
- moai_adk/templates/.moai/announcements/zh.json +18 -0
- moai_adk/templates/.moai/config/config.yaml +8 -2
- moai_adk/templates/.moai/config/multilingual-triggers.yaml +213 -0
- moai_adk/templates/.moai/config/sections/language.yaml +2 -2
- moai_adk/templates/.moai/config/sections/llm.yaml +41 -0
- moai_adk/templates/.moai/config/sections/pricing.yaml +30 -0
- moai_adk/templates/.moai/config/sections/project.yaml +2 -2
- moai_adk/templates/.moai/config/sections/quality.yaml +43 -5
- moai_adk/templates/.moai/config/sections/ralph.yaml +55 -0
- moai_adk/templates/.moai/config/sections/system.yaml +46 -1
- moai_adk/templates/.moai/config/sections/user.yaml +1 -1
- moai_adk/templates/.moai/config/statusline-config.yaml +2 -2
- moai_adk/templates/.moai/llm-configs/glm.json +22 -0
- moai_adk/templates/CLAUDE.ja.md +343 -0
- moai_adk/templates/CLAUDE.ko.md +343 -0
- moai_adk/templates/CLAUDE.md +200 -499
- moai_adk/templates/CLAUDE.zh.md +343 -0
- moai_adk/utils/common.py +37 -0
- moai_adk/version.py +1 -1
- moai_adk-1.1.0.dist-info/METADATA +2443 -0
- moai_adk-1.1.0.dist-info/RECORD +701 -0
- {moai_adk-0.34.0.dist-info → moai_adk-1.1.0.dist-info}/entry_points.txt +2 -0
- moai_adk-1.1.0.dist-info/licenses/LICENSE +99 -0
- moai_adk/core/config/auto_spec_config.py +0 -340
- moai_adk/core/hooks/post_tool_auto_spec_completion.py +0 -901
- moai_adk/core/spec/confidence_scoring.py +0 -680
- moai_adk/core/spec/ears_template_engine.py +0 -1247
- moai_adk/core/spec/quality_validator.py +0 -687
- moai_adk/templates/.claude/agents/moai/ai-nano-banana.md +0 -670
- moai_adk/templates/.claude/agents/moai/expert-database.md +0 -777
- moai_adk/templates/.claude/agents/moai/expert-uiux.md +0 -1041
- moai_adk/templates/.claude/agents/moai/mcp-context7.md +0 -458
- moai_adk/templates/.claude/agents/moai/mcp-figma.md +0 -1607
- moai_adk/templates/.claude/agents/moai/mcp-notion.md +0 -789
- moai_adk/templates/.claude/agents/moai/mcp-playwright.md +0 -469
- moai_adk/templates/.claude/agents/moai/mcp-sequential-thinking.md +0 -1032
- moai_adk/templates/.claude/skills/moai-ai-nano-banana/SKILL.md +0 -438
- moai_adk/templates/.claude/skills/moai-ai-nano-banana/examples.md +0 -431
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/design-system-tokens.md +0 -405
- moai_adk/templates/.claude/skills/moai-library-nextra/advanced-patterns.md +0 -336
- moai_adk/templates/.claude/skills/moai-mcp-figma/SKILL.md +0 -402
- moai_adk/templates/.claude/skills/moai-mcp-figma/advanced-patterns.md +0 -607
- moai_adk/templates/.claude/skills/moai-mcp-notion/SKILL.md +0 -300
- moai_adk/templates/.claude/skills/moai-mcp-notion/advanced-patterns.md +0 -537
- moai_adk/templates/.claude/skills/moai-workflow-project/__init__.py +0 -520
- moai_adk/templates/.claude/skills/moai-workflow-project/complete_workflow_demo_fixed.py +0 -574
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_project_setup.py +0 -317
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_workflow_demo.py +0 -663
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/config-migration-example.json +0 -190
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/question-examples.json +0 -175
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/quick_start.py +0 -196
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/__init__.py +0 -17
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/advanced-patterns.md +0 -158
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/ask_user_integration.py +0 -340
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/batch_questions.py +0 -713
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/config_manager.py +0 -538
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/documentation_manager.py +0 -1336
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/language_initializer.py +0 -730
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/migration_manager.py +0 -608
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/template_optimizer.py +0 -1005
- moai_adk/templates/.claude/skills/moai-workflow-project/test_integration_simple.py +0 -436
- moai_adk/templates/.claude/skills/moai-worktree/SKILL.md +0 -411
- moai_adk/templates/.claude/skills/moai-worktree/modules/integration-patterns.md +0 -982
- moai_adk/templates/.claude/skills/moai-worktree/modules/parallel-development.md +0 -778
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-commands.md +0 -646
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-management.md +0 -782
- moai_adk/templates/.moai/config/questions/_schema.yaml +0 -151
- moai_adk/templates/.moai/config/questions/tab0-init.yaml +0 -251
- moai_adk/templates/.moai/config/questions/tab1-user.yaml +0 -108
- moai_adk/templates/.moai/config/questions/tab2-project.yaml +0 -81
- moai_adk/templates/.moai/config/questions/tab3-git.yaml +0 -634
- moai_adk/templates/.moai/config/questions/tab4-quality.yaml +0 -170
- moai_adk/templates/.moai/config/questions/tab5-system.yaml +0 -87
- moai_adk/templates/.moai/scripts/setup-glm.py +0 -136
- moai_adk-0.34.0.dist-info/METADATA +0 -2999
- moai_adk-0.34.0.dist-info/RECORD +0 -463
- moai_adk-0.34.0.dist-info/licenses/LICENSE +0 -21
- /moai_adk/foundation/{git.py → git/__init__.py} +0 -0
- /moai_adk/templates/.claude/skills/moai-library-mermaid/{advanced-patterns.md → modules/advanced-patterns.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-library-mermaid/{optimization.md → modules/optimization.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-library-nextra/{optimization.md → modules/optimization.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-workflow-jit-docs/{advanced-patterns.md → modules/advanced-patterns.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-workflow-jit-docs/{optimization.md → modules/optimization.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-workflow-testing/{advanced-patterns.md → modules/advanced-patterns.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-workflow-testing/{optimization.md → modules/optimization.md} +0 -0
- /moai_adk/templates/.claude/skills/{moai-worktree → moai-workflow-worktree}/examples.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-worktree → moai-workflow-worktree}/reference.md +0 -0
- {moai_adk-0.34.0.dist-info → moai_adk-1.1.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
# CQRS and Validation Patterns
|
|
2
|
+
|
|
3
|
+
Comprehensive guide to MediatR CQRS, FluentValidation, and Handler patterns for clean architecture.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## MediatR Setup
|
|
8
|
+
|
|
9
|
+
### Installation and Configuration
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
dotnet add package MediatR
|
|
13
|
+
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```csharp
|
|
17
|
+
// Program.cs
|
|
18
|
+
builder.Services.AddMediatR(cfg =>
|
|
19
|
+
{
|
|
20
|
+
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
|
|
21
|
+
|
|
22
|
+
// Add behaviors (pipeline)
|
|
23
|
+
cfg.AddBehavior<LoggingBehavior<,>>();
|
|
24
|
+
cfg.AddBehavior<ValidationBehavior<,>>();
|
|
25
|
+
cfg.AddBehavior<TransactionBehavior<,>>();
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
### Command Definition
|
|
34
|
+
|
|
35
|
+
```csharp
|
|
36
|
+
// Command with response
|
|
37
|
+
public record CreateUserCommand(
|
|
38
|
+
string Name,
|
|
39
|
+
string Email,
|
|
40
|
+
string Password) : IRequest<UserDto>;
|
|
41
|
+
|
|
42
|
+
// Command without response
|
|
43
|
+
public record DeleteUserCommand(Guid Id) : IRequest;
|
|
44
|
+
|
|
45
|
+
// Command with result type
|
|
46
|
+
public record UpdateUserCommand(
|
|
47
|
+
Guid Id,
|
|
48
|
+
string Name,
|
|
49
|
+
string Email) : IRequest<Result<UserDto>>;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Command Handler
|
|
53
|
+
|
|
54
|
+
```csharp
|
|
55
|
+
public class CreateUserCommandHandler(
|
|
56
|
+
AppDbContext context,
|
|
57
|
+
IPasswordHasher passwordHasher,
|
|
58
|
+
IValidator<CreateUserCommand> validator,
|
|
59
|
+
ILogger<CreateUserCommandHandler> logger)
|
|
60
|
+
: IRequestHandler<CreateUserCommand, UserDto>
|
|
61
|
+
{
|
|
62
|
+
public async Task<UserDto> Handle(CreateUserCommand request, CancellationToken ct)
|
|
63
|
+
{
|
|
64
|
+
// Validation
|
|
65
|
+
var validationResult = await validator.ValidateAsync(request, ct);
|
|
66
|
+
if (!validationResult.IsValid)
|
|
67
|
+
throw new ValidationException(validationResult.Errors);
|
|
68
|
+
|
|
69
|
+
// Check for duplicates
|
|
70
|
+
var exists = await context.Users.AnyAsync(u => u.Email == request.Email, ct);
|
|
71
|
+
if (exists)
|
|
72
|
+
throw new ConflictException($"User with email {request.Email} already exists");
|
|
73
|
+
|
|
74
|
+
// Create entity
|
|
75
|
+
var user = User.Create(
|
|
76
|
+
request.Name,
|
|
77
|
+
request.Email,
|
|
78
|
+
passwordHasher.Hash(request.Password));
|
|
79
|
+
|
|
80
|
+
context.Users.Add(user);
|
|
81
|
+
await context.SaveChangesAsync(ct);
|
|
82
|
+
|
|
83
|
+
logger.LogInformation("Created user {UserId} with email {Email}", user.Id, user.Email);
|
|
84
|
+
|
|
85
|
+
return new UserDto(user.Id, user.Name, user.Email, user.Role, user.CreatedAt);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Command with Domain Events
|
|
91
|
+
|
|
92
|
+
```csharp
|
|
93
|
+
public record CreateOrderCommand(
|
|
94
|
+
Guid CustomerId,
|
|
95
|
+
List<OrderItemDto> Items) : IRequest<OrderDto>;
|
|
96
|
+
|
|
97
|
+
public class CreateOrderCommandHandler(
|
|
98
|
+
AppDbContext context,
|
|
99
|
+
IMediator mediator)
|
|
100
|
+
: IRequestHandler<CreateOrderCommand, OrderDto>
|
|
101
|
+
{
|
|
102
|
+
public async Task<OrderDto> Handle(CreateOrderCommand request, CancellationToken ct)
|
|
103
|
+
{
|
|
104
|
+
var order = Order.Create(request.CustomerId, request.Items);
|
|
105
|
+
|
|
106
|
+
context.Orders.Add(order);
|
|
107
|
+
await context.SaveChangesAsync(ct);
|
|
108
|
+
|
|
109
|
+
// Publish domain events
|
|
110
|
+
foreach (var domainEvent in order.DomainEvents)
|
|
111
|
+
{
|
|
112
|
+
await mediator.Publish(domainEvent, ct);
|
|
113
|
+
}
|
|
114
|
+
order.ClearDomainEvents();
|
|
115
|
+
|
|
116
|
+
return MapToDto(order);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Queries
|
|
124
|
+
|
|
125
|
+
### Query Definition
|
|
126
|
+
|
|
127
|
+
```csharp
|
|
128
|
+
// Simple query
|
|
129
|
+
public record GetUserByIdQuery(Guid Id) : IRequest<UserDto?>;
|
|
130
|
+
|
|
131
|
+
// Query with pagination
|
|
132
|
+
public record GetUsersQuery(
|
|
133
|
+
int Page = 1,
|
|
134
|
+
int PageSize = 10,
|
|
135
|
+
string? SearchTerm = null,
|
|
136
|
+
string? SortBy = null,
|
|
137
|
+
bool SortDescending = false) : IRequest<PagedResult<UserDto>>;
|
|
138
|
+
|
|
139
|
+
// Query with includes
|
|
140
|
+
public record GetUserWithPostsQuery(Guid Id) : IRequest<UserWithPostsDto?>;
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Query Handler
|
|
144
|
+
|
|
145
|
+
```csharp
|
|
146
|
+
public class GetUserByIdQueryHandler(AppDbContext context)
|
|
147
|
+
: IRequestHandler<GetUserByIdQuery, UserDto?>
|
|
148
|
+
{
|
|
149
|
+
public async Task<UserDto?> Handle(GetUserByIdQuery request, CancellationToken ct)
|
|
150
|
+
{
|
|
151
|
+
return await context.Users
|
|
152
|
+
.AsNoTracking()
|
|
153
|
+
.Where(u => u.Id == request.Id)
|
|
154
|
+
.Select(u => new UserDto(u.Id, u.Name, u.Email, u.Role, u.CreatedAt))
|
|
155
|
+
.FirstOrDefaultAsync(ct);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public class GetUsersQueryHandler(AppDbContext context)
|
|
160
|
+
: IRequestHandler<GetUsersQuery, PagedResult<UserDto>>
|
|
161
|
+
{
|
|
162
|
+
public async Task<PagedResult<UserDto>> Handle(GetUsersQuery request, CancellationToken ct)
|
|
163
|
+
{
|
|
164
|
+
var query = context.Users.AsNoTracking();
|
|
165
|
+
|
|
166
|
+
// Apply search filter
|
|
167
|
+
if (!string.IsNullOrEmpty(request.SearchTerm))
|
|
168
|
+
{
|
|
169
|
+
query = query.Where(u =>
|
|
170
|
+
u.Name.Contains(request.SearchTerm) ||
|
|
171
|
+
u.Email.Contains(request.SearchTerm));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Apply sorting
|
|
175
|
+
query = request.SortBy?.ToLower() switch
|
|
176
|
+
{
|
|
177
|
+
"name" => request.SortDescending
|
|
178
|
+
? query.OrderByDescending(u => u.Name)
|
|
179
|
+
: query.OrderBy(u => u.Name),
|
|
180
|
+
"email" => request.SortDescending
|
|
181
|
+
? query.OrderByDescending(u => u.Email)
|
|
182
|
+
: query.OrderBy(u => u.Email),
|
|
183
|
+
"createdat" => request.SortDescending
|
|
184
|
+
? query.OrderByDescending(u => u.CreatedAt)
|
|
185
|
+
: query.OrderBy(u => u.CreatedAt),
|
|
186
|
+
_ => query.OrderBy(u => u.Name)
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
var totalCount = await query.CountAsync(ct);
|
|
190
|
+
|
|
191
|
+
var items = await query
|
|
192
|
+
.Skip((request.Page - 1) * request.PageSize)
|
|
193
|
+
.Take(request.PageSize)
|
|
194
|
+
.Select(u => new UserDto(u.Id, u.Name, u.Email, u.Role, u.CreatedAt))
|
|
195
|
+
.ToListAsync(ct);
|
|
196
|
+
|
|
197
|
+
return new PagedResult<UserDto>(items, totalCount, request.Page, request.PageSize);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## FluentValidation
|
|
205
|
+
|
|
206
|
+
### Installation
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
dotnet add package FluentValidation
|
|
210
|
+
dotnet add package FluentValidation.DependencyInjectionExtensions
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```csharp
|
|
214
|
+
// Program.cs
|
|
215
|
+
builder.Services.AddValidatorsFromAssemblyContaining<Program>();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Basic Validators
|
|
219
|
+
|
|
220
|
+
```csharp
|
|
221
|
+
public class CreateUserCommandValidator : AbstractValidator<CreateUserCommand>
|
|
222
|
+
{
|
|
223
|
+
public CreateUserCommandValidator()
|
|
224
|
+
{
|
|
225
|
+
RuleFor(x => x.Name)
|
|
226
|
+
.NotEmpty().WithMessage("Name is required")
|
|
227
|
+
.MinimumLength(2).WithMessage("Name must be at least 2 characters")
|
|
228
|
+
.MaximumLength(100).WithMessage("Name cannot exceed 100 characters");
|
|
229
|
+
|
|
230
|
+
RuleFor(x => x.Email)
|
|
231
|
+
.NotEmpty().WithMessage("Email is required")
|
|
232
|
+
.EmailAddress().WithMessage("Invalid email format")
|
|
233
|
+
.MaximumLength(256).WithMessage("Email cannot exceed 256 characters");
|
|
234
|
+
|
|
235
|
+
RuleFor(x => x.Password)
|
|
236
|
+
.NotEmpty().WithMessage("Password is required")
|
|
237
|
+
.MinimumLength(8).WithMessage("Password must be at least 8 characters")
|
|
238
|
+
.Matches(@"[A-Z]").WithMessage("Password must contain at least one uppercase letter")
|
|
239
|
+
.Matches(@"[a-z]").WithMessage("Password must contain at least one lowercase letter")
|
|
240
|
+
.Matches(@"[0-9]").WithMessage("Password must contain at least one digit")
|
|
241
|
+
.Matches(@"[^a-zA-Z0-9]").WithMessage("Password must contain at least one special character");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Async Validation with Dependencies
|
|
247
|
+
|
|
248
|
+
```csharp
|
|
249
|
+
public class CreateUserCommandValidator : AbstractValidator<CreateUserCommand>
|
|
250
|
+
{
|
|
251
|
+
public CreateUserCommandValidator(IUserRepository userRepository)
|
|
252
|
+
{
|
|
253
|
+
RuleFor(x => x.Name)
|
|
254
|
+
.NotEmpty()
|
|
255
|
+
.MaximumLength(100);
|
|
256
|
+
|
|
257
|
+
RuleFor(x => x.Email)
|
|
258
|
+
.NotEmpty()
|
|
259
|
+
.EmailAddress()
|
|
260
|
+
.MustAsync(async (email, ct) => !await userRepository.EmailExistsAsync(email, ct))
|
|
261
|
+
.WithMessage("Email is already in use");
|
|
262
|
+
|
|
263
|
+
RuleFor(x => x.Password)
|
|
264
|
+
.SetValidator(new PasswordValidator());
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Reusable validator
|
|
269
|
+
public class PasswordValidator : AbstractValidator<string>
|
|
270
|
+
{
|
|
271
|
+
public PasswordValidator()
|
|
272
|
+
{
|
|
273
|
+
RuleFor(x => x)
|
|
274
|
+
.NotEmpty().WithMessage("Password is required")
|
|
275
|
+
.MinimumLength(8).WithMessage("Password must be at least 8 characters")
|
|
276
|
+
.Matches(@"[A-Z]").WithMessage("Must contain uppercase letter")
|
|
277
|
+
.Matches(@"[a-z]").WithMessage("Must contain lowercase letter")
|
|
278
|
+
.Matches(@"[0-9]").WithMessage("Must contain digit");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Complex Validation Rules
|
|
284
|
+
|
|
285
|
+
```csharp
|
|
286
|
+
public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
|
|
287
|
+
{
|
|
288
|
+
public CreateOrderCommandValidator(IProductRepository productRepository)
|
|
289
|
+
{
|
|
290
|
+
RuleFor(x => x.CustomerId)
|
|
291
|
+
.NotEmpty().WithMessage("Customer ID is required");
|
|
292
|
+
|
|
293
|
+
RuleFor(x => x.Items)
|
|
294
|
+
.NotEmpty().WithMessage("At least one item is required")
|
|
295
|
+
.Must(items => items.Count <= 50).WithMessage("Maximum 50 items per order");
|
|
296
|
+
|
|
297
|
+
RuleForEach(x => x.Items).ChildRules(item =>
|
|
298
|
+
{
|
|
299
|
+
item.RuleFor(i => i.ProductId)
|
|
300
|
+
.NotEmpty()
|
|
301
|
+
.MustAsync(async (id, ct) => await productRepository.ExistsAsync(id, ct))
|
|
302
|
+
.WithMessage("Product not found");
|
|
303
|
+
|
|
304
|
+
item.RuleFor(i => i.Quantity)
|
|
305
|
+
.GreaterThan(0).WithMessage("Quantity must be positive")
|
|
306
|
+
.LessThanOrEqualTo(100).WithMessage("Maximum quantity is 100");
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// Cross-field validation
|
|
310
|
+
RuleFor(x => x)
|
|
311
|
+
.MustAsync(async (cmd, ct) =>
|
|
312
|
+
{
|
|
313
|
+
var totalItems = cmd.Items.Sum(i => i.Quantity);
|
|
314
|
+
return totalItems <= 500;
|
|
315
|
+
})
|
|
316
|
+
.WithMessage("Total items cannot exceed 500");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Validation Groups
|
|
322
|
+
|
|
323
|
+
```csharp
|
|
324
|
+
public class UpdateUserCommandValidator : AbstractValidator<UpdateUserCommand>
|
|
325
|
+
{
|
|
326
|
+
public UpdateUserCommandValidator()
|
|
327
|
+
{
|
|
328
|
+
// Always validate
|
|
329
|
+
RuleFor(x => x.Id).NotEmpty();
|
|
330
|
+
|
|
331
|
+
// Validate when updating profile
|
|
332
|
+
RuleSet("Profile", () =>
|
|
333
|
+
{
|
|
334
|
+
RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
|
|
335
|
+
RuleFor(x => x.Bio).MaximumLength(500);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Validate when updating email
|
|
339
|
+
RuleSet("Email", () =>
|
|
340
|
+
{
|
|
341
|
+
RuleFor(x => x.Email).NotEmpty().EmailAddress();
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Usage
|
|
347
|
+
var result = await validator.ValidateAsync(command, options =>
|
|
348
|
+
options.IncludeRuleSets("Profile"));
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Pipeline Behaviors
|
|
354
|
+
|
|
355
|
+
### Validation Behavior
|
|
356
|
+
|
|
357
|
+
```csharp
|
|
358
|
+
public class ValidationBehavior<TRequest, TResponse>(
|
|
359
|
+
IEnumerable<IValidator<TRequest>> validators)
|
|
360
|
+
: IPipelineBehavior<TRequest, TResponse>
|
|
361
|
+
where TRequest : notnull
|
|
362
|
+
{
|
|
363
|
+
public async Task<TResponse> Handle(
|
|
364
|
+
TRequest request,
|
|
365
|
+
RequestHandlerDelegate<TResponse> next,
|
|
366
|
+
CancellationToken cancellationToken)
|
|
367
|
+
{
|
|
368
|
+
if (!validators.Any())
|
|
369
|
+
return await next();
|
|
370
|
+
|
|
371
|
+
var context = new ValidationContext<TRequest>(request);
|
|
372
|
+
|
|
373
|
+
var validationResults = await Task.WhenAll(
|
|
374
|
+
validators.Select(v => v.ValidateAsync(context, cancellationToken)));
|
|
375
|
+
|
|
376
|
+
var failures = validationResults
|
|
377
|
+
.SelectMany(r => r.Errors)
|
|
378
|
+
.Where(f => f is not null)
|
|
379
|
+
.ToList();
|
|
380
|
+
|
|
381
|
+
if (failures.Count > 0)
|
|
382
|
+
throw new ValidationException(failures);
|
|
383
|
+
|
|
384
|
+
return await next();
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Logging Behavior
|
|
390
|
+
|
|
391
|
+
```csharp
|
|
392
|
+
public class LoggingBehavior<TRequest, TResponse>(
|
|
393
|
+
ILogger<LoggingBehavior<TRequest, TResponse>> logger)
|
|
394
|
+
: IPipelineBehavior<TRequest, TResponse>
|
|
395
|
+
where TRequest : notnull
|
|
396
|
+
{
|
|
397
|
+
public async Task<TResponse> Handle(
|
|
398
|
+
TRequest request,
|
|
399
|
+
RequestHandlerDelegate<TResponse> next,
|
|
400
|
+
CancellationToken cancellationToken)
|
|
401
|
+
{
|
|
402
|
+
var requestName = typeof(TRequest).Name;
|
|
403
|
+
var requestId = Guid.NewGuid().ToString("N")[..8];
|
|
404
|
+
|
|
405
|
+
logger.LogInformation(
|
|
406
|
+
"Handling {RequestName} ({RequestId})",
|
|
407
|
+
requestName, requestId);
|
|
408
|
+
|
|
409
|
+
var sw = Stopwatch.StartNew();
|
|
410
|
+
|
|
411
|
+
try
|
|
412
|
+
{
|
|
413
|
+
var response = await next();
|
|
414
|
+
sw.Stop();
|
|
415
|
+
|
|
416
|
+
logger.LogInformation(
|
|
417
|
+
"Handled {RequestName} ({RequestId}) in {ElapsedMs}ms",
|
|
418
|
+
requestName, requestId, sw.ElapsedMilliseconds);
|
|
419
|
+
|
|
420
|
+
return response;
|
|
421
|
+
}
|
|
422
|
+
catch (Exception ex)
|
|
423
|
+
{
|
|
424
|
+
sw.Stop();
|
|
425
|
+
logger.LogError(
|
|
426
|
+
ex,
|
|
427
|
+
"Error handling {RequestName} ({RequestId}) after {ElapsedMs}ms",
|
|
428
|
+
requestName, requestId, sw.ElapsedMilliseconds);
|
|
429
|
+
throw;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Transaction Behavior
|
|
436
|
+
|
|
437
|
+
```csharp
|
|
438
|
+
public class TransactionBehavior<TRequest, TResponse>(
|
|
439
|
+
AppDbContext context,
|
|
440
|
+
ILogger<TransactionBehavior<TRequest, TResponse>> logger)
|
|
441
|
+
: IPipelineBehavior<TRequest, TResponse>
|
|
442
|
+
where TRequest : notnull
|
|
443
|
+
{
|
|
444
|
+
public async Task<TResponse> Handle(
|
|
445
|
+
TRequest request,
|
|
446
|
+
RequestHandlerDelegate<TResponse> next,
|
|
447
|
+
CancellationToken cancellationToken)
|
|
448
|
+
{
|
|
449
|
+
// Skip for queries
|
|
450
|
+
if (typeof(TRequest).Name.EndsWith("Query"))
|
|
451
|
+
return await next();
|
|
452
|
+
|
|
453
|
+
await using var transaction = await context.Database.BeginTransactionAsync(cancellationToken);
|
|
454
|
+
|
|
455
|
+
try
|
|
456
|
+
{
|
|
457
|
+
var response = await next();
|
|
458
|
+
await transaction.CommitAsync(cancellationToken);
|
|
459
|
+
return response;
|
|
460
|
+
}
|
|
461
|
+
catch
|
|
462
|
+
{
|
|
463
|
+
await transaction.RollbackAsync(cancellationToken);
|
|
464
|
+
throw;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Caching Behavior
|
|
471
|
+
|
|
472
|
+
```csharp
|
|
473
|
+
public interface ICacheable
|
|
474
|
+
{
|
|
475
|
+
string CacheKey { get; }
|
|
476
|
+
TimeSpan? CacheDuration { get; }
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
public class CachingBehavior<TRequest, TResponse>(
|
|
480
|
+
IDistributedCache cache,
|
|
481
|
+
ILogger<CachingBehavior<TRequest, TResponse>> logger)
|
|
482
|
+
: IPipelineBehavior<TRequest, TResponse>
|
|
483
|
+
where TRequest : ICacheable
|
|
484
|
+
{
|
|
485
|
+
public async Task<TResponse> Handle(
|
|
486
|
+
TRequest request,
|
|
487
|
+
RequestHandlerDelegate<TResponse> next,
|
|
488
|
+
CancellationToken cancellationToken)
|
|
489
|
+
{
|
|
490
|
+
var cacheKey = request.CacheKey;
|
|
491
|
+
|
|
492
|
+
var cachedValue = await cache.GetStringAsync(cacheKey, cancellationToken);
|
|
493
|
+
if (cachedValue is not null)
|
|
494
|
+
{
|
|
495
|
+
logger.LogDebug("Cache hit for {CacheKey}", cacheKey);
|
|
496
|
+
return JsonSerializer.Deserialize<TResponse>(cachedValue)!;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
logger.LogDebug("Cache miss for {CacheKey}", cacheKey);
|
|
500
|
+
var response = await next();
|
|
501
|
+
|
|
502
|
+
var options = new DistributedCacheEntryOptions
|
|
503
|
+
{
|
|
504
|
+
AbsoluteExpirationRelativeToNow = request.CacheDuration ?? TimeSpan.FromMinutes(5)
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
await cache.SetStringAsync(
|
|
508
|
+
cacheKey,
|
|
509
|
+
JsonSerializer.Serialize(response),
|
|
510
|
+
options,
|
|
511
|
+
cancellationToken);
|
|
512
|
+
|
|
513
|
+
return response;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## Notifications (Domain Events)
|
|
521
|
+
|
|
522
|
+
### Notification Definition
|
|
523
|
+
|
|
524
|
+
```csharp
|
|
525
|
+
public record UserCreatedNotification(Guid UserId, string Email) : INotification;
|
|
526
|
+
|
|
527
|
+
public record OrderPlacedNotification(Guid OrderId, Guid CustomerId, decimal Total) : INotification;
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Notification Handlers
|
|
531
|
+
|
|
532
|
+
```csharp
|
|
533
|
+
public class SendWelcomeEmailHandler(IEmailService emailService)
|
|
534
|
+
: INotificationHandler<UserCreatedNotification>
|
|
535
|
+
{
|
|
536
|
+
public async Task Handle(UserCreatedNotification notification, CancellationToken ct)
|
|
537
|
+
{
|
|
538
|
+
await emailService.SendWelcomeEmailAsync(notification.Email, ct);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
public class UpdateAnalyticsHandler(IAnalyticsService analyticsService)
|
|
543
|
+
: INotificationHandler<UserCreatedNotification>
|
|
544
|
+
{
|
|
545
|
+
public async Task Handle(UserCreatedNotification notification, CancellationToken ct)
|
|
546
|
+
{
|
|
547
|
+
await analyticsService.TrackUserCreatedAsync(notification.UserId, ct);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Publishing Notifications
|
|
553
|
+
|
|
554
|
+
```csharp
|
|
555
|
+
public class CreateUserCommandHandler(
|
|
556
|
+
AppDbContext context,
|
|
557
|
+
IMediator mediator)
|
|
558
|
+
: IRequestHandler<CreateUserCommand, UserDto>
|
|
559
|
+
{
|
|
560
|
+
public async Task<UserDto> Handle(CreateUserCommand request, CancellationToken ct)
|
|
561
|
+
{
|
|
562
|
+
var user = User.Create(request.Name, request.Email, request.Password);
|
|
563
|
+
|
|
564
|
+
context.Users.Add(user);
|
|
565
|
+
await context.SaveChangesAsync(ct);
|
|
566
|
+
|
|
567
|
+
// Publish notification
|
|
568
|
+
await mediator.Publish(new UserCreatedNotification(user.Id, user.Email), ct);
|
|
569
|
+
|
|
570
|
+
return MapToDto(user);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## Result Pattern
|
|
578
|
+
|
|
579
|
+
```csharp
|
|
580
|
+
public class Result<T>
|
|
581
|
+
{
|
|
582
|
+
public bool IsSuccess { get; }
|
|
583
|
+
public T? Value { get; }
|
|
584
|
+
public string? Error { get; }
|
|
585
|
+
public List<string> ValidationErrors { get; } = [];
|
|
586
|
+
|
|
587
|
+
private Result(T value) { IsSuccess = true; Value = value; }
|
|
588
|
+
private Result(string error) { IsSuccess = false; Error = error; }
|
|
589
|
+
private Result(List<string> errors) { IsSuccess = false; ValidationErrors = errors; }
|
|
590
|
+
|
|
591
|
+
public static Result<T> Success(T value) => new(value);
|
|
592
|
+
public static Result<T> Failure(string error) => new(error);
|
|
593
|
+
public static Result<T> ValidationFailure(List<string> errors) => new(errors);
|
|
594
|
+
|
|
595
|
+
public TResult Match<TResult>(
|
|
596
|
+
Func<T, TResult> onSuccess,
|
|
597
|
+
Func<string, TResult> onFailure)
|
|
598
|
+
=> IsSuccess ? onSuccess(Value!) : onFailure(Error ?? string.Join(", ", ValidationErrors));
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Usage in handler
|
|
602
|
+
public async Task<Result<UserDto>> Handle(CreateUserCommand request, CancellationToken ct)
|
|
603
|
+
{
|
|
604
|
+
var validation = await validator.ValidateAsync(request, ct);
|
|
605
|
+
if (!validation.IsValid)
|
|
606
|
+
return Result<UserDto>.ValidationFailure(
|
|
607
|
+
validation.Errors.Select(e => e.ErrorMessage).ToList());
|
|
608
|
+
|
|
609
|
+
// ... create user
|
|
610
|
+
return Result<UserDto>.Success(userDto);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Usage in endpoint
|
|
614
|
+
app.MapPost("/api/users", async (CreateUserCommand cmd, IMediator mediator) =>
|
|
615
|
+
{
|
|
616
|
+
var result = await mediator.Send(cmd);
|
|
617
|
+
return result.Match(
|
|
618
|
+
user => Results.Created($"/api/users/{user.Id}", user),
|
|
619
|
+
error => Results.BadRequest(new { error }));
|
|
620
|
+
});
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
625
|
+
Version: 2.0.0
|
|
626
|
+
Last Updated: 2026-01-06
|