@polymorphism-tech/morph-spec 4.3.3 → 4.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.morph/.morphversion +5 -0
- package/.morph/analytics/threads-log.jsonl +9 -0
- package/{stacks/blazor-azure/.morph → .morph}/config/agents.json +948 -948
- package/.morph/config/config.json +9 -0
- package/{stacks/blazor-azure/.morph → .morph}/project/context/README.md +1 -1
- package/.morph/project/context/detection-log.md +16 -0
- package/.morph/project/standards/inferred.md +59 -0
- package/.morph/state.json +48 -0
- package/.morph/templates/.idea/morph-templates.xml +92 -0
- package/.morph/templates/.vscode/morph-templates.code-snippets +186 -0
- package/.morph/templates/IDE-SNIPPETS.md +266 -0
- package/.morph/templates/README.md +814 -0
- package/.morph/templates/REGISTRY.json +1677 -0
- package/.morph/templates/code/dotnet/backend/repository.cs +141 -0
- package/.morph/templates/code/dotnet/backend/service.cs +139 -0
- package/.morph/templates/code/dotnet/contracts/Commands.cs +74 -0
- package/.morph/templates/code/dotnet/contracts/Entities.cs +25 -0
- package/.morph/templates/code/dotnet/contracts/Queries.cs +74 -0
- package/.morph/templates/code/dotnet/contracts/README.md +74 -0
- package/.morph/templates/code/dotnet/contracts/api-contracts.cs +173 -0
- package/.morph/templates/code/dotnet/contracts/contracts.cs +217 -0
- package/.morph/templates/code/dotnet/database/migration.cs +83 -0
- package/.morph/templates/code/dotnet/frontend/component.razor +239 -0
- package/.morph/templates/code/dotnet/jobs/agent.cs +163 -0
- package/.morph/templates/code/dotnet/jobs/job.cs +171 -0
- package/.morph/templates/code/dotnet/test.cs +239 -0
- package/.morph/templates/code/sql/rls-policy.sql +57 -0
- package/.morph/templates/code/sql/supabase-migration.sql +100 -0
- package/.morph/templates/code/sql/supabase-migration.template.sql +113 -0
- package/.morph/templates/code/typescript/contracts.ts +168 -0
- package/.morph/templates/context/CONTEXT-FEATURE.md +276 -0
- package/.morph/templates/context/CONTEXT.md +181 -0
- package/.morph/templates/docs/proposal.md +182 -0
- package/.morph/templates/docs/spec.md +149 -0
- package/.morph/templates/examples/design-system-examples.md +357 -0
- package/.morph/templates/examples/spec-examples.md +90 -0
- package/.morph/templates/feature/decisions.md +187 -0
- package/.morph/templates/feature/recap.md +146 -0
- package/.morph/templates/feature/tasks.md +199 -0
- package/.morph/templates/infrastructure/azure/Dockerfile.example +82 -0
- package/.morph/templates/infrastructure/azure/README.md +286 -0
- package/.morph/templates/infrastructure/azure/app-insights.bicep +63 -0
- package/.morph/templates/infrastructure/azure/app-service.bicep +164 -0
- package/.morph/templates/infrastructure/azure/container-app-env.bicep +49 -0
- package/.morph/templates/infrastructure/azure/container-app.bicep +156 -0
- package/.morph/templates/infrastructure/azure/deploy-checklist.md +426 -0
- package/.morph/templates/infrastructure/azure/deploy.ps1 +229 -0
- package/.morph/templates/infrastructure/azure/deploy.sh +208 -0
- package/.morph/templates/infrastructure/azure/key-vault.bicep +91 -0
- package/.morph/templates/infrastructure/azure/main.bicep +189 -0
- package/.morph/templates/infrastructure/azure/parameters.dev.json +29 -0
- package/.morph/templates/infrastructure/azure/parameters.prod.json +29 -0
- package/.morph/templates/infrastructure/azure/parameters.staging.json +29 -0
- package/.morph/templates/infrastructure/azure/sql-database.bicep +103 -0
- package/.morph/templates/infrastructure/azure/storage.bicep +106 -0
- package/.morph/templates/infrastructure/docker/Dockerfile.template +58 -0
- package/.morph/templates/infrastructure/docker/docker-compose.template.yml +67 -0
- package/.morph/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -0
- package/.morph/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -0
- package/.morph/templates/infrastructure/docker/easypanel.template.json +54 -0
- package/.morph/templates/infrastructure/github/README.md +593 -0
- package/.morph/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +22 -0
- package/.morph/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -0
- package/.morph/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -0
- package/.morph/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +61 -0
- package/.morph/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +31 -0
- package/.morph/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -0
- package/.morph/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -0
- package/.morph/templates/integrations/asaas-client.cs +387 -0
- package/.morph/templates/integrations/asaas-webhook.cs +351 -0
- package/.morph/templates/integrations/azure-identity-config.cs +288 -0
- package/.morph/templates/integrations/clerk-config.cs +258 -0
- package/.morph/templates/meta-prompts/fusion/fusion-agent.md +76 -0
- package/.morph/templates/meta-prompts/fusion/fusion-aggregator.md +100 -0
- package/.morph/templates/meta-prompts/hops/hop-retry.md +78 -0
- package/.morph/templates/meta-prompts/hops/hop-validation.md +97 -0
- package/.morph/templates/meta-prompts/hops/hop-wrapper.md +36 -0
- package/.morph/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -0
- package/.morph/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -0
- package/.morph/templates/meta-prompts/squad-leaders/backend-squad.md +90 -0
- package/.morph/templates/meta-prompts/squad-leaders/frontend-squad.md +126 -0
- package/.morph/templates/meta-prompts/squad-leaders/squad-leader.md +43 -0
- package/.morph/templates/meta-prompts/validators/checkpoint-validator.md +107 -0
- package/.morph/templates/meta-prompts/validators/pre-commit-validator.md +95 -0
- package/.morph/templates/saas/subscription.cs +347 -0
- package/.morph/templates/saas/tenant.cs +338 -0
- package/.morph/templates/state.template.json +17 -0
- package/.morph/templates/ui/FluentDesignTheme.cs +149 -0
- package/.morph/templates/ui/MudTheme.cs +281 -0
- package/.morph/templates/ui/design-system.css +226 -0
- package/bin/detect-agents.js +1 -2
- package/bin/morph-spec.js +1 -14
- package/framework/agents.json +948 -0
- package/{stacks/nextjs-supabase/.claude → framework}/commands/morph-infra.md +1 -1
- package/framework/hooks/README.md +282 -0
- package/framework/hooks/agent-stop/validate-and-continue.js +96 -0
- package/framework/hooks/agent-stop/validate-checkpoints.js +101 -0
- package/framework/hooks/agent-stop/validate-tests.js +109 -0
- package/framework/hooks/agent-teams/dispatch.js +67 -0
- package/framework/hooks/agent-teams/phase-advanced.js +80 -0
- package/framework/hooks/agent-teams/task-completed.js +76 -0
- package/framework/hooks/agent-teams/teammate-idle.js +70 -0
- package/framework/hooks/commit-msg/conventional-commits.sh +33 -0
- package/framework/hooks/pre-commit/agents.sh +25 -0
- package/framework/hooks/pre-commit/orchestrator.sh +64 -0
- package/framework/hooks/pre-commit/specs.sh +50 -0
- package/framework/hooks/pre-push/run-tests.sh +44 -0
- package/framework/index/troubleshooting-index.json +184 -0
- package/framework/memory/patterns-learned.md +766 -0
- package/framework/skills/level-0-meta/README.md +7 -0
- package/framework/skills/level-0-meta/code-review.md +226 -0
- package/framework/skills/level-0-meta/morph-checklist.md +117 -0
- package/framework/skills/level-0-meta/simulation-checklist.md +77 -0
- package/framework/skills/level-1-workflows/README.md +7 -0
- package/framework/skills/level-1-workflows/morph-replicate.md +213 -0
- package/framework/skills/level-1-workflows/phase-clarify.md +131 -0
- package/framework/skills/level-1-workflows/phase-design.md +213 -0
- package/framework/skills/level-1-workflows/phase-setup.md +106 -0
- package/framework/skills/level-1-workflows/phase-tasks.md +164 -0
- package/framework/skills/level-1-workflows/phase-uiux.md +169 -0
- package/framework/skills/level-2-domains/README.md +14 -0
- package/framework/skills/level-2-domains/ai-agents/ai-system-architect.md +192 -0
- package/framework/skills/level-2-domains/architecture/po-pm-advisor.md +197 -0
- package/framework/skills/level-2-domains/architecture/prompt-engineer.md +189 -0
- package/framework/skills/level-2-domains/architecture/seo-growth-hacker.md +320 -0
- package/framework/skills/level-2-domains/architecture/standards-architect.md +156 -0
- package/framework/skills/level-2-domains/backend/api-designer.md +59 -0
- package/framework/skills/level-2-domains/backend/dotnet-senior.md +77 -0
- package/framework/skills/level-2-domains/backend/ef-modeler.md +58 -0
- package/framework/skills/level-2-domains/backend/hangfire-orchestrator.md +126 -0
- package/framework/skills/level-2-domains/backend/ms-agent-expert.md +45 -0
- package/framework/skills/level-2-domains/frontend/blazor-builder.md +210 -0
- package/framework/skills/level-2-domains/frontend/nextjs-expert.md +154 -0
- package/framework/skills/level-2-domains/frontend/ui-ux-designer.md +191 -0
- package/framework/skills/level-2-domains/infrastructure/azure-architect.md +142 -0
- package/framework/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +699 -0
- package/framework/skills/level-2-domains/infrastructure/bicep-architect.md +126 -0
- package/framework/skills/level-2-domains/infrastructure/container-specialist.md +131 -0
- package/framework/skills/level-2-domains/infrastructure/devops-engineer.md +119 -0
- package/framework/skills/level-2-domains/integrations/asaas-financial.md +130 -0
- package/framework/skills/level-2-domains/integrations/azure-identity.md +142 -0
- package/framework/skills/level-2-domains/integrations/clerk-auth.md +108 -0
- package/framework/skills/level-2-domains/integrations/hangfire-orchestrator.md +64 -0
- package/framework/skills/level-2-domains/integrations/resend-email.md +119 -0
- package/framework/skills/level-2-domains/quality/code-analyzer.md +235 -0
- package/framework/skills/level-2-domains/quality/testing-specialist.md +126 -0
- package/framework/skills/level-3-technologies/README.md +7 -0
- package/framework/skills/level-4-patterns/README.md +7 -0
- package/framework/squad-templates/backend-only.json +34 -0
- package/framework/squad-templates/frontend-only.json +34 -0
- package/framework/squad-templates/full-stack.json +52 -0
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/framework/templates/IDE-SNIPPETS.md +266 -0
- package/framework/templates/README.md +814 -0
- package/framework/templates/REGISTRY.json +1677 -0
- package/framework/templates/code/dotnet/backend/repository.cs +141 -0
- package/framework/templates/code/dotnet/backend/service.cs +139 -0
- package/framework/templates/code/dotnet/contracts/Commands.cs +74 -0
- package/framework/templates/code/dotnet/contracts/Entities.cs +25 -0
- package/framework/templates/code/dotnet/contracts/Queries.cs +74 -0
- package/framework/templates/code/dotnet/contracts/README.md +74 -0
- package/framework/templates/code/dotnet/contracts/api-contracts.cs +173 -0
- package/framework/templates/code/dotnet/contracts/contracts.cs +217 -0
- package/framework/templates/code/dotnet/database/migration.cs +83 -0
- package/framework/templates/code/dotnet/frontend/component.razor +239 -0
- package/framework/templates/code/dotnet/jobs/agent.cs +163 -0
- package/framework/templates/code/dotnet/jobs/job.cs +171 -0
- package/framework/templates/code/dotnet/test.cs +239 -0
- package/framework/templates/code/sql/rls-policy.sql +57 -0
- package/framework/templates/code/sql/supabase-migration.sql +100 -0
- package/framework/templates/code/sql/supabase-migration.template.sql +113 -0
- package/framework/templates/code/typescript/contracts.ts +168 -0
- package/framework/templates/context/CONTEXT-FEATURE.md +276 -0
- package/framework/templates/context/CONTEXT.md +181 -0
- package/framework/templates/docs/proposal.md +182 -0
- package/framework/templates/docs/spec.md +149 -0
- package/framework/templates/examples/design-system-examples.md +357 -0
- package/framework/templates/examples/spec-examples.md +90 -0
- package/framework/templates/feature/decisions.md +187 -0
- package/framework/templates/feature/recap.md +146 -0
- package/framework/templates/feature/tasks.md +199 -0
- package/framework/templates/infrastructure/azure/Dockerfile.example +82 -0
- package/framework/templates/infrastructure/azure/README.md +286 -0
- package/framework/templates/infrastructure/azure/app-insights.bicep +63 -0
- package/framework/templates/infrastructure/azure/app-service.bicep +164 -0
- package/framework/templates/infrastructure/azure/container-app-env.bicep +49 -0
- package/framework/templates/infrastructure/azure/container-app.bicep +156 -0
- package/framework/templates/infrastructure/azure/deploy-checklist.md +426 -0
- package/framework/templates/infrastructure/azure/deploy.ps1 +229 -0
- package/framework/templates/infrastructure/azure/deploy.sh +208 -0
- package/framework/templates/infrastructure/azure/key-vault.bicep +91 -0
- package/framework/templates/infrastructure/azure/main.bicep +189 -0
- package/framework/templates/infrastructure/azure/parameters.dev.json +29 -0
- package/framework/templates/infrastructure/azure/parameters.prod.json +29 -0
- package/framework/templates/infrastructure/azure/parameters.staging.json +29 -0
- package/framework/templates/infrastructure/azure/sql-database.bicep +103 -0
- package/framework/templates/infrastructure/azure/storage.bicep +106 -0
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -0
- package/framework/templates/infrastructure/docker/docker-compose.template.yml +67 -0
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -0
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -0
- package/framework/templates/infrastructure/docker/easypanel.template.json +54 -0
- package/framework/templates/infrastructure/github/README.md +593 -0
- package/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +22 -0
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -0
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -0
- package/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +61 -0
- package/framework/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +31 -0
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -0
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -0
- package/framework/templates/integrations/asaas-client.cs +387 -0
- package/framework/templates/integrations/asaas-webhook.cs +351 -0
- package/framework/templates/integrations/azure-identity-config.cs +288 -0
- package/framework/templates/integrations/clerk-config.cs +258 -0
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -0
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -0
- package/framework/templates/meta-prompts/hops/hop-retry.md +78 -0
- package/framework/templates/meta-prompts/hops/hop-validation.md +97 -0
- package/framework/templates/meta-prompts/hops/hop-wrapper.md +36 -0
- package/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -0
- package/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -0
- package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +90 -0
- package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +126 -0
- package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +43 -0
- package/framework/templates/meta-prompts/validators/checkpoint-validator.md +107 -0
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -0
- package/framework/templates/saas/subscription.cs +347 -0
- package/framework/templates/saas/tenant.cs +338 -0
- package/framework/templates/state.template.json +17 -0
- package/framework/templates/ui/FluentDesignTheme.cs +149 -0
- package/framework/templates/ui/MudTheme.cs +281 -0
- package/framework/templates/ui/design-system.css +226 -0
- package/framework/workflows/README.md +1041 -0
- package/framework/workflows/configs/design-impl.json +49 -0
- package/framework/workflows/configs/fast-track.json +42 -0
- package/framework/workflows/configs/full-morph.json +79 -0
- package/framework/workflows/configs/fusion.json +39 -0
- package/framework/workflows/configs/long-running.json +33 -0
- package/framework/workflows/configs/standard.json +60 -0
- package/framework/workflows/configs/ui-refresh.json +49 -0
- package/framework/workflows/configs/zero-touch.json +75 -0
- package/framework/workflows/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -0
- package/framework/workflows/docs/design-impl.md +37 -0
- package/framework/workflows/docs/enforcement-pipeline.md +668 -0
- package/framework/workflows/docs/fast-track.md +29 -0
- package/framework/workflows/docs/full-morph.md +76 -0
- package/framework/workflows/docs/standard.md +44 -0
- package/framework/workflows/docs/ui-refresh.md +39 -0
- package/package.json +3 -3
- package/src/commands/feature/create-story.js +11 -7
- package/src/commands/project/detect-agents.js +1 -2
- package/src/commands/project/init.js +69 -32
- package/src/commands/project/update.js +102 -15
- package/src/commands/templates/template-customize.js +3 -17
- package/src/commands/templates/template-list.js +1 -15
- package/src/commands/templates/template-render.js +2 -3
- package/src/commands/templates/template-show.js +3 -5
- package/src/core/templates/template-registry.js +9 -23
- package/src/lib/detectors/structure-detector.js +3 -3
- package/src/lib/generators/context-generator.js +18 -6
- package/src/lib/hooks/hook-executor.js +0 -2
- package/src/lib/orchestration/team-orchestrator.js +1 -2
- package/src/lib/standards/standards-context-injector.js +3 -4
- package/src/lib/troubleshooting/troubleshoot-grep.js +3 -9
- package/src/lib/validators/validation-runner.js +1 -2
- package/src/utils/file-copier.js +1 -2
- package/docs/README.md +0 -144
- package/docs/api/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/api/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -978
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -1049
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/api/scripts/collapse.js +0 -39
- package/docs/api/scripts/commonNav.js +0 -28
- package/docs/api/scripts/linenumber.js +0 -25
- package/docs/api/scripts/nav.js +0 -12
- package/docs/api/scripts/polyfill.js +0 -4
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +0 -202
- package/docs/api/scripts/prettify/lang-css.js +0 -2
- package/docs/api/scripts/prettify/prettify.js +0 -28
- package/docs/api/scripts/search.js +0 -99
- package/docs/api/styles/jsdoc.css +0 -776
- package/docs/api/styles/prettify.css +0 -80
- package/docs/cli-auto-detection.md +0 -219
- package/docs/getting-started.md +0 -296
- package/docs/installation.md +0 -361
- package/docs/next-generation/AGENTS.md +0 -521
- package/docs/next-generation/ANALYSIS.md +0 -555
- package/docs/next-generation/ARCHITECTURE.md +0 -436
- package/docs/next-generation/CONTEXT-OPTIMIZATION.md +0 -267
- package/docs/next-generation/EXECUTION-FLOW.md +0 -274
- package/docs/next-generation/FEATURES.md +0 -688
- package/docs/next-generation/META-PROMPTS.md +0 -235
- package/docs/next-generation/MIGRATION-GUIDE.md +0 -253
- package/docs/next-generation/README.md +0 -231
- package/docs/next-generation/ROADMAP.md +0 -801
- package/docs/next-generation/THREAD-MANAGEMENT.md +0 -240
- package/docs/templates.md +0 -418
- package/docs/troubleshooting.md +0 -269
- package/docs/validation-checklist.md +0 -264
- package/scripts/postinstall.js +0 -132
- package/src/lib/stacks/index.js +0 -7
- package/src/lib/stacks/stack-resolver.js +0 -180
- package/stacks/blazor-azure/.claude/commands/morph-deploy.md +0 -529
- package/stacks/blazor-azure/.claude/commands/morph-infra.md +0 -209
- package/stacks/blazor-azure/.morph/.morphversion +0 -5
- package/stacks/blazor-azure/.morph/config/config.json +0 -9
- package/stacks/blazor-azure/CLAUDE.md +0 -155
- package/stacks/blazor-azure/README.md +0 -79
- package/stacks/nextjs-supabase/.claude/commands/morph-apply.md +0 -221
- package/stacks/nextjs-supabase/.claude/commands/morph-archive.md +0 -79
- package/stacks/nextjs-supabase/.claude/commands/morph-deploy.md +0 -529
- package/stacks/nextjs-supabase/.claude/commands/morph-preflight.md +0 -227
- package/stacks/nextjs-supabase/.claude/commands/morph-proposal.md +0 -122
- package/stacks/nextjs-supabase/.claude/commands/morph-status.md +0 -86
- package/stacks/nextjs-supabase/.claude/commands/morph-troubleshoot.md +0 -122
- package/stacks/nextjs-supabase/.morph/.morphversion +0 -5
- package/stacks/nextjs-supabase/.morph/config/agents.json +0 -345
- package/stacks/nextjs-supabase/.morph/config/config.json +0 -9
- package/stacks/nextjs-supabase/.morph/project/context/README.md +0 -17
- package/stacks/nextjs-supabase/CLAUDE.md +0 -155
- package/stacks/nextjs-supabase/README.md +0 -103
- /package/{stacks/blazor-azure/.morph → .morph}/standards/ai-agents/blazor-ui.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/ai-agents/production.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/ai-agents/setup.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/ai-agents/team-orchestration.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/ai-agents/workflows.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/architecture/ddd/aggregates.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/architecture/ddd/entities.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/architecture/ddd/value-objects.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/api/minimal-api.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/api/rest.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/api/validation.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/authentication/passkeys.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/database/ef-core.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/database/migrations.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/database/postgresql/database.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/database/repository-patterns.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/database/vector-search-rag.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/dotnet/async.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/dotnet/core.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/dotnet/di.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/dotnet/program-cs-checklist.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/integrations/asaas/asaas-api.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/integrations/clerk/clerk-auth.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/integrations/hangfire/hangfire-jobs.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/backend/integrations/resend/resend-email.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/context/analytics.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/context/bundles.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/context/priming.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/core/architecture.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/core/coding.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/core/git-branching-strategy.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/core/git.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/core/testing.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/data/nosql/blob-storage.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/data/nosql/cache/redis.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/data/nosql/cosmos-db.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/data/vector-search/azure-ai-search.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/data/vector-search/rag-chunking.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/blazor/design-checklist.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/blazor/fluent-ui-setup.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/blazor/fluent-ui.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/blazor/html-conversion.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/blazor/lifecycle.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/blazor/pitfalls.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/blazor/state.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/design-system/animations.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/design-system/naming.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/frontend/nextjs/nextjs-patterns.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/azure/azure.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/azure/devops/local-development.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/azure/services/functions.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/azure/services/service-bus.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/azure/services/storage.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/docker/easypanel-deploy.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/supabase/mcp-setup.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/supabase/supabase-auth.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/supabase/supabase-pgvector.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/supabase/supabase-rls.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/infrastructure/supabase/supabase-storage.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/integration/api/graphql.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/integration/api/grpc.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/integration/api/rest-design.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/integration/event-driven/cqrs.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/integration/event-driven/event-sourcing.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/integration/event-driven/service-bus.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/observability/logging.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/observability/metrics.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/observability/monitoring.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/observability/tracing.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/workflows/parallel-execution.md +0 -0
- /package/{stacks/blazor-azure/.morph → .morph}/standards/workflows/thread-management.md +0 -0
- /package/{stacks/blazor-azure/.claude → framework}/commands/morph-apply.md +0 -0
- /package/{stacks/blazor-azure/.claude → framework}/commands/morph-archive.md +0 -0
- /package/{stacks/blazor-azure/.claude → framework}/commands/morph-preflight.md +0 -0
- /package/{stacks/blazor-azure/.claude → framework}/commands/morph-proposal.md +0 -0
- /package/{stacks/blazor-azure/.claude → framework}/commands/morph-status.md +0 -0
- /package/{stacks/blazor-azure/.claude → framework}/commands/morph-troubleshoot.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/ai-agents/blazor-ui.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/ai-agents/production.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/ai-agents/setup.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/ai-agents/team-orchestration.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/ai-agents/workflows.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/architecture/ddd/aggregates.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/architecture/ddd/entities.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/architecture/ddd/value-objects.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/api/minimal-api.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/api/rest.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/api/validation.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/authentication/passkeys.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/database/ef-core.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/database/migrations.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/database/postgresql/database.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/database/repository-patterns.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/database/vector-search-rag.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/dotnet/async.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/dotnet/core.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/dotnet/di.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/dotnet/program-cs-checklist.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/integrations/asaas/asaas-api.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/integrations/clerk/clerk-auth.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/integrations/hangfire/hangfire-jobs.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/backend/integrations/resend/resend-email.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/context/analytics.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/context/bundles.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/context/priming.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/core/architecture.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/core/coding.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/core/git-branching-strategy.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/core/git.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/core/testing.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/data/nosql/blob-storage.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/data/nosql/cache/redis.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/data/nosql/cosmos-db.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/data/vector-search/azure-ai-search.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/data/vector-search/rag-chunking.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/blazor/design-checklist.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/blazor/fluent-ui-setup.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/blazor/fluent-ui.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/blazor/html-conversion.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/blazor/lifecycle.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/blazor/pitfalls.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/blazor/state.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/design-system/animations.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/design-system/naming.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/frontend/nextjs/nextjs-patterns.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/azure/azure.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/azure/devops/local-development.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/azure/services/functions.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/azure/services/service-bus.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/azure/services/storage.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/docker/easypanel-deploy.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/supabase/mcp-setup.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/supabase/supabase-auth.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/supabase/supabase-pgvector.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/supabase/supabase-rls.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/infrastructure/supabase/supabase-storage.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/integration/api/graphql.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/integration/api/grpc.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/integration/api/rest-design.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/integration/event-driven/cqrs.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/integration/event-driven/event-sourcing.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/integration/event-driven/service-bus.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/observability/logging.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/observability/metrics.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/observability/monitoring.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/observability/tracing.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/workflows/parallel-execution.md +0 -0
- /package/{stacks/nextjs-supabase/.morph → framework}/standards/workflows/thread-management.md +0 -0
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
# Pattern Library - Lessons Learned
|
|
2
|
+
|
|
3
|
+
> **Auto-populated:** Pre-seeded patterns from MORPH-SPEC framework development
|
|
4
|
+
> **Updated:** 2026-02-17
|
|
5
|
+
|
|
6
|
+
Biblioteca de patterns bem-sucedidos, anti-patterns a evitar, e otimizações comprovadas.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## How to Use This Library
|
|
11
|
+
|
|
12
|
+
**Before starting a feature:**
|
|
13
|
+
```bash
|
|
14
|
+
npx morph-spec search-patterns "blazor state"
|
|
15
|
+
npx morph-spec search-patterns "background job"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**After completing a feature:**
|
|
19
|
+
```bash
|
|
20
|
+
npx morph-spec capture-pattern {feature} success "Pattern description"
|
|
21
|
+
npx morph-spec capture-pattern {feature} avoid "Anti-pattern description"
|
|
22
|
+
npx morph-spec capture-pattern {feature} optimization "Performance improvement"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Pattern Categories
|
|
28
|
+
|
|
29
|
+
| Category | Use When | Examples |
|
|
30
|
+
|----------|----------|----------|
|
|
31
|
+
| `success` | Proven approaches to replicate | DI patterns, architecture choices |
|
|
32
|
+
| `avoid` | Anti-patterns and mistakes made | Common pitfalls, bad practices |
|
|
33
|
+
| `optimization` | Performance improvements | Query optimization, caching |
|
|
34
|
+
| `security` | Security best practices | Auth, secrets management |
|
|
35
|
+
| `convention` | Project conventions | Naming, file structure |
|
|
36
|
+
| `best-practice` | General recommendations | Testing, error handling |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 1. Blazor DbContext Lifecycle
|
|
41
|
+
|
|
42
|
+
**Category:** `avoid` (Anti-Pattern)
|
|
43
|
+
**Scope:** blazor-azure
|
|
44
|
+
**Source:** Framework standard ([ef-core.md](../standards/backend/database/ef-core.md))
|
|
45
|
+
|
|
46
|
+
### Problem
|
|
47
|
+
|
|
48
|
+
Directly injecting `DbContext` in Blazor components causes concurrency errors:
|
|
49
|
+
|
|
50
|
+
```csharp
|
|
51
|
+
// ❌ WRONG - DbContext is scoped per circuit, not per request
|
|
52
|
+
@inject AppDbContext DbContext
|
|
53
|
+
|
|
54
|
+
protected override async Task OnInitializedAsync()
|
|
55
|
+
{
|
|
56
|
+
// This breaks when multiple operations run
|
|
57
|
+
var users = await DbContext.Users.ToListAsync();
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Error:**
|
|
62
|
+
```
|
|
63
|
+
InvalidOperationException: A second operation was started on this context
|
|
64
|
+
instance before a previous operation completed.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Correct Approach
|
|
68
|
+
|
|
69
|
+
Use `IDbContextFactory<T>` for Blazor components:
|
|
70
|
+
|
|
71
|
+
```csharp
|
|
72
|
+
// ✅ CORRECT
|
|
73
|
+
@inject IDbContextFactory<AppDbContext> DbFactory
|
|
74
|
+
|
|
75
|
+
protected override async Task OnInitializedAsync()
|
|
76
|
+
{
|
|
77
|
+
await using var db = await DbFactory.CreateDbContextAsync();
|
|
78
|
+
var users = await db.Users.ToListAsync();
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Why it works:** Each operation gets its own DbContext instance, avoiding concurrency.
|
|
83
|
+
|
|
84
|
+
### When to Apply
|
|
85
|
+
|
|
86
|
+
- All Blazor components that access database
|
|
87
|
+
- Background operations in Blazor (Task.Run, Timer)
|
|
88
|
+
- Long-running circuits with multiple user interactions
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 2. Background Job Retry Strategy
|
|
93
|
+
|
|
94
|
+
**Category:** `best-practice`
|
|
95
|
+
**Scope:** blazor-azure
|
|
96
|
+
**Source:** [hangfire-jobs.md](../standards/backend/integrations/hangfire/hangfire-jobs.md)
|
|
97
|
+
|
|
98
|
+
### Pattern
|
|
99
|
+
|
|
100
|
+
Implement exponential backoff with max retry limits:
|
|
101
|
+
|
|
102
|
+
```csharp
|
|
103
|
+
[AutomaticRetry(Attempts = 5, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
|
|
104
|
+
public async Task ProcessPaymentAsync(string orderId)
|
|
105
|
+
{
|
|
106
|
+
await using var db = await _dbFactory.CreateDbContextAsync();
|
|
107
|
+
|
|
108
|
+
var order = await db.Orders.FindAsync(orderId);
|
|
109
|
+
if (order == null)
|
|
110
|
+
{
|
|
111
|
+
throw new InvalidOperationException($"Order {orderId} not found");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try
|
|
115
|
+
{
|
|
116
|
+
await _paymentService.ChargeAsync(order.Total);
|
|
117
|
+
order.Status = "Paid";
|
|
118
|
+
await db.SaveChangesAsync();
|
|
119
|
+
}
|
|
120
|
+
catch (PaymentProviderException ex)
|
|
121
|
+
{
|
|
122
|
+
// Hangfire will retry with exponential backoff
|
|
123
|
+
throw new Exception($"Payment failed: {ex.Message}", ex);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Configuration
|
|
129
|
+
|
|
130
|
+
```csharp
|
|
131
|
+
// Program.cs
|
|
132
|
+
services.AddHangfire(config => config
|
|
133
|
+
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
|
|
134
|
+
.UseSimpleAssemblyNameTypeSerializer()
|
|
135
|
+
.UseRecommendedSerializerSettings()
|
|
136
|
+
.UseInMemoryStorage());
|
|
137
|
+
|
|
138
|
+
GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute
|
|
139
|
+
{
|
|
140
|
+
Attempts = 5,
|
|
141
|
+
DelaysInSeconds = new[] { 10, 30, 60, 300, 900 } // 10s, 30s, 1m, 5m, 15m
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### When to Apply
|
|
146
|
+
|
|
147
|
+
- Payment processing
|
|
148
|
+
- Email sending
|
|
149
|
+
- External API calls
|
|
150
|
+
- File uploads/downloads
|
|
151
|
+
- Any operation that can fail transiently
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 3. Azure Bicep Resource Naming Convention
|
|
156
|
+
|
|
157
|
+
**Category:** `convention`
|
|
158
|
+
**Scope:** blazor-azure
|
|
159
|
+
**Source:** [bicep-patterns.md](../standards/infrastructure/azure/bicep/bicep-patterns.md)
|
|
160
|
+
|
|
161
|
+
### Pattern
|
|
162
|
+
|
|
163
|
+
Use consistent naming with environment and region prefixes:
|
|
164
|
+
|
|
165
|
+
```bicep
|
|
166
|
+
param environment string = 'dev'
|
|
167
|
+
param location string = 'eastus'
|
|
168
|
+
param projectName string = 'myapp'
|
|
169
|
+
|
|
170
|
+
var resourcePrefix = '${projectName}-${environment}'
|
|
171
|
+
var locationShort = location == 'eastus' ? 'eus' : 'wus'
|
|
172
|
+
|
|
173
|
+
resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
|
|
174
|
+
name: '${resourcePrefix}-app-${locationShort}'
|
|
175
|
+
location: location
|
|
176
|
+
// ...
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
resource sqlServer 'Microsoft.Sql/servers@2023-08-01-preview' = {
|
|
180
|
+
name: '${resourcePrefix}-sql-${locationShort}'
|
|
181
|
+
location: location
|
|
182
|
+
// ...
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
|
|
186
|
+
name: '${resourcePrefix}-kv-${locationShort}'
|
|
187
|
+
location: location
|
|
188
|
+
// ...
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Naming Pattern
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
{project}-{env}-{resource}-{region}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Examples:
|
|
199
|
+
- `myapp-prod-app-eus` (Container App in East US)
|
|
200
|
+
- `myapp-dev-sql-wus` (SQL Server in West US)
|
|
201
|
+
- `myapp-staging-kv-eus` (Key Vault in East US)
|
|
202
|
+
|
|
203
|
+
### Resource Type Abbreviations
|
|
204
|
+
|
|
205
|
+
| Resource | Abbreviation |
|
|
206
|
+
|----------|--------------|
|
|
207
|
+
| Container App | `app` |
|
|
208
|
+
| SQL Server | `sql` |
|
|
209
|
+
| SQL Database | `db` |
|
|
210
|
+
| Key Vault | `kv` |
|
|
211
|
+
| Storage Account | `st` |
|
|
212
|
+
| App Service Plan | `plan` |
|
|
213
|
+
| Service Bus | `sb` |
|
|
214
|
+
| Container Registry | `acr` |
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 4. API Versioning Strategy
|
|
219
|
+
|
|
220
|
+
**Category:** `best-practice`
|
|
221
|
+
**Scope:** universal
|
|
222
|
+
**Source:** [rest.md](../standards/backend/api/rest.md)
|
|
223
|
+
|
|
224
|
+
### Pattern
|
|
225
|
+
|
|
226
|
+
Use URL-based versioning with backward compatibility:
|
|
227
|
+
|
|
228
|
+
```csharp
|
|
229
|
+
// Controllers/V1/UsersController.cs
|
|
230
|
+
[ApiController]
|
|
231
|
+
[Route("api/v1/[controller]")]
|
|
232
|
+
public class UsersController : ControllerBase
|
|
233
|
+
{
|
|
234
|
+
[HttpGet]
|
|
235
|
+
public async Task<ActionResult<List<UserDto>>> GetUsers()
|
|
236
|
+
{
|
|
237
|
+
// V1 implementation
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Controllers/V2/UsersController.cs
|
|
242
|
+
[ApiController]
|
|
243
|
+
[Route("api/v2/[controller]")]
|
|
244
|
+
public class UsersController : ControllerBase
|
|
245
|
+
{
|
|
246
|
+
[HttpGet]
|
|
247
|
+
public async Task<ActionResult<List<UserV2Dto>>> GetUsers()
|
|
248
|
+
{
|
|
249
|
+
// V2 implementation with pagination
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Breaking vs Non-Breaking Changes
|
|
255
|
+
|
|
256
|
+
**Non-Breaking (same version):**
|
|
257
|
+
- Adding new optional fields
|
|
258
|
+
- Adding new endpoints
|
|
259
|
+
- Adding new query parameters (optional)
|
|
260
|
+
|
|
261
|
+
**Breaking (new version):**
|
|
262
|
+
- Removing fields from response
|
|
263
|
+
- Changing field types
|
|
264
|
+
- Making optional parameters required
|
|
265
|
+
- Changing response structure
|
|
266
|
+
|
|
267
|
+
### Migration Strategy
|
|
268
|
+
|
|
269
|
+
1. Deploy V2 alongside V1
|
|
270
|
+
2. Update clients gradually
|
|
271
|
+
3. Monitor V1 usage (add metrics)
|
|
272
|
+
4. Deprecate V1 after 6-12 months
|
|
273
|
+
5. Remove V1 code
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 5. EF Core Migration Naming Convention
|
|
278
|
+
|
|
279
|
+
**Category:** `convention`
|
|
280
|
+
**Scope:** blazor-azure, nextjs-supabase
|
|
281
|
+
**Source:** [migrations.md](../standards/backend/database/migrations.md)
|
|
282
|
+
|
|
283
|
+
### Pattern
|
|
284
|
+
|
|
285
|
+
Use descriptive, action-based migration names:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# ✅ GOOD
|
|
289
|
+
dotnet ef migrations add AddUserEmailVerification
|
|
290
|
+
dotnet ef migrations add CreateOrdersTable
|
|
291
|
+
dotnet ef migrations add UpdateProductPricingModel
|
|
292
|
+
dotnet ef migrations add RemoveObsoleteUserFields
|
|
293
|
+
|
|
294
|
+
# ❌ BAD
|
|
295
|
+
dotnet ef migrations add Migration1
|
|
296
|
+
dotnet ef migrations add Changes
|
|
297
|
+
dotnet ef migrations add Update
|
|
298
|
+
dotnet ef migrations add Fix
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Naming Convention
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
{Action}{EntityOrFeature}{OptionalDetail}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Actions:**
|
|
308
|
+
- `Add` - New columns/tables
|
|
309
|
+
- `Create` - New tables/schemas
|
|
310
|
+
- `Update` - Modify existing structure
|
|
311
|
+
- `Remove` - Delete columns/tables
|
|
312
|
+
- `Rename` - Rename entities
|
|
313
|
+
- `Refactor` - Structural changes
|
|
314
|
+
|
|
315
|
+
**Examples:**
|
|
316
|
+
- `AddUserProfilePicture`
|
|
317
|
+
- `CreateProductCategoriesTable`
|
|
318
|
+
- `UpdateOrderStatusEnum`
|
|
319
|
+
- `RemoveDeprecatedPaymentMethods`
|
|
320
|
+
- `RenameCustomerToUser`
|
|
321
|
+
- `RefactorOrderItemsRelationship`
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## 6. Blazor DI Registration Order
|
|
326
|
+
|
|
327
|
+
**Category:** `best-practice`
|
|
328
|
+
**Scope:** blazor-azure
|
|
329
|
+
**Source:** [program-cs-checklist.md](../standards/backend/dotnet/program-cs-checklist.md)
|
|
330
|
+
|
|
331
|
+
### Pattern
|
|
332
|
+
|
|
333
|
+
Register services in strict order to avoid dependency resolution errors:
|
|
334
|
+
|
|
335
|
+
```csharp
|
|
336
|
+
// Program.cs - CORRECT ORDER
|
|
337
|
+
|
|
338
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
339
|
+
|
|
340
|
+
// 1. Configuration (first - others depend on this)
|
|
341
|
+
builder.Configuration.AddJsonFile("appsettings.json");
|
|
342
|
+
builder.Configuration.AddEnvironmentVariables();
|
|
343
|
+
|
|
344
|
+
// 2. Infrastructure (database, storage, external APIs)
|
|
345
|
+
builder.Services.AddDbContextFactory<AppDbContext>(options =>
|
|
346
|
+
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
|
|
347
|
+
|
|
348
|
+
// 3. Application Services (depend on infrastructure)
|
|
349
|
+
builder.Services.AddScoped<IUserService, UserService>();
|
|
350
|
+
builder.Services.AddScoped<IOrderService, OrderService>();
|
|
351
|
+
|
|
352
|
+
// 4. Framework Services (depend on application services)
|
|
353
|
+
builder.Services.AddRazorComponents()
|
|
354
|
+
.AddInteractiveServerComponents();
|
|
355
|
+
|
|
356
|
+
// 5. Third-Party Libraries (may have cross-dependencies)
|
|
357
|
+
builder.Services.AddFluentUIComponents();
|
|
358
|
+
|
|
359
|
+
var app = builder.Build();
|
|
360
|
+
|
|
361
|
+
// Middleware order also matters!
|
|
362
|
+
app.UseStaticFiles();
|
|
363
|
+
app.UseRouting();
|
|
364
|
+
app.UseAuthentication();
|
|
365
|
+
app.UseAuthorization();
|
|
366
|
+
app.MapRazorComponents<App>()
|
|
367
|
+
.AddInteractiveServerRenderMode();
|
|
368
|
+
|
|
369
|
+
app.Run();
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Why Order Matters
|
|
373
|
+
|
|
374
|
+
- Services registered later can depend on services registered earlier
|
|
375
|
+
- Middleware executes in the order added (request pipeline)
|
|
376
|
+
- Configuration must be loaded before services that read it
|
|
377
|
+
|
|
378
|
+
### Common Errors
|
|
379
|
+
|
|
380
|
+
```csharp
|
|
381
|
+
// ❌ WRONG - Service depends on DbContextFactory not yet registered
|
|
382
|
+
builder.Services.AddScoped<IUserService, UserService>();
|
|
383
|
+
builder.Services.AddDbContextFactory<AppDbContext>(...); // TOO LATE!
|
|
384
|
+
|
|
385
|
+
// ✅ CORRECT - DbContextFactory first
|
|
386
|
+
builder.Services.AddDbContextFactory<AppDbContext>(...);
|
|
387
|
+
builder.Services.AddScoped<IUserService, UserService>(); // Now UserService can inject it
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## 7. Component Parameter Validation
|
|
393
|
+
|
|
394
|
+
**Category:** `best-practice`
|
|
395
|
+
**Scope:** blazor-azure
|
|
396
|
+
**Source:** [lifecycle.md](../standards/frontend/blazor/lifecycle.md)
|
|
397
|
+
|
|
398
|
+
### Pattern
|
|
399
|
+
|
|
400
|
+
Validate parameters in `OnParametersSet`:
|
|
401
|
+
|
|
402
|
+
```csharp
|
|
403
|
+
@code {
|
|
404
|
+
[Parameter, EditorRequired]
|
|
405
|
+
public string UserId { get; set; } = default!;
|
|
406
|
+
|
|
407
|
+
[Parameter]
|
|
408
|
+
public int PageSize { get; set; } = 10;
|
|
409
|
+
|
|
410
|
+
protected override void OnParametersSet()
|
|
411
|
+
{
|
|
412
|
+
if (string.IsNullOrWhiteSpace(UserId))
|
|
413
|
+
{
|
|
414
|
+
throw new ArgumentException("UserId is required", nameof(UserId));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (PageSize <= 0 || PageSize > 100)
|
|
418
|
+
{
|
|
419
|
+
throw new ArgumentOutOfRangeException(nameof(PageSize),
|
|
420
|
+
"PageSize must be between 1 and 100");
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
protected override async Task OnInitializedAsync()
|
|
425
|
+
{
|
|
426
|
+
// Parameters are already validated here
|
|
427
|
+
await LoadUserDataAsync(UserId);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Why OnParametersSet?
|
|
433
|
+
|
|
434
|
+
- Runs **before** `OnInitializedAsync`
|
|
435
|
+
- Runs **every time** parameters change (not just once)
|
|
436
|
+
- Catches invalid state early
|
|
437
|
+
|
|
438
|
+
### When to Apply
|
|
439
|
+
|
|
440
|
+
- Required parameters (validate not null/empty)
|
|
441
|
+
- Numeric ranges (min/max validation)
|
|
442
|
+
- Enum values (validate within allowed set)
|
|
443
|
+
- Cross-parameter validation (e.g., StartDate < EndDate)
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## 8. Async Method Naming Convention
|
|
448
|
+
|
|
449
|
+
**Category:** `convention`
|
|
450
|
+
**Scope:** universal
|
|
451
|
+
**Source:** [async.md](../standards/backend/dotnet/async.md)
|
|
452
|
+
|
|
453
|
+
### Pattern
|
|
454
|
+
|
|
455
|
+
All async methods must end with `Async` suffix:
|
|
456
|
+
|
|
457
|
+
```csharp
|
|
458
|
+
// ✅ CORRECT
|
|
459
|
+
public async Task<User> GetUserAsync(string userId) { }
|
|
460
|
+
public async Task SaveChangesAsync() { }
|
|
461
|
+
public async Task<bool> ValidateEmailAsync(string email) { }
|
|
462
|
+
|
|
463
|
+
// ❌ WRONG
|
|
464
|
+
public async Task<User> GetUser(string userId) { } // Missing Async
|
|
465
|
+
public async Task SaveChanges() { } // Missing Async
|
|
466
|
+
public async Task<bool> ValidateEmail(string email) { } // Missing Async
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Exception: Event Handlers
|
|
470
|
+
|
|
471
|
+
```csharp
|
|
472
|
+
// ✅ OK - Event handlers don't need Async suffix
|
|
473
|
+
private async Task HandleSubmit()
|
|
474
|
+
{
|
|
475
|
+
await SaveFormAsync();
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
private async Task OnButtonClick()
|
|
479
|
+
{
|
|
480
|
+
await ProcessDataAsync();
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Benefits
|
|
485
|
+
|
|
486
|
+
- Clear indication that method is asynchronous
|
|
487
|
+
- Avoids confusion with synchronous counterparts
|
|
488
|
+
- IDE tooling can detect missing awaits
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## 9. Error Handling Strategy
|
|
493
|
+
|
|
494
|
+
**Category:** `best-practice`
|
|
495
|
+
**Scope:** universal
|
|
496
|
+
**Source:** [coding.md](../standards/core/coding.md)
|
|
497
|
+
|
|
498
|
+
### Pattern
|
|
499
|
+
|
|
500
|
+
Use layered error handling with specific exception types:
|
|
501
|
+
|
|
502
|
+
```csharp
|
|
503
|
+
// Domain Layer - Business Exceptions
|
|
504
|
+
public class InsufficientBalanceException : Exception
|
|
505
|
+
{
|
|
506
|
+
public decimal RequiredAmount { get; }
|
|
507
|
+
public decimal AvailableBalance { get; }
|
|
508
|
+
|
|
509
|
+
public InsufficientBalanceException(decimal required, decimal available)
|
|
510
|
+
: base($"Insufficient balance. Required: {required}, Available: {available}")
|
|
511
|
+
{
|
|
512
|
+
RequiredAmount = required;
|
|
513
|
+
AvailableBalance = available;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Service Layer - Catch and Transform
|
|
518
|
+
public class PaymentService
|
|
519
|
+
{
|
|
520
|
+
public async Task<PaymentResult> ProcessPaymentAsync(Order order)
|
|
521
|
+
{
|
|
522
|
+
try
|
|
523
|
+
{
|
|
524
|
+
await _paymentGateway.ChargeAsync(order.Total);
|
|
525
|
+
return PaymentResult.Success();
|
|
526
|
+
}
|
|
527
|
+
catch (InsufficientBalanceException ex)
|
|
528
|
+
{
|
|
529
|
+
return PaymentResult.Failed($"Insufficient funds: {ex.Message}");
|
|
530
|
+
}
|
|
531
|
+
catch (PaymentGatewayException ex)
|
|
532
|
+
{
|
|
533
|
+
_logger.LogError(ex, "Payment gateway error for order {OrderId}", order.Id);
|
|
534
|
+
return PaymentResult.Failed("Payment provider error. Please try again.");
|
|
535
|
+
}
|
|
536
|
+
catch (Exception ex)
|
|
537
|
+
{
|
|
538
|
+
_logger.LogCritical(ex, "Unexpected error processing payment for order {OrderId}", order.Id);
|
|
539
|
+
throw; // Re-throw unexpected errors
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Controller/Component Layer - Present to User
|
|
545
|
+
try
|
|
546
|
+
{
|
|
547
|
+
var result = await _paymentService.ProcessPaymentAsync(order);
|
|
548
|
+
|
|
549
|
+
if (!result.IsSuccess)
|
|
550
|
+
{
|
|
551
|
+
// Show user-friendly error
|
|
552
|
+
ErrorMessage = result.ErrorMessage;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
catch (Exception ex)
|
|
556
|
+
{
|
|
557
|
+
// Unexpected errors - show generic message
|
|
558
|
+
ErrorMessage = "An unexpected error occurred. Our team has been notified.";
|
|
559
|
+
_logger.LogError(ex, "Unhandled error in payment UI");
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Layers of Error Handling
|
|
564
|
+
|
|
565
|
+
1. **Domain:** Throw specific business exceptions
|
|
566
|
+
2. **Service:** Catch, log, and transform to result objects
|
|
567
|
+
3. **UI/API:** Present user-friendly messages
|
|
568
|
+
4. **Global:** Catch-all for unhandled exceptions
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## 10. Bicep Output Exports Convention
|
|
573
|
+
|
|
574
|
+
**Category:** `convention`
|
|
575
|
+
**Scope:** blazor-azure
|
|
576
|
+
**Source:** [bicep-patterns.md](../standards/infrastructure/azure/bicep/bicep-patterns.md)
|
|
577
|
+
|
|
578
|
+
### Pattern
|
|
579
|
+
|
|
580
|
+
Export resource IDs and connection info for dependent resources:
|
|
581
|
+
|
|
582
|
+
```bicep
|
|
583
|
+
// modules/sql-database.bicep
|
|
584
|
+
output sqlServerFqdn string = sqlServer.properties.fullyQualifiedDomainName
|
|
585
|
+
output databaseName string = sqlDatabase.name
|
|
586
|
+
output connectionString string = 'Server=${sqlServer.properties.fullyQualifiedDomainName};Database=${sqlDatabase.name};'
|
|
587
|
+
|
|
588
|
+
// modules/container-app.bicep
|
|
589
|
+
output containerAppUrl string = containerApp.properties.configuration.ingress.fqdn
|
|
590
|
+
output containerAppId string = containerApp.id
|
|
591
|
+
|
|
592
|
+
// main.bicep
|
|
593
|
+
module sqlDatabase 'modules/sql-database.bicep' = {
|
|
594
|
+
name: 'sqlDatabaseDeployment'
|
|
595
|
+
params: {
|
|
596
|
+
location: location
|
|
597
|
+
serverName: sqlServerName
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
module containerApp 'modules/container-app.bicep' = {
|
|
602
|
+
name: 'containerAppDeployment'
|
|
603
|
+
params: {
|
|
604
|
+
location: location
|
|
605
|
+
databaseConnectionString: sqlDatabase.outputs.connectionString // USE OUTPUT
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Export to deployment output
|
|
610
|
+
output appUrl string = containerApp.outputs.containerAppUrl
|
|
611
|
+
output databaseServer string = sqlDatabase.outputs.sqlServerFqdn
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
### What to Export
|
|
615
|
+
|
|
616
|
+
- Resource FQDNs (SQL Server, Key Vault, Storage)
|
|
617
|
+
- Connection strings (with placeholders for secrets)
|
|
618
|
+
- Resource IDs (for RBAC assignments)
|
|
619
|
+
- URLs/Endpoints (App URLs, API endpoints)
|
|
620
|
+
- Names (for reference in other modules)
|
|
621
|
+
|
|
622
|
+
### What NOT to Export
|
|
623
|
+
|
|
624
|
+
- Secrets/passwords (use Key Vault references)
|
|
625
|
+
- Internal IPs (expose only public endpoints)
|
|
626
|
+
- Temporary values (deployment-specific data)
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
## 11. Azure Key Vault Secrets Management
|
|
631
|
+
|
|
632
|
+
**Category:** `security`
|
|
633
|
+
**Scope:** blazor-azure
|
|
634
|
+
**Source:** [azure.md](../standards/infrastructure/azure/azure.md)
|
|
635
|
+
|
|
636
|
+
### Pattern
|
|
637
|
+
|
|
638
|
+
Never hardcode secrets - use Key Vault with Managed Identity:
|
|
639
|
+
|
|
640
|
+
```csharp
|
|
641
|
+
// ❌ WRONG - Secrets in appsettings.json
|
|
642
|
+
{
|
|
643
|
+
"ConnectionStrings": {
|
|
644
|
+
"DefaultConnection": "Server=myserver.database.windows.net;Database=mydb;User=admin;Password=MyPassword123!;"
|
|
645
|
+
},
|
|
646
|
+
"Stripe": {
|
|
647
|
+
"SecretKey": "sk_live_51ABC123..."
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// ✅ CORRECT - Reference Key Vault secrets
|
|
652
|
+
{
|
|
653
|
+
"KeyVaultUri": "https://myapp-prod-kv-eus.vault.azure.net/",
|
|
654
|
+
"ConnectionStrings": {
|
|
655
|
+
"DefaultConnection": "@Microsoft.KeyVault(SecretUri=https://myapp-prod-kv-eus.vault.azure.net/secrets/SqlConnectionString/)"
|
|
656
|
+
},
|
|
657
|
+
"Stripe": {
|
|
658
|
+
"SecretKey": "@Microsoft.KeyVault(SecretUri=https://myapp-prod-kv-eus.vault.azure.net/secrets/StripeSecretKey/)"
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Program.cs Setup
|
|
664
|
+
|
|
665
|
+
```csharp
|
|
666
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
667
|
+
|
|
668
|
+
// Load Key Vault secrets using Managed Identity
|
|
669
|
+
var keyVaultUri = builder.Configuration["KeyVaultUri"];
|
|
670
|
+
if (!string.IsNullOrEmpty(keyVaultUri))
|
|
671
|
+
{
|
|
672
|
+
builder.Configuration.AddAzureKeyVault(
|
|
673
|
+
new Uri(keyVaultUri),
|
|
674
|
+
new DefaultAzureCredential());
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Services can now access secrets via IConfiguration
|
|
678
|
+
builder.Services.AddScoped<IPaymentService>(sp =>
|
|
679
|
+
{
|
|
680
|
+
var config = sp.GetRequiredService<IConfiguration>();
|
|
681
|
+
var stripeKey = config["Stripe:SecretKey"]; // Loaded from Key Vault
|
|
682
|
+
return new StripePaymentService(stripeKey);
|
|
683
|
+
});
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### Bicep - Grant Access
|
|
687
|
+
|
|
688
|
+
```bicep
|
|
689
|
+
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
|
|
690
|
+
name: keyVaultName
|
|
691
|
+
properties: {
|
|
692
|
+
tenantId: subscription().tenantId
|
|
693
|
+
sku: { family: 'A', name: 'standard' }
|
|
694
|
+
accessPolicies: []
|
|
695
|
+
enableRbacAuthorization: true // Use RBAC instead of access policies
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Grant Container App access to secrets
|
|
700
|
+
resource keyVaultSecretUser 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
|
701
|
+
scope: keyVault
|
|
702
|
+
name: guid(keyVault.id, containerApp.id, 'Key Vault Secrets User')
|
|
703
|
+
properties: {
|
|
704
|
+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')
|
|
705
|
+
principalId: containerApp.identity.principalId
|
|
706
|
+
principalType: 'ServicePrincipal'
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### Local Development
|
|
712
|
+
|
|
713
|
+
```csharp
|
|
714
|
+
// Use Azure CLI or Visual Studio authentication locally
|
|
715
|
+
// No need for connection strings in local appsettings.json
|
|
716
|
+
|
|
717
|
+
// Developers run: az login
|
|
718
|
+
// DefaultAzureCredential will use their identity to access Key Vault
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### When to Apply
|
|
722
|
+
|
|
723
|
+
- **ALWAYS** for production secrets
|
|
724
|
+
- Database connection strings
|
|
725
|
+
- API keys (Stripe, SendGrid, etc.)
|
|
726
|
+
- Encryption keys
|
|
727
|
+
- OAuth client secrets
|
|
728
|
+
- Storage account keys
|
|
729
|
+
|
|
730
|
+
---
|
|
731
|
+
|
|
732
|
+
## Pattern Statistics
|
|
733
|
+
|
|
734
|
+
| Category | Count |
|
|
735
|
+
|----------|-------|
|
|
736
|
+
| success | 0 |
|
|
737
|
+
| avoid | 1 |
|
|
738
|
+
| optimization | 0 |
|
|
739
|
+
| security | 1 |
|
|
740
|
+
| convention | 4 |
|
|
741
|
+
| best-practice | 5 |
|
|
742
|
+
|
|
743
|
+
**Total Patterns:** 11
|
|
744
|
+
|
|
745
|
+
---
|
|
746
|
+
|
|
747
|
+
## How to Search
|
|
748
|
+
|
|
749
|
+
```bash
|
|
750
|
+
# By keyword
|
|
751
|
+
npx morph-spec search-patterns "blazor"
|
|
752
|
+
npx morph-spec search-patterns "async"
|
|
753
|
+
npx morph-spec search-patterns "bicep"
|
|
754
|
+
|
|
755
|
+
# By category
|
|
756
|
+
npx morph-spec search-patterns --category=avoid
|
|
757
|
+
npx morph-spec search-patterns --category=security
|
|
758
|
+
|
|
759
|
+
# By scope
|
|
760
|
+
npx morph-spec search-patterns --scope=blazor-azure
|
|
761
|
+
npx morph-spec search-patterns --scope=universal
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
766
|
+
*MORPH-SPEC by Polymorphism Tech*
|