@polymorphism-tech/morph-spec 4.7.1 → 4.7.2
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 +5 -0
- package/.morph/config/config.json +8 -0
- package/.morph/framework/agents.json +1815 -0
- package/.morph/framework/hooks/README.md +205 -0
- package/.morph/framework/hooks/claude-code/notification/approval-reminder.js +54 -0
- package/.morph/framework/hooks/claude-code/post-tool-use/dispatch.js +83 -0
- package/.morph/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +42 -0
- package/.morph/framework/hooks/claude-code/pre-compact/save-morph-context.js +61 -0
- package/.morph/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +71 -0
- package/.morph/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +58 -0
- package/.morph/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +64 -0
- package/.morph/framework/hooks/claude-code/session-start/inject-morph-context.js +94 -0
- package/.morph/framework/hooks/claude-code/statusline.py +538 -0
- package/.morph/framework/hooks/claude-code/statusline.sh +7 -0
- package/.morph/framework/hooks/claude-code/stop/validate-completion.js +88 -0
- package/.morph/framework/hooks/claude-code/user-prompt/enrich-prompt.js +91 -0
- package/.morph/framework/hooks/git/commit-msg/conventional-commits.sh +33 -0
- package/.morph/framework/hooks/git/pre-commit/agents.sh +25 -0
- package/.morph/framework/hooks/git/pre-commit/orchestrator.sh +64 -0
- package/.morph/framework/hooks/git/pre-commit/specs.sh +50 -0
- package/.morph/framework/hooks/git/pre-push/run-tests.sh +44 -0
- package/.morph/framework/hooks/shared/hook-response.js +45 -0
- package/.morph/framework/hooks/shared/phase-utils.js +129 -0
- package/.morph/framework/hooks/shared/state-reader.js +138 -0
- package/.morph/framework/hooks/shared/stdin-reader.js +26 -0
- package/.morph/framework/standards/STANDARDS.json +933 -0
- package/.morph/framework/standards/ai-agents/blazor-ui.md +364 -0
- package/.morph/framework/standards/ai-agents/production.md +415 -0
- package/.morph/framework/standards/ai-agents/setup.md +418 -0
- package/.morph/framework/standards/ai-agents/team-orchestration.md +479 -0
- package/.morph/framework/standards/ai-agents/workflows.md +354 -0
- package/.morph/framework/standards/architecture/ddd/aggregates.md +120 -0
- package/.morph/framework/standards/architecture/ddd/bounded-contexts.md +105 -0
- package/.morph/framework/standards/architecture/ddd/complexity-levels.md +108 -0
- package/.morph/framework/standards/architecture/ddd/entities.md +99 -0
- package/.morph/framework/standards/architecture/ddd/ubiquitous-language.md +58 -0
- package/.morph/framework/standards/architecture/ddd/value-objects.md +124 -0
- package/.morph/framework/standards/backend/api/minimal-api.md +494 -0
- package/.morph/framework/standards/backend/api/rest.md +492 -0
- package/.morph/framework/standards/backend/api/validation.md +88 -0
- package/.morph/framework/standards/backend/authentication/passkeys.md +428 -0
- package/.morph/framework/standards/backend/database/ef-core.md +199 -0
- package/.morph/framework/standards/backend/database/migrations.md +393 -0
- package/.morph/framework/standards/backend/database/postgresql/database.md +352 -0
- package/.morph/framework/standards/backend/database/repository-patterns.md +528 -0
- package/.morph/framework/standards/backend/database/vector-search-rag.md +541 -0
- package/.morph/framework/standards/backend/dotnet/async.md +366 -0
- package/.morph/framework/standards/backend/dotnet/core.md +117 -0
- package/.morph/framework/standards/backend/dotnet/di.md +439 -0
- package/.morph/framework/standards/backend/dotnet/program-cs-checklist.md +92 -0
- package/.morph/framework/standards/backend/integrations/asaas/asaas-api.md +216 -0
- package/.morph/framework/standards/backend/integrations/clerk/clerk-auth.md +290 -0
- package/.morph/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
- package/.morph/framework/standards/backend/integrations/resend/resend-email.md +385 -0
- package/.morph/framework/standards/context/analytics.md +96 -0
- package/.morph/framework/standards/context/bundles.md +110 -0
- package/.morph/framework/standards/context/priming.md +78 -0
- package/.morph/framework/standards/core/architecture.md +185 -0
- package/.morph/framework/standards/core/coding.md +214 -0
- package/.morph/framework/standards/core/git-branching-strategy.md +403 -0
- package/.morph/framework/standards/core/git.md +185 -0
- package/.morph/framework/standards/core/testing.md +295 -0
- package/.morph/framework/standards/data/nosql/blob-storage.md +102 -0
- package/.morph/framework/standards/data/nosql/cache/redis.md +97 -0
- package/.morph/framework/standards/data/nosql/cosmos-db.md +118 -0
- package/.morph/framework/standards/data/vector-search/azure-ai-search.md +121 -0
- package/.morph/framework/standards/data/vector-search/rag-chunking.md +104 -0
- package/.morph/framework/standards/frontend/blazor/design-checklist.md +222 -0
- package/.morph/framework/standards/frontend/blazor/fluent-ui-setup.md +595 -0
- package/.morph/framework/standards/frontend/blazor/fluent-ui.md +137 -0
- package/.morph/framework/standards/frontend/blazor/html-conversion.md +184 -0
- package/.morph/framework/standards/frontend/blazor/lifecycle.md +195 -0
- package/.morph/framework/standards/frontend/blazor/pitfalls.md +198 -0
- package/.morph/framework/standards/frontend/blazor/state.md +191 -0
- package/.morph/framework/standards/frontend/design-system/animations.md +151 -0
- package/.morph/framework/standards/frontend/design-system/naming.md +64 -0
- package/.morph/framework/standards/frontend/nextjs/app-router.md +123 -0
- package/.morph/framework/standards/frontend/nextjs/components.md +132 -0
- package/.morph/framework/standards/frontend/nextjs/data-fetching.md +126 -0
- package/.morph/framework/standards/frontend/nextjs/forms.md +128 -0
- package/.morph/framework/standards/frontend/nextjs/naming-conventions.md +67 -0
- package/.morph/framework/standards/frontend/nextjs/nextjs-patterns.md +215 -0
- package/.morph/framework/standards/frontend/nextjs/project-structure.md +102 -0
- package/.morph/framework/standards/frontend/nextjs/state-management.md +72 -0
- package/.morph/framework/standards/frontend/nextjs/testing.md +111 -0
- package/.morph/framework/standards/infrastructure/azure/azure.md +624 -0
- package/.morph/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
- package/.morph/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
- package/.morph/framework/standards/infrastructure/azure/devops/local-development.md +520 -0
- package/.morph/framework/standards/infrastructure/azure/services/functions.md +486 -0
- package/.morph/framework/standards/infrastructure/azure/services/service-bus.md +459 -0
- package/.morph/framework/standards/infrastructure/azure/services/storage.md +407 -0
- package/.morph/framework/standards/infrastructure/docker/easypanel-deploy.md +196 -0
- package/.morph/framework/standards/infrastructure/supabase/mcp-setup.md +252 -0
- package/.morph/framework/standards/infrastructure/supabase/supabase-auth.md +176 -0
- package/.morph/framework/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
- package/.morph/framework/standards/infrastructure/supabase/supabase-rls.md +184 -0
- package/.morph/framework/standards/infrastructure/supabase/supabase-storage.md +153 -0
- package/.morph/framework/standards/integration/api/graphql.md +91 -0
- package/.morph/framework/standards/integration/api/grpc.md +114 -0
- package/.morph/framework/standards/integration/api/rest-design.md +95 -0
- package/.morph/framework/standards/integration/event-driven/cqrs.md +101 -0
- package/.morph/framework/standards/integration/event-driven/event-sourcing.md +124 -0
- package/.morph/framework/standards/integration/event-driven/service-bus.md +95 -0
- package/.morph/framework/standards/integration/mcp/mcp-tools.md +384 -0
- package/.morph/framework/standards/observability/logging.md +131 -0
- package/.morph/framework/standards/observability/metrics.md +121 -0
- package/.morph/framework/standards/observability/monitoring.md +114 -0
- package/.morph/framework/standards/observability/tracing.md +132 -0
- package/.morph/framework/standards/workflows/parallel-execution.md +112 -0
- package/.morph/framework/standards/workflows/thread-management.md +113 -0
- package/.morph/framework/templates/.idea/morph-templates.xml +92 -0
- package/.morph/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/.morph/framework/templates/IDE-SNIPPETS.md +266 -0
- package/.morph/framework/templates/README.md +814 -0
- package/.morph/framework/templates/REGISTRY.json +1888 -0
- package/.morph/framework/templates/code/dotnet/backend/repository.cs +141 -0
- package/.morph/framework/templates/code/dotnet/backend/service.cs +139 -0
- package/.morph/framework/templates/code/dotnet/contracts/Commands.cs +74 -0
- package/.morph/framework/templates/code/dotnet/contracts/Entities.cs +25 -0
- package/.morph/framework/templates/code/dotnet/contracts/Queries.cs +74 -0
- package/.morph/framework/templates/code/dotnet/contracts/README.md +74 -0
- package/.morph/framework/templates/code/dotnet/contracts/api-contracts.cs +173 -0
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level1.cs +69 -0
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level2.cs +86 -0
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level3.cs +41 -0
- package/.morph/framework/templates/code/dotnet/database/migration.cs +83 -0
- package/.morph/framework/templates/code/dotnet/frontend/component.razor +239 -0
- package/.morph/framework/templates/code/dotnet/jobs/agent.cs +163 -0
- package/.morph/framework/templates/code/dotnet/jobs/job.cs +171 -0
- package/.morph/framework/templates/code/dotnet/test.cs +239 -0
- package/.morph/framework/templates/code/sql/rls-policy.sql +57 -0
- package/.morph/framework/templates/code/sql/supabase-migration.sql +100 -0
- package/.morph/framework/templates/code/sql/supabase-migration.template.sql +113 -0
- package/.morph/framework/templates/code/typescript/contracts.ts +168 -0
- package/.morph/framework/templates/context/CONTEXT-FEATURE.md +276 -0
- package/.morph/framework/templates/context/CONTEXT.md +181 -0
- package/.morph/framework/templates/docs/clarifications.md +253 -0
- package/.morph/framework/templates/docs/onboarding.md +123 -0
- package/.morph/framework/templates/docs/proposal.md +182 -0
- package/.morph/framework/templates/docs/schema-analysis.md +119 -0
- package/.morph/framework/templates/docs/spec.md +198 -0
- package/.morph/framework/templates/docs/ui-components.md +124 -0
- package/.morph/framework/templates/docs/ui-design-system.md +76 -0
- package/.morph/framework/templates/docs/ui-flows.md +167 -0
- package/.morph/framework/templates/docs/ui-mockups.md +98 -0
- package/.morph/framework/templates/docs/user-stories.md +34 -0
- package/.morph/framework/templates/examples/design-system-examples.md +357 -0
- package/.morph/framework/templates/examples/spec-examples.md +90 -0
- package/.morph/framework/templates/feature/decisions.md +187 -0
- package/.morph/framework/templates/feature/recap.md +146 -0
- package/.morph/framework/templates/feature/tasks.md +199 -0
- package/.morph/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -0
- package/.morph/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -0
- package/.morph/framework/templates/frontend/nextjs/env.mjs.hbs +32 -0
- package/.morph/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -0
- package/.morph/framework/templates/frontend/nextjs/page.tsx.hbs +22 -0
- package/.morph/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -0
- package/.morph/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -0
- package/.morph/framework/templates/infrastructure/azure/Dockerfile.example +82 -0
- package/.morph/framework/templates/infrastructure/azure/README.md +286 -0
- package/.morph/framework/templates/infrastructure/azure/app-insights.bicep +63 -0
- package/.morph/framework/templates/infrastructure/azure/app-service.bicep +164 -0
- package/.morph/framework/templates/infrastructure/azure/container-app-env.bicep +49 -0
- package/.morph/framework/templates/infrastructure/azure/container-app.bicep +156 -0
- package/.morph/framework/templates/infrastructure/azure/deploy-checklist.md +426 -0
- package/.morph/framework/templates/infrastructure/azure/deploy.ps1 +229 -0
- package/.morph/framework/templates/infrastructure/azure/deploy.sh +208 -0
- package/.morph/framework/templates/infrastructure/azure/key-vault.bicep +91 -0
- package/.morph/framework/templates/infrastructure/azure/main.bicep +189 -0
- package/.morph/framework/templates/infrastructure/azure/parameters.dev.json +29 -0
- package/.morph/framework/templates/infrastructure/azure/parameters.prod.json +29 -0
- package/.morph/framework/templates/infrastructure/azure/parameters.staging.json +29 -0
- package/.morph/framework/templates/infrastructure/azure/sql-database.bicep +103 -0
- package/.morph/framework/templates/infrastructure/azure/storage.bicep +106 -0
- package/.morph/framework/templates/infrastructure/docker/Dockerfile.template +58 -0
- package/.morph/framework/templates/infrastructure/docker/docker-compose.template.yml +67 -0
- package/.morph/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -0
- package/.morph/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -0
- package/.morph/framework/templates/infrastructure/docker/easypanel.template.json +54 -0
- package/.morph/framework/templates/infrastructure/github/README.md +593 -0
- package/.morph/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +22 -0
- package/.morph/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -0
- package/.morph/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -0
- package/.morph/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +61 -0
- package/.morph/framework/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +31 -0
- package/.morph/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -0
- package/.morph/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -0
- package/.morph/framework/templates/integrations/asaas-client.cs +387 -0
- package/.morph/framework/templates/integrations/asaas-webhook.cs +351 -0
- package/.morph/framework/templates/integrations/azure-identity-config.cs +288 -0
- package/.morph/framework/templates/integrations/clerk-config.cs +258 -0
- package/.morph/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -0
- package/.morph/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -0
- package/.morph/framework/templates/meta-prompts/hops/hop-retry.md +78 -0
- package/.morph/framework/templates/meta-prompts/hops/hop-validation.md +97 -0
- package/.morph/framework/templates/meta-prompts/hops/hop-wrapper.md +36 -0
- package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -0
- package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -0
- package/.morph/framework/templates/meta-prompts/squad-leaders/backend-squad.md +90 -0
- package/.morph/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +126 -0
- package/.morph/framework/templates/meta-prompts/squad-leaders/squad-leader.md +43 -0
- package/.morph/framework/templates/meta-prompts/validators/checkpoint-validator.md +107 -0
- package/.morph/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -0
- package/.morph/framework/templates/project-structure/dotnet-ddd.md +70 -0
- package/.morph/framework/templates/saas/subscription.cs +347 -0
- package/.morph/framework/templates/saas/tenant.cs +338 -0
- package/.morph/framework/templates/state.template.json +17 -0
- package/.morph/framework/templates/ui/FluentDesignTheme.cs +149 -0
- package/.morph/framework/templates/ui/MudTheme.cs +281 -0
- package/.morph/framework/templates/ui/design-system.css +226 -0
- package/.morph/logs/tool-failures.log +17 -0
- package/.morph/memory/pre-compact-2026-02-24T17-43-30-049Z.json +16 -0
- package/.morph/plans/eager-watching-bunny.md +105 -0
- package/.morph/plans/temporal-seeking-nebula.md +45 -0
- package/.morph/state.json +48 -0
- package/CLAUDE.md +1 -1
- package/README.md +2 -2
- package/bin/morph-spec.js +0 -9
- package/framework/CLAUDE.md +1 -1
- package/framework/hooks/README.md +10 -6
- package/framework/hooks/claude-code/notification/approval-reminder.js +2 -0
- package/framework/hooks/claude-code/post-tool-use/dispatch.js +1 -1
- package/framework/hooks/claude-code/stop/validate-completion.js +1 -1
- package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +1 -1
- package/package.json +1 -1
- package/src/commands/project/init.js +15 -42
- package/src/commands/project/update.js +22 -37
- package/src/lib/installers/mcp-installer.js +18 -3
- package/src/utils/hooks-installer.js +5 -15
- package/src/commands/project/detect.js +0 -114
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# Azure Bicep IaC Patterns Standard
|
|
2
|
+
|
|
3
|
+
> **Scope:** blazor-azure
|
|
4
|
+
> **Layer:** 2 (on keyword)
|
|
5
|
+
> **Keywords:** bicep, iac, infrastructure as code, azure, deployment
|
|
6
|
+
> **Load When:** bicep or azure infrastructure keywords detected
|
|
7
|
+
|
|
8
|
+
Infrastructure as Code patterns for Azure using Bicep.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
Bicep provides:
|
|
15
|
+
- Declarative Azure resource definitions
|
|
16
|
+
- Type safety and IntelliSense
|
|
17
|
+
- Modular templates with parameters
|
|
18
|
+
- Automatic dependency management
|
|
19
|
+
- Preview deployments with `what-if`
|
|
20
|
+
|
|
21
|
+
**Stack:** Blazor Server + Azure Container Apps + Azure SQL
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Core Principles
|
|
26
|
+
|
|
27
|
+
1. **Modules First**: Break infrastructure into reusable modules
|
|
28
|
+
2. **Parameters Over Hardcoding**: Use parameters for environment-specific values
|
|
29
|
+
3. **Naming Conventions**: Follow Azure naming conventions (lowercase, hyphens)
|
|
30
|
+
4. **Outputs**: Export resource IDs and connection strings
|
|
31
|
+
5. **Idempotency**: All deployments should be idempotent
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Project Structure
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
infra/
|
|
39
|
+
├── main.bicep # Entry point
|
|
40
|
+
├── parameters/
|
|
41
|
+
│ ├── dev.bicepparam
|
|
42
|
+
│ ├── staging.bicepparam
|
|
43
|
+
│ └── prod.bicepparam
|
|
44
|
+
└── modules/
|
|
45
|
+
├── containerapp.bicep
|
|
46
|
+
├── sql.bicep
|
|
47
|
+
├── keyvault.bicep
|
|
48
|
+
└── storage.bicep
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Main Template
|
|
54
|
+
|
|
55
|
+
```bicep
|
|
56
|
+
// infra/main.bicep
|
|
57
|
+
targetScope = 'resourceGroup'
|
|
58
|
+
|
|
59
|
+
@description('Environment name (dev, staging, prod)')
|
|
60
|
+
param environment string
|
|
61
|
+
|
|
62
|
+
@description('Location for all resources')
|
|
63
|
+
param location string = resourceGroup().location
|
|
64
|
+
|
|
65
|
+
@description('Container image tag')
|
|
66
|
+
param imageTag string = 'latest'
|
|
67
|
+
|
|
68
|
+
// Variables
|
|
69
|
+
var appName = 'myapp'
|
|
70
|
+
var resourcePrefix = '${appName}-${environment}'
|
|
71
|
+
|
|
72
|
+
// Modules
|
|
73
|
+
module containerApp 'modules/containerapp.bicep' = {
|
|
74
|
+
name: '${resourcePrefix}-containerapp-deployment'
|
|
75
|
+
params: {
|
|
76
|
+
name: '${resourcePrefix}-app'
|
|
77
|
+
location: location
|
|
78
|
+
imageTag: imageTag
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module sql 'modules/sql.bicep' = {
|
|
83
|
+
name: '${resourcePrefix}-sql-deployment'
|
|
84
|
+
params: {
|
|
85
|
+
serverName: '${resourcePrefix}-sql'
|
|
86
|
+
databaseName: '${appName}db'
|
|
87
|
+
location: location
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module keyVault 'modules/keyvault.bicep' = {
|
|
92
|
+
name: '${resourcePrefix}-kv-deployment'
|
|
93
|
+
params: {
|
|
94
|
+
name: '${resourcePrefix}-kv'
|
|
95
|
+
location: location
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Outputs
|
|
100
|
+
output containerAppUrl string = containerApp.outputs.fqdn
|
|
101
|
+
output sqlConnectionString string = sql.outputs.connectionString
|
|
102
|
+
output keyVaultUri string = keyVault.outputs.vaultUri
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Module Examples
|
|
108
|
+
|
|
109
|
+
### Container App Module
|
|
110
|
+
|
|
111
|
+
```bicep
|
|
112
|
+
// modules/containerapp.bicep
|
|
113
|
+
param name string
|
|
114
|
+
param location string
|
|
115
|
+
param imageTag string
|
|
116
|
+
|
|
117
|
+
resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = {
|
|
118
|
+
name: '${name}-env'
|
|
119
|
+
location: location
|
|
120
|
+
properties: {
|
|
121
|
+
appLogsConfiguration: {
|
|
122
|
+
destination: 'log-analytics'
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
|
|
128
|
+
name: name
|
|
129
|
+
location: location
|
|
130
|
+
identity: {
|
|
131
|
+
type: 'SystemAssigned'
|
|
132
|
+
}
|
|
133
|
+
properties: {
|
|
134
|
+
managedEnvironmentId: containerAppEnvironment.id
|
|
135
|
+
configuration: {
|
|
136
|
+
ingress: {
|
|
137
|
+
external: true
|
|
138
|
+
targetPort: 8080
|
|
139
|
+
allowInsecure: false
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
template: {
|
|
143
|
+
containers: [
|
|
144
|
+
{
|
|
145
|
+
name: 'api'
|
|
146
|
+
image: 'myregistry.azurecr.io/myapp:${imageTag}'
|
|
147
|
+
resources: {
|
|
148
|
+
cpu: json('0.5')
|
|
149
|
+
memory: '1Gi'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
scale: {
|
|
154
|
+
minReplicas: 1
|
|
155
|
+
maxReplicas: 10
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
output fqdn string = containerApp.properties.configuration.ingress.fqdn
|
|
162
|
+
output principalId string = containerApp.identity.principalId
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### SQL Database Module
|
|
166
|
+
|
|
167
|
+
```bicep
|
|
168
|
+
// modules/sql.bicep
|
|
169
|
+
param serverName string
|
|
170
|
+
param databaseName string
|
|
171
|
+
param location string
|
|
172
|
+
|
|
173
|
+
@secure()
|
|
174
|
+
param adminPassword string
|
|
175
|
+
|
|
176
|
+
resource sqlServer 'Microsoft.Sql/servers@2023-05-01-preview' = {
|
|
177
|
+
name: serverName
|
|
178
|
+
location: location
|
|
179
|
+
properties: {
|
|
180
|
+
administratorLogin: 'sqladmin'
|
|
181
|
+
administratorLoginPassword: adminPassword
|
|
182
|
+
version: '12.0'
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
resource sqlDatabase 'Microsoft.Sql/servers/databases@2023-05-01-preview' = {
|
|
187
|
+
parent: sqlServer
|
|
188
|
+
name: databaseName
|
|
189
|
+
location: location
|
|
190
|
+
sku: {
|
|
191
|
+
name: 'Basic'
|
|
192
|
+
tier: 'Basic'
|
|
193
|
+
capacity: 5
|
|
194
|
+
}
|
|
195
|
+
properties: {
|
|
196
|
+
collation: 'SQL_Latin1_General_CP1_CI_AS'
|
|
197
|
+
maxSizeBytes: 2147483648 // 2GB
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Allow Azure services
|
|
202
|
+
resource firewallRule 'Microsoft.Sql/servers/firewallRules@2023-05-01-preview' = {
|
|
203
|
+
parent: sqlServer
|
|
204
|
+
name: 'AllowAzureServices'
|
|
205
|
+
properties: {
|
|
206
|
+
startIpAddress: '0.0.0.0'
|
|
207
|
+
endIpAddress: '0.0.0.0'
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
output connectionString string = 'Server=tcp:${sqlServer.properties.fullyQualifiedDomainName},1433;Initial Catalog=${databaseName};Persist Security Info=False;User ID=sqladmin;Password=${adminPassword};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;'
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Key Vault Module
|
|
215
|
+
|
|
216
|
+
```bicep
|
|
217
|
+
// modules/keyvault.bicep
|
|
218
|
+
param name string
|
|
219
|
+
param location string
|
|
220
|
+
param principalId string = ''
|
|
221
|
+
|
|
222
|
+
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
|
|
223
|
+
name: name
|
|
224
|
+
location: location
|
|
225
|
+
properties: {
|
|
226
|
+
sku: {
|
|
227
|
+
family: 'A'
|
|
228
|
+
name: 'standard'
|
|
229
|
+
}
|
|
230
|
+
tenantId: subscription().tenantId
|
|
231
|
+
enableRbacAuthorization: true
|
|
232
|
+
enabledForDeployment: false
|
|
233
|
+
enabledForDiskEncryption: false
|
|
234
|
+
enabledForTemplateDeployment: false
|
|
235
|
+
enableSoftDelete: true
|
|
236
|
+
softDeleteRetentionInDays: 90
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Grant Container App access to secrets
|
|
241
|
+
resource kvAccessPolicy 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(principalId)) {
|
|
242
|
+
scope: keyVault
|
|
243
|
+
name: guid(keyVault.id, principalId, 'Key Vault Secrets User')
|
|
244
|
+
properties: {
|
|
245
|
+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6') // Key Vault Secrets User
|
|
246
|
+
principalId: principalId
|
|
247
|
+
principalType: 'ServicePrincipal'
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
output vaultUri string = keyVault.properties.vaultUri
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Parameter Files
|
|
257
|
+
|
|
258
|
+
```bicep
|
|
259
|
+
// parameters/dev.bicepparam
|
|
260
|
+
using '../main.bicep'
|
|
261
|
+
|
|
262
|
+
param environment = 'dev'
|
|
263
|
+
param imageTag = 'latest'
|
|
264
|
+
param location = 'East US'
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
```bicep
|
|
268
|
+
// parameters/prod.bicepparam
|
|
269
|
+
using '../main.bicep'
|
|
270
|
+
|
|
271
|
+
param environment = 'prod'
|
|
272
|
+
param imageTag = readEnvironmentVariable('IMAGE_TAG')
|
|
273
|
+
param location = 'East US'
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Deployment Commands
|
|
279
|
+
|
|
280
|
+
### Deploy to Resource Group
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Create resource group
|
|
284
|
+
az group create --name myapp-dev-rg --location eastus
|
|
285
|
+
|
|
286
|
+
# Preview deployment (what-if)
|
|
287
|
+
az deployment group what-if \
|
|
288
|
+
--resource-group myapp-dev-rg \
|
|
289
|
+
--template-file infra/main.bicep \
|
|
290
|
+
--parameters infra/parameters/dev.bicepparam
|
|
291
|
+
|
|
292
|
+
# Deploy
|
|
293
|
+
az deployment group create \
|
|
294
|
+
--resource-group myapp-dev-rg \
|
|
295
|
+
--template-file infra/main.bicep \
|
|
296
|
+
--parameters infra/parameters/dev.bicepparam
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Deploy with CI/CD (GitHub Actions)
|
|
300
|
+
|
|
301
|
+
```yaml
|
|
302
|
+
# .github/workflows/deploy-infra.yml
|
|
303
|
+
name: Deploy Infrastructure
|
|
304
|
+
|
|
305
|
+
on:
|
|
306
|
+
push:
|
|
307
|
+
branches: [main]
|
|
308
|
+
paths:
|
|
309
|
+
- 'infra/**'
|
|
310
|
+
|
|
311
|
+
env:
|
|
312
|
+
AZURE_RESOURCE_GROUP: myapp-prod-rg
|
|
313
|
+
|
|
314
|
+
jobs:
|
|
315
|
+
deploy:
|
|
316
|
+
runs-on: ubuntu-latest
|
|
317
|
+
steps:
|
|
318
|
+
- uses: actions/checkout@v3
|
|
319
|
+
|
|
320
|
+
- name: Azure Login
|
|
321
|
+
uses: azure/login@v1
|
|
322
|
+
with:
|
|
323
|
+
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
|
324
|
+
|
|
325
|
+
- name: Deploy Bicep
|
|
326
|
+
uses: azure/arm-deploy@v1
|
|
327
|
+
with:
|
|
328
|
+
resourceGroupName: ${{ env.AZURE_RESOURCE_GROUP }}
|
|
329
|
+
template: ./infra/main.bicep
|
|
330
|
+
parameters: ./infra/parameters/prod.bicepparam imageTag=${{ github.sha }}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Best Practices
|
|
336
|
+
|
|
337
|
+
### Naming Conventions
|
|
338
|
+
|
|
339
|
+
```bicep
|
|
340
|
+
// Azure resource naming: lowercase with hyphens
|
|
341
|
+
var storageAccountName = replace('${resourcePrefix}st', '-', '') // Storage accounts: no hyphens
|
|
342
|
+
var containerAppName = '${resourcePrefix}-app' // Other resources: hyphens OK
|
|
343
|
+
var keyVaultName = '${resourcePrefix}-kv'
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Resource Tags
|
|
347
|
+
|
|
348
|
+
```bicep
|
|
349
|
+
var commonTags = {
|
|
350
|
+
environment: environment
|
|
351
|
+
project: 'myapp'
|
|
352
|
+
managedBy: 'bicep'
|
|
353
|
+
costCenter: 'engineering'
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
|
|
357
|
+
name: name
|
|
358
|
+
location: location
|
|
359
|
+
tags: commonTags
|
|
360
|
+
// ...
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Conditional Resources
|
|
365
|
+
|
|
366
|
+
```bicep
|
|
367
|
+
@description('Deploy Redis cache?')
|
|
368
|
+
param deployRedis bool = false
|
|
369
|
+
|
|
370
|
+
resource redis 'Microsoft.Cache/redis@2023-08-01' = if (deployRedis) {
|
|
371
|
+
name: '${resourcePrefix}-redis'
|
|
372
|
+
location: location
|
|
373
|
+
properties: {
|
|
374
|
+
sku: {
|
|
375
|
+
name: 'Basic'
|
|
376
|
+
family: 'C'
|
|
377
|
+
capacity: 0
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Troubleshooting
|
|
386
|
+
|
|
387
|
+
### Common Errors
|
|
388
|
+
|
|
389
|
+
| Error | Cause | Solution |
|
|
390
|
+
|-------|-------|----------|
|
|
391
|
+
| Resource name already exists | Name conflict | Use unique `resourcePrefix` with environment |
|
|
392
|
+
| Invalid location | Unsupported region | Check `az account list-locations` |
|
|
393
|
+
| Missing role assignments | Insufficient permissions | Grant Contributor role to service principal |
|
|
394
|
+
| Deployment timeout | Large template | Break into smaller modules |
|
|
395
|
+
|
|
396
|
+
### Debugging
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# View deployment operations
|
|
400
|
+
az deployment group show \
|
|
401
|
+
--resource-group myapp-dev-rg \
|
|
402
|
+
--name main \
|
|
403
|
+
--query properties.outputResources
|
|
404
|
+
|
|
405
|
+
# View deployment errors
|
|
406
|
+
az deployment operation group list \
|
|
407
|
+
--resource-group myapp-dev-rg \
|
|
408
|
+
--name main \
|
|
409
|
+
--query "[?properties.statusMessage.error!=null]"
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## References
|
|
415
|
+
|
|
416
|
+
- [Bicep Documentation](https://learn.microsoft.com/azure/azure-resource-manager/bicep/)
|
|
417
|
+
- [Bicep Playground](https://aka.ms/bicepdemo)
|
|
418
|
+
- [Azure Resource Reference](https://learn.microsoft.com/azure/templates/)
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
*MORPH-SPEC by Polymorphism Tech*
|