@polymorphism-tech/morph-spec 1.0.0

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 (83) hide show
  1. package/README.md +279 -0
  2. package/bin/morph-spec.js +53 -0
  3. package/content/.claude/commands/morph-apply.md +66 -0
  4. package/content/.claude/commands/morph-archive.md +79 -0
  5. package/content/.claude/commands/morph-costs.md +206 -0
  6. package/content/.claude/commands/morph-infra.md +209 -0
  7. package/content/.claude/commands/morph-proposal.md +60 -0
  8. package/content/.claude/commands/morph-status.md +71 -0
  9. package/content/.claude/settings.local.json +15 -0
  10. package/content/.claude/skills/infra/bicep-architect.md +419 -0
  11. package/content/.claude/skills/infra/container-specialist.md +437 -0
  12. package/content/.claude/skills/infra/devops-engineer.md +405 -0
  13. package/content/.claude/skills/integrations/asaas-financial.md +333 -0
  14. package/content/.claude/skills/integrations/azure-identity.md +309 -0
  15. package/content/.claude/skills/integrations/clerk-auth.md +290 -0
  16. package/content/.claude/skills/specialists/azure-architect.md +142 -0
  17. package/content/.claude/skills/specialists/cost-guardian.md +110 -0
  18. package/content/.claude/skills/specialists/ef-modeler.md +200 -0
  19. package/content/.claude/skills/specialists/hangfire-orchestrator.md +245 -0
  20. package/content/.claude/skills/specialists/ms-agent-expert.md +209 -0
  21. package/content/.claude/skills/specialists/po-pm-advisor.md +197 -0
  22. package/content/.claude/skills/specialists/standards-architect.md +78 -0
  23. package/content/.claude/skills/specialists/ui-ux-designer.md +325 -0
  24. package/content/.claude/skills/stacks/dotnet-blazor.md +352 -0
  25. package/content/.claude/skills/stacks/dotnet-nextjs.md +402 -0
  26. package/content/.claude/skills/stacks/shopify.md +445 -0
  27. package/content/.morph/archive/.gitkeep +25 -0
  28. package/content/.morph/config/agents.json +149 -0
  29. package/content/.morph/config/config.template.json +96 -0
  30. package/content/.morph/examples/api-nextjs/README.md +241 -0
  31. package/content/.morph/examples/api-nextjs/contracts.ts +307 -0
  32. package/content/.morph/examples/api-nextjs/spec.md +399 -0
  33. package/content/.morph/examples/api-nextjs/tasks.md +168 -0
  34. package/content/.morph/examples/micro-saas/README.md +125 -0
  35. package/content/.morph/examples/micro-saas/contracts.cs +358 -0
  36. package/content/.morph/examples/micro-saas/decisions.md +246 -0
  37. package/content/.morph/examples/micro-saas/spec.md +236 -0
  38. package/content/.morph/examples/micro-saas/tasks.md +150 -0
  39. package/content/.morph/examples/multi-agent/README.md +309 -0
  40. package/content/.morph/examples/multi-agent/contracts.cs +433 -0
  41. package/content/.morph/examples/multi-agent/spec.md +479 -0
  42. package/content/.morph/examples/multi-agent/tasks.md +185 -0
  43. package/content/.morph/features/.gitkeep +25 -0
  44. package/content/.morph/project.md +159 -0
  45. package/content/.morph/specs/.gitkeep +20 -0
  46. package/content/.morph/standards/architecture.md +190 -0
  47. package/content/.morph/standards/azure.md +184 -0
  48. package/content/.morph/standards/coding.md +342 -0
  49. package/content/.morph/templates/agent.cs +172 -0
  50. package/content/.morph/templates/component.razor +239 -0
  51. package/content/.morph/templates/contracts.cs +217 -0
  52. package/content/.morph/templates/decisions.md +106 -0
  53. package/content/.morph/templates/infra/app-insights.bicep +63 -0
  54. package/content/.morph/templates/infra/container-app-env.bicep +49 -0
  55. package/content/.morph/templates/infra/container-app.bicep +156 -0
  56. package/content/.morph/templates/infra/key-vault.bicep +91 -0
  57. package/content/.morph/templates/infra/main.bicep +155 -0
  58. package/content/.morph/templates/infra/parameters.dev.json +23 -0
  59. package/content/.morph/templates/infra/parameters.prod.json +23 -0
  60. package/content/.morph/templates/infra/sql-database.bicep +103 -0
  61. package/content/.morph/templates/infra/storage.bicep +106 -0
  62. package/content/.morph/templates/integrations/asaas-client.cs +387 -0
  63. package/content/.morph/templates/integrations/asaas-webhook.cs +351 -0
  64. package/content/.morph/templates/integrations/azure-identity-config.cs +288 -0
  65. package/content/.morph/templates/integrations/clerk-config.cs +258 -0
  66. package/content/.morph/templates/job.cs +171 -0
  67. package/content/.morph/templates/migration.cs +83 -0
  68. package/content/.morph/templates/proposal.md +155 -0
  69. package/content/.morph/templates/recap.md +105 -0
  70. package/content/.morph/templates/repository.cs +141 -0
  71. package/content/.morph/templates/saas/subscription.cs +347 -0
  72. package/content/.morph/templates/saas/tenant.cs +338 -0
  73. package/content/.morph/templates/service.cs +139 -0
  74. package/content/.morph/templates/spec.md +147 -0
  75. package/content/.morph/templates/tasks.md +235 -0
  76. package/content/.morph/templates/test.cs +239 -0
  77. package/content/CLAUDE.md +318 -0
  78. package/package.json +50 -0
  79. package/src/commands/doctor.js +132 -0
  80. package/src/commands/init.js +121 -0
  81. package/src/commands/update.js +84 -0
  82. package/src/utils/file-copier.js +50 -0
  83. package/src/utils/logger.js +32 -0
@@ -0,0 +1,239 @@
1
+ @* ============================================================
2
+ BLAZOR COMPONENT TEMPLATE
3
+ Generated by MORPH Framework
4
+ ============================================================ *@
5
+
6
+ @page "/{feature}/{feature}s"
7
+ @attribute [Authorize(Policy = "CanView{Feature}")]
8
+ @inject I{Feature}Service {Feature}Service
9
+ @inject ILogger<{Feature}List> Logger
10
+ @inject NavigationManager Navigation
11
+
12
+ <PageTitle>{Feature}s</PageTitle>
13
+
14
+ <div class="container-fluid">
15
+ <div class="row mb-4">
16
+ <div class="col">
17
+ <h1>{Feature}s</h1>
18
+ </div>
19
+ <div class="col-auto">
20
+ <AuthorizeView Policy="CanManage{Feature}">
21
+ <button class="btn btn-primary" @onclick="ShowCreateModal">
22
+ <i class="bi bi-plus-lg"></i> New {Feature}
23
+ </button>
24
+ </AuthorizeView>
25
+ </div>
26
+ </div>
27
+
28
+ @if (_isLoading)
29
+ {
30
+ <div class="d-flex justify-content-center py-5">
31
+ <div class="spinner-border text-primary" role="status">
32
+ <span class="visually-hidden">Loading...</span>
33
+ </div>
34
+ </div>
35
+ }
36
+ else if (_error is not null)
37
+ {
38
+ <div class="alert alert-danger" role="alert">
39
+ <i class="bi bi-exclamation-triangle"></i>
40
+ @_error
41
+ <button class="btn btn-link" @onclick="LoadDataAsync">Retry</button>
42
+ </div>
43
+ }
44
+ else if (_items is null || !_items.Any())
45
+ {
46
+ <div class="text-center py-5">
47
+ <i class="bi bi-inbox display-1 text-muted"></i>
48
+ <p class="lead mt-3">No {feature}s found</p>
49
+ <AuthorizeView Policy="CanManage{Feature}">
50
+ <button class="btn btn-primary" @onclick="ShowCreateModal">
51
+ Create your first {feature}
52
+ </button>
53
+ </AuthorizeView>
54
+ </div>
55
+ }
56
+ else
57
+ {
58
+ <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
59
+ @foreach (var item in _items)
60
+ {
61
+ <div class="col">
62
+ <div class="card h-100">
63
+ <div class="card-body">
64
+ <h5 class="card-title">@item.Name</h5>
65
+ <p class="card-text">
66
+ <span class="badge @GetStatusBadgeClass(item.Status)">
67
+ @item.Status
68
+ </span>
69
+ </p>
70
+ </div>
71
+ <div class="card-footer bg-transparent">
72
+ <small class="text-muted">
73
+ Created @item.CreatedAt.ToString("d")
74
+ </small>
75
+ <AuthorizeView Policy="CanManage{Feature}">
76
+ <div class="float-end">
77
+ <button class="btn btn-sm btn-outline-primary"
78
+ @onclick="() => ShowEditModal(item)">
79
+ Edit
80
+ </button>
81
+ </div>
82
+ </AuthorizeView>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ }
87
+ </div>
88
+ }
89
+ </div>
90
+
91
+ @* Modal for Create/Edit *@
92
+ @if (_showModal)
93
+ {
94
+ <div class="modal fade show d-block" tabindex="-1" style="background: rgba(0,0,0,0.5)">
95
+ <div class="modal-dialog">
96
+ <div class="modal-content">
97
+ <div class="modal-header">
98
+ <h5 class="modal-title">
99
+ @(_editingItem is null ? "New {Feature}" : "Edit {Feature}")
100
+ </h5>
101
+ <button type="button" class="btn-close" @onclick="CloseModal"></button>
102
+ </div>
103
+ <EditForm Model="_formModel" OnValidSubmit="HandleSubmitAsync">
104
+ <DataAnnotationsValidator />
105
+ <div class="modal-body">
106
+ <div class="mb-3">
107
+ <label class="form-label">Name</label>
108
+ <InputText class="form-control" @bind-Value="_formModel.Name" />
109
+ <ValidationMessage For="() => _formModel.Name" />
110
+ </div>
111
+ @* Add more fields as needed *@
112
+ </div>
113
+ <div class="modal-footer">
114
+ <button type="button" class="btn btn-secondary" @onclick="CloseModal">
115
+ Cancel
116
+ </button>
117
+ <button type="submit" class="btn btn-primary" disabled="@_isSaving">
118
+ @if (_isSaving)
119
+ {
120
+ <span class="spinner-border spinner-border-sm"></span>
121
+ }
122
+ Save
123
+ </button>
124
+ </div>
125
+ </EditForm>
126
+ </div>
127
+ </div>
128
+ </div>
129
+ }
130
+
131
+ @code {
132
+ private List<{Feature}Dto>? _items;
133
+ private bool _isLoading = true;
134
+ private bool _showModal;
135
+ private bool _isSaving;
136
+ private string? _error;
137
+ private {Feature}Dto? _editingItem;
138
+ private {Feature}FormModel _formModel = new();
139
+
140
+ protected override async Task OnInitializedAsync()
141
+ {
142
+ await LoadDataAsync();
143
+ }
144
+
145
+ private async Task LoadDataAsync()
146
+ {
147
+ _isLoading = true;
148
+ _error = null;
149
+
150
+ try
151
+ {
152
+ _items = await {Feature}Service.GetAllAsync();
153
+ }
154
+ catch (Exception ex)
155
+ {
156
+ Logger.LogError(ex, "Failed to load {feature}s");
157
+ _error = "Failed to load data. Please try again.";
158
+ }
159
+ finally
160
+ {
161
+ _isLoading = false;
162
+ }
163
+ }
164
+
165
+ private void ShowCreateModal()
166
+ {
167
+ _editingItem = null;
168
+ _formModel = new {Feature}FormModel();
169
+ _showModal = true;
170
+ }
171
+
172
+ private void ShowEditModal({Feature}Dto item)
173
+ {
174
+ _editingItem = item;
175
+ _formModel = new {Feature}FormModel
176
+ {
177
+ Name = item.Name
178
+ // Map other fields
179
+ };
180
+ _showModal = true;
181
+ }
182
+
183
+ private void CloseModal()
184
+ {
185
+ _showModal = false;
186
+ _formModel = new();
187
+ }
188
+
189
+ private async Task HandleSubmitAsync()
190
+ {
191
+ _isSaving = true;
192
+
193
+ try
194
+ {
195
+ if (_editingItem is null)
196
+ {
197
+ // Create
198
+ var request = new Create{Feature}Request(_formModel.Name);
199
+ await {Feature}Service.CreateAsync(request);
200
+ }
201
+ else
202
+ {
203
+ // Update
204
+ var request = new Update{Feature}Request(_formModel.Name);
205
+ await {Feature}Service.UpdateAsync(_editingItem.Id, request);
206
+ }
207
+
208
+ CloseModal();
209
+ await LoadDataAsync();
210
+ }
211
+ catch (Exception ex)
212
+ {
213
+ Logger.LogError(ex, "Failed to save {feature}");
214
+ // Show error to user
215
+ }
216
+ finally
217
+ {
218
+ _isSaving = false;
219
+ }
220
+ }
221
+
222
+ private static string GetStatusBadgeClass({Feature}Status status) => status switch
223
+ {
224
+ {Feature}Status.Active => "bg-success",
225
+ {Feature}Status.Pending => "bg-warning text-dark",
226
+ {Feature}Status.Completed => "bg-info",
227
+ {Feature}Status.Failed => "bg-danger",
228
+ _ => "bg-secondary"
229
+ };
230
+
231
+ private class {Feature}FormModel
232
+ {
233
+ [Required]
234
+ [StringLength(200, MinimumLength = 3)]
235
+ public string Name { get; set; } = string.Empty;
236
+
237
+ // Add more fields as needed
238
+ }
239
+ }
@@ -0,0 +1,217 @@
1
+ // ============================================================
2
+ // CONTRACTS: {Feature Name}
3
+ // Generated by MORPH Framework
4
+ // Date: {date}
5
+ // ============================================================
6
+
7
+ #region Usings
8
+
9
+ using System;
10
+ using System.Collections.Generic;
11
+ using System.Threading;
12
+ using System.Threading.Tasks;
13
+
14
+ #endregion
15
+
16
+ namespace MyProject.Application.Features.{Feature};
17
+
18
+ #region Service Interfaces
19
+
20
+ /// <summary>
21
+ /// Service for managing {Feature} operations.
22
+ /// </summary>
23
+ public interface I{Feature}Service
24
+ {
25
+ /// <summary>
26
+ /// Gets a {feature} by its identifier.
27
+ /// </summary>
28
+ Task<{Feature}Dto?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
29
+
30
+ /// <summary>
31
+ /// Gets all {features}.
32
+ /// </summary>
33
+ Task<List<{Feature}Dto>> GetAllAsync(CancellationToken cancellationToken = default);
34
+
35
+ /// <summary>
36
+ /// Creates a new {feature}.
37
+ /// </summary>
38
+ Task<{Feature}Dto> CreateAsync(Create{Feature}Request request, CancellationToken cancellationToken = default);
39
+
40
+ /// <summary>
41
+ /// Updates an existing {feature}.
42
+ /// </summary>
43
+ Task UpdateAsync(int id, Update{Feature}Request request, CancellationToken cancellationToken = default);
44
+
45
+ /// <summary>
46
+ /// Deletes a {feature}.
47
+ /// </summary>
48
+ Task DeleteAsync(int id, CancellationToken cancellationToken = default);
49
+ }
50
+
51
+ #endregion
52
+
53
+ #region DTOs
54
+
55
+ /// <summary>
56
+ /// Data transfer object for {Feature}.
57
+ /// </summary>
58
+ public record {Feature}Dto(
59
+ int Id,
60
+ string Name,
61
+ {Feature}Status Status,
62
+ DateTime CreatedAt,
63
+ DateTime? UpdatedAt
64
+ );
65
+
66
+ /// <summary>
67
+ /// Request to create a new {Feature}.
68
+ /// </summary>
69
+ public record Create{Feature}Request(
70
+ string Name
71
+ // Add other required fields
72
+ );
73
+
74
+ /// <summary>
75
+ /// Request to update an existing {Feature}.
76
+ /// </summary>
77
+ public record Update{Feature}Request(
78
+ string Name
79
+ // Add other updatable fields
80
+ );
81
+
82
+ #endregion
83
+
84
+ #region Enums
85
+
86
+ /// <summary>
87
+ /// Status of a {Feature}.
88
+ /// </summary>
89
+ public enum {Feature}Status
90
+ {
91
+ Pending = 0,
92
+ Active = 1,
93
+ Completed = 2,
94
+ Failed = 3
95
+ }
96
+
97
+ #endregion
98
+
99
+ #region Repository Interfaces
100
+
101
+ /// <summary>
102
+ /// Repository for {Feature} data access.
103
+ /// </summary>
104
+ public interface I{Feature}Repository
105
+ {
106
+ Task<{Feature}?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
107
+ Task<List<{Feature}>> GetAllAsync(CancellationToken cancellationToken = default);
108
+ Task AddAsync({Feature} entity, CancellationToken cancellationToken = default);
109
+ void Update({Feature} entity);
110
+ void Remove({Feature} entity);
111
+ Task SaveChangesAsync(CancellationToken cancellationToken = default);
112
+ }
113
+
114
+ #endregion
115
+
116
+ #region Domain Entity Reference
117
+
118
+ /*
119
+ /// <summary>
120
+ /// {Feature} domain entity.
121
+ /// Implement in Domain/Entities/{Feature}.cs
122
+ /// </summary>
123
+ public class {Feature}
124
+ {
125
+ public int Id { get; private set; }
126
+ public string Name { get; private set; } = string.Empty;
127
+ public {Feature}Status Status { get; private set; }
128
+ public DateTime CreatedAt { get; private set; }
129
+ public DateTime? UpdatedAt { get; private set; }
130
+
131
+ private {Feature}() { } // EF Constructor
132
+
133
+ public static {Feature} Create(string name)
134
+ {
135
+ return new {Feature}
136
+ {
137
+ Name = name,
138
+ Status = {Feature}Status.Pending,
139
+ CreatedAt = DateTime.UtcNow
140
+ };
141
+ }
142
+
143
+ public void Activate()
144
+ {
145
+ Status = {Feature}Status.Active;
146
+ UpdatedAt = DateTime.UtcNow;
147
+ }
148
+
149
+ public void Complete()
150
+ {
151
+ Status = {Feature}Status.Completed;
152
+ UpdatedAt = DateTime.UtcNow;
153
+ }
154
+ }
155
+ */
156
+
157
+ #endregion
158
+
159
+ #region AI Agent Interfaces (if applicable)
160
+
161
+ /// <summary>
162
+ /// AI Agent for {Feature} analysis.
163
+ /// </summary>
164
+ public interface I{Feature}AnalyzerAgent
165
+ {
166
+ /// <summary>
167
+ /// Analyzes {feature} data using AI.
168
+ /// </summary>
169
+ Task<{Feature}AnalysisResult> AnalyzeAsync(
170
+ {Feature}Data data,
171
+ CancellationToken cancellationToken = default);
172
+ }
173
+
174
+ public record {Feature}Data(
175
+ // Input data for analysis
176
+ string Content
177
+ );
178
+
179
+ public record {Feature}AnalysisResult(
180
+ string Summary,
181
+ List<string> Insights,
182
+ List<string> Recommendations,
183
+ double ConfidenceScore
184
+ );
185
+
186
+ #endregion
187
+
188
+ #region Hangfire Job Interfaces (if applicable)
189
+
190
+ /// <summary>
191
+ /// Background job for processing {Feature}.
192
+ /// </summary>
193
+ public interface I{Feature}ProcessorJob
194
+ {
195
+ /// <summary>
196
+ /// Executes the {feature} processing job.
197
+ /// </summary>
198
+ Task ExecuteAsync(int id, CancellationToken cancellationToken = default);
199
+ }
200
+
201
+ #endregion
202
+
203
+ #region Exceptions
204
+
205
+ public class {Feature}NotFoundException : Exception
206
+ {
207
+ public {Feature}NotFoundException(int id)
208
+ : base($"{Feature} with ID {id} was not found.") { }
209
+ }
210
+
211
+ public class {Feature}ProcessingException : Exception
212
+ {
213
+ public {Feature}ProcessingException(string message, Exception? innerException = null)
214
+ : base(message, innerException) { }
215
+ }
216
+
217
+ #endregion
@@ -0,0 +1,106 @@
1
+ # Architecture Decision Records - {Feature Name}
2
+
3
+ ## ADR-001: {Decision Title}
4
+
5
+ **Date:** {date}
6
+ **Status:** Proposed | Accepted | Deprecated | Superseded
7
+ **Deciders:** MORPH Agents, Developer
8
+
9
+ ### Context
10
+
11
+ {Descreva o contexto e o problema que levou a esta decisão}
12
+
13
+ ### Decision
14
+
15
+ {Descreva a decisão tomada}
16
+
17
+ ### Consequences
18
+
19
+ **Positivas:**
20
+ - {Consequência positiva 1}
21
+ - {Consequência positiva 2}
22
+
23
+ **Negativas:**
24
+ - {Consequência negativa 1}
25
+
26
+ **Riscos:**
27
+ - {Risco identificado}
28
+
29
+ ### Alternatives Considered
30
+
31
+ #### Option A: {Nome}
32
+ - Pros: {vantagens}
33
+ - Cons: {desvantagens}
34
+ - **Rejected because:** {motivo}
35
+
36
+ #### Option B: {Nome}
37
+ - Pros: {vantagens}
38
+ - Cons: {desvantagens}
39
+ - **Rejected because:** {motivo}
40
+
41
+ ---
42
+
43
+ ## ADR-002: Database Model
44
+
45
+ **Date:** {date}
46
+ **Status:** Accepted
47
+
48
+ ### Context
49
+
50
+ Need to define how {Feature} data will be stored.
51
+
52
+ ### Decision
53
+
54
+ Use Azure SQL with the following model:
55
+ - {Entity} table with {columns}
56
+ - JSON columns for {flexible data}
57
+
58
+ ### Consequences
59
+
60
+ **Positivas:**
61
+ - Fits within free tier (32GB)
62
+ - Good query performance
63
+
64
+ ---
65
+
66
+ ## ADR-003: AI Integration
67
+
68
+ **Date:** {date}
69
+ **Status:** Accepted
70
+
71
+ ### Context
72
+
73
+ Feature requires AI capabilities for {purpose}.
74
+
75
+ ### Decision
76
+
77
+ Use MS Agent Framework with gpt-4o-mini model.
78
+
79
+ ### Consequences
80
+
81
+ **Positivas:**
82
+ - Cost effective (~$0.15/1M input tokens)
83
+ - Good enough quality for this use case
84
+
85
+ **Negativas:**
86
+ - Slightly less capable than gpt-4o
87
+
88
+ ---
89
+
90
+ ## Template for New ADRs
91
+
92
+ ```markdown
93
+ ## ADR-XXX: {Title}
94
+
95
+ **Date:**
96
+ **Status:** Proposed | Accepted | Deprecated | Superseded
97
+
98
+ ### Context
99
+ {Why is this decision needed?}
100
+
101
+ ### Decision
102
+ {What was decided?}
103
+
104
+ ### Consequences
105
+ {What are the results?}
106
+ ```
@@ -0,0 +1,63 @@
1
+ // ==============================================================================
2
+ // MORPH-SPEC - Application Insights
3
+ // Azure Application Insights for monitoring and telemetry
4
+ // ==============================================================================
5
+
6
+ @description('Application Insights name')
7
+ param name string
8
+
9
+ @description('Location')
10
+ param location string
11
+
12
+ @description('Tags')
13
+ param tags object = {}
14
+
15
+ @description('Log Analytics Workspace ID')
16
+ param logAnalyticsWorkspaceId string
17
+
18
+ @description('Application type')
19
+ @allowed(['web', 'other'])
20
+ param applicationType string = 'web'
21
+
22
+ @description('Retention in days')
23
+ @minValue(30)
24
+ @maxValue(730)
25
+ param retentionInDays int = 90
26
+
27
+ // ==============================================================================
28
+ // APPLICATION INSIGHTS
29
+ // ==============================================================================
30
+
31
+ resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
32
+ name: name
33
+ location: location
34
+ tags: tags
35
+ kind: applicationType
36
+ properties: {
37
+ Application_Type: applicationType
38
+ WorkspaceResourceId: logAnalyticsWorkspaceId
39
+ IngestionMode: 'LogAnalytics'
40
+ publicNetworkAccessForIngestion: 'Enabled'
41
+ publicNetworkAccessForQuery: 'Enabled'
42
+ RetentionInDays: retentionInDays
43
+ }
44
+ }
45
+
46
+ // ==============================================================================
47
+ // OUTPUTS
48
+ // ==============================================================================
49
+
50
+ @description('Application Insights ID')
51
+ output id string = appInsights.id
52
+
53
+ @description('Application Insights name')
54
+ output name string = appInsights.name
55
+
56
+ @description('Instrumentation Key')
57
+ output instrumentationKey string = appInsights.properties.InstrumentationKey
58
+
59
+ @description('Connection String')
60
+ output connectionString string = appInsights.properties.ConnectionString
61
+
62
+ @description('App ID')
63
+ output appId string = appInsights.properties.AppId
@@ -0,0 +1,49 @@
1
+ // ==============================================================================
2
+ // MORPH-SPEC - Container Apps Environment
3
+ // Azure Container Apps managed environment
4
+ // ==============================================================================
5
+
6
+ @description('Environment name')
7
+ param name string
8
+
9
+ @description('Location')
10
+ param location string
11
+
12
+ @description('Tags')
13
+ param tags object = {}
14
+
15
+ @description('Log Analytics Workspace ID')
16
+ param logAnalyticsWorkspaceId string
17
+
18
+ // ==============================================================================
19
+ // CONTAINER APPS ENVIRONMENT
20
+ // ==============================================================================
21
+
22
+ resource containerAppEnv 'Microsoft.App/managedEnvironments@2023-05-01' = {
23
+ name: name
24
+ location: location
25
+ tags: tags
26
+ properties: {
27
+ appLogsConfiguration: {
28
+ destination: 'log-analytics'
29
+ logAnalyticsConfiguration: {
30
+ customerId: reference(logAnalyticsWorkspaceId, '2022-10-01').customerId
31
+ sharedKey: listKeys(logAnalyticsWorkspaceId, '2022-10-01').primarySharedKey
32
+ }
33
+ }
34
+ zoneRedundant: false
35
+ }
36
+ }
37
+
38
+ // ==============================================================================
39
+ // OUTPUTS
40
+ // ==============================================================================
41
+
42
+ @description('Container Apps Environment ID')
43
+ output id string = containerAppEnv.id
44
+
45
+ @description('Container Apps Environment name')
46
+ output name string = containerAppEnv.name
47
+
48
+ @description('Default domain')
49
+ output defaultDomain string = containerAppEnv.properties.defaultDomain