@polymorphism-tech/morph-spec 4.3.4 → 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.
Files changed (164) hide show
  1. package/.morph/.morphversion +5 -0
  2. package/.morph/config/agents.json +948 -0
  3. package/.morph/config/config.json +9 -9
  4. package/.morph/project/context/README.md +17 -0
  5. package/.morph/project/context/detection-log.md +16 -0
  6. package/.morph/project/standards/inferred.md +59 -0
  7. package/.morph/standards/ai-agents/blazor-ui.md +364 -0
  8. package/.morph/standards/ai-agents/production.md +415 -0
  9. package/.morph/standards/ai-agents/setup.md +418 -0
  10. package/.morph/standards/ai-agents/team-orchestration.md +479 -0
  11. package/.morph/standards/ai-agents/workflows.md +354 -0
  12. package/.morph/standards/architecture/ddd/aggregates.md +120 -0
  13. package/.morph/standards/architecture/ddd/entities.md +99 -0
  14. package/.morph/standards/architecture/ddd/value-objects.md +124 -0
  15. package/.morph/standards/backend/api/minimal-api.md +494 -0
  16. package/.morph/standards/backend/api/rest.md +492 -0
  17. package/.morph/standards/backend/api/validation.md +88 -0
  18. package/.morph/standards/backend/authentication/passkeys.md +428 -0
  19. package/.morph/standards/backend/database/ef-core.md +199 -0
  20. package/.morph/standards/backend/database/migrations.md +393 -0
  21. package/.morph/standards/backend/database/postgresql/database.md +352 -0
  22. package/.morph/standards/backend/database/repository-patterns.md +528 -0
  23. package/.morph/standards/backend/database/vector-search-rag.md +541 -0
  24. package/.morph/standards/backend/dotnet/async.md +366 -0
  25. package/.morph/standards/backend/dotnet/core.md +117 -0
  26. package/.morph/standards/backend/dotnet/di.md +439 -0
  27. package/.morph/standards/backend/dotnet/program-cs-checklist.md +92 -0
  28. package/.morph/standards/backend/integrations/asaas/asaas-api.md +216 -0
  29. package/.morph/standards/backend/integrations/clerk/clerk-auth.md +290 -0
  30. package/.morph/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
  31. package/.morph/standards/backend/integrations/resend/resend-email.md +385 -0
  32. package/.morph/standards/context/analytics.md +96 -0
  33. package/.morph/standards/context/bundles.md +110 -0
  34. package/.morph/standards/context/priming.md +78 -0
  35. package/.morph/standards/core/architecture.md +185 -0
  36. package/.morph/standards/core/coding.md +214 -0
  37. package/.morph/standards/core/git-branching-strategy.md +403 -0
  38. package/.morph/standards/core/git.md +185 -0
  39. package/.morph/standards/core/testing.md +295 -0
  40. package/.morph/standards/data/nosql/blob-storage.md +102 -0
  41. package/.morph/standards/data/nosql/cache/redis.md +97 -0
  42. package/.morph/standards/data/nosql/cosmos-db.md +118 -0
  43. package/.morph/standards/data/vector-search/azure-ai-search.md +121 -0
  44. package/.morph/standards/data/vector-search/rag-chunking.md +104 -0
  45. package/.morph/standards/frontend/blazor/design-checklist.md +222 -0
  46. package/.morph/standards/frontend/blazor/fluent-ui-setup.md +595 -0
  47. package/.morph/standards/frontend/blazor/fluent-ui.md +137 -0
  48. package/.morph/standards/frontend/blazor/html-conversion.md +184 -0
  49. package/.morph/standards/frontend/blazor/lifecycle.md +195 -0
  50. package/.morph/standards/frontend/blazor/pitfalls.md +198 -0
  51. package/.morph/standards/frontend/blazor/state.md +191 -0
  52. package/.morph/standards/frontend/design-system/animations.md +151 -0
  53. package/.morph/standards/frontend/design-system/naming.md +64 -0
  54. package/.morph/standards/frontend/nextjs/nextjs-patterns.md +198 -0
  55. package/.morph/standards/infrastructure/azure/azure.md +624 -0
  56. package/.morph/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
  57. package/.morph/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
  58. package/.morph/standards/infrastructure/azure/devops/local-development.md +520 -0
  59. package/.morph/standards/infrastructure/azure/services/functions.md +486 -0
  60. package/.morph/standards/infrastructure/azure/services/service-bus.md +459 -0
  61. package/.morph/standards/infrastructure/azure/services/storage.md +407 -0
  62. package/.morph/standards/infrastructure/docker/easypanel-deploy.md +196 -0
  63. package/.morph/standards/infrastructure/supabase/mcp-setup.md +252 -0
  64. package/.morph/standards/infrastructure/supabase/supabase-auth.md +176 -0
  65. package/.morph/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
  66. package/.morph/standards/infrastructure/supabase/supabase-rls.md +184 -0
  67. package/.morph/standards/infrastructure/supabase/supabase-storage.md +153 -0
  68. package/.morph/standards/integration/api/graphql.md +91 -0
  69. package/.morph/standards/integration/api/grpc.md +114 -0
  70. package/.morph/standards/integration/api/rest-design.md +95 -0
  71. package/.morph/standards/integration/event-driven/cqrs.md +101 -0
  72. package/.morph/standards/integration/event-driven/event-sourcing.md +124 -0
  73. package/.morph/standards/integration/event-driven/service-bus.md +95 -0
  74. package/.morph/standards/observability/logging.md +131 -0
  75. package/.morph/standards/observability/metrics.md +121 -0
  76. package/.morph/standards/observability/monitoring.md +114 -0
  77. package/.morph/standards/observability/tracing.md +132 -0
  78. package/.morph/standards/workflows/parallel-execution.md +112 -0
  79. package/.morph/standards/workflows/thread-management.md +113 -0
  80. package/.morph/templates/.idea/morph-templates.xml +92 -0
  81. package/.morph/templates/.vscode/morph-templates.code-snippets +186 -0
  82. package/.morph/templates/IDE-SNIPPETS.md +266 -0
  83. package/.morph/templates/README.md +814 -0
  84. package/.morph/templates/REGISTRY.json +1677 -0
  85. package/.morph/templates/code/dotnet/backend/repository.cs +141 -0
  86. package/.morph/templates/code/dotnet/backend/service.cs +139 -0
  87. package/.morph/templates/code/dotnet/contracts/Commands.cs +74 -0
  88. package/.morph/templates/code/dotnet/contracts/Entities.cs +25 -0
  89. package/.morph/templates/code/dotnet/contracts/Queries.cs +74 -0
  90. package/.morph/templates/code/dotnet/contracts/README.md +74 -0
  91. package/.morph/templates/code/dotnet/contracts/api-contracts.cs +173 -0
  92. package/.morph/templates/code/dotnet/contracts/contracts.cs +217 -0
  93. package/.morph/templates/code/dotnet/database/migration.cs +83 -0
  94. package/.morph/templates/code/dotnet/frontend/component.razor +239 -0
  95. package/.morph/templates/code/dotnet/jobs/agent.cs +163 -0
  96. package/.morph/templates/code/dotnet/jobs/job.cs +171 -0
  97. package/.morph/templates/code/dotnet/test.cs +239 -0
  98. package/.morph/templates/code/sql/rls-policy.sql +57 -0
  99. package/.morph/templates/code/sql/supabase-migration.sql +100 -0
  100. package/.morph/templates/code/sql/supabase-migration.template.sql +113 -0
  101. package/.morph/templates/code/typescript/contracts.ts +168 -0
  102. package/.morph/templates/context/CONTEXT-FEATURE.md +276 -0
  103. package/.morph/templates/context/CONTEXT.md +181 -0
  104. package/.morph/templates/docs/proposal.md +182 -0
  105. package/.morph/templates/docs/spec.md +149 -0
  106. package/.morph/templates/examples/design-system-examples.md +357 -0
  107. package/.morph/templates/examples/spec-examples.md +90 -0
  108. package/.morph/templates/feature/decisions.md +187 -0
  109. package/.morph/templates/feature/recap.md +146 -0
  110. package/.morph/templates/feature/tasks.md +199 -0
  111. package/.morph/templates/infrastructure/azure/Dockerfile.example +82 -0
  112. package/.morph/templates/infrastructure/azure/README.md +286 -0
  113. package/.morph/templates/infrastructure/azure/app-insights.bicep +63 -0
  114. package/.morph/templates/infrastructure/azure/app-service.bicep +164 -0
  115. package/.morph/templates/infrastructure/azure/container-app-env.bicep +49 -0
  116. package/.morph/templates/infrastructure/azure/container-app.bicep +156 -0
  117. package/.morph/templates/infrastructure/azure/deploy-checklist.md +426 -0
  118. package/.morph/templates/infrastructure/azure/deploy.ps1 +229 -0
  119. package/.morph/templates/infrastructure/azure/deploy.sh +208 -0
  120. package/.morph/templates/infrastructure/azure/key-vault.bicep +91 -0
  121. package/.morph/templates/infrastructure/azure/main.bicep +189 -0
  122. package/.morph/templates/infrastructure/azure/parameters.dev.json +29 -0
  123. package/.morph/templates/infrastructure/azure/parameters.prod.json +29 -0
  124. package/.morph/templates/infrastructure/azure/parameters.staging.json +29 -0
  125. package/.morph/templates/infrastructure/azure/sql-database.bicep +103 -0
  126. package/.morph/templates/infrastructure/azure/storage.bicep +106 -0
  127. package/.morph/templates/infrastructure/docker/Dockerfile.template +58 -0
  128. package/.morph/templates/infrastructure/docker/docker-compose.template.yml +67 -0
  129. package/.morph/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -0
  130. package/.morph/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -0
  131. package/.morph/templates/infrastructure/docker/easypanel.template.json +54 -0
  132. package/.morph/templates/infrastructure/github/README.md +593 -0
  133. package/.morph/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +22 -0
  134. package/.morph/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -0
  135. package/.morph/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -0
  136. package/.morph/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +61 -0
  137. package/.morph/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +31 -0
  138. package/.morph/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -0
  139. package/.morph/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -0
  140. package/.morph/templates/integrations/asaas-client.cs +387 -0
  141. package/.morph/templates/integrations/asaas-webhook.cs +351 -0
  142. package/.morph/templates/integrations/azure-identity-config.cs +288 -0
  143. package/.morph/templates/integrations/clerk-config.cs +258 -0
  144. package/.morph/templates/meta-prompts/fusion/fusion-agent.md +76 -0
  145. package/.morph/templates/meta-prompts/fusion/fusion-aggregator.md +100 -0
  146. package/.morph/templates/meta-prompts/hops/hop-retry.md +78 -0
  147. package/.morph/templates/meta-prompts/hops/hop-validation.md +97 -0
  148. package/.morph/templates/meta-prompts/hops/hop-wrapper.md +36 -0
  149. package/.morph/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -0
  150. package/.morph/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -0
  151. package/.morph/templates/meta-prompts/squad-leaders/backend-squad.md +90 -0
  152. package/.morph/templates/meta-prompts/squad-leaders/frontend-squad.md +126 -0
  153. package/.morph/templates/meta-prompts/squad-leaders/squad-leader.md +43 -0
  154. package/.morph/templates/meta-prompts/validators/checkpoint-validator.md +107 -0
  155. package/.morph/templates/meta-prompts/validators/pre-commit-validator.md +95 -0
  156. package/.morph/templates/saas/subscription.cs +347 -0
  157. package/.morph/templates/saas/tenant.cs +338 -0
  158. package/.morph/templates/state.template.json +17 -0
  159. package/.morph/templates/ui/FluentDesignTheme.cs +149 -0
  160. package/.morph/templates/ui/MudTheme.cs +281 -0
  161. package/.morph/templates/ui/design-system.css +226 -0
  162. package/bin/morph-spec.js +1 -1
  163. package/package.json +1 -1
  164. package/src/commands/project/update.js +100 -13
@@ -0,0 +1,593 @@
1
+ # GitHub Actions Templates for MORPH-SPEC
2
+
3
+ > **Framework-Level CI/CD Templates for Azure App Service & EasyPanel Deployments**
4
+
5
+ ## Overview
6
+
7
+ This directory contains reusable GitHub Actions workflows and composite actions that enable CI/CD automation for both **blazor-azure** (Azure App Service) and **nextjs-supabase** (EasyPanel/Docker) stacks.
8
+
9
+ **Key Features:**
10
+ - ✅ Framework-level reusability across stacks
11
+ - ✅ Handlebars v2.0 templating with helpers
12
+ - ✅ OIDC authentication for Azure (no long-lived secrets)
13
+ - ✅ Composite actions for shared logic
14
+ - ✅ Stack-specific override mechanism
15
+
16
+ ---
17
+
18
+ ## 📁 Structure
19
+
20
+ ```
21
+ infrastructure/github/
22
+ ├── workflows/ # Reusable workflow templates
23
+ │ ├── dotnet-build.yml.hbs # .NET restore, build, test, coverage
24
+ │ ├── docker-build-push.yml.hbs # Docker build & push to registry
25
+ │ ├── deploy-azure-app-service.yml.hbs # Azure App Service deployment
26
+ │ └── deploy-easypanel.yml.hbs # EasyPanel deployment via webhook
27
+
28
+ └── actions/ # Composite action templates
29
+ ├── docker-build-push/action.yml.hbs # Build & push Docker image
30
+ ├── health-check/action.yml.hbs # Poll health endpoint
31
+ └── azure-auth/action.yml.hbs # Azure OIDC login
32
+ ```
33
+
34
+ ---
35
+
36
+ ## 🔄 Reusable Workflows vs Composite Actions
37
+
38
+ | Type | Purpose | When to Use | Example |
39
+ |------|---------|-------------|---------|
40
+ | **Reusable Workflows** | Complete CI/CD pipeline (multiple jobs) | Build + test + deploy | `dotnet-build.yml.hbs`, `deploy-azure-app-service.yml.hbs` |
41
+ | **Composite Actions** | Single responsibility (grouped steps) | Reusable task across workflows | `azure-auth/action.yml.hbs`, `health-check/action.yml.hbs` |
42
+
43
+ ### Reusable Workflows
44
+
45
+ **Characteristics:**
46
+ - Defined with `on: workflow_call`
47
+ - Can have multiple jobs
48
+ - Accept inputs and secrets via `with:` and `secrets: inherit`
49
+ - Called from other workflows using `uses:` at job level
50
+
51
+ **Example Usage:**
52
+ ```yaml
53
+ jobs:
54
+ build:
55
+ uses: ./.github/workflows/dotnet-build.yml
56
+ with:
57
+ dotnet-version: '10.0'
58
+ run-tests: true
59
+ secrets: inherit
60
+ ```
61
+
62
+ ### Composite Actions
63
+
64
+ **Characteristics:**
65
+ - Defined with `runs: using: 'composite'`
66
+ - Bundle related shell commands
67
+ - Lightweight (no containerization needed)
68
+ - Called using `uses:` at step level
69
+
70
+ **Example Usage:**
71
+ ```yaml
72
+ steps:
73
+ - name: Azure Login
74
+ uses: ./.github/actions/azure-auth
75
+ with:
76
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
77
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
78
+ subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 🏗️ Deployment Architectures
84
+
85
+ ### Blazor-Azure (Azure App Service)
86
+
87
+ **Deployment Flow:**
88
+ 1. **Build:** `dotnet restore` → `dotnet build` → `dotnet test`
89
+ 2. **Publish:** `dotnet publish -c Release -o ./publish`
90
+ 3. **Infrastructure:** Deploy Bicep (App Service Plan + App Service)
91
+ 4. **Deploy:** `azure/webapps-deploy@v2` with publish folder
92
+ 5. **Health Check:** Poll `/health` endpoint
93
+
94
+ **Key Characteristics:**
95
+ - ✅ Direct .NET publish (no Docker)
96
+ - ✅ OIDC authentication (Federated Identity)
97
+ - ✅ Bicep IaC for infrastructure
98
+ - ✅ App Service deployment slots for blue-green
99
+
100
+ **GitHub Secrets Required:**
101
+ - `AZURE_CLIENT_ID` - Entra ID app registration client ID
102
+ - `AZURE_TENANT_ID` - Azure AD tenant ID
103
+ - `AZURE_SUBSCRIPTION_ID` - Azure subscription ID
104
+
105
+ **Workflows:**
106
+ - Framework: `deploy-azure-app-service.yml.hbs`
107
+ - Stack: `stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs`
108
+
109
+ ### NextJS-Supabase (EasyPanel/Docker)
110
+
111
+ **Deployment Flow:**
112
+ 1. **Build Backend:** `dotnet restore` → `dotnet build` → `dotnet test`
113
+ 2. **Build Frontend:** `npm ci` → `npm run build` → `npm test`
114
+ 3. **Docker:** Multi-stage build for API + Web
115
+ 4. **Push:** Docker image to GitHub Container Registry (ghcr.io)
116
+ 5. **Deploy:** Trigger EasyPanel webhook with image tag
117
+ 6. **Health Check:** Poll `/health` endpoint
118
+
119
+ **Key Characteristics:**
120
+ - ✅ Docker-based deployment
121
+ - ✅ Multi-service (API + Web)
122
+ - ✅ GitHub Container Registry (ghcr.io)
123
+ - ✅ EasyPanel webhook deployment
124
+
125
+ **GitHub Secrets Required:**
126
+ - `GITHUB_TOKEN` - Auto-provided for ghcr.io
127
+ - `EASYPANEL_WEBHOOK_URL` - EasyPanel deployment webhook
128
+ - `EASYPANEL_API_TOKEN` - EasyPanel API authentication
129
+ - `APP_URL` - Application URL for health checks
130
+
131
+ **Workflows:**
132
+ - Framework: `docker-build-push.yml.hbs`, `deploy-easypanel.yml.hbs`
133
+ - Stack: `stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs`
134
+
135
+ ---
136
+
137
+ ## 🔐 Authentication & Security
138
+
139
+ ### Azure OIDC (Blazor-Azure)
140
+
141
+ **Setup Steps:**
142
+
143
+ 1. **Create Entra ID App Registration:**
144
+ ```bash
145
+ az ad app create --display-name "GitHub-Blazor-Azure-OIDC"
146
+ ```
147
+
148
+ 2. **Configure Federated Credentials:**
149
+ ```bash
150
+ az ad app federated-credential create \
151
+ --id <APP_ID> \
152
+ --parameters '{
153
+ "name": "github-prod",
154
+ "issuer": "https://token.actions.githubusercontent.com",
155
+ "subject": "repo:<ORG>/<REPO>:environment:production",
156
+ "audiences": ["api://AzureADTokenExchange"]
157
+ }'
158
+ ```
159
+
160
+ 3. **Assign RBAC Roles:**
161
+ ```bash
162
+ az role assignment create \
163
+ --assignee <APP_ID> \
164
+ --role "Contributor" \
165
+ --scope /subscriptions/<SUBSCRIPTION_ID>
166
+ ```
167
+
168
+ 4. **Configure GitHub Secrets:**
169
+ - `AZURE_CLIENT_ID` - App registration client ID
170
+ - `AZURE_TENANT_ID` - Tenant ID
171
+ - `AZURE_SUBSCRIPTION_ID` - Subscription ID
172
+
173
+ **Workflow Usage:**
174
+ ```yaml
175
+ - name: Azure Login (OIDC)
176
+ uses: azure/login@v1
177
+ with:
178
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
179
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
180
+ subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
181
+ ```
182
+
183
+ ### GitHub Container Registry (NextJS-Supabase)
184
+
185
+ **Setup:**
186
+
187
+ 1. **Enable GHCR:**
188
+ - No additional setup needed - `GITHUB_TOKEN` is auto-provided
189
+
190
+ 2. **Workflow Usage:**
191
+ ```yaml
192
+ - name: Login to GHCR
193
+ uses: docker/login-action@v3
194
+ with:
195
+ registry: ghcr.io
196
+ username: ${{ github.actor }}
197
+ password: ${{ secrets.GITHUB_TOKEN }}
198
+ ```
199
+
200
+ 3. **Image Naming:**
201
+ ```yaml
202
+ image: ghcr.io/${{ github.repository_owner }}/myapp:${{ github.sha }}
203
+ ```
204
+
205
+ ---
206
+
207
+ ## 📝 Handlebars Variables & Helpers
208
+
209
+ ### Auto-Injected Variables
210
+
211
+ | Variable | Example | Source |
212
+ |----------|---------|--------|
213
+ | `{{APP_NAME}}` | `myapp` | config.json → project.name |
214
+ | `{{DOTNET_VERSION}}` | `10.0` | config.json → dotnet.version |
215
+ | `{{GITHUB_OWNER}}` | `myorg` | config.json → repository.owner |
216
+ | `{{DATE}}` | `2026-02-18` | Generated at render time |
217
+ | `{{YEAR}}` | `2026` | Generated at render time |
218
+
219
+ ### Handlebars Helpers
220
+
221
+ | Helper | Input | Output | Use Case |
222
+ |--------|-------|--------|----------|
223
+ | `{{kebabCase str}}` | `MyApp` | `my-app` | Docker image names, Azure resources |
224
+ | `{{pascalCase str}}` | `my-app` | `MyApp` | Class names (rarely needed in YAML) |
225
+ | `{{camelCase str}}` | `my-app` | `myApp` | Variables (rarely needed in YAML) |
226
+
227
+ ### Escaping GitHub Actions Syntax
228
+
229
+ **Problem:** GitHub Actions uses `${{ }}` syntax, which conflicts with Handlebars.
230
+
231
+ **Solution:** Use `{{{{raw}}}}` blocks to preserve GitHub Actions syntax:
232
+
233
+ ```yaml
234
+ # WRONG (Handlebars will interpret this)
235
+ dotnet-version: ${{ inputs.dotnet-version }}
236
+
237
+ # CORRECT (Escaped for GitHub Actions)
238
+ dotnet-version: {{{{raw}}}}${{ inputs.dotnet-version }}{{{{/raw}}}}
239
+ ```
240
+
241
+ **In Templates:**
242
+ ```handlebars
243
+ {{#if run-tests}}
244
+ - name: Test
245
+ run: dotnet test --configuration {{{{raw}}}}${{ inputs.build-configuration }}{{{{/raw}}}}
246
+ {{/if}}
247
+ ```
248
+
249
+ ---
250
+
251
+ ## 🚀 Template Rendering Process
252
+
253
+ ### GitHub Actions Constraint
254
+
255
+ ❌ **GitHub Actions CANNOT reference parent directories**
256
+ - Example: `uses: ../../../../framework/templates/...` ❌ NOT SUPPORTED
257
+
258
+ ✅ **Solution:** Render framework templates into each stack's `.github/` directory
259
+
260
+ **Rendering Flow:**
261
+ ```
262
+ framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs
263
+ ↓ (render with Handlebars)
264
+ stacks/blazor-azure/.github/workflows/dotnet-build.yml
265
+ ↓ (commit to repo)
266
+ GitHub Actions execution
267
+ ```
268
+
269
+ ### Rendering Command (Manual for Now)
270
+
271
+ **Current Approach:**
272
+ ```bash
273
+ # Manual rendering using Node.js script (future: CLI command)
274
+ node scripts/render-github-workflows.js \
275
+ --stack blazor-azure \
276
+ --app-name myapp \
277
+ --dotnet-version 10.0 \
278
+ --output stacks/blazor-azure/.github/
279
+ ```
280
+
281
+ **Future CLI Command:**
282
+ ```bash
283
+ # Planned (not yet implemented)
284
+ morph-spec template render github-workflows \
285
+ --stack blazor-azure \
286
+ --environment prod \
287
+ --output stacks/blazor-azure/.github/
288
+ ```
289
+
290
+ ### What Gets Committed
291
+
292
+ ✅ **Commit:** Rendered `.yml` files in `.github/workflows/` and `.github/actions/`
293
+ ❌ **Don't Commit:** Template sources (`.yml.hbs` files) - these stay in `.morph/templates/`
294
+
295
+ **Example:**
296
+ ```
297
+ # Committed to repo:
298
+ .github/
299
+ ├── workflows/
300
+ │ ├── ci-build.yml # Rendered from template
301
+ │ ├── cd-staging.yml # Rendered from template
302
+ │ └── cd-prod.yml # Rendered from template
303
+ └── actions/
304
+ └── azure-auth/
305
+ └── action.yml # Rendered from template
306
+
307
+ # NOT committed (template sources):
308
+ .morph/templates/infrastructure/github/
309
+ ├── workflows/
310
+ │ ├── ci-build.yml.hbs # Template source
311
+ │ └── ...
312
+ ```
313
+
314
+ ---
315
+
316
+ ## 🔀 Stack Override Mechanism
317
+
318
+ Templates follow the 3-tier resolution hierarchy:
319
+
320
+ 1. **Project-local** (highest priority)
321
+ - `.morph/templates/infrastructure/github/workflows/ci-build.yml.hbs`
322
+ - Use for project-specific customizations
323
+
324
+ 2. **Stack default** (medium priority)
325
+ - `stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/ci-build.yml.hbs`
326
+ - Stack-specific workflows (production, staging, CI)
327
+
328
+ 3. **Framework fallback** (lowest priority)
329
+ - `framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs`
330
+ - Reusable fragments called by stack workflows
331
+
332
+ **Example:**
333
+
334
+ Stack workflow `cd-prod.yml.hbs` **calls** framework workflow `dotnet-build.yml.hbs`:
335
+ ```yaml
336
+ # Stack: stacks/blazor-azure/.morph/templates/.../cd-prod.yml.hbs
337
+ jobs:
338
+ build:
339
+ uses: ./.github/workflows/dotnet-build.yml # Framework template (rendered)
340
+ with:
341
+ dotnet-version: '{{DOTNET_VERSION}}'
342
+ ```
343
+
344
+ ---
345
+
346
+ ## 🧪 Testing & Validation
347
+
348
+ ### Local Testing with `act`
349
+
350
+ Use [act](https://github.com/nektos/act) to test GitHub Actions locally:
351
+
352
+ ```bash
353
+ # Install act
354
+ brew install act # macOS
355
+ # or: choco install act # Windows
356
+
357
+ # List all workflows
358
+ cd stacks/blazor-azure
359
+ act -l
360
+
361
+ # Dry run (validate syntax)
362
+ act --dry-run
363
+
364
+ # Run specific workflow
365
+ act push -W .github/workflows/ci-build.yml
366
+
367
+ # Run with secrets (from .secrets file)
368
+ act push --secret-file .secrets
369
+ ```
370
+
371
+ ### Syntax Validation
372
+
373
+ **Validate YAML syntax:**
374
+ ```bash
375
+ # Using yamllint
376
+ yamllint .github/workflows/*.yml
377
+
378
+ # Using actionlint (GitHub Actions-specific)
379
+ actionlint .github/workflows/*.yml
380
+ ```
381
+
382
+ ### Integration Testing
383
+
384
+ **Test in Staging First:**
385
+ 1. Push to `staging` branch
386
+ 2. Monitor workflow execution in GitHub Actions tab
387
+ 3. Verify deployment to staging environment
388
+ 4. Test health endpoints
389
+ 5. Once validated, merge to `main` for production
390
+
391
+ ---
392
+
393
+ ## 📊 Workflow Examples
394
+
395
+ ### Example 1: CI Build (Blazor-Azure)
396
+
397
+ **Stack Template:** `stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/ci-build.yml.hbs`
398
+
399
+ ```yaml
400
+ name: CI Build
401
+
402
+ on:
403
+ pull_request:
404
+ branches: [main, staging]
405
+ push:
406
+ branches: [main, staging]
407
+
408
+ jobs:
409
+ build:
410
+ uses: ./.github/workflows/dotnet-build.yml
411
+ with:
412
+ dotnet-version: '{{DOTNET_VERSION}}'
413
+ build-configuration: 'Release'
414
+ run-tests: true
415
+
416
+ security:
417
+ runs-on: ubuntu-latest
418
+ steps:
419
+ - uses: actions/checkout@v4
420
+
421
+ - name: Check vulnerable packages
422
+ run: dotnet list package --vulnerable --include-transitive
423
+ ```
424
+
425
+ ### Example 2: Production Deployment (NextJS-Supabase)
426
+
427
+ **Stack Template:** `stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs`
428
+
429
+ ```yaml
430
+ name: Deploy to Production
431
+
432
+ on:
433
+ push:
434
+ branches: [main]
435
+
436
+ jobs:
437
+ build-docker:
438
+ uses: ./.github/workflows/docker-build-push.yml
439
+ with:
440
+ registry: 'ghcr.io'
441
+ image-name: '{{GITHUB_OWNER}}/{{kebabCase APP_NAME}}'
442
+ dockerfile-path: 'Dockerfile'
443
+ secrets: inherit
444
+
445
+ deploy:
446
+ needs: build-docker
447
+ uses: ./.github/workflows/deploy-easypanel.yml
448
+ with:
449
+ environment: 'production'
450
+ image: {{{{raw}}}}${{ needs.build-docker.outputs.image-tag }}{{{{/raw}}}}
451
+ secrets: inherit
452
+ ```
453
+
454
+ ---
455
+
456
+ ## 🔧 Customization Guide
457
+
458
+ ### Creating Stack-Specific Workflows
459
+
460
+ 1. **Create override template:**
461
+ ```bash
462
+ mkdir -p stacks/blazor-azure/.morph/templates/infrastructure/github/workflows
463
+ ```
464
+
465
+ 2. **Copy framework template:**
466
+ ```bash
467
+ cp framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs \
468
+ stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/
469
+ ```
470
+
471
+ 3. **Customize:**
472
+ - Add stack-specific jobs (e.g., blue-green deployment)
473
+ - Modify environment variables
474
+ - Add security scanning steps
475
+
476
+ 4. **Render:**
477
+ ```bash
478
+ # Manual rendering (future: CLI command)
479
+ node scripts/render-github-workflows.js --stack blazor-azure
480
+ ```
481
+
482
+ ### Adding Custom Composite Actions
483
+
484
+ 1. **Create action directory:**
485
+ ```bash
486
+ mkdir -p framework/templates/infrastructure/github/actions/my-action
487
+ ```
488
+
489
+ 2. **Create `action.yml.hbs`:**
490
+ ```yaml
491
+ name: 'My Custom Action'
492
+ description: 'Description here'
493
+ inputs:
494
+ my-input:
495
+ description: 'Input description'
496
+ required: true
497
+
498
+ runs:
499
+ using: 'composite'
500
+ steps:
501
+ - name: Do something
502
+ shell: bash
503
+ run: |
504
+ echo "Input: {{{{raw}}}}${{ inputs.my-input }}{{{{/raw}}}}"
505
+ ```
506
+
507
+ 3. **Register in REGISTRY.json:**
508
+ ```json
509
+ {
510
+ "id": "github-action-my-action",
511
+ "name": "My Custom Action",
512
+ "path": "infrastructure/github/actions/my-action/action.yml.hbs",
513
+ "location": "framework",
514
+ "category": "infrastructure",
515
+ "technology": "github-actions",
516
+ "engine": "handlebars"
517
+ }
518
+ ```
519
+
520
+ ---
521
+
522
+ ## 📚 Resources
523
+
524
+ - [GitHub Actions Documentation](https://docs.github.com/en/actions)
525
+ - [Reusable Workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows)
526
+ - [Composite Actions](https://docs.github.com/en/actions/creating-actions/creating-a-composite-action)
527
+ - [Azure Login Action](https://github.com/Azure/login)
528
+ - [Docker Login Action](https://github.com/docker/login-action)
529
+ - [OIDC in Azure](https://docs.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation)
530
+
531
+ ---
532
+
533
+ ## 🐛 Troubleshooting
534
+
535
+ ### Common Issues
536
+
537
+ **Issue 1: "uses: path is not valid"**
538
+ ```yaml
539
+ # WRONG
540
+ uses: ../../../../framework/templates/.../workflow.yml
541
+
542
+ # CORRECT
543
+ uses: ./.github/workflows/workflow.yml # Rendered template
544
+ ```
545
+
546
+ **Issue 2: Handlebars placeholders in rendered YAML**
547
+ ```yaml
548
+ # Check for unreplaced placeholders
549
+ grep -r "{{" .github/workflows/
550
+
551
+ # If found, ensure rendering process completed successfully
552
+ ```
553
+
554
+ **Issue 3: OIDC authentication fails**
555
+ ```
556
+ Error: Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable
557
+ ```
558
+
559
+ **Fix:** Ensure federated credentials are configured correctly in Azure AD:
560
+ ```bash
561
+ # Verify federated credential
562
+ az ad app federated-credential show \
563
+ --id <APP_ID> \
564
+ --federated-credential-id github-prod
565
+ ```
566
+
567
+ **Issue 4: Health check fails**
568
+ ```
569
+ curl: (7) Failed to connect to app-myapp-prod.azurewebsites.net
570
+ ```
571
+
572
+ **Fix:** Add startup delay before health check:
573
+ ```yaml
574
+ - name: Wait for app startup
575
+ run: sleep 30
576
+
577
+ - name: Health Check
578
+ run: curl --retry 10 --retry-delay 5 ...
579
+ ```
580
+
581
+ ---
582
+
583
+ ## 🎯 Summary
584
+
585
+ - ✅ **Framework-level reusability** across blazor-azure and nextjs-supabase stacks
586
+ - ✅ **Handlebars v2.0 templating** with helpers (kebabCase, pascalCase, etc.)
587
+ - ✅ **OIDC authentication** for Azure (modern, secure, no long-lived secrets)
588
+ - ✅ **Composite actions** for shared logic (docker-build-push, health-check, azure-auth)
589
+ - ✅ **Reusable workflows** for complete pipelines (dotnet-build, deploy-azure-app-service)
590
+ - ✅ **Stack override mechanism** for customization (3-tier resolution)
591
+ - ✅ **Rendered outputs committed** to `.github/` (GitHub Actions constraint)
592
+
593
+ For questions or issues, see [framework/templates/README.md](../README.md) or open a GitHub issue.
@@ -0,0 +1,22 @@
1
+ name: 'Azure Authentication'
2
+ description: 'Login to Azure using OIDC'
3
+ inputs:
4
+ client-id:
5
+ description: 'Azure Client ID'
6
+ required: true
7
+ tenant-id:
8
+ description: 'Azure Tenant ID'
9
+ required: true
10
+ subscription-id:
11
+ description: 'Azure Subscription ID'
12
+ required: true
13
+
14
+ runs:
15
+ using: 'composite'
16
+ steps:
17
+ - name: Azure Login (OIDC)
18
+ uses: azure/login@v1
19
+ with:
20
+ client-id: ${{{{ inputs.client-id }}}}
21
+ tenant-id: ${{{{ inputs.tenant-id }}}}
22
+ subscription-id: ${{{{ inputs.subscription-id }}}}
@@ -0,0 +1,45 @@
1
+ name: 'Build & Push Docker Image'
2
+ description: 'Build multi-stage Docker image and push to registry'
3
+ inputs:
4
+ registry:
5
+ description: 'Docker registry URL'
6
+ required: true
7
+ image-name:
8
+ description: 'Docker image name'
9
+ required: true
10
+ dockerfile-path:
11
+ description: 'Path to Dockerfile'
12
+ required: false
13
+ default: 'Dockerfile'
14
+ build-context:
15
+ description: 'Docker build context'
16
+ required: false
17
+ default: '.'
18
+ outputs:
19
+ image-tag:
20
+ description: 'Full image tag with registry'
21
+ value: ${{{{ steps.build.outputs.tags }}}}
22
+
23
+ runs:
24
+ using: 'composite'
25
+ steps:
26
+ - name: Set up Docker Buildx
27
+ uses: docker/setup-buildx-action@v3
28
+
29
+ - name: Login to Registry
30
+ uses: docker/login-action@v3
31
+ with:
32
+ registry: ${{{{ inputs.registry }}}}
33
+ username: ${{{{ secrets.REGISTRY_USERNAME }}}}
34
+ password: ${{{{ secrets.REGISTRY_PASSWORD }}}}
35
+
36
+ - name: Build and push
37
+ id: build
38
+ uses: docker/build-push-action@v5
39
+ with:
40
+ context: ${{{{ inputs.build-context }}}}
41
+ file: ${{{{ inputs.dockerfile-path }}}}
42
+ push: true
43
+ tags: ${{{{ inputs.registry }}}}/${{{{ inputs.image-name }}}}:${{{{ github.sha }}}}
44
+ cache-from: type=gha
45
+ cache-to: type=gha,mode=max
@@ -0,0 +1,27 @@
1
+ name: 'Health Check'
2
+ description: 'Poll health endpoint until ready'
3
+ inputs:
4
+ url:
5
+ description: 'Health check URL'
6
+ required: true
7
+ timeout:
8
+ description: 'Timeout in seconds'
9
+ required: false
10
+ default: '300'
11
+ interval:
12
+ description: 'Polling interval in seconds'
13
+ required: false
14
+ default: '5'
15
+
16
+ runs:
17
+ using: 'composite'
18
+ steps:
19
+ - name: Wait for health
20
+ shell: bash
21
+ run: |
22
+ RETRIES=$(($${{{{ inputs.timeout }}}} / ${{{{ inputs.interval }}}}))
23
+ curl --retry $RETRIES \
24
+ --retry-delay ${{{{ inputs.interval }}}} \
25
+ --retry-connrefused \
26
+ --fail \
27
+ ${{{{ inputs.url }}}}