@polymorphism-tech/morph-spec 4.2.0 → 4.3.1
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/CLAUDE.md +108 -946
- package/bin/morph-spec.js +284 -9
- package/bin/task-manager.cjs +102 -14
- package/bin/validate.js +4 -4
- package/docs/{v3.0 → next-generation}/AGENTS.md +1 -1
- package/docs/next-generation/CONTEXT-OPTIMIZATION.md +267 -0
- package/docs/next-generation/EXECUTION-FLOW.md +274 -0
- package/docs/next-generation/META-PROMPTS.md +235 -0
- package/docs/next-generation/MIGRATION-GUIDE.md +253 -0
- package/docs/next-generation/THREAD-MANAGEMENT.md +240 -0
- package/package.json +5 -5
- package/src/commands/agents/agents-fuse.js +97 -0
- package/src/commands/agents/micro-agent.js +112 -0
- package/src/commands/agents/spawn-team.js +69 -4
- package/src/commands/agents/squad-template.js +146 -0
- package/src/commands/analytics/analytics.js +176 -0
- package/src/commands/context/context-prime.js +63 -0
- package/src/commands/context/core-four.js +54 -0
- package/src/commands/mcp/mcp.js +102 -0
- package/src/commands/project/detect-agents.js +32 -2
- package/src/commands/project/detect.js +11 -1
- package/src/commands/project/doctor.js +573 -356
- package/src/commands/project/init.js +9 -2
- package/src/commands/project/update.js +13 -3
- package/src/commands/state/advance-phase.js +448 -416
- package/src/commands/state/state.js +14 -12
- package/src/commands/tasks/task.js +1 -1
- package/src/commands/templates/template-render.js +80 -1
- package/src/commands/threads/thread-template.js +103 -0
- package/src/commands/threads/threads.js +261 -0
- package/src/commands/trust/trust.js +205 -0
- package/src/{orchestrator.js → core/orchestrator.js} +8 -8
- package/src/core/state/state-manager.js +37 -17
- package/src/core/workflows/workflow-detector.js +114 -3
- package/src/lib/agents/micro-agent-factory.js +161 -0
- package/src/lib/analytics/analytics-engine.js +345 -0
- package/src/lib/checkpoints/checkpoint-hooks.js +298 -258
- package/src/lib/context/context-bundler.js +240 -0
- package/src/lib/context/context-optimizer.js +212 -0
- package/src/lib/context/context-tracker.js +273 -0
- package/src/lib/context/core-four-tracker.js +201 -0
- package/src/lib/context/mcp-optimizer.js +200 -0
- package/src/lib/detectors/index.js +1 -1
- package/src/lib/detectors/standards-generator.js +77 -17
- package/src/lib/detectors/structure-detector.js +67 -39
- package/src/lib/execution/fusion-executor.js +304 -0
- package/src/lib/execution/parallel-executor.js +270 -0
- package/src/lib/generators/context-generator.js +3 -3
- package/src/lib/generators/recap-generator.js +32 -12
- package/src/lib/hooks/hook-executor.js +169 -0
- package/src/lib/hooks/stop-hook-executor.js +286 -0
- package/src/lib/hops/hop-composer.js +221 -0
- package/src/lib/threads/thread-coordinator.js +238 -0
- package/src/lib/threads/thread-manager.js +317 -0
- package/src/lib/tracking/artifact-trail.js +202 -0
- package/src/lib/trust/trust-manager.js +269 -0
- package/src/lib/validators/design-system/design-system-validator.js +2 -2
- package/src/lib/validators/validation-runner.js +14 -30
- package/src/utils/hooks-installer.js +69 -0
- package/stacks/blazor-azure/.morph/config/agents.json +72 -3
- package/stacks/nextjs-supabase/.morph/config/agents.json +3 -3
- package/docs/llm-interaction-config.md +0 -735
- package/docs/v3.0/EXECUTION-FLOW.md +0 -1304
- package/src/commands/utils/migrate-state.js +0 -158
- package/src/commands/utils/upgrade.js +0 -346
- package/src/lib/validators/architecture-validator.js +0 -60
- package/src/lib/validators/content-validator.js +0 -164
- package/src/lib/validators/package-validator.js +0 -61
- package/src/lib/validators/ui-contrast-validator.js +0 -44
- package/stacks/blazor-azure/.claude/commands/morph-apply.md +0 -221
- package/stacks/blazor-azure/.claude/commands/morph-archive.md +0 -79
- 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/.claude/commands/morph-preflight.md +0 -227
- package/stacks/blazor-azure/.claude/commands/morph-proposal.md +0 -122
- package/stacks/blazor-azure/.claude/commands/morph-status.md +0 -86
- package/stacks/blazor-azure/.claude/commands/morph-troubleshoot.md +0 -122
- package/stacks/blazor-azure/.claude/skills/level-0-meta/README.md +0 -7
- package/stacks/blazor-azure/.claude/skills/level-0-meta/code-review.md +0 -226
- package/stacks/blazor-azure/.claude/skills/level-0-meta/morph-checklist.md +0 -117
- package/stacks/blazor-azure/.claude/skills/level-0-meta/simulation-checklist.md +0 -77
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/README.md +0 -7
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/morph-replicate.md +0 -213
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-clarify.md +0 -131
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-design.md +0 -213
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-setup.md +0 -106
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-tasks.md +0 -164
- package/stacks/blazor-azure/.claude/skills/level-1-workflows/phase-uiux.md +0 -169
- package/stacks/blazor-azure/.claude/skills/level-2-domains/README.md +0 -14
- package/stacks/blazor-azure/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -192
- package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -197
- package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/prompt-engineer.md +0 -189
- package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/seo-growth-hacker.md +0 -320
- package/stacks/blazor-azure/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -156
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/api-designer.md +0 -59
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -77
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -58
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -126
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -45
- package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -210
- package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -154
- package/stacks/blazor-azure/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -191
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -142
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +0 -699
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -126
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -131
- package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -119
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -130
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -142
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -108
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/hangfire-orchestrator.md +0 -64
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/resend-email.md +0 -119
- package/stacks/blazor-azure/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -235
- package/stacks/blazor-azure/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -126
- package/stacks/blazor-azure/.claude/skills/level-3-technologies/README.md +0 -7
- package/stacks/blazor-azure/.claude/skills/level-4-patterns/README.md +0 -7
- package/stacks/blazor-azure/.morph/archive/.gitkeep +0 -25
- package/stacks/blazor-azure/.morph/features/.gitkeep +0 -25
- package/stacks/blazor-azure/.morph/schemas/agent.schema.json +0 -296
- package/stacks/blazor-azure/.morph/schemas/tasks.schema.json +0 -220
- package/stacks/blazor-azure/.morph/specs/.gitkeep +0 -20
- package/stacks/blazor-azure/.morph/test-infra/example.bicep +0 -59
- 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-infra.md +0 -209
- 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/.claude/settings.local.json +0 -6
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +0 -244
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +0 -335
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +0 -189
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +0 -50
- /package/docs/{v3.0 → next-generation}/ANALYSIS.md +0 -0
- /package/docs/{v3.0 → next-generation}/ARCHITECTURE.md +0 -0
- /package/docs/{v3.0 → next-generation}/FEATURES.md +0 -0
- /package/docs/{v3.0 → next-generation}/README.md +0 -0
- /package/docs/{v3.0 → next-generation}/ROADMAP.md +0 -0
package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/bicep-architect.md
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
# Bicep Architect
|
|
2
|
-
|
|
3
|
-
> **Layer:** 2 | **Load:** on-keyword | **Keywords:** bicep, iac, infrastructure as code, provision, azure resource, deploy
|
|
4
|
-
|
|
5
|
-
Especialista em Infrastructure as Code com Azure Bicep. **Zero Portal** — all infra via code.
|
|
6
|
-
|
|
7
|
-
## Structure
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
infra/
|
|
11
|
-
├── main.bicep # Entry point
|
|
12
|
-
├── main.bicepparam # Parameters (alt to JSON)
|
|
13
|
-
├── parameters.dev.json
|
|
14
|
-
├── parameters.prod.json
|
|
15
|
-
└── modules/
|
|
16
|
-
├── container-app.bicep
|
|
17
|
-
├── container-app-env.bicep
|
|
18
|
-
├── sql-database.bicep
|
|
19
|
-
├── storage.bicep
|
|
20
|
-
├── key-vault.bicep
|
|
21
|
-
├── app-insights.bicep
|
|
22
|
-
├── service-bus.bicep
|
|
23
|
-
└── redis-cache.bicep
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Main Template Pattern
|
|
27
|
-
|
|
28
|
-
```bicep
|
|
29
|
-
targetScope = 'resourceGroup'
|
|
30
|
-
|
|
31
|
-
@allowed(['dev', 'staging', 'prod'])
|
|
32
|
-
param environment string = 'dev'
|
|
33
|
-
param location string = resourceGroup().location
|
|
34
|
-
@minLength(3) @maxLength(20) param appName string
|
|
35
|
-
@secure() param sqlAdminPassword string
|
|
36
|
-
|
|
37
|
-
var resourcePrefix = '${appName}-${environment}'
|
|
38
|
-
var tags = { environment: environment, application: appName, managedBy: 'bicep' }
|
|
39
|
-
|
|
40
|
-
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
|
|
41
|
-
name: '${resourcePrefix}-logs'
|
|
42
|
-
location: location
|
|
43
|
-
tags: tags
|
|
44
|
-
properties: { sku: { name: 'PerGB2018' }, retentionInDays: 30 }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
module appInsights 'modules/app-insights.bicep' = { name: 'appInsights', params: { ... } }
|
|
48
|
-
module containerAppEnv 'modules/container-app-env.bicep' = { name: 'env', params: { ... } }
|
|
49
|
-
module containerApp 'modules/container-app.bicep' = { name: 'app', params: { ... } }
|
|
50
|
-
module sqlDatabase 'modules/sql-database.bicep' = { name: 'sql', params: { ... } }
|
|
51
|
-
module keyVault 'modules/key-vault.bicep' = { name: 'kv', params: { ... } }
|
|
52
|
-
|
|
53
|
-
output containerAppUrl string = containerApp.outputs.url
|
|
54
|
-
output sqlConnectionString string = sqlDatabase.outputs.connectionString
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## SQL Database Module (Free Tier)
|
|
58
|
-
|
|
59
|
-
```bicep
|
|
60
|
-
// modules/sql-database.bicep
|
|
61
|
-
param serverName string
|
|
62
|
-
param databaseName string
|
|
63
|
-
param location string
|
|
64
|
-
param tags object = {}
|
|
65
|
-
param adminUsername string = 'sqladmin'
|
|
66
|
-
@secure() param adminPassword string
|
|
67
|
-
param useFree bool = true
|
|
68
|
-
|
|
69
|
-
resource sqlServer 'Microsoft.Sql/servers@2023-05-01-preview' = {
|
|
70
|
-
name: serverName
|
|
71
|
-
location: location
|
|
72
|
-
tags: tags
|
|
73
|
-
properties: { administratorLogin: adminUsername, administratorLoginPassword: adminPassword,
|
|
74
|
-
version: '12.0', minimalTlsVersion: '1.2', publicNetworkAccess: 'Enabled' }
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
resource db 'Microsoft.Sql/servers/databases@2023-05-01-preview' = {
|
|
78
|
-
parent: sqlServer
|
|
79
|
-
name: databaseName
|
|
80
|
-
location: location
|
|
81
|
-
sku: useFree ? { name: 'Free', tier: 'Free' } : { name: 'Basic', tier: 'Basic' }
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
resource firewall 'Microsoft.Sql/servers/firewallRules@2023-05-01-preview' = {
|
|
85
|
-
parent: sqlServer
|
|
86
|
-
name: 'AllowAllAzureIps'
|
|
87
|
-
properties: { startIpAddress: '0.0.0.0', endIpAddress: '0.0.0.0' }
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
> **Container App module:** See `container-specialist.md` for full Container App + ACR Bicep.
|
|
92
|
-
|
|
93
|
-
## Commands
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
az bicep build --file infra/main.bicep # Validate
|
|
97
|
-
az deployment group what-if -g rg-app-dev -f infra/main.bicep -p @infra/parameters.dev.json # Preview
|
|
98
|
-
az deployment group create -g rg-app-dev -f infra/main.bicep -p @infra/parameters.dev.json # Deploy
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Parameters File
|
|
102
|
-
|
|
103
|
-
```json
|
|
104
|
-
{
|
|
105
|
-
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
|
|
106
|
-
"contentVersion": "1.0.0.0",
|
|
107
|
-
"parameters": {
|
|
108
|
-
"environment": { "value": "dev" },
|
|
109
|
-
"appName": { "value": "myapp" },
|
|
110
|
-
"sqlAdminPassword": { "reference": { "keyVault": { "id": "/subscriptions/.../vaults/{kv}" }, "secretName": "sql-admin-password" } }
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## Checklist
|
|
116
|
-
- [ ] Bicep valid (`az bicep build`)
|
|
117
|
-
- [ ] Modules for reusable resources
|
|
118
|
-
- [ ] Parameters for dev and prod
|
|
119
|
-
- [ ] Secrets referenced from Key Vault
|
|
120
|
-
- [ ] Tags on all resources
|
|
121
|
-
- [ ] What-if executed before deploy
|
|
122
|
-
- [ ] Outputs for important values
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
*MORPH-SPEC by Polymorphism Tech*
|
package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/container-specialist.md
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
# Container Specialist
|
|
2
|
-
|
|
3
|
-
> **Layer:** 2 | **Load:** on-keyword | **Keywords:** docker, container, containerize, container apps, acr, registry, image
|
|
4
|
-
|
|
5
|
-
Especialista em containerização com Docker e deploy para Azure Container Apps.
|
|
6
|
-
|
|
7
|
-
## Dockerfile (.NET Multi-stage)
|
|
8
|
-
|
|
9
|
-
```dockerfile
|
|
10
|
-
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
|
|
11
|
-
WORKDIR /src
|
|
12
|
-
COPY ["src/Web/Web.csproj", "src/Web/"]
|
|
13
|
-
COPY ["src/Application/Application.csproj", "src/Application/"]
|
|
14
|
-
COPY ["src/Domain/Domain.csproj", "src/Domain/"]
|
|
15
|
-
COPY ["src/Infrastructure/Infrastructure.csproj", "src/Infrastructure/"]
|
|
16
|
-
RUN dotnet restore "src/Web/Web.csproj"
|
|
17
|
-
COPY . .
|
|
18
|
-
WORKDIR "/src/src/Web"
|
|
19
|
-
RUN dotnet publish "Web.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
|
20
|
-
|
|
21
|
-
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
|
|
22
|
-
WORKDIR /app
|
|
23
|
-
RUN addgroup -g 1000 appgroup && adduser -u 1000 -G appgroup -D appuser
|
|
24
|
-
COPY --from=publish /app/publish .
|
|
25
|
-
RUN chown -R appuser:appgroup /app
|
|
26
|
-
USER appuser
|
|
27
|
-
EXPOSE 8080
|
|
28
|
-
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
29
|
-
CMD wget --quiet --tries=1 --spider http://localhost:8080/health || exit 1
|
|
30
|
-
ENTRYPOINT ["dotnet", "Web.dll"]
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Image Sizes
|
|
34
|
-
| Base Image | Size |
|
|
35
|
-
|------------|------|
|
|
36
|
-
| `aspnet:10.0` | ~220MB |
|
|
37
|
-
| `aspnet:10.0-alpine` | ~110MB |
|
|
38
|
-
| `aspnet:10.0-chiseled` | ~80MB (most secure) |
|
|
39
|
-
|
|
40
|
-
## ACR (Azure Container Registry)
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
az acr create -g rg-myapp -n myappacr --sku Basic
|
|
44
|
-
az acr login -n myappacr
|
|
45
|
-
az acr build --registry myappacr --image myapp:v1 .
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Container App (Bicep)
|
|
49
|
-
|
|
50
|
-
```bicep
|
|
51
|
-
param name string
|
|
52
|
-
param location string
|
|
53
|
-
param tags object = {}
|
|
54
|
-
param environmentId string
|
|
55
|
-
param containerImage string
|
|
56
|
-
param registryServer string
|
|
57
|
-
param registryUsername string
|
|
58
|
-
@secure() param registryPassword string
|
|
59
|
-
|
|
60
|
-
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
|
|
61
|
-
name: name
|
|
62
|
-
location: location
|
|
63
|
-
tags: tags
|
|
64
|
-
properties: {
|
|
65
|
-
managedEnvironmentId: environmentId
|
|
66
|
-
configuration: {
|
|
67
|
-
ingress: { external: true, targetPort: 8080, transport: 'http', allowInsecure: false }
|
|
68
|
-
registries: [{ server: registryServer, username: registryUsername, passwordSecretRef: 'reg-pwd' }]
|
|
69
|
-
secrets: [{ name: 'reg-pwd', value: registryPassword }]
|
|
70
|
-
}
|
|
71
|
-
template: {
|
|
72
|
-
containers: [{
|
|
73
|
-
name: name, image: containerImage
|
|
74
|
-
resources: { cpu: json('0.25'), memory: '0.5Gi' }
|
|
75
|
-
probes: [
|
|
76
|
-
{ type: 'Liveness', httpGet: { path: '/health', port: 8080 }, initialDelaySeconds: 10 }
|
|
77
|
-
{ type: 'Readiness', httpGet: { path: '/health/ready', port: 8080 }, initialDelaySeconds: 5 }
|
|
78
|
-
]
|
|
79
|
-
}]
|
|
80
|
-
scale: { minReplicas: 0, maxReplicas: 5
|
|
81
|
-
rules: [{ name: 'http-scale', http: { metadata: { concurrentRequests: '100' } } }]
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
output url string = 'https://${containerApp.properties.configuration.ingress.fqdn}'
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Health Checks (ASP.NET)
|
|
90
|
-
|
|
91
|
-
```csharp
|
|
92
|
-
builder.Services.AddHealthChecks()
|
|
93
|
-
.AddSqlServer(connString, name: "database", tags: new[] { "ready" });
|
|
94
|
-
|
|
95
|
-
app.MapHealthChecks("/health");
|
|
96
|
-
app.MapHealthChecks("/health/ready", new() { Predicate = c => c.Tags.Contains("ready") });
|
|
97
|
-
app.MapHealthChecks("/health/live", new() { Predicate = _ => false }); // Always healthy
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Docker Compose (Dev)
|
|
101
|
-
|
|
102
|
-
```yaml
|
|
103
|
-
services:
|
|
104
|
-
web:
|
|
105
|
-
build: { context: ., dockerfile: Dockerfile }
|
|
106
|
-
ports: ["8080:8080"]
|
|
107
|
-
environment:
|
|
108
|
-
- ConnectionStrings__Default=Server=db;Database=App;User=sa;Password=Pass!;TrustServerCertificate=true
|
|
109
|
-
depends_on: { db: { condition: service_healthy } }
|
|
110
|
-
db:
|
|
111
|
-
image: mcr.microsoft.com/mssql/server:2022-latest
|
|
112
|
-
environment: [ACCEPT_EULA=Y, SA_PASSWORD=YourStrong!Passw0rd]
|
|
113
|
-
ports: ["1433:1433"]
|
|
114
|
-
volumes: [sqldata:/var/opt/mssql]
|
|
115
|
-
volumes:
|
|
116
|
-
sqldata:
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Checklist
|
|
120
|
-
- [ ] Dockerfile multi-stage with alpine/chiseled
|
|
121
|
-
- [ ] .dockerignore configured
|
|
122
|
-
- [ ] Non-root user in container
|
|
123
|
-
- [ ] Health checks (liveness + readiness)
|
|
124
|
-
- [ ] Docker Compose for dev
|
|
125
|
-
- [ ] ACR created and configured
|
|
126
|
-
- [ ] Container App with scale-to-zero
|
|
127
|
-
- [ ] Probes configured
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
*MORPH-SPEC by Polymorphism Tech*
|
package/stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure/devops-engineer.md
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
# DevOps Engineer
|
|
2
|
-
|
|
3
|
-
> **Layer:** 2 | **Load:** on-keyword | **Keywords:** pipeline, ci/cd, deploy, release, azure devops, github actions, build, automation
|
|
4
|
-
|
|
5
|
-
Especialista em CI/CD, pipelines e automação de deploy.
|
|
6
|
-
|
|
7
|
-
## Azure Pipelines
|
|
8
|
-
|
|
9
|
-
```yaml
|
|
10
|
-
trigger:
|
|
11
|
-
branches: { include: [main, develop] }
|
|
12
|
-
paths: { exclude: ['**/*.md'] }
|
|
13
|
-
|
|
14
|
-
variables:
|
|
15
|
-
buildConfiguration: 'Release'
|
|
16
|
-
dotnetVersion: '10.0.x'
|
|
17
|
-
|
|
18
|
-
stages:
|
|
19
|
-
- stage: Build
|
|
20
|
-
jobs:
|
|
21
|
-
- job: BuildJob
|
|
22
|
-
pool: { vmImage: 'ubuntu-latest' }
|
|
23
|
-
steps:
|
|
24
|
-
- task: UseDotNet@2
|
|
25
|
-
inputs: { version: '$(dotnetVersion)' }
|
|
26
|
-
- task: DotNetCoreCLI@2
|
|
27
|
-
displayName: 'Restore'
|
|
28
|
-
inputs: { command: 'restore', projects: '**/*.csproj' }
|
|
29
|
-
- task: DotNetCoreCLI@2
|
|
30
|
-
displayName: 'Build'
|
|
31
|
-
inputs: { command: 'build', arguments: '-c $(buildConfiguration) --no-restore' }
|
|
32
|
-
- task: DotNetCoreCLI@2
|
|
33
|
-
displayName: 'Test'
|
|
34
|
-
inputs: { command: 'test', projects: '**/tests/**/*.csproj', arguments: '--collect:"XPlat Code Coverage"' }
|
|
35
|
-
- task: DotNetCoreCLI@2
|
|
36
|
-
displayName: 'Publish'
|
|
37
|
-
inputs: { command: 'publish', publishWebProjects: true, arguments: '-c $(buildConfiguration) -o $(Build.ArtifactStagingDirectory)' }
|
|
38
|
-
- task: PublishBuildArtifacts@1
|
|
39
|
-
inputs: { pathToPublish: '$(Build.ArtifactStagingDirectory)', artifactName: 'drop' }
|
|
40
|
-
|
|
41
|
-
- stage: DeployDev
|
|
42
|
-
dependsOn: Build
|
|
43
|
-
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/develop'))
|
|
44
|
-
jobs:
|
|
45
|
-
- deployment: Deploy
|
|
46
|
-
environment: 'development'
|
|
47
|
-
strategy:
|
|
48
|
-
runOnce:
|
|
49
|
-
deploy:
|
|
50
|
-
steps:
|
|
51
|
-
- task: AzureCLI@2
|
|
52
|
-
inputs:
|
|
53
|
-
scriptType: 'bash'
|
|
54
|
-
inlineScript: 'az containerapp update --name app-dev -g rg-dev --image $(image)'
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## GitHub Actions
|
|
58
|
-
|
|
59
|
-
```yaml
|
|
60
|
-
name: CI/CD
|
|
61
|
-
on:
|
|
62
|
-
push: { branches: [main, develop] }
|
|
63
|
-
pull_request: { branches: [main] }
|
|
64
|
-
|
|
65
|
-
jobs:
|
|
66
|
-
build:
|
|
67
|
-
runs-on: ubuntu-latest
|
|
68
|
-
steps:
|
|
69
|
-
- uses: actions/checkout@v4
|
|
70
|
-
- uses: actions/setup-dotnet@v4
|
|
71
|
-
with: { dotnet-version: '10.0.x' }
|
|
72
|
-
- run: dotnet restore && dotnet build -c Release --no-restore && dotnet test -c Release --no-build
|
|
73
|
-
- run: dotnet publish src/Web/Web.csproj -c Release -o ./publish
|
|
74
|
-
|
|
75
|
-
docker:
|
|
76
|
-
needs: build
|
|
77
|
-
if: github.event_name == 'push'
|
|
78
|
-
runs-on: ubuntu-latest
|
|
79
|
-
permissions: { contents: read, packages: write }
|
|
80
|
-
steps:
|
|
81
|
-
- uses: actions/checkout@v4
|
|
82
|
-
- uses: docker/login-action@v3
|
|
83
|
-
with: { registry: ghcr.io, username: '${{ github.actor }}', password: '${{ secrets.GITHUB_TOKEN }}' }
|
|
84
|
-
- uses: docker/build-push-action@v5
|
|
85
|
-
with: { push: true, tags: 'ghcr.io/${{ github.repository }}:${{ github.sha }}' }
|
|
86
|
-
|
|
87
|
-
deploy:
|
|
88
|
-
needs: docker
|
|
89
|
-
if: github.ref == 'refs/heads/main'
|
|
90
|
-
runs-on: ubuntu-latest
|
|
91
|
-
environment: production
|
|
92
|
-
steps:
|
|
93
|
-
- uses: azure/login@v2
|
|
94
|
-
with: { creds: '${{ secrets.AZURE_CREDENTIALS }}' }
|
|
95
|
-
- uses: azure/container-apps-deploy-action@v1
|
|
96
|
-
with: { resourceGroup: rg-prod, containerAppName: app-prod, imageToDeploy: 'ghcr.io/${{ github.repository }}:${{ github.sha }}' }
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
> **Dockerfile:** See `container-specialist.md` for optimized multi-stage Dockerfile.
|
|
100
|
-
|
|
101
|
-
## Secrets Management
|
|
102
|
-
|
|
103
|
-
| Platform | Method |
|
|
104
|
-
|----------|--------|
|
|
105
|
-
| Azure DevOps | Variable Groups + Key Vault references |
|
|
106
|
-
| GitHub Actions | Repository/Environment Secrets |
|
|
107
|
-
|
|
108
|
-
## Checklist
|
|
109
|
-
- [ ] Trigger configured (branches, paths)
|
|
110
|
-
- [ ] Build: restore, build, test, publish
|
|
111
|
-
- [ ] Code coverage published
|
|
112
|
-
- [ ] Deploy to dev automatic (develop branch)
|
|
113
|
-
- [ ] Deploy to prod with approval (main branch)
|
|
114
|
-
- [ ] Secrets in Key Vault or variable groups
|
|
115
|
-
- [ ] Health check after deploy
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# Asaas Financial
|
|
2
|
-
|
|
3
|
-
> **Layer:** 2 | **Load:** on-keyword | **Keywords:** asaas, payment, pix, boleto, cobranca, subscription, billing, pagamento
|
|
4
|
-
|
|
5
|
-
Integração com Asaas para pagamentos no Brasil. API REST, sem SDK .NET oficial. Suporta PIX, Boleto, Cartão.
|
|
6
|
-
|
|
7
|
-
## Setup
|
|
8
|
-
|
|
9
|
-
```csharp
|
|
10
|
-
// appsettings.json
|
|
11
|
-
{ "Asaas": { "BaseUrl": "https://sandbox.asaas.com/api/v3", "ApiKey": "${ASAAS_API_KEY}" } }
|
|
12
|
-
|
|
13
|
-
// Program.cs
|
|
14
|
-
builder.Services.Configure<AsaasOptions>(builder.Configuration.GetSection("Asaas"));
|
|
15
|
-
builder.Services.AddHttpClient<IAsaasClient, AsaasClient>((sp, client) =>
|
|
16
|
-
{
|
|
17
|
-
var options = sp.GetRequiredService<IOptions<AsaasOptions>>().Value;
|
|
18
|
-
client.BaseAddress = new Uri(options.BaseUrl);
|
|
19
|
-
client.DefaultRequestHeaders.Add("access_token", options.ApiKey);
|
|
20
|
-
client.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");
|
|
21
|
-
});
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Client Interface
|
|
25
|
-
|
|
26
|
-
```csharp
|
|
27
|
-
public interface IAsaasClient
|
|
28
|
-
{
|
|
29
|
-
Task<AsaasCustomer> CreateCustomerAsync(CreateCustomerRequest request);
|
|
30
|
-
Task<AsaasPayment> CreatePaymentAsync(CreatePaymentRequest request);
|
|
31
|
-
Task<AsaasPayment> GetPaymentAsync(string paymentId);
|
|
32
|
-
Task<AsaasSubscription> CreateSubscriptionAsync(CreateSubscriptionRequest request);
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Implementation: standard `HttpClient.PostAsJsonAsync` / `GetAsync` + `ReadFromJsonAsync` pattern. Log errors, throw `AsaasException` on failure.
|
|
37
|
-
|
|
38
|
-
## DTOs (all use `[JsonPropertyName]`)
|
|
39
|
-
|
|
40
|
-
```csharp
|
|
41
|
-
public record CreateCustomerRequest
|
|
42
|
-
{
|
|
43
|
-
[JsonPropertyName("name")] public required string Name { get; init; }
|
|
44
|
-
[JsonPropertyName("cpfCnpj")] public required string CpfCnpj { get; init; } // REQUIRED even in sandbox
|
|
45
|
-
[JsonPropertyName("email")] public string? Email { get; init; }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public record CreatePaymentRequest
|
|
49
|
-
{
|
|
50
|
-
[JsonPropertyName("customer")] public required string Customer { get; init; }
|
|
51
|
-
[JsonPropertyName("billingType")] public required string BillingType { get; init; } // BOLETO, PIX, CREDIT_CARD
|
|
52
|
-
[JsonPropertyName("value")] public required decimal Value { get; init; }
|
|
53
|
-
[JsonPropertyName("dueDate")] public required string DueDate { get; init; } // yyyy-MM-dd
|
|
54
|
-
[JsonPropertyName("description")] public string? Description { get; init; }
|
|
55
|
-
[JsonPropertyName("externalReference")] public string? ExternalReference { get; init; }
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public record AsaasPayment
|
|
59
|
-
{
|
|
60
|
-
[JsonPropertyName("id")] public string Id { get; init; } = "";
|
|
61
|
-
[JsonPropertyName("status")] public string Status { get; init; } = ""; // PENDING, RECEIVED, CONFIRMED, OVERDUE
|
|
62
|
-
[JsonPropertyName("invoiceUrl")] public string? InvoiceUrl { get; init; }
|
|
63
|
-
[JsonPropertyName("bankSlipUrl")] public string? BankSlipUrl { get; init; }
|
|
64
|
-
[JsonPropertyName("pixQrCode")] public AsaasPixQrCode? PixQrCode { get; init; }
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public record AsaasPixQrCode
|
|
68
|
-
{
|
|
69
|
-
[JsonPropertyName("encodedImage")] public string? EncodedImage { get; init; } // Base64
|
|
70
|
-
[JsonPropertyName("payload")] public string? Payload { get; init; } // PIX copia-e-cola
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Follow same pattern for `CreateSubscriptionRequest` (add `cycle`: MONTHLY/WEEKLY/YEARLY, `nextDueDate`).
|
|
75
|
-
|
|
76
|
-
## Webhooks
|
|
77
|
-
|
|
78
|
-
```csharp
|
|
79
|
-
[ApiController, Route("api/webhooks/asaas")]
|
|
80
|
-
public class AsaasWebhookController(IPaymentService payments, ILogger<AsaasWebhookController> logger) : ControllerBase
|
|
81
|
-
{
|
|
82
|
-
[HttpPost]
|
|
83
|
-
public async Task<IActionResult> Handle([FromBody] AsaasWebhookPayload payload)
|
|
84
|
-
{
|
|
85
|
-
logger.LogInformation("Asaas webhook: {Event} payment {Id}", payload.Event, payload.Payment?.Id);
|
|
86
|
-
switch (payload.Event)
|
|
87
|
-
{
|
|
88
|
-
case "PAYMENT_CONFIRMED": case "PAYMENT_RECEIVED":
|
|
89
|
-
await payments.ConfirmPaymentAsync(payload.Payment!.Id); break;
|
|
90
|
-
case "PAYMENT_OVERDUE":
|
|
91
|
-
await payments.MarkOverdueAsync(payload.Payment!.Id); break;
|
|
92
|
-
case "PAYMENT_REFUNDED":
|
|
93
|
-
await payments.RefundPaymentAsync(payload.Payment!.Id); break;
|
|
94
|
-
}
|
|
95
|
-
return Ok();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Environments
|
|
101
|
-
|
|
102
|
-
| Environment | Base URL |
|
|
103
|
-
|-------------|----------|
|
|
104
|
-
| Sandbox | `https://sandbox.asaas.com/api/v3` |
|
|
105
|
-
| Production | `https://www.asaas.com/api/v3` |
|
|
106
|
-
|
|
107
|
-
## Gotchas
|
|
108
|
-
|
|
109
|
-
| Issue | Fix |
|
|
110
|
-
|-------|-----|
|
|
111
|
-
| PIX QR Code returns Base64, NOT URL | `$"data:image/png;base64,{response.EncodedImage}"` |
|
|
112
|
-
| CPF required even in sandbox | Always include `cpfCnpj` in CreateCustomer |
|
|
113
|
-
| Missing `User-Agent` header | Add to HttpClient defaults |
|
|
114
|
-
| Date format must be `yyyy-MM-dd` | `DateTime.Today.AddDays(1).ToString("yyyy-MM-dd")` |
|
|
115
|
-
|
|
116
|
-
## Checklist
|
|
117
|
-
|
|
118
|
-
- [ ] API Key configured (not hardcoded)
|
|
119
|
-
- [ ] HttpClient with retry policy (Polly)
|
|
120
|
-
- [ ] Headers: `access_token` + `User-Agent`
|
|
121
|
-
- [ ] CPF/CNPJ always included for customers
|
|
122
|
-
- [ ] PIX QR Code → data URI conversion
|
|
123
|
-
- [ ] Dates in `yyyy-MM-dd` format
|
|
124
|
-
- [ ] Webhook endpoint + signature validation
|
|
125
|
-
- [ ] ExternalReference for reconciliation
|
|
126
|
-
- [ ] Tests with sandbox
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# Azure Identity (Microsoft Identity)
|
|
2
|
-
|
|
3
|
-
> **Layer:** 2 | **Load:** on-keyword | **Keywords:** identity, entra, azure ad, microsoft auth, msal, oauth, oidc, microsoft identity
|
|
4
|
-
|
|
5
|
-
Microsoft Identity Platform for .NET/Blazor. SDK: `Microsoft.Identity.Web`.
|
|
6
|
-
|
|
7
|
-
## Setup
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
dotnet add package Microsoft.Identity.Web
|
|
11
|
-
dotnet add package Microsoft.Identity.Web.UI # For Blazor
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
```json
|
|
15
|
-
// appsettings.json
|
|
16
|
-
{ "AzureAd": {
|
|
17
|
-
"Instance": "https://login.microsoftonline.com/",
|
|
18
|
-
"Domain": "yourdomain.onmicrosoft.com",
|
|
19
|
-
"TenantId": "your-tenant-id",
|
|
20
|
-
"ClientId": "your-client-id",
|
|
21
|
-
"ClientSecret": "${AZURE_AD_CLIENT_SECRET}",
|
|
22
|
-
"CallbackPath": "/signin-oidc"
|
|
23
|
-
} }
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
```csharp
|
|
27
|
-
// Program.cs
|
|
28
|
-
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
|
|
29
|
-
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
|
|
30
|
-
builder.Services.AddControllersWithViews().AddMicrosoftIdentityUI();
|
|
31
|
-
builder.Services.AddAuthorization();
|
|
32
|
-
app.UseAuthentication();
|
|
33
|
-
app.UseAuthorization();
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Blazor Server
|
|
37
|
-
|
|
38
|
-
```csharp
|
|
39
|
-
// Additional setup
|
|
40
|
-
builder.Services.AddServerSideBlazor().AddMicrosoftIdentityConsentHandler();
|
|
41
|
-
|
|
42
|
-
// App.razor
|
|
43
|
-
<CascadingAuthenticationState>
|
|
44
|
-
<Router AppAssembly="@typeof(App).Assembly">
|
|
45
|
-
<Found Context="routeData">
|
|
46
|
-
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
|
|
47
|
-
<NotAuthorized>
|
|
48
|
-
@if (!context.User.Identity?.IsAuthenticated ?? true) { <RedirectToLogin /> }
|
|
49
|
-
else { <p>No permission.</p> }
|
|
50
|
-
</NotAuthorized>
|
|
51
|
-
</AuthorizeRouteView>
|
|
52
|
-
</Found>
|
|
53
|
-
</Router>
|
|
54
|
-
</CascadingAuthenticationState>
|
|
55
|
-
|
|
56
|
-
// RedirectToLogin.razor
|
|
57
|
-
@inject NavigationManager Nav
|
|
58
|
-
@code {
|
|
59
|
-
protected override void OnInitialized() =>
|
|
60
|
-
Nav.NavigateTo($"MicrosoftIdentity/Account/SignIn?redirectUri={Uri.EscapeDataString(Nav.Uri)}", forceLoad: true);
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Protected Pages
|
|
65
|
-
|
|
66
|
-
```razor
|
|
67
|
-
@page "/secure"
|
|
68
|
-
@attribute [Authorize]
|
|
69
|
-
|
|
70
|
-
<AuthorizeView>
|
|
71
|
-
<Authorized>Welcome, @context.User.Identity?.Name!</Authorized>
|
|
72
|
-
</AuthorizeView>
|
|
73
|
-
|
|
74
|
-
<AuthorizeView Roles="Admin"><Authorized><AdminPanel /></Authorized></AuthorizeView>
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## API Protection
|
|
78
|
-
|
|
79
|
-
```csharp
|
|
80
|
-
// API Program.cs
|
|
81
|
-
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
82
|
-
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
|
|
83
|
-
|
|
84
|
-
// Controller
|
|
85
|
-
[ApiController, Route("api/[controller]"), Authorize]
|
|
86
|
-
public class ProfileController : ControllerBase
|
|
87
|
-
{
|
|
88
|
-
[HttpGet]
|
|
89
|
-
public IActionResult GetProfile() => Ok(new {
|
|
90
|
-
UserId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value,
|
|
91
|
-
Name = User.Identity?.Name
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
[HttpGet("admin"), Authorize(Roles = "Admin")]
|
|
95
|
-
public IActionResult AdminOnly() => Ok("Admin access");
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Downstream APIs (Microsoft Graph)
|
|
100
|
-
|
|
101
|
-
```csharp
|
|
102
|
-
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
|
|
103
|
-
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
|
|
104
|
-
.EnableTokenAcquisitionToCallDownstreamApi()
|
|
105
|
-
.AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
|
|
106
|
-
.AddInMemoryTokenCaches();
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## Authorization Policies
|
|
110
|
-
|
|
111
|
-
```csharp
|
|
112
|
-
builder.Services.AddAuthorization(o => {
|
|
113
|
-
o.AddPolicy("RequireAdmin", p => p.RequireRole("Admin"));
|
|
114
|
-
o.AddPolicy("RequireManager", p => p.RequireAssertion(c =>
|
|
115
|
-
c.User.IsInRole("Admin") || c.User.IsInRole("Manager")));
|
|
116
|
-
});
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Multi-tenant & B2C
|
|
120
|
-
|
|
121
|
-
```json
|
|
122
|
-
// Multi-tenant: TenantId = "common" or "organizations"
|
|
123
|
-
// Then validate allowed tenants in TokenValidationParameters.IssuerValidator
|
|
124
|
-
|
|
125
|
-
// B2C: Use "AzureAdB2C" section with SignUpSignInPolicyId, ResetPasswordPolicyId
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Checklist
|
|
129
|
-
|
|
130
|
-
- [ ] App registered in Azure Portal
|
|
131
|
-
- [ ] Client ID + Tenant ID configured
|
|
132
|
-
- [ ] Client Secret in Key Vault
|
|
133
|
-
- [ ] Redirect URIs configured
|
|
134
|
-
- [ ] API permissions defined
|
|
135
|
-
- [ ] Token caching configured
|
|
136
|
-
- [ ] Authorization policies created
|
|
137
|
-
- [ ] Logout flow implemented
|
|
138
|
-
- [ ] Token expiry error handling
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
*MORPH-SPEC by Polymorphism Tech*
|