@polymorphism-tech/morph-spec 7.4.0 → 7.6.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 (66) hide show
  1. package/README.md +2 -2
  2. package/bin/morph-spec.js +18 -0
  3. package/claude-plugin.json +1 -1
  4. package/docs/CHEATSHEET.md +1 -1
  5. package/docs/QUICKSTART.md +1 -1
  6. package/framework/CLAUDE.md +9 -4
  7. package/framework/MORPH.md +4 -4
  8. package/framework/agents.json +1 -1
  9. package/framework/commands/create-umbraco-lp.md +35 -0
  10. package/framework/commands/migrate-lp-to-umbraco.md +33 -0
  11. package/framework/commands/morph-archive.md +17 -27
  12. package/framework/commands/morph-preflight.md +10 -5
  13. package/framework/hooks/claude-code/core/enforce-phase-writes.js +115 -90
  14. package/framework/hooks/claude-code/core/protect-spec-files.js +32 -30
  15. package/framework/hooks/claude-code/core/state-sync.js +16 -48
  16. package/framework/hooks/shared/state-reader.js +74 -8
  17. package/framework/hooks/shared/state-writer.js +124 -0
  18. package/framework/rules/infrastructure-standards.md +4 -4
  19. package/framework/rules/morph-task-tracking.md +69 -49
  20. package/framework/rules/morph-workflow.md +192 -191
  21. package/framework/skills/core/create-umbraco-lp/SKILL.md +272 -0
  22. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +531 -0
  23. package/framework/skills/core/morph-apply/SKILL.md +15 -15
  24. package/framework/skills/core/morph-brainstorming/SKILL.md +5 -5
  25. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  26. package/framework/skills/core/morph-implement/SKILL.md +5 -4
  27. package/framework/skills/core/morph-plan/SKILL.md +6 -6
  28. package/framework/skills/core/morph-proposal/SKILL.md +8 -7
  29. package/framework/skills/core/morph-review/SKILL.md +3 -3
  30. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  31. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  32. package/framework/standards/STANDARDS.json +80 -8
  33. package/framework/standards/ai-agents/durable-workflows-hitl.md +191 -0
  34. package/framework/standards/ai-agents/rag-custom-pgvector.md +246 -243
  35. package/framework/standards/ai-agents/setup.md +3 -0
  36. package/framework/standards/ai-agents/vector-data-extensions.md +170 -0
  37. package/framework/standards/ai-agents/workflows.md +190 -187
  38. package/framework/standards/infrastructure/docker/{easypanel-deploy.md → coolify-deploy.md} +49 -20
  39. package/framework/templates/README.md +7 -7
  40. package/framework/templates/REGISTRY.json +15 -17
  41. package/framework/templates/context/CONTEXT-FEATURE.md +10 -17
  42. package/framework/templates/context/CONTEXT.md +181 -180
  43. package/framework/templates/docs/onboarding.md +122 -118
  44. package/framework/templates/docs/proposal.md +12 -2
  45. package/framework/templates/docs/spec.md +228 -228
  46. package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +1 -1
  47. package/framework/templates/infrastructure/docker/coolify.template.json +49 -0
  48. package/framework/templates/infrastructure/github/README.md +6 -6
  49. package/framework/templates/infrastructure/github/workflows/deploy-coolify.yml.hbs +33 -0
  50. package/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -80
  51. package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +90 -89
  52. package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +2 -1
  53. package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +44 -43
  54. package/framework/templates/meta-prompts/validators/checkpoint-validator.md +107 -107
  55. package/package.json +1 -1
  56. package/src/commands/project/update.js +415 -368
  57. package/src/commands/project/worktree.js +212 -210
  58. package/src/commands/state/advance.js +82 -0
  59. package/src/commands/state/archive.js +111 -0
  60. package/src/commands/validation/validate-feature.js +229 -105
  61. package/src/core/state/state-manager.js +238 -66
  62. package/src/dashboard/scanner/state-scanner.js +35 -8
  63. package/src/lib/generators/context-generator.js +12 -8
  64. package/src/utils/file-copier.js +7 -0
  65. package/framework/templates/infrastructure/docker/easypanel.template.json +0 -46
  66. package/framework/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +0 -31
@@ -1,228 +1,228 @@
1
- # Feature Specification: {{titleCase FEATURE_NAME}}
2
-
3
- | Field | Value |
4
- |-------|-------|
5
- | **ID** | {{FEATURE_NAME}} |
6
- | **Status** | Draft / In Review / Approved / In Progress / Done |
7
- | **Created** | {{DATE}} |
8
- | **Stack** | {{STACK}} |
9
- | **Complexity** | Low / Medium / High |
10
- | **Estimated Cost** | $X/month |
11
- | **Agents** | Core: All / Specialists: {list} |
12
-
13
- ---
14
-
15
- ## Overview
16
-
17
- **Problem:** {What problem this feature solves}
18
-
19
- **Solution:** {High-level solution}
20
-
21
- **Success Criteria:**
22
- - [ ] {Criterion 1}
23
- - [ ] {Criterion 2}
24
-
25
- ---
26
-
27
- ## Requirements
28
-
29
- **Functional:** FR1: {desc} | FR2: {desc} | FR3: {desc}
30
-
31
- **Non-Functional:** NFR1: Performance - {target} | NFR2: Reliability - {target}
32
-
33
- ---
34
-
35
- ## User Stories
36
-
37
- ### US001: {Title}
38
- **As** {user type} **I want** {feature} **so that** {benefit}
39
-
40
- **Acceptance Criteria:** 1. {criterion} 2. {criterion}
41
-
42
- **Edge Cases:** {edge case}: {handling}
43
-
44
- ---
45
-
46
- ## Technical Design
47
-
48
- ### Stack
49
- | Component | Technology |
50
- |-----------|------------|
51
- | Frontend | {Next.js / .NET 10} |
52
- | Backend | .NET 10 / C# 14 |
53
- | Database | {Azure SQL / Cosmos DB} |
54
-
55
- ### Data Model
56
-
57
- #### {EntityName}
58
- | Column | Type | Constraints |
59
- |--------|------|-------------|
60
- | Id | Guid | PK |
61
- | {Property} | {Type} | {Constraints} |
62
- | CreatedAt | datetime2 | Default: GETUTCDATE() |
63
-
64
- ### Contracts
65
-
66
- ```csharp
67
- public interface I{{pascalCase FEATURE_NAME}}Service
68
- {
69
- Task<{{pascalCase FEATURE_NAME}}Dto> GetByIdAsync(int id);
70
- Task<{{pascalCase FEATURE_NAME}}Dto> CreateAsync(Create{{pascalCase FEATURE_NAME}}Request request);
71
- }
72
- ```
73
-
74
- **Contracts Workflow:** Generate `contracts.cs` FIRST → validate names → reference in spec → approve with user.
75
-
76
- **Validation Checklist:**
77
- - [ ] Property names are descriptive (not generic "Data", "Value")
78
- - [ ] Records use correct types (Stream vs byte[], Guid vs string)
79
- - [ ] Response DTOs have all properties needed for UI
80
- - [ ] Request DTOs have implicit validations (required, nullable)
81
-
82
- ---
83
-
84
- ## Domain Complexity
85
-
86
- **Nível:** {1 — CRUD / 2 — Business Logic / 3 — Bounded Context}
87
-
88
- **Justificativa:** {Por que este nível foi escolhido — mencionar invariants, eventos ou BCs se Nível 2+}
89
-
90
- **Padrões Aplicados:**
91
- - {Nível 1: Entity simples, Service CRUD, DTOs}
92
- - {Nível 2: AggregateRoot, Value Objects, Domain Events, CQRS}
93
- - {Nível 3: Bounded Context isolation, cross-BC events, Linguagem Ubíqua}
94
-
95
- **Padrões Omitidos:**
96
- - {ex: Bounded Contexts — sistema single-domain}
97
-
98
- ---
99
-
100
- ## Architecture Style: Vertical Slice
101
-
102
- > Preencher SOMENTE se `config.architecture.style === "vertical-slice"`. Omitir em projetos DDD.
103
-
104
- **Architecture Style:** Vertical Slice Architecture (VSA)
105
-
106
- **Entity Fields:**
107
- | Field | Type | Constraints |
108
- |-------|------|-------------|
109
- | Id | Guid | PK, `Guid.CreateVersion7()` |
110
- | {Field} | {C# Type} | {Required / Optional / Unique} |
111
- | CreatedAt | DateTimeOffset | Auto |
112
-
113
- **Operations:**
114
- | Slice | HTTP | Route | Has Validator |
115
- |-------|------|-------|---------------|
116
- | Create{Entity} | POST | {ROUTE} | Yes |
117
- | GetAll{Entity}s | GET | {ROUTE} | No |
118
- | Get{Entity}ById | GET | {ROUTE}/{id} | Yes |
119
- | Update{Entity} | PUT | {ROUTE}/{id} | Yes |
120
- | Delete{Entity} | DELETE | {ROUTE}/{id} | Yes |
121
-
122
- **Error Types ({Entity}Errors):**
123
- - `{Entity}Errors.{ErrorName}()` — {description}
124
-
125
- **Validation Rules:**
126
- | Field | Rules |
127
- |-------|-------|
128
- | {Field} | NotEmpty(), MaxLength({N}), {etc.} |
129
-
130
- ---
131
-
132
- ## Aggregate Blueprint (Nível 2+ apenas)
133
-
134
- > Omitir esta seção se Nível 1 (CRUD) ou se Architecture Style = Vertical Slice.
135
-
136
- ### Aggregate Root: {EntityName}
137
-
138
- **Invariants:**
139
- - {Invariant 1 em linguagem natural}
140
- - {Invariant 2}
141
-
142
- **Estados e Transições:**
143
- ```
144
- {Status.Draft} → Confirm() → {Status.Confirmed} → Cancel() → {Status.Cancelled}
145
- ```
146
-
147
- **Domain Events:**
148
- - `{EntityName}CreatedEvent` — publicado ao criar
149
- - `{EntityName}StatusChangedEvent` — publicado em mudança de estado
150
-
151
- **Value Objects:**
152
- - `{ValueObjectName}` — {por que não é primitivo simples}
153
-
154
- **Referências Cross-Aggregate (por ID):**
155
- - `{OtherEntity}Id: Guid`
156
-
157
- ### Linguagem Ubíqua
158
-
159
- | Termo | Definição | Código |
160
- |-------|-----------|--------|
161
- | {Termo} | {Definição do negócio} | `{ClassName.MethodName()}` |
162
-
163
- ---
164
-
165
- ## UI/UX Design (if front-end)
166
-
167
- ### Wireframes
168
- ```
169
- {ASCII wireframe per screen - include states: loading, error, empty}
170
- ```
171
-
172
- ### User Flow
173
- 1. {Step} → {System response}
174
-
175
- ---
176
-
177
- ## Flows
178
-
179
- ### {Flow Name}
180
- **Trigger:** {what starts this flow}
181
- 1. {Actor} {action} → {system response}
182
- 2. If {condition}: Path A / Else: Path B
183
- **End State:** {final state}
184
-
185
- ---
186
-
187
- ## Cost Estimate
188
-
189
- | Resource | SKU | Monthly Cost | Justification |
190
- |----------|-----|--------------|---------------|
191
- | {Resource} | {SKU} | ${X} | {Why} |
192
- | **Total** | | **${X}/month** | |
193
-
194
- ---
195
-
196
- ## ADRs (Architectural Decision Records)
197
-
198
- ### ADR-001: {Decision Title}
199
- **Status:** Proposed / Accepted
200
- **Context:** {Why decide now}
201
- **Decision:** {What we chose}
202
- **Alternatives:** 1. {Alt} (pros/cons) 2. {Alt} (pros/cons)
203
- **Trade-offs:** {key trade-offs}
204
-
205
- ---
206
-
207
- ## Security
208
-
209
- | Action | Required Policy |
210
- |--------|-----------------|
211
- | View | CanView{Feature} |
212
- | Create | CanManage{Feature} |
213
-
214
- ## Risks
215
-
216
- | Risk | Impact | Mitigation |
217
- |------|--------|------------|
218
- | {Risk} | {H/M/L} | {Mitigation} |
219
-
220
- ## Out of Scope
221
- - {Item}
222
-
223
- ## Definition of Done
224
- - [ ] Code implemented
225
- - [ ] Tests >80% coverage
226
- - [ ] Code review approved
227
- - [ ] Deploy to staging
228
- - [ ] Recap.md generated
1
+ # Feature Specification: {{titleCase FEATURE_NAME}}
2
+
3
+ | Field | Value |
4
+ |-------|-------|
5
+ | **ID** | {{FEATURE_NAME}} |
6
+ | **Status** | Draft / In Review / Approved / In Progress / Done |
7
+ | **Created** | {{DATE}} |
8
+ | **Stack** | {{STACK}} |
9
+ | **Complexity** | Low / Medium / High |
10
+ | **Estimated Cost** | $X/month |
11
+ | **Agents** | Core: All / Specialists: {list} |
12
+
13
+ ---
14
+
15
+ ## Overview
16
+
17
+ **Problem:** {What problem this feature solves}
18
+
19
+ **Solution:** {High-level solution}
20
+
21
+ **Success Criteria:**
22
+ - [ ] {Criterion 1}
23
+ - [ ] {Criterion 2}
24
+
25
+ ---
26
+
27
+ ## Requirements
28
+
29
+ **Functional:** FR1: {desc} | FR2: {desc} | FR3: {desc}
30
+
31
+ **Non-Functional:** NFR1: Performance - {target} | NFR2: Reliability - {target}
32
+
33
+ ---
34
+
35
+ ## User Stories
36
+
37
+ ### US001: {Title}
38
+ **As** {user type} **I want** {feature} **so that** {benefit}
39
+
40
+ **Acceptance Criteria:** 1. {criterion} 2. {criterion}
41
+
42
+ **Edge Cases:** {edge case}: {handling}
43
+
44
+ ---
45
+
46
+ ## Technical Architecture
47
+
48
+ ### Stack
49
+ | Component | Technology |
50
+ |-----------|------------|
51
+ | Frontend | {Next.js / .NET 10} |
52
+ | Backend | .NET 10 / C# 14 |
53
+ | Database | {Azure SQL / Cosmos DB} |
54
+
55
+ ### Data Model
56
+
57
+ #### {EntityName}
58
+ | Column | Type | Constraints |
59
+ |--------|------|-------------|
60
+ | Id | Guid | PK |
61
+ | {Property} | {Type} | {Constraints} |
62
+ | CreatedAt | datetime2 | Default: GETUTCDATE() |
63
+
64
+ ### Contracts
65
+
66
+ ```csharp
67
+ public interface I{{pascalCase FEATURE_NAME}}Service
68
+ {
69
+ Task<{{pascalCase FEATURE_NAME}}Dto> GetByIdAsync(int id);
70
+ Task<{{pascalCase FEATURE_NAME}}Dto> CreateAsync(Create{{pascalCase FEATURE_NAME}}Request request);
71
+ }
72
+ ```
73
+
74
+ **Contracts Workflow:** Generate `contracts.cs` FIRST → validate names → reference in spec → approve with user.
75
+
76
+ **Validation Checklist:**
77
+ - [ ] Property names are descriptive (not generic "Data", "Value")
78
+ - [ ] Records use correct types (Stream vs byte[], Guid vs string)
79
+ - [ ] Response DTOs have all properties needed for UI
80
+ - [ ] Request DTOs have implicit validations (required, nullable)
81
+
82
+ ---
83
+
84
+ ## Domain Complexity
85
+
86
+ **Nível:** {1 — CRUD / 2 — Business Logic / 3 — Bounded Context}
87
+
88
+ **Justificativa:** {Por que este nível foi escolhido — mencionar invariants, eventos ou BCs se Nível 2+}
89
+
90
+ **Padrões Aplicados:**
91
+ - {Nível 1: Entity simples, Service CRUD, DTOs}
92
+ - {Nível 2: AggregateRoot, Value Objects, Domain Events, CQRS}
93
+ - {Nível 3: Bounded Context isolation, cross-BC events, Linguagem Ubíqua}
94
+
95
+ **Padrões Omitidos:**
96
+ - {ex: Bounded Contexts — sistema single-domain}
97
+
98
+ ---
99
+
100
+ ## Architecture Style: Vertical Slice
101
+
102
+ > Preencher SOMENTE se `config.architecture.style === "vertical-slice"`. Omitir em projetos DDD.
103
+
104
+ **Architecture Style:** Vertical Slice Architecture (VSA)
105
+
106
+ **Entity Fields:**
107
+ | Field | Type | Constraints |
108
+ |-------|------|-------------|
109
+ | Id | Guid | PK, `Guid.CreateVersion7()` |
110
+ | {Field} | {C# Type} | {Required / Optional / Unique} |
111
+ | CreatedAt | DateTimeOffset | Auto |
112
+
113
+ **Operations:**
114
+ | Slice | HTTP | Route | Has Validator |
115
+ |-------|------|-------|---------------|
116
+ | Create{Entity} | POST | {ROUTE} | Yes |
117
+ | GetAll{Entity}s | GET | {ROUTE} | No |
118
+ | Get{Entity}ById | GET | {ROUTE}/{id} | Yes |
119
+ | Update{Entity} | PUT | {ROUTE}/{id} | Yes |
120
+ | Delete{Entity} | DELETE | {ROUTE}/{id} | Yes |
121
+
122
+ **Error Types ({Entity}Errors):**
123
+ - `{Entity}Errors.{ErrorName}()` — {description}
124
+
125
+ **Validation Rules:**
126
+ | Field | Rules |
127
+ |-------|-------|
128
+ | {Field} | NotEmpty(), MaxLength({N}), {etc.} |
129
+
130
+ ---
131
+
132
+ ## Aggregate Blueprint (Nível 2+ apenas)
133
+
134
+ > Omitir esta seção se Nível 1 (CRUD) ou se Architecture Style = Vertical Slice.
135
+
136
+ ### Aggregate Root: {EntityName}
137
+
138
+ **Invariants:**
139
+ - {Invariant 1 em linguagem natural}
140
+ - {Invariant 2}
141
+
142
+ **Estados e Transições:**
143
+ ```
144
+ {Status.Draft} → Confirm() → {Status.Confirmed} → Cancel() → {Status.Cancelled}
145
+ ```
146
+
147
+ **Domain Events:**
148
+ - `{EntityName}CreatedEvent` — publicado ao criar
149
+ - `{EntityName}StatusChangedEvent` — publicado em mudança de estado
150
+
151
+ **Value Objects:**
152
+ - `{ValueObjectName}` — {por que não é primitivo simples}
153
+
154
+ **Referências Cross-Aggregate (por ID):**
155
+ - `{OtherEntity}Id: Guid`
156
+
157
+ ### Linguagem Ubíqua
158
+
159
+ | Termo | Definição | Código |
160
+ |-------|-----------|--------|
161
+ | {Termo} | {Definição do negócio} | `{ClassName.MethodName()}` |
162
+
163
+ ---
164
+
165
+ ## UI/UX Design (if front-end)
166
+
167
+ ### Wireframes
168
+ ```
169
+ {ASCII wireframe per screen - include states: loading, error, empty}
170
+ ```
171
+
172
+ ### User Flow
173
+ 1. {Step} → {System response}
174
+
175
+ ---
176
+
177
+ ## Flows
178
+
179
+ ### {Flow Name}
180
+ **Trigger:** {what starts this flow}
181
+ 1. {Actor} {action} → {system response}
182
+ 2. If {condition}: Path A / Else: Path B
183
+ **End State:** {final state}
184
+
185
+ ---
186
+
187
+ ## Cost Estimate
188
+
189
+ | Resource | SKU | Monthly Cost | Justification |
190
+ |----------|-----|--------------|---------------|
191
+ | {Resource} | {SKU} | ${X} | {Why} |
192
+ | **Total** | | **${X}/month** | |
193
+
194
+ ---
195
+
196
+ ## ADRs (Architectural Decision Records)
197
+
198
+ ### ADR-001: {Decision Title}
199
+ **Status:** Proposed / Accepted
200
+ **Context:** {Why decide now}
201
+ **Decision:** {What we chose}
202
+ **Alternatives:** 1. {Alt} (pros/cons) 2. {Alt} (pros/cons)
203
+ **Trade-offs:** {key trade-offs}
204
+
205
+ ---
206
+
207
+ ## Security
208
+
209
+ | Action | Required Policy |
210
+ |--------|-----------------|
211
+ | View | CanView{Feature} |
212
+ | Create | CanManage{Feature} |
213
+
214
+ ## Risks
215
+
216
+ | Risk | Impact | Mitigation |
217
+ |------|--------|------------|
218
+ | {Risk} | {H/M/L} | {Mitigation} |
219
+
220
+ ## Out of Scope
221
+ - {Item}
222
+
223
+ ## Definition of Done
224
+ - [ ] Code implemented
225
+ - [ ] Tests >80% coverage
226
+ - [ ] Code review approved
227
+ - [ ] Deploy to staging
228
+ - [ ] Recap.md generated
@@ -1,4 +1,4 @@
1
- # Multi-stage Next.js production build for EasyPanel
1
+ # Multi-stage Next.js production build for Coolify
2
2
  # Stage 1: Dependencies
3
3
  FROM node:20-alpine AS deps
4
4
  RUN apk add --no-cache libc6-compat
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "{{kebabCase FEATURE_NAME}}",
3
+ "provider": "coolify",
4
+ "access": {
5
+ "method": "ssh",
6
+ "note": "No MCP/CLI exists for Coolify — replace sshHost with the real SSH alias for the target VPS. The API is reached only from inside the VPS, at apiBaseUrl.",
7
+ "sshHost": "REPLACE_WITH_VPS_SSH_ALIAS",
8
+ "apiBaseUrl": "http://localhost:8000/api/v1",
9
+ "tokenPath": "~/.coolify-token"
10
+ },
11
+ "application": {
12
+ "uuid": "REPLACE_WITH_COOLIFY_APPLICATION_UUID",
13
+ "projectUuid": "REPLACE_WITH_COOLIFY_PROJECT_UUID",
14
+ "serverUuid": "REPLACE_WITH_COOLIFY_SERVER_UUID"
15
+ },
16
+ "source": {
17
+ "type": "github",
18
+ "owner": "{{GITHUB_OWNER}}",
19
+ "repo": "{{GITHUB_REPO}}",
20
+ "branch": "main",
21
+ "autoDeploy": true
22
+ },
23
+ "build": {
24
+ "type": "dockerfile",
25
+ "dockerfile": "Dockerfile"
26
+ },
27
+ "deploy": {
28
+ "replicas": 1,
29
+ "zeroDowntime": true
30
+ },
31
+ "env": [
32
+ {
33
+ "key": "NODE_ENV",
34
+ "value": "production"
35
+ },
36
+ {
37
+ "key": "DATABASE_URL",
38
+ "value": "${DATABASE_URL}"
39
+ }
40
+ ],
41
+ "domains": [
42
+ {
43
+ "host": "{{kebabCase FEATURE_NAME}}.example.com",
44
+ "port": 3000,
45
+ "https": true
46
+ }
47
+ ],
48
+ "deployCommand": "ssh REPLACE_WITH_VPS_SSH_ALIAS 'T=$(cat ~/.coolify-token); curl -s -X GET -H \"Authorization: Bearer $T\" \"http://localhost:8000/api/v1/deploy?uuid=REPLACE_WITH_COOLIFY_APPLICATION_UUID\"'"
49
+ }
@@ -1,16 +1,16 @@
1
1
  # GitHub Actions Templates for MORPH-SPEC
2
2
 
3
- > **Framework-Level CI/CD Templates for EasyPanel/Docker Deployments**
3
+ > **Framework-Level CI/CD Templates for Coolify/Docker Deployments**
4
4
 
5
5
  ## Overview
6
6
 
7
- Reusable GitHub Actions workflows and composite actions for the **nextjs-neon** stack (EasyPanel/Docker deployment).
7
+ Reusable GitHub Actions workflows and composite actions for the **nextjs-neon** stack (Coolify/Docker deployment).
8
8
 
9
9
  **Key Features:**
10
10
  - Handlebars v2.0 templating with helpers
11
11
  - Composite actions for shared logic
12
12
  - Docker multi-stage builds (.NET API + Next.js Web)
13
- - EasyPanel webhook deployment
13
+ - Coolify deployment via SSH (no MCP/CLI exists — the Coolify API is not publicly exposed, so the runner SSHes into the VPS to trigger it)
14
14
 
15
15
  ---
16
16
 
@@ -21,7 +21,7 @@ infrastructure/github/
21
21
  ├── workflows/
22
22
  │ ├── dotnet-build.yml.hbs # .NET restore, build, test, coverage
23
23
  │ ├── docker-build-push.yml.hbs # Docker build & push to registry
24
- │ └── deploy-easypanel.yml.hbs # EasyPanel deployment via webhook
24
+ │ └── deploy-coolify.yml.hbs # Coolify deployment via SSH
25
25
  │
26
26
  └── actions/
27
27
  ├── docker-build-push/action.yml.hbs # Build & push Docker image
@@ -38,8 +38,8 @@ infrastructure/github/
38
38
  - Multi-stage Docker build
39
39
  - Push to container registry (GHCR or Docker Hub)
40
40
 
41
- ### Deploy EasyPanel (`deploy-easypanel.yml.hbs`)
42
- - Triggers EasyPanel webhook after Docker push
41
+ ### Deploy Coolify (`deploy-coolify.yml.hbs`)
42
+ - SSHes into the VPS and calls the local Coolify API (`localhost:8000/api/v1/deploy?uuid=...`) after Docker push
43
43
  - Runs health check after deployment
44
44
  - Supports staging + production environments
45
45
 
@@ -0,0 +1,33 @@
1
+ name: Deploy to Coolify
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ environment:
7
+ required: true
8
+ type: string
9
+ image:
10
+ required: true
11
+ type: string
12
+
13
+ jobs:
14
+ deploy:
15
+ runs-on: ubuntu-latest
16
+ environment: ${{{{ inputs.environment }}}}
17
+ steps:
18
+ - name: Configure SSH
19
+ run: |
20
+ mkdir -p ~/.ssh
21
+ echo "${{{{ secrets.COOLIFY_SSH_KEY }}}}" > ~/.ssh/id_ed25519
22
+ chmod 600 ~/.ssh/id_ed25519
23
+ ssh-keyscan -H ${{{{ secrets.COOLIFY_SSH_HOST }}}} >> ~/.ssh/known_hosts
24
+
25
+ - name: Trigger Coolify Deploy (via SSH — the Coolify API is not publicly exposed)
26
+ run: |
27
+ ssh -i ~/.ssh/id_ed25519 ${{{{ secrets.COOLIFY_SSH_USER }}}}@${{{{ secrets.COOLIFY_SSH_HOST }}}} \
28
+ 'T=$(cat ~/.coolify-token); curl -s -X GET -H "Authorization: Bearer $T" "http://localhost:8000/api/v1/deploy?uuid=${{{{ secrets.COOLIFY_APPLICATION_UUID }}}}"'
29
+
30
+ - name: Health Check
31
+ run: |
32
+ sleep 30 # Wait for deployment
33
+ curl --retry 10 --retry-delay 5 --retry-connrefused ${{{{ secrets.APP_URL }}}}/health