@startanaicompany/cli 1.1.0 → 1.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 +145 -9
- package/README.md +75 -10
- package/bin/saac.js +59 -2
- package/create-application-update.md +759 -0
- package/package.json +2 -2
- package/src/commands/create.js +278 -4
- package/src/commands/init.js +160 -4
- package/src/commands/status.js +164 -4
- package/src/commands/update.js +284 -0
- package/src/lib/api.js +10 -0
- package/src/lib/config.js +8 -7
|
@@ -0,0 +1,759 @@
|
|
|
1
|
+
# Create Application Endpoint - Comprehensive Update
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-01-25
|
|
4
|
+
**Target**: SAAC CLI Team
|
|
5
|
+
**Endpoint**: `POST /api/v1/applications`
|
|
6
|
+
**Status**: ✅ MAJOR UPDATE - Tier-based resource limits, advanced configuration fields
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## What Changed?
|
|
11
|
+
|
|
12
|
+
The `POST /api/v1/applications` endpoint has been significantly enhanced with:
|
|
13
|
+
|
|
14
|
+
1. **Tier-Based Resource Limits** - Automatic CPU and memory limits based on user tier (free, starter, pro, enterprise)
|
|
15
|
+
2. **Advanced Build Configuration** - Support for Nixpacks, Dockerfile, Static builds (not just Docker Compose)
|
|
16
|
+
3. **Health Check Configuration** - Optional health checks for auto-restart and zero-downtime deployments
|
|
17
|
+
4. **Custom Commands** - Pre/post deployment hooks, custom install/build/start commands
|
|
18
|
+
5. **Resource Allocation** - Manual CPU/memory limits (enforced by tier)
|
|
19
|
+
6. **Field Renaming** - `gitea_username` → `git_username`, `gitea_api_token` → `git_api_token`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Tier-Based Resource Limits (NEW!)
|
|
24
|
+
|
|
25
|
+
### Overview
|
|
26
|
+
|
|
27
|
+
All applications now have **automatic resource limits** based on user tier to prevent resource exhaustion:
|
|
28
|
+
|
|
29
|
+
| Tier | CPU Limit | Memory Limit | Max Applications | Description |
|
|
30
|
+
|------------|-----------|--------------|------------------|-----------------------------------------------|
|
|
31
|
+
| **free** | 1 vCPU | 1024M (1GB) | 3 apps | Perfect for testing and small projects |
|
|
32
|
+
| **starter**| 2 vCPU | 2048M (2GB) | 10 apps | For small production apps |
|
|
33
|
+
| **pro** | 4 vCPU | 8192M (8GB) | 50 apps | For serious production workloads |
|
|
34
|
+
| **enterprise** | Unlimited | Unlimited | Unlimited | Custom resource allocation |
|
|
35
|
+
|
|
36
|
+
### How It Works
|
|
37
|
+
|
|
38
|
+
1. **Automatic Application** - When creating an app, the wrapper retrieves the user's tier from the database
|
|
39
|
+
2. **Default Limits Applied** - If user doesn't specify limits, tier defaults are applied
|
|
40
|
+
3. **Enforcement** - If user tries to exceed tier limits, wrapper caps at tier maximum
|
|
41
|
+
4. **Current Status** - All users are currently on the **free tier** (1GB RAM, 1 vCPU)
|
|
42
|
+
|
|
43
|
+
### Examples
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Free tier user - defaults to 1GB RAM, 1 vCPU (automatic)
|
|
47
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
48
|
+
-H "X-API-Key: $API_KEY" \
|
|
49
|
+
-H "Content-Type: application/json" \
|
|
50
|
+
-d '{
|
|
51
|
+
"name": "my-app",
|
|
52
|
+
"subdomain": "myapp",
|
|
53
|
+
...
|
|
54
|
+
}'
|
|
55
|
+
# Result: cpu_limit="1", memory_limit="1024M" (enforced by wrapper)
|
|
56
|
+
|
|
57
|
+
# Free tier user tries to request 4GB - capped at 1GB
|
|
58
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
59
|
+
-H "X-API-Key: $API_KEY" \
|
|
60
|
+
-H "Content-Type: application/json" \
|
|
61
|
+
-d '{
|
|
62
|
+
"name": "my-app",
|
|
63
|
+
"subdomain": "myapp",
|
|
64
|
+
"memory_limit": "4096M", # User requests 4GB
|
|
65
|
+
...
|
|
66
|
+
}'
|
|
67
|
+
# Result: memory_limit="1024M" (capped at tier limit)
|
|
68
|
+
|
|
69
|
+
# Pro tier user - can use up to 8GB RAM, 4 vCPU
|
|
70
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
71
|
+
-H "X-API-Key: $API_KEY" \
|
|
72
|
+
-H "Content-Type: application/json" \
|
|
73
|
+
-d '{
|
|
74
|
+
"name": "my-app",
|
|
75
|
+
"subdomain": "myapp",
|
|
76
|
+
"cpu_limit": "4",
|
|
77
|
+
"memory_limit": "8192M",
|
|
78
|
+
...
|
|
79
|
+
}'
|
|
80
|
+
# Result: Full allocation granted (within tier limits)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Complete Request Schema (Updated)
|
|
86
|
+
|
|
87
|
+
### Required Fields
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"name": "string (required, max 255)",
|
|
92
|
+
"subdomain": "string (required, lowercase alphanumeric + hyphens)",
|
|
93
|
+
"domain_suffix": "string (required, e.g., 'startanaicompany.com')",
|
|
94
|
+
"git_repository": "string (required, SSH format: git@...)",
|
|
95
|
+
"git_api_token": "string (required, min 40 chars)"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Optional Fields (NEW!)
|
|
100
|
+
|
|
101
|
+
#### Build & Deployment Configuration
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"git_branch": "string (default: 'master')",
|
|
106
|
+
"ports_exposes": "string (default: '3000', e.g., '3000', '8080', '3000,8080')",
|
|
107
|
+
"build_pack": "string (default: 'dockercompose')",
|
|
108
|
+
// Options: 'dockercompose', 'nixpacks', 'dockerfile', 'static'
|
|
109
|
+
|
|
110
|
+
"docker_compose_location": "string (default: 'docker-compose.yml')",
|
|
111
|
+
"dockerfile_location": "string (for Dockerfile builds)",
|
|
112
|
+
"static_directory": "string (for static builds)",
|
|
113
|
+
"base_directory": "string",
|
|
114
|
+
"publish_directory": "string"
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### Custom Commands (NEW!)
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"install_command": "string (max 1000 chars, e.g., 'pnpm install')",
|
|
123
|
+
"build_command": "string (max 1000 chars, e.g., 'npm run build:production')",
|
|
124
|
+
"start_command": "string (max 1000 chars, e.g., 'node dist/server.js')",
|
|
125
|
+
"pre_deployment_command": "string (max 1000 chars, e.g., 'npm run migrate')",
|
|
126
|
+
"post_deployment_command": "string (max 1000 chars, e.g., 'npm run seed')"
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Resource Limits (NEW!)
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"cpu_limit": "string (e.g., '1', '2.5')",
|
|
135
|
+
// Enforced by tier: free=1, starter=2, pro=4, enterprise=unlimited
|
|
136
|
+
|
|
137
|
+
"memory_limit": "string (e.g., '512M', '2G')",
|
|
138
|
+
// Enforced by tier: free=1024M, starter=2048M, pro=8192M, enterprise=unlimited
|
|
139
|
+
|
|
140
|
+
"memory_swap_limit": "string (e.g., '512M', '2G')",
|
|
141
|
+
"memory_swappiness": "number (0-100)"
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### Health Check Configuration (NEW!)
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"health_check_enabled": "boolean (default: false)",
|
|
150
|
+
"health_check_path": "string (default: '/health')",
|
|
151
|
+
"health_check_port": "number (1-65535)",
|
|
152
|
+
"health_check_interval": "number (seconds)",
|
|
153
|
+
"health_check_timeout": "number (seconds)",
|
|
154
|
+
"health_check_retries": "number (1-10)"
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### Other Configuration
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"template_type": "string (optional, max 100)",
|
|
163
|
+
"environment_variables": "object (max 50 keys)",
|
|
164
|
+
"restart": "string (options: 'always', 'on-failure', 'unless-stopped', 'no')"
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Complete Examples
|
|
171
|
+
|
|
172
|
+
### Example 1: Basic Docker Compose App (Free Tier)
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
176
|
+
-H "X-API-Key: cw_RJ1gH8Sd1nvmPF4lWigu2g3Nkjt1mwEJXYd2aycD0IIniNPhImE5XgWaz3Tcz" \
|
|
177
|
+
-H "Content-Type: application/json" \
|
|
178
|
+
-d '{
|
|
179
|
+
"name": "my-app",
|
|
180
|
+
"subdomain": "myapp",
|
|
181
|
+
"domain_suffix": "startanaicompany.com",
|
|
182
|
+
"git_repository": "git@git.startanaicompany.com:username/repo.git",
|
|
183
|
+
"git_branch": "main",
|
|
184
|
+
"git_api_token": "7a4821935f9b8304bc2b6380af51d36a97978e4d"
|
|
185
|
+
}'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Result**: App deployed with:
|
|
189
|
+
- `build_pack`: "dockercompose" (default)
|
|
190
|
+
- `ports_exposes`: "3000" (default)
|
|
191
|
+
- `cpu_limit`: "1" (free tier default)
|
|
192
|
+
- `memory_limit`: "1024M" (free tier default)
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### Example 2: Node.js App with Nixpacks (Automatic Detection)
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
200
|
+
-H "X-API-Key: $API_KEY" \
|
|
201
|
+
-H "Content-Type: application/json" \
|
|
202
|
+
-d '{
|
|
203
|
+
"name": "nodejs-app",
|
|
204
|
+
"subdomain": "nodeapp",
|
|
205
|
+
"domain_suffix": "startanaicompany.com",
|
|
206
|
+
"git_repository": "git@git.startanaicompany.com:username/nodejs-repo.git",
|
|
207
|
+
"git_api_token": "your_token",
|
|
208
|
+
"build_pack": "nixpacks",
|
|
209
|
+
"ports_exposes": "8080",
|
|
210
|
+
"start_command": "node server.js"
|
|
211
|
+
}'
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Result**: Nixpacks automatically detects Node.js, runs `npm install`, builds, and starts with custom command.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### Example 3: Production App with Health Checks & Pre-Deployment Migration
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
222
|
+
-H "X-API-Key: $API_KEY" \
|
|
223
|
+
-H "Content-Type: application/json" \
|
|
224
|
+
-d '{
|
|
225
|
+
"name": "production-api",
|
|
226
|
+
"subdomain": "api",
|
|
227
|
+
"domain_suffix": "startanaicompany.com",
|
|
228
|
+
"git_repository": "git@git.startanaicompany.com:username/api.git",
|
|
229
|
+
"git_api_token": "your_token",
|
|
230
|
+
"build_pack": "dockercompose",
|
|
231
|
+
"ports_exposes": "3000",
|
|
232
|
+
"pre_deployment_command": "npm run migrate",
|
|
233
|
+
"health_check_enabled": true,
|
|
234
|
+
"health_check_path": "/api/health",
|
|
235
|
+
"health_check_interval": 30,
|
|
236
|
+
"health_check_retries": 3,
|
|
237
|
+
"restart": "always",
|
|
238
|
+
"environment_variables": {
|
|
239
|
+
"NODE_ENV": "production",
|
|
240
|
+
"LOG_LEVEL": "info"
|
|
241
|
+
}
|
|
242
|
+
}'
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Result**:
|
|
246
|
+
- Runs `npm run migrate` before deployment
|
|
247
|
+
- Health check on `/api/health` every 30 seconds
|
|
248
|
+
- Auto-restarts if health check fails 3 times
|
|
249
|
+
- Resource limits: 1GB RAM, 1 vCPU (free tier)
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### Example 4: Custom Port Python App
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
257
|
+
-H "X-API-Key: $API_KEY" \
|
|
258
|
+
-H "Content-Type: application/json" \
|
|
259
|
+
-d '{
|
|
260
|
+
"name": "python-api",
|
|
261
|
+
"subdomain": "pyapi",
|
|
262
|
+
"domain_suffix": "startanaicompany.com",
|
|
263
|
+
"git_repository": "git@git.startanaicompany.com:username/python-api.git",
|
|
264
|
+
"git_api_token": "your_token",
|
|
265
|
+
"build_pack": "dockerfile",
|
|
266
|
+
"dockerfile_location": "Dockerfile.prod",
|
|
267
|
+
"ports_exposes": "5000"
|
|
268
|
+
}'
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Result**: Builds using `Dockerfile.prod`, exposes port 5000, with free tier limits.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
### Example 5: Static Site with Custom Directory
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
279
|
+
-H "X-API-Key: $API_KEY" \
|
|
280
|
+
-H "Content-Type: application/json" \
|
|
281
|
+
-d '{
|
|
282
|
+
"name": "landing-page",
|
|
283
|
+
"subdomain": "landing",
|
|
284
|
+
"domain_suffix": "startanaicompany.com",
|
|
285
|
+
"git_repository": "git@git.startanaicompany.com:username/landing.git",
|
|
286
|
+
"git_api_token": "your_token",
|
|
287
|
+
"build_pack": "static",
|
|
288
|
+
"build_command": "npm run build",
|
|
289
|
+
"publish_directory": "dist",
|
|
290
|
+
"ports_exposes": "80"
|
|
291
|
+
}'
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Result**: Builds static site, serves from `dist/` directory.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Field Renaming (BREAKING CHANGE)
|
|
299
|
+
|
|
300
|
+
### Changed Field Names
|
|
301
|
+
|
|
302
|
+
| Old Name | New Name | Impact |
|
|
303
|
+
|---------------------|-------------------|-------------------------------------------------|
|
|
304
|
+
| `gitea_username` | `git_username` | ⚠️ Update registration payload |
|
|
305
|
+
| `gitea_api_token` | `git_api_token` | ⚠️ Update application creation payload |
|
|
306
|
+
|
|
307
|
+
### Migration Guide
|
|
308
|
+
|
|
309
|
+
**Before** (deprecated):
|
|
310
|
+
```json
|
|
311
|
+
{
|
|
312
|
+
"email": "user@example.com",
|
|
313
|
+
"gitea_username": "myusername",
|
|
314
|
+
"gitea_api_token": "token123"
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**After** (new):
|
|
319
|
+
```json
|
|
320
|
+
{
|
|
321
|
+
"email": "user@example.com",
|
|
322
|
+
"git_username": "myusername",
|
|
323
|
+
"git_api_token": "token123"
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**CLI Update Required**:
|
|
328
|
+
1. Update `POST /api/v1/register` - use `git_username` instead of `gitea_username`
|
|
329
|
+
2. Update `POST /api/v1/applications` - use `git_api_token` instead of `gitea_api_token`
|
|
330
|
+
3. Update `GET /api/v1/users/me` - expect `git_username` in response
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Response Format (Updated)
|
|
335
|
+
|
|
336
|
+
```json
|
|
337
|
+
{
|
|
338
|
+
"id": 42,
|
|
339
|
+
"coolify_app_uuid": "vgsc0gcwgso8wwggc08sc8kw",
|
|
340
|
+
"coolify_project_uuid": "abc123...",
|
|
341
|
+
"app_name": "my-app",
|
|
342
|
+
"subdomain": "myapp",
|
|
343
|
+
"domain": "https://myapp.startanaicompany.com",
|
|
344
|
+
"created_at": "2026-01-25T10:30:00.000Z",
|
|
345
|
+
"webhook_url": "https://apps.startanaicompany.com/api/v1/webhooks/deploy/vgsc0gcwgso8wwggc08sc8kw",
|
|
346
|
+
"deployment_status": "creating",
|
|
347
|
+
"next_steps": [
|
|
348
|
+
"Configure webhook in your Git repository",
|
|
349
|
+
"Push to trigger automatic deployment",
|
|
350
|
+
"Monitor logs: GET /api/v1/applications/vgsc0gcwgso8wwggc08sc8kw/logs"
|
|
351
|
+
]
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Error Handling
|
|
358
|
+
|
|
359
|
+
### Tier Limit Exceeded
|
|
360
|
+
|
|
361
|
+
**Scenario**: Free tier user tries to create 4th application (limit is 3).
|
|
362
|
+
|
|
363
|
+
**Response**:
|
|
364
|
+
```json
|
|
365
|
+
{
|
|
366
|
+
"error": "Application limit reached. You have 3 active applications (maximum: 3).",
|
|
367
|
+
"code": "QUOTA_EXCEEDED",
|
|
368
|
+
"current_tier": "free",
|
|
369
|
+
"upgrade_info": "Contact support to upgrade your tier"
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Invalid Port Format
|
|
374
|
+
|
|
375
|
+
**Scenario**: User provides invalid `ports_exposes` value.
|
|
376
|
+
|
|
377
|
+
**Response**:
|
|
378
|
+
```json
|
|
379
|
+
{
|
|
380
|
+
"error": "Validation failed",
|
|
381
|
+
"details": {
|
|
382
|
+
"ports_exposes": "Ports must be comma-separated numbers (e.g., \"3000\" or \"3000,8080\")"
|
|
383
|
+
},
|
|
384
|
+
"code": "VALIDATION_ERROR"
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Invalid Build Pack
|
|
389
|
+
|
|
390
|
+
**Scenario**: User provides unsupported build pack.
|
|
391
|
+
|
|
392
|
+
**Response**:
|
|
393
|
+
```json
|
|
394
|
+
{
|
|
395
|
+
"error": "Validation failed",
|
|
396
|
+
"details": {
|
|
397
|
+
"build_pack": "Build pack must be one of: dockercompose, nixpacks, dockerfile, static"
|
|
398
|
+
},
|
|
399
|
+
"code": "VALIDATION_ERROR"
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Testing Scenarios
|
|
406
|
+
|
|
407
|
+
### Test 1: Verify Tier Limits (Free Tier)
|
|
408
|
+
|
|
409
|
+
**Goal**: Confirm free tier users get 1GB RAM, 1 vCPU limits.
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
# Create app without specifying limits
|
|
413
|
+
API_KEY="cw_RJ1gH8Sd1nvmPF4lWigu2g3Nkjt1mwEJXYd2aycD0IIniNPhImE5XgWaz3Tcz"
|
|
414
|
+
|
|
415
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
416
|
+
-H "X-API-Key: $API_KEY" \
|
|
417
|
+
-H "Content-Type: application/json" \
|
|
418
|
+
-d '{
|
|
419
|
+
"name": "tier-test-app",
|
|
420
|
+
"subdomain": "tiertest",
|
|
421
|
+
"domain_suffix": "startanaicompany.com",
|
|
422
|
+
"git_repository": "git@git.startanaicompany.com:username/test.git",
|
|
423
|
+
"git_api_token": "token123"
|
|
424
|
+
}'
|
|
425
|
+
|
|
426
|
+
# Expected Result:
|
|
427
|
+
# - Check wrapper logs for: "Prepared Coolify config with tier limits"
|
|
428
|
+
# - Verify logs show: cpu_limit="1", memory_limit="1024M"
|
|
429
|
+
# - Query Coolify API to confirm application has these limits set
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Verification**:
|
|
433
|
+
```bash
|
|
434
|
+
# Check Coolify application details
|
|
435
|
+
curl -s https://app.coolify.io/api/v1/applications/{app_uuid} \
|
|
436
|
+
-H "Authorization: Bearer ${COOLIFY_API_TOKEN}" \
|
|
437
|
+
| jq '{cpu_limit, memory_limit}'
|
|
438
|
+
|
|
439
|
+
# Expected output:
|
|
440
|
+
# {
|
|
441
|
+
# "cpu_limit": "1",
|
|
442
|
+
# "memory_limit": "1024M"
|
|
443
|
+
# }
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
### Test 2: Verify Tier Enforcement
|
|
449
|
+
|
|
450
|
+
**Goal**: Confirm free tier user cannot exceed 1GB RAM limit.
|
|
451
|
+
|
|
452
|
+
```bash
|
|
453
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
454
|
+
-H "X-API-Key: $API_KEY" \
|
|
455
|
+
-H "Content-Type: application/json" \
|
|
456
|
+
-d '{
|
|
457
|
+
"name": "exceed-limit-test",
|
|
458
|
+
"subdomain": "exceedtest",
|
|
459
|
+
"domain_suffix": "startanaicompany.com",
|
|
460
|
+
"git_repository": "git@git.startanaicompany.com:username/test.git",
|
|
461
|
+
"git_api_token": "token123",
|
|
462
|
+
"memory_limit": "4096M",
|
|
463
|
+
"cpu_limit": "4"
|
|
464
|
+
}'
|
|
465
|
+
|
|
466
|
+
# Expected Result:
|
|
467
|
+
# - Wrapper caps at tier limits: cpu_limit="1", memory_limit="1024M"
|
|
468
|
+
# - No error returned (silent capping)
|
|
469
|
+
# - Logs show: "Applied tier limits: free"
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
### Test 3: Custom Build Pack (Nixpacks)
|
|
475
|
+
|
|
476
|
+
**Goal**: Verify non-Docker Compose builds work.
|
|
477
|
+
|
|
478
|
+
```bash
|
|
479
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
480
|
+
-H "X-API-Key: $API_KEY" \
|
|
481
|
+
-H "Content-Type: application/json" \
|
|
482
|
+
-d '{
|
|
483
|
+
"name": "nixpacks-test",
|
|
484
|
+
"subdomain": "nixtest",
|
|
485
|
+
"domain_suffix": "startanaicompany.com",
|
|
486
|
+
"git_repository": "git@git.startanaicompany.com:username/nodejs-app.git",
|
|
487
|
+
"git_api_token": "token123",
|
|
488
|
+
"build_pack": "nixpacks",
|
|
489
|
+
"ports_exposes": "8080"
|
|
490
|
+
}'
|
|
491
|
+
|
|
492
|
+
# Expected Result:
|
|
493
|
+
# - Application created with build_pack="nixpacks"
|
|
494
|
+
# - Coolify uses Nixpacks to detect and build Node.js app
|
|
495
|
+
# - Port 8080 exposed (not default 3000)
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
### Test 4: Health Checks Enabled
|
|
501
|
+
|
|
502
|
+
**Goal**: Verify health check configuration is passed to Coolify.
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
506
|
+
-H "X-API-Key: $API_KEY" \
|
|
507
|
+
-H "Content-Type: application/json" \
|
|
508
|
+
-d '{
|
|
509
|
+
"name": "health-check-test",
|
|
510
|
+
"subdomain": "healthtest",
|
|
511
|
+
"domain_suffix": "startanaicompany.com",
|
|
512
|
+
"git_repository": "git@git.startanaicompany.com:username/api.git",
|
|
513
|
+
"git_api_token": "token123",
|
|
514
|
+
"health_check_enabled": true,
|
|
515
|
+
"health_check_path": "/api/health",
|
|
516
|
+
"health_check_interval": 30
|
|
517
|
+
}'
|
|
518
|
+
|
|
519
|
+
# Verification:
|
|
520
|
+
curl -s https://app.coolify.io/api/v1/applications/{app_uuid} \
|
|
521
|
+
-H "Authorization: Bearer ${COOLIFY_API_TOKEN}" \
|
|
522
|
+
| jq '{health_check_enabled, health_check_path, health_check_interval}'
|
|
523
|
+
|
|
524
|
+
# Expected output:
|
|
525
|
+
# {
|
|
526
|
+
# "health_check_enabled": true,
|
|
527
|
+
# "health_check_path": "/api/health",
|
|
528
|
+
# "health_check_interval": 30
|
|
529
|
+
# }
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
### Test 5: Pre-Deployment Command
|
|
535
|
+
|
|
536
|
+
**Goal**: Verify pre-deployment hooks run before deployment.
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
curl -X POST https://apps.startanaicompany.com/api/v1/applications \
|
|
540
|
+
-H "X-API-Key: $API_KEY" \
|
|
541
|
+
-H "Content-Type: application/json" \
|
|
542
|
+
-d '{
|
|
543
|
+
"name": "migration-test",
|
|
544
|
+
"subdomain": "migtest",
|
|
545
|
+
"domain_suffix": "startanaicompany.com",
|
|
546
|
+
"git_repository": "git@git.startanaicompany.com:username/db-app.git",
|
|
547
|
+
"git_api_token": "token123",
|
|
548
|
+
"pre_deployment_command": "npm run migrate"
|
|
549
|
+
}'
|
|
550
|
+
|
|
551
|
+
# Verification:
|
|
552
|
+
# - Deploy the application: POST /api/v1/applications/{uuid}/deploy
|
|
553
|
+
# - Check deployment logs: GET /api/v1/applications/{uuid}/logs
|
|
554
|
+
# - Verify logs show: "Running pre-deployment command: npm run migrate"
|
|
555
|
+
# - Confirm migration ran before app started
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Summary of Changes for CLI Team
|
|
561
|
+
|
|
562
|
+
### Action Items
|
|
563
|
+
|
|
564
|
+
1. **Update field names** in all API calls:
|
|
565
|
+
- `gitea_username` → `git_username`
|
|
566
|
+
- `gitea_api_token` → `git_api_token`
|
|
567
|
+
|
|
568
|
+
2. **Add support for new optional fields**:
|
|
569
|
+
- `ports_exposes` - Allow users to specify custom ports
|
|
570
|
+
- `build_pack` - Allow selection of build method (dockercompose, nixpacks, dockerfile, static)
|
|
571
|
+
- `pre_deployment_command` - For database migrations
|
|
572
|
+
- `health_check_enabled` - For production deployments
|
|
573
|
+
|
|
574
|
+
3. **Update documentation**:
|
|
575
|
+
- Explain tier-based resource limits (all users start on free tier: 1GB RAM, 1 vCPU)
|
|
576
|
+
- Document new build pack options
|
|
577
|
+
- Add examples for health checks and deployment hooks
|
|
578
|
+
|
|
579
|
+
4. **Testing**:
|
|
580
|
+
- Test creating apps with custom ports (e.g., 8080, 5000)
|
|
581
|
+
- Test Nixpacks build (simple Node.js app without docker-compose.yml)
|
|
582
|
+
- Verify tier limits are applied (check Coolify app config after creation)
|
|
583
|
+
- Test pre-deployment command (migration scenario)
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## Questions?
|
|
588
|
+
|
|
589
|
+
If you have any questions about these changes, please:
|
|
590
|
+
|
|
591
|
+
1. Check the updated OpenAPI docs at: https://apps.startanaicompany.com/api-docs
|
|
592
|
+
2. Review the wrapper source code at: `src/services/application.js`, `src/utils/validators.js`
|
|
593
|
+
3. Test against the live wrapper API: https://apps.startanaicompany.com
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## UPDATE Configuration Endpoint (NEW!)
|
|
598
|
+
|
|
599
|
+
### Endpoint: `PATCH /api/v1/applications/:uuid`
|
|
600
|
+
|
|
601
|
+
**Status**: ✅ **IMPLEMENTED** (2026-01-25)
|
|
602
|
+
|
|
603
|
+
All configuration fields that can be set during creation can now be **updated after deployment** using this endpoint.
|
|
604
|
+
|
|
605
|
+
### Use Cases
|
|
606
|
+
|
|
607
|
+
- Change port from 3000 to 8080
|
|
608
|
+
- Switch from Docker Compose to Nixpacks build
|
|
609
|
+
- Enable/disable health checks
|
|
610
|
+
- Adjust resource limits (within tier constraints)
|
|
611
|
+
- Update custom build commands
|
|
612
|
+
- Change restart policy
|
|
613
|
+
|
|
614
|
+
### Request Format
|
|
615
|
+
|
|
616
|
+
```bash
|
|
617
|
+
PATCH https://apps.startanaicompany.com/api/v1/applications/{app_uuid}
|
|
618
|
+
Content-Type: application/json
|
|
619
|
+
X-API-Key: cw_...
|
|
620
|
+
|
|
621
|
+
{
|
|
622
|
+
"ports_exposes": "8080",
|
|
623
|
+
"health_check_enabled": true,
|
|
624
|
+
"health_check_path": "/health",
|
|
625
|
+
"cpu_limit": "2",
|
|
626
|
+
"memory_limit": "2048M"
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### All Updatable Fields
|
|
631
|
+
|
|
632
|
+
```json
|
|
633
|
+
{
|
|
634
|
+
// Basic fields
|
|
635
|
+
"name": "my-updated-app-name",
|
|
636
|
+
"git_branch": "develop",
|
|
637
|
+
"environment_variables": { "KEY": "value" },
|
|
638
|
+
|
|
639
|
+
// Build & Deployment
|
|
640
|
+
"ports_exposes": "8080",
|
|
641
|
+
"build_pack": "nixpacks",
|
|
642
|
+
"docker_compose_location": "docker-compose.prod.yml",
|
|
643
|
+
"dockerfile_location": "Dockerfile.prod",
|
|
644
|
+
"static_directory": "dist",
|
|
645
|
+
|
|
646
|
+
// Custom Commands
|
|
647
|
+
"install_command": "npm ci",
|
|
648
|
+
"build_command": "npm run build:prod",
|
|
649
|
+
"start_command": "npm run start:prod",
|
|
650
|
+
"pre_deployment_command": "npm run migrate",
|
|
651
|
+
"post_deployment_command": "npm run seed",
|
|
652
|
+
|
|
653
|
+
// Resource Limits (capped at tier limits!)
|
|
654
|
+
"cpu_limit": "2",
|
|
655
|
+
"memory_limit": "2048M",
|
|
656
|
+
"memory_swap_limit": "2048M",
|
|
657
|
+
"memory_swappiness": 60,
|
|
658
|
+
|
|
659
|
+
// Health Checks
|
|
660
|
+
"health_check_enabled": true,
|
|
661
|
+
"health_check_path": "/api/health",
|
|
662
|
+
"health_check_port": 8080,
|
|
663
|
+
"health_check_interval": 30,
|
|
664
|
+
"health_check_timeout": 5,
|
|
665
|
+
"health_check_retries": 3,
|
|
666
|
+
|
|
667
|
+
// Restart Policy
|
|
668
|
+
"restart": "on-failure"
|
|
669
|
+
}
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### Response Format
|
|
673
|
+
|
|
674
|
+
```json
|
|
675
|
+
{
|
|
676
|
+
"success": true,
|
|
677
|
+
"message": "Application configuration updated successfully",
|
|
678
|
+
"uuid": "vgsc0gcwgso8wwggc08sc8kw",
|
|
679
|
+
"updated_fields": [
|
|
680
|
+
"ports_exposes",
|
|
681
|
+
"health_check_enabled",
|
|
682
|
+
"health_check_path"
|
|
683
|
+
],
|
|
684
|
+
"applied_tier_limits": false
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### Important Notes
|
|
689
|
+
|
|
690
|
+
1. **Tier Limits Enforced**: Resource limits (CPU/memory) are capped at user's tier maximum
|
|
691
|
+
2. **Partial Updates**: You only need to send fields you want to update (not all fields)
|
|
692
|
+
3. **Redeploy Required**: After updating configuration, you must redeploy for changes to take effect:
|
|
693
|
+
```bash
|
|
694
|
+
POST /api/v1/applications/{uuid}/deploy
|
|
695
|
+
```
|
|
696
|
+
4. **Free Tier Users**: Any CPU/memory requests above 1 vCPU / 1GB will be capped automatically
|
|
697
|
+
|
|
698
|
+
### Example: Update Port and Enable Health Checks
|
|
699
|
+
|
|
700
|
+
```bash
|
|
701
|
+
# 1. Update configuration
|
|
702
|
+
curl -X PATCH "https://apps.startanaicompany.com/api/v1/applications/vgsc0gcwgso8wwggc08sc8kw" \
|
|
703
|
+
-H "X-API-Key: $API_KEY" \
|
|
704
|
+
-H "Content-Type: application/json" \
|
|
705
|
+
-d '{
|
|
706
|
+
"ports_exposes": "8080",
|
|
707
|
+
"health_check_enabled": true,
|
|
708
|
+
"health_check_path": "/health"
|
|
709
|
+
}'
|
|
710
|
+
|
|
711
|
+
# 2. Redeploy to apply changes
|
|
712
|
+
curl -X POST "https://apps.startanaicompany.com/api/v1/applications/vgsc0gcwgso8wwggc08sc8kw/deploy" \
|
|
713
|
+
-H "X-API-Key: $API_KEY"
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### Example: Try to Exceed Tier Limits (Free Tier)
|
|
717
|
+
|
|
718
|
+
```bash
|
|
719
|
+
# Free tier user tries to request 4 vCPU and 4GB RAM
|
|
720
|
+
curl -X PATCH "https://apps.startanaicompany.com/api/v1/applications/vgsc0gcwgso8wwggc08sc8kw" \
|
|
721
|
+
-H "X-API-Key: $API_KEY" \
|
|
722
|
+
-H "Content-Type: application/json" \
|
|
723
|
+
-d '{
|
|
724
|
+
"cpu_limit": "4",
|
|
725
|
+
"memory_limit": "4096M"
|
|
726
|
+
}'
|
|
727
|
+
|
|
728
|
+
# Response: Limits will be capped at 1 vCPU / 1GB
|
|
729
|
+
{
|
|
730
|
+
"success": true,
|
|
731
|
+
"message": "Application configuration updated successfully",
|
|
732
|
+
"uuid": "vgsc0gcwgso8wwggc08sc8kw",
|
|
733
|
+
"updated_fields": ["cpu_limit", "memory_limit"],
|
|
734
|
+
"applied_tier_limits": true // ← Indicates limits were capped
|
|
735
|
+
}
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
### CLI Implementation Suggestion
|
|
739
|
+
|
|
740
|
+
```bash
|
|
741
|
+
# saac update <app> [options]
|
|
742
|
+
saac update my-app \
|
|
743
|
+
--port 8080 \
|
|
744
|
+
--health-check \
|
|
745
|
+
--health-path /api/health \
|
|
746
|
+
--cpu 2 \
|
|
747
|
+
--memory 2G
|
|
748
|
+
|
|
749
|
+
# Example output:
|
|
750
|
+
# ✓ Configuration updated (3 fields changed)
|
|
751
|
+
# ⚠ Resource limits capped at your tier (free: 1 vCPU, 1GB)
|
|
752
|
+
# ℹ Run 'saac deploy my-app' to apply changes
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
**Generated**: 2026-01-25
|
|
758
|
+
**Author**: Coolify Wrapper Team
|
|
759
|
+
**Version**: 2.1.0 (Added PATCH endpoint)
|