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,585 @@
|
|
|
1
|
+
# C# 12 / .NET 8 Production Examples
|
|
2
|
+
|
|
3
|
+
Production-ready code examples, full-stack patterns, and testing templates.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Complete Web API Example
|
|
8
|
+
|
|
9
|
+
### Program.cs (Entry Point)
|
|
10
|
+
|
|
11
|
+
```csharp
|
|
12
|
+
using Microsoft.EntityFrameworkCore;
|
|
13
|
+
using FluentValidation;
|
|
14
|
+
using MediatR;
|
|
15
|
+
|
|
16
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
17
|
+
|
|
18
|
+
// Database
|
|
19
|
+
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
20
|
+
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
|
|
21
|
+
|
|
22
|
+
// MediatR and FluentValidation
|
|
23
|
+
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
|
|
24
|
+
builder.Services.AddValidatorsFromAssemblyContaining<Program>();
|
|
25
|
+
|
|
26
|
+
// Services
|
|
27
|
+
builder.Services.AddScoped<IUserRepository, EfUserRepository>();
|
|
28
|
+
builder.Services.AddScoped<IPasswordHasher, PasswordHasher>();
|
|
29
|
+
|
|
30
|
+
// Authentication
|
|
31
|
+
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
32
|
+
.AddJwtBearer(options =>
|
|
33
|
+
{
|
|
34
|
+
options.TokenValidationParameters = new TokenValidationParameters
|
|
35
|
+
{
|
|
36
|
+
ValidateIssuer = true,
|
|
37
|
+
ValidateAudience = true,
|
|
38
|
+
ValidateLifetime = true,
|
|
39
|
+
ValidateIssuerSigningKey = true,
|
|
40
|
+
ValidIssuer = builder.Configuration["Jwt:Issuer"],
|
|
41
|
+
ValidAudience = builder.Configuration["Jwt:Audience"],
|
|
42
|
+
IssuerSigningKey = new SymmetricSecurityKey(
|
|
43
|
+
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
builder.Services.AddAuthorization();
|
|
48
|
+
builder.Services.AddEndpointsApiExplorer();
|
|
49
|
+
builder.Services.AddSwaggerGen();
|
|
50
|
+
|
|
51
|
+
var app = builder.Build();
|
|
52
|
+
|
|
53
|
+
if (app.Environment.IsDevelopment())
|
|
54
|
+
{
|
|
55
|
+
app.UseSwagger();
|
|
56
|
+
app.UseSwaggerUI();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
app.UseHttpsRedirection();
|
|
60
|
+
app.UseAuthentication();
|
|
61
|
+
app.UseAuthorization();
|
|
62
|
+
|
|
63
|
+
// Map endpoints
|
|
64
|
+
app.MapUserEndpoints();
|
|
65
|
+
|
|
66
|
+
app.Run();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### User Endpoints
|
|
70
|
+
|
|
71
|
+
```csharp
|
|
72
|
+
public static class UserEndpoints
|
|
73
|
+
{
|
|
74
|
+
public static void MapUserEndpoints(this WebApplication app)
|
|
75
|
+
{
|
|
76
|
+
var group = app.MapGroup("/api/users")
|
|
77
|
+
.WithTags("Users")
|
|
78
|
+
.WithOpenApi();
|
|
79
|
+
|
|
80
|
+
group.MapGet("/", async (IMediator mediator) =>
|
|
81
|
+
{
|
|
82
|
+
var users = await mediator.Send(new GetAllUsersQuery());
|
|
83
|
+
return Results.Ok(users);
|
|
84
|
+
})
|
|
85
|
+
.WithName("GetAllUsers")
|
|
86
|
+
.Produces<List<UserDto>>();
|
|
87
|
+
|
|
88
|
+
group.MapGet("/{id:guid}", async (Guid id, IMediator mediator) =>
|
|
89
|
+
{
|
|
90
|
+
var user = await mediator.Send(new GetUserByIdQuery(id));
|
|
91
|
+
return user is not null ? Results.Ok(user) : Results.NotFound();
|
|
92
|
+
})
|
|
93
|
+
.WithName("GetUserById")
|
|
94
|
+
.Produces<UserDto>()
|
|
95
|
+
.Produces(StatusCodes.Status404NotFound);
|
|
96
|
+
|
|
97
|
+
group.MapPost("/", async (CreateUserCommand command, IMediator mediator) =>
|
|
98
|
+
{
|
|
99
|
+
var user = await mediator.Send(command);
|
|
100
|
+
return Results.Created($"/api/users/{user.Id}", user);
|
|
101
|
+
})
|
|
102
|
+
.WithName("CreateUser")
|
|
103
|
+
.Produces<UserDto>(StatusCodes.Status201Created)
|
|
104
|
+
.ProducesValidationProblem();
|
|
105
|
+
|
|
106
|
+
group.MapPut("/{id:guid}", async (Guid id, UpdateUserCommand command, IMediator mediator) =>
|
|
107
|
+
{
|
|
108
|
+
if (id != command.Id)
|
|
109
|
+
return Results.BadRequest("ID mismatch");
|
|
110
|
+
|
|
111
|
+
var result = await mediator.Send(command);
|
|
112
|
+
return result ? Results.NoContent() : Results.NotFound();
|
|
113
|
+
})
|
|
114
|
+
.WithName("UpdateUser")
|
|
115
|
+
.Produces(StatusCodes.Status204NoContent)
|
|
116
|
+
.Produces(StatusCodes.Status404NotFound);
|
|
117
|
+
|
|
118
|
+
group.MapDelete("/{id:guid}", async (Guid id, IMediator mediator) =>
|
|
119
|
+
{
|
|
120
|
+
var result = await mediator.Send(new DeleteUserCommand(id));
|
|
121
|
+
return result ? Results.NoContent() : Results.NotFound();
|
|
122
|
+
})
|
|
123
|
+
.WithName("DeleteUser")
|
|
124
|
+
.Produces(StatusCodes.Status204NoContent)
|
|
125
|
+
.Produces(StatusCodes.Status404NotFound)
|
|
126
|
+
.RequireAuthorization("Admin");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Domain Entities
|
|
134
|
+
|
|
135
|
+
### User Entity
|
|
136
|
+
|
|
137
|
+
```csharp
|
|
138
|
+
public class User
|
|
139
|
+
{
|
|
140
|
+
public Guid Id { get; private set; }
|
|
141
|
+
public string Name { get; private set; } = string.Empty;
|
|
142
|
+
public string Email { get; private set; } = string.Empty;
|
|
143
|
+
public string PasswordHash { get; private set; } = string.Empty;
|
|
144
|
+
public string Role { get; private set; } = "User";
|
|
145
|
+
public DateTime CreatedAt { get; private set; }
|
|
146
|
+
public DateTime? UpdatedAt { get; private set; }
|
|
147
|
+
public bool IsActive { get; private set; } = true;
|
|
148
|
+
|
|
149
|
+
private readonly List<Post> _posts = [];
|
|
150
|
+
public IReadOnlyCollection<Post> Posts => _posts.AsReadOnly();
|
|
151
|
+
|
|
152
|
+
private User() { } // EF Core constructor
|
|
153
|
+
|
|
154
|
+
public static User Create(string name, string email, string passwordHash)
|
|
155
|
+
{
|
|
156
|
+
return new User
|
|
157
|
+
{
|
|
158
|
+
Id = Guid.NewGuid(),
|
|
159
|
+
Name = name,
|
|
160
|
+
Email = email,
|
|
161
|
+
PasswordHash = passwordHash,
|
|
162
|
+
CreatedAt = DateTime.UtcNow
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public void Update(string name, string email)
|
|
167
|
+
{
|
|
168
|
+
Name = name;
|
|
169
|
+
Email = email;
|
|
170
|
+
UpdatedAt = DateTime.UtcNow;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public void Deactivate()
|
|
174
|
+
{
|
|
175
|
+
IsActive = false;
|
|
176
|
+
UpdatedAt = DateTime.UtcNow;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
public void AddPost(Post post)
|
|
180
|
+
{
|
|
181
|
+
_posts.Add(post);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Post Entity
|
|
187
|
+
|
|
188
|
+
```csharp
|
|
189
|
+
public class Post
|
|
190
|
+
{
|
|
191
|
+
public Guid Id { get; private set; }
|
|
192
|
+
public string Title { get; private set; } = string.Empty;
|
|
193
|
+
public string Content { get; private set; } = string.Empty;
|
|
194
|
+
public Guid AuthorId { get; private set; }
|
|
195
|
+
public User Author { get; private set; } = null!;
|
|
196
|
+
public DateTime CreatedAt { get; private set; }
|
|
197
|
+
public DateTime? PublishedAt { get; private set; }
|
|
198
|
+
public PostStatus Status { get; private set; } = PostStatus.Draft;
|
|
199
|
+
|
|
200
|
+
private readonly List<Tag> _tags = [];
|
|
201
|
+
public IReadOnlyCollection<Tag> Tags => _tags.AsReadOnly();
|
|
202
|
+
|
|
203
|
+
private Post() { }
|
|
204
|
+
|
|
205
|
+
public static Post Create(string title, string content, User author)
|
|
206
|
+
{
|
|
207
|
+
var post = new Post
|
|
208
|
+
{
|
|
209
|
+
Id = Guid.NewGuid(),
|
|
210
|
+
Title = title,
|
|
211
|
+
Content = content,
|
|
212
|
+
AuthorId = author.Id,
|
|
213
|
+
Author = author,
|
|
214
|
+
CreatedAt = DateTime.UtcNow
|
|
215
|
+
};
|
|
216
|
+
author.AddPost(post);
|
|
217
|
+
return post;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public void Publish()
|
|
221
|
+
{
|
|
222
|
+
if (Status == PostStatus.Draft)
|
|
223
|
+
{
|
|
224
|
+
Status = PostStatus.Published;
|
|
225
|
+
PublishedAt = DateTime.UtcNow;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public void AddTag(Tag tag)
|
|
230
|
+
{
|
|
231
|
+
if (!_tags.Contains(tag))
|
|
232
|
+
_tags.Add(tag);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
public enum PostStatus
|
|
237
|
+
{
|
|
238
|
+
Draft,
|
|
239
|
+
Published,
|
|
240
|
+
Archived
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## CQRS Handlers
|
|
247
|
+
|
|
248
|
+
### Query Handler
|
|
249
|
+
|
|
250
|
+
```csharp
|
|
251
|
+
public record GetUserByIdQuery(Guid Id) : IRequest<UserDto?>;
|
|
252
|
+
|
|
253
|
+
public class GetUserByIdQueryHandler(AppDbContext context)
|
|
254
|
+
: IRequestHandler<GetUserByIdQuery, UserDto?>
|
|
255
|
+
{
|
|
256
|
+
public async Task<UserDto?> Handle(GetUserByIdQuery request, CancellationToken ct)
|
|
257
|
+
{
|
|
258
|
+
return await context.Users
|
|
259
|
+
.AsNoTracking()
|
|
260
|
+
.Where(u => u.Id == request.Id)
|
|
261
|
+
.Select(u => new UserDto(u.Id, u.Name, u.Email, u.Role, u.CreatedAt))
|
|
262
|
+
.FirstOrDefaultAsync(ct);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Command Handler with Validation
|
|
268
|
+
|
|
269
|
+
```csharp
|
|
270
|
+
public record CreateUserCommand(string Name, string Email, string Password) : IRequest<UserDto>;
|
|
271
|
+
|
|
272
|
+
public class CreateUserCommandValidator : AbstractValidator<CreateUserCommand>
|
|
273
|
+
{
|
|
274
|
+
public CreateUserCommandValidator(IUserRepository userRepository)
|
|
275
|
+
{
|
|
276
|
+
RuleFor(x => x.Name)
|
|
277
|
+
.NotEmpty().WithMessage("Name is required")
|
|
278
|
+
.MaximumLength(100).WithMessage("Name cannot exceed 100 characters");
|
|
279
|
+
|
|
280
|
+
RuleFor(x => x.Email)
|
|
281
|
+
.NotEmpty().WithMessage("Email is required")
|
|
282
|
+
.EmailAddress().WithMessage("Invalid email format")
|
|
283
|
+
.MustAsync(async (email, ct) => !await userRepository.EmailExistsAsync(email, ct))
|
|
284
|
+
.WithMessage("Email already exists");
|
|
285
|
+
|
|
286
|
+
RuleFor(x => x.Password)
|
|
287
|
+
.NotEmpty().WithMessage("Password is required")
|
|
288
|
+
.MinimumLength(8).WithMessage("Password must be at least 8 characters")
|
|
289
|
+
.Matches(@"[A-Z]").WithMessage("Password must contain uppercase letter")
|
|
290
|
+
.Matches(@"[a-z]").WithMessage("Password must contain lowercase letter")
|
|
291
|
+
.Matches(@"[0-9]").WithMessage("Password must contain digit");
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
public class CreateUserCommandHandler(
|
|
296
|
+
AppDbContext context,
|
|
297
|
+
IPasswordHasher passwordHasher,
|
|
298
|
+
IValidator<CreateUserCommand> validator)
|
|
299
|
+
: IRequestHandler<CreateUserCommand, UserDto>
|
|
300
|
+
{
|
|
301
|
+
public async Task<UserDto> Handle(CreateUserCommand request, CancellationToken ct)
|
|
302
|
+
{
|
|
303
|
+
var validationResult = await validator.ValidateAsync(request, ct);
|
|
304
|
+
if (!validationResult.IsValid)
|
|
305
|
+
throw new ValidationException(validationResult.Errors);
|
|
306
|
+
|
|
307
|
+
var user = User.Create(
|
|
308
|
+
request.Name,
|
|
309
|
+
request.Email,
|
|
310
|
+
passwordHasher.Hash(request.Password));
|
|
311
|
+
|
|
312
|
+
context.Users.Add(user);
|
|
313
|
+
await context.SaveChangesAsync(ct);
|
|
314
|
+
|
|
315
|
+
return new UserDto(user.Id, user.Name, user.Email, user.Role, user.CreatedAt);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Repository Pattern
|
|
323
|
+
|
|
324
|
+
### Repository Interface
|
|
325
|
+
|
|
326
|
+
```csharp
|
|
327
|
+
public interface IRepository<T> where T : class
|
|
328
|
+
{
|
|
329
|
+
Task<T?> GetByIdAsync(Guid id, CancellationToken ct = default);
|
|
330
|
+
Task<IReadOnlyList<T>> GetAllAsync(CancellationToken ct = default);
|
|
331
|
+
Task<T> AddAsync(T entity, CancellationToken ct = default);
|
|
332
|
+
Task UpdateAsync(T entity, CancellationToken ct = default);
|
|
333
|
+
Task DeleteAsync(T entity, CancellationToken ct = default);
|
|
334
|
+
Task<bool> ExistsAsync(Guid id, CancellationToken ct = default);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
public interface IUserRepository : IRepository<User>
|
|
338
|
+
{
|
|
339
|
+
Task<User?> GetByEmailAsync(string email, CancellationToken ct = default);
|
|
340
|
+
Task<bool> EmailExistsAsync(string email, CancellationToken ct = default);
|
|
341
|
+
Task<IReadOnlyList<User>> GetActiveUsersAsync(CancellationToken ct = default);
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Repository Implementation
|
|
346
|
+
|
|
347
|
+
```csharp
|
|
348
|
+
public class EfRepository<T>(AppDbContext context) : IRepository<T> where T : class
|
|
349
|
+
{
|
|
350
|
+
protected readonly AppDbContext Context = context;
|
|
351
|
+
protected readonly DbSet<T> DbSet = context.Set<T>();
|
|
352
|
+
|
|
353
|
+
public virtual async Task<T?> GetByIdAsync(Guid id, CancellationToken ct = default)
|
|
354
|
+
=> await DbSet.FindAsync([id], ct);
|
|
355
|
+
|
|
356
|
+
public virtual async Task<IReadOnlyList<T>> GetAllAsync(CancellationToken ct = default)
|
|
357
|
+
=> await DbSet.ToListAsync(ct);
|
|
358
|
+
|
|
359
|
+
public virtual async Task<T> AddAsync(T entity, CancellationToken ct = default)
|
|
360
|
+
{
|
|
361
|
+
await DbSet.AddAsync(entity, ct);
|
|
362
|
+
await Context.SaveChangesAsync(ct);
|
|
363
|
+
return entity;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
public virtual async Task UpdateAsync(T entity, CancellationToken ct = default)
|
|
367
|
+
{
|
|
368
|
+
DbSet.Update(entity);
|
|
369
|
+
await Context.SaveChangesAsync(ct);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
public virtual async Task DeleteAsync(T entity, CancellationToken ct = default)
|
|
373
|
+
{
|
|
374
|
+
DbSet.Remove(entity);
|
|
375
|
+
await Context.SaveChangesAsync(ct);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
public virtual async Task<bool> ExistsAsync(Guid id, CancellationToken ct = default)
|
|
379
|
+
=> await DbSet.FindAsync([id], ct) is not null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
public class EfUserRepository(AppDbContext context)
|
|
383
|
+
: EfRepository<User>(context), IUserRepository
|
|
384
|
+
{
|
|
385
|
+
public async Task<User?> GetByEmailAsync(string email, CancellationToken ct = default)
|
|
386
|
+
=> await DbSet
|
|
387
|
+
.Include(u => u.Posts)
|
|
388
|
+
.FirstOrDefaultAsync(u => u.Email == email, ct);
|
|
389
|
+
|
|
390
|
+
public async Task<bool> EmailExistsAsync(string email, CancellationToken ct = default)
|
|
391
|
+
=> await DbSet.AnyAsync(u => u.Email == email, ct);
|
|
392
|
+
|
|
393
|
+
public async Task<IReadOnlyList<User>> GetActiveUsersAsync(CancellationToken ct = default)
|
|
394
|
+
=> await DbSet
|
|
395
|
+
.AsNoTracking()
|
|
396
|
+
.Where(u => u.IsActive)
|
|
397
|
+
.OrderBy(u => u.Name)
|
|
398
|
+
.ToListAsync(ct);
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Testing Examples
|
|
405
|
+
|
|
406
|
+
### Unit Test with xUnit and Moq
|
|
407
|
+
|
|
408
|
+
```csharp
|
|
409
|
+
public class CreateUserCommandHandlerTests
|
|
410
|
+
{
|
|
411
|
+
private readonly Mock<AppDbContext> _contextMock;
|
|
412
|
+
private readonly Mock<IPasswordHasher> _hasherMock;
|
|
413
|
+
private readonly Mock<IValidator<CreateUserCommand>> _validatorMock;
|
|
414
|
+
private readonly CreateUserCommandHandler _handler;
|
|
415
|
+
|
|
416
|
+
public CreateUserCommandHandlerTests()
|
|
417
|
+
{
|
|
418
|
+
_contextMock = new Mock<AppDbContext>(new DbContextOptions<AppDbContext>());
|
|
419
|
+
_hasherMock = new Mock<IPasswordHasher>();
|
|
420
|
+
_validatorMock = new Mock<IValidator<CreateUserCommand>>();
|
|
421
|
+
|
|
422
|
+
_handler = new CreateUserCommandHandler(
|
|
423
|
+
_contextMock.Object,
|
|
424
|
+
_hasherMock.Object,
|
|
425
|
+
_validatorMock.Object);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
[Fact]
|
|
429
|
+
public async Task Handle_ValidCommand_ReturnsUserDto()
|
|
430
|
+
{
|
|
431
|
+
// Arrange
|
|
432
|
+
var command = new CreateUserCommand("John Doe", "john@example.com", "Password123");
|
|
433
|
+
|
|
434
|
+
_validatorMock.Setup(v => v.ValidateAsync(command, It.IsAny<CancellationToken>()))
|
|
435
|
+
.ReturnsAsync(new ValidationResult());
|
|
436
|
+
|
|
437
|
+
_hasherMock.Setup(h => h.Hash(command.Password))
|
|
438
|
+
.Returns("hashed_password");
|
|
439
|
+
|
|
440
|
+
var mockSet = new Mock<DbSet<User>>();
|
|
441
|
+
_contextMock.Setup(c => c.Users).Returns(mockSet.Object);
|
|
442
|
+
|
|
443
|
+
// Act
|
|
444
|
+
var result = await _handler.Handle(command, CancellationToken.None);
|
|
445
|
+
|
|
446
|
+
// Assert
|
|
447
|
+
result.Should().NotBeNull();
|
|
448
|
+
result.Name.Should().Be("John Doe");
|
|
449
|
+
result.Email.Should().Be("john@example.com");
|
|
450
|
+
|
|
451
|
+
mockSet.Verify(m => m.Add(It.IsAny<User>()), Times.Once);
|
|
452
|
+
_contextMock.Verify(c => c.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
[Fact]
|
|
456
|
+
public async Task Handle_InvalidCommand_ThrowsValidationException()
|
|
457
|
+
{
|
|
458
|
+
// Arrange
|
|
459
|
+
var command = new CreateUserCommand("", "invalid-email", "short");
|
|
460
|
+
var failures = new List<ValidationFailure>
|
|
461
|
+
{
|
|
462
|
+
new("Name", "Name is required"),
|
|
463
|
+
new("Email", "Invalid email format")
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
_validatorMock.Setup(v => v.ValidateAsync(command, It.IsAny<CancellationToken>()))
|
|
467
|
+
.ReturnsAsync(new ValidationResult(failures));
|
|
468
|
+
|
|
469
|
+
// Act & Assert
|
|
470
|
+
await Assert.ThrowsAsync<ValidationException>(() =>
|
|
471
|
+
_handler.Handle(command, CancellationToken.None));
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Integration Test with TestServer
|
|
477
|
+
|
|
478
|
+
```csharp
|
|
479
|
+
public class UsersEndpointsTests : IClassFixture<WebApplicationFactory<Program>>
|
|
480
|
+
{
|
|
481
|
+
private readonly HttpClient _client;
|
|
482
|
+
private readonly WebApplicationFactory<Program> _factory;
|
|
483
|
+
|
|
484
|
+
public UsersEndpointsTests(WebApplicationFactory<Program> factory)
|
|
485
|
+
{
|
|
486
|
+
_factory = factory.WithWebHostBuilder(builder =>
|
|
487
|
+
{
|
|
488
|
+
builder.ConfigureServices(services =>
|
|
489
|
+
{
|
|
490
|
+
// Replace real database with in-memory
|
|
491
|
+
var descriptor = services.SingleOrDefault(
|
|
492
|
+
d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
|
|
493
|
+
if (descriptor != null)
|
|
494
|
+
services.Remove(descriptor);
|
|
495
|
+
|
|
496
|
+
services.AddDbContext<AppDbContext>(options =>
|
|
497
|
+
options.UseInMemoryDatabase("TestDb"));
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
_client = _factory.CreateClient();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
[Fact]
|
|
505
|
+
public async Task CreateUser_ValidRequest_ReturnsCreated()
|
|
506
|
+
{
|
|
507
|
+
// Arrange
|
|
508
|
+
var request = new { Name = "Test User", Email = "test@example.com", Password = "Password123" };
|
|
509
|
+
var content = new StringContent(
|
|
510
|
+
JsonSerializer.Serialize(request),
|
|
511
|
+
Encoding.UTF8,
|
|
512
|
+
"application/json");
|
|
513
|
+
|
|
514
|
+
// Act
|
|
515
|
+
var response = await _client.PostAsync("/api/users", content);
|
|
516
|
+
|
|
517
|
+
// Assert
|
|
518
|
+
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
519
|
+
response.Headers.Location.Should().NotBeNull();
|
|
520
|
+
|
|
521
|
+
var user = await response.Content.ReadFromJsonAsync<UserDto>();
|
|
522
|
+
user.Should().NotBeNull();
|
|
523
|
+
user!.Name.Should().Be("Test User");
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
[Fact]
|
|
527
|
+
public async Task GetUserById_ExistingUser_ReturnsOk()
|
|
528
|
+
{
|
|
529
|
+
// Arrange
|
|
530
|
+
using var scope = _factory.Services.CreateScope();
|
|
531
|
+
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
532
|
+
var user = User.Create("Existing User", "existing@example.com", "hash");
|
|
533
|
+
context.Users.Add(user);
|
|
534
|
+
await context.SaveChangesAsync();
|
|
535
|
+
|
|
536
|
+
// Act
|
|
537
|
+
var response = await _client.GetAsync($"/api/users/{user.Id}");
|
|
538
|
+
|
|
539
|
+
// Assert
|
|
540
|
+
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
541
|
+
var result = await response.Content.ReadFromJsonAsync<UserDto>();
|
|
542
|
+
result!.Id.Should().Be(user.Id);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
[Fact]
|
|
546
|
+
public async Task GetUserById_NonExistingUser_ReturnsNotFound()
|
|
547
|
+
{
|
|
548
|
+
// Act
|
|
549
|
+
var response = await _client.GetAsync($"/api/users/{Guid.NewGuid()}");
|
|
550
|
+
|
|
551
|
+
// Assert
|
|
552
|
+
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## DTOs and Records
|
|
560
|
+
|
|
561
|
+
```csharp
|
|
562
|
+
// User DTOs
|
|
563
|
+
public record UserDto(Guid Id, string Name, string Email, string Role, DateTime CreatedAt);
|
|
564
|
+
public record CreateUserRequest(string Name, string Email, string Password);
|
|
565
|
+
public record UpdateUserRequest(string Name, string Email);
|
|
566
|
+
public record UserWithPostsDto(Guid Id, string Name, string Email, List<PostSummaryDto> Posts);
|
|
567
|
+
|
|
568
|
+
// Post DTOs
|
|
569
|
+
public record PostDto(Guid Id, string Title, string Content, DateTime CreatedAt, PostStatus Status);
|
|
570
|
+
public record PostSummaryDto(Guid Id, string Title, DateTime CreatedAt);
|
|
571
|
+
public record CreatePostRequest(string Title, string Content);
|
|
572
|
+
|
|
573
|
+
// Pagination
|
|
574
|
+
public record PagedResult<T>(List<T> Items, int TotalCount, int Page, int PageSize)
|
|
575
|
+
{
|
|
576
|
+
public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize);
|
|
577
|
+
public bool HasPreviousPage => Page > 1;
|
|
578
|
+
public bool HasNextPage => Page < TotalPages;
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
Version: 2.0.0
|
|
585
|
+
Last Updated: 2026-01-06
|