You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .agents/skills/smbcloud-deploy-monorepo/SKILL.md
+68-27Lines changed: 68 additions & 27 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,7 +18,18 @@ Applies to:
18
18
19
19
## What makes a monorepo
20
20
21
-
A monorepo is a repository where `[project]` has `runner = 255` (the `Monorepo` variant) and deployable sub-projects are listed as `[[projects]]` entries. The root project is never deployed directly — it is a container.
21
+
A monorepo is a repository where `[project]` has `runner = 255` (the `Monorepo` variant) and deployable targets are listed as `[[projects]]` entries. The root project is never deployed directly — it is a container.
22
+
23
+
Keep the deploy hierarchy straight:
24
+
25
+
- root `[project]` = umbrella workspace in smbCloud (not deployable)
26
+
- repo = the monorepo itself, represented by a `DeployRepo` record
27
+
- each `[[projects]]` entry = one deployable `FrontendApp` inside that repo, identified by `frontend_app_id`
28
+
- each deployment record = one release of one `FrontendApp`, linked via `frontend_app_id`
29
+
30
+
The canonical chain is: Deployment → FrontendApp → DeployRepo → Project
31
+
32
+
The config format still uses `[[projects]]` for historical reasons, but conceptually those entries are app targets, not separate umbrella workspaces. Each entry should include `frontend_app_id` and `deploy_repo_id` so deployments are attributed to the correct app.
|`kind`| depends | deploy strategy: `"nextjs-ssr"`, `"vite-spa"`, `"rails"`, or omitted for generic deploy |
140
+
|`package_manager`| depends |`"pnpm"` or `"npm"` — required for `nextjs-ssr` and `vite-spa`|
141
+
|`pm2_app`| depends | PM2 process name — required for `nextjs-ssr`|
142
+
|`port`| depends | runtime port — required for `nextjs-ssr`, defaults to `3000` if omitted |
143
+
|`output`| depends | build output directory — required for `vite-spa`, typically `"dist"`|
144
+
|`shared_lib`| no | path to shared library directory to rsync before deploy — used by `rails`|
145
+
|`compile_cmd`| no | SSH command to run on the server after syncing shared libs — used by `rails`|
146
+
|`deployment_method`| no |`0` (Git) or `1` (Rsync) — only matters when `kind` is not set |
147
+
|`created_at`| yes | ISO 8601 timestamp |
148
+
|`updated_at`| yes | ISO 8601 timestamp |
132
149
133
150
## Deploy routing
134
151
@@ -163,7 +180,7 @@ smb deploy --project <name>
163
180
164
181
### Strategy: `nextjs-ssr`
165
182
166
-
Local build, rsync three directories, SSH PM2 restart. See `smbcloud-deploy-nextjs` skill for details.
183
+
Local build, rsync three directories, then SSH delete + fresh PM2 start (prefer server `ecosystem.config.js` when present). See `smbcloud-deploy-nextjs` skill for details.
@@ -427,7 +448,14 @@ All CI rsync commands must include:
427
448
428
449
### CI PM2 restart
429
450
430
-
The CI restart command must use `pm2 restart <app> --update-env` on subsequent deploys so environment variable changes from the ecosystem file are picked up. Without `--update-env`, PM2 keeps the environment from the original `pm2 start` invocation.
451
+
Current CI and CLI parity should use delete + fresh start, not restart-in-place:
452
+
453
+
- `pm2 delete <app>`if it exists
454
+
- `pm2 start ecosystem.config.js --only <app> --env production`when the server file exists
455
+
- otherwise fall back to `PORT=<port> HOSTNAME=127.0.0.1 pm2 start node --name <app> -- server.js`
456
+
- `pm2 save`
457
+
458
+
This matches the standalone Next.js deploy model and avoids stale PM2 command state from older deploy methods.
431
459
432
460
## Deployment tracking
433
461
@@ -437,6 +465,11 @@ Every deploy records status in the smbCloud API regardless of strategy:
437
465
2. `PATCH /deployments/:id` with `status: Done` on success
438
466
3. `PATCH /deployments/:id` with `status: Failed` on failure
439
467
468
+
Current tracking model in the CLI:
469
+
470
+
- requests still route through the umbrella workspace `id`
471
+
- when `frontend_app_id` is present in the deploy target config, the payload also carries it so the API can attribute the deploy to the correct app inside the repo or monorepo
472
+
440
473
For non-git deploys (rsync, nextjs-ssr, vite-spa), the `commit_hash` field is a UTC timestamp (`20250920T163305Z`) since there is no git commit on the deploy path.
441
474
442
475
## Adding a new sub-project to a monorepo
@@ -496,7 +529,13 @@ The Nginx `alias` directive for `/_next/static/` or the `root` for a Vite SPA po
496
529
497
530
### PM2 not picking up new environment variables
498
531
499
-
Use `pm2 restart <app> --update-env && pm2 save`. Without `--update-env`, PM2 reuses the environment from the original start.
532
+
Current CLI parity is delete + fresh start. Check these in order:
533
+
534
+
1. the server's `ecosystem.config.js` was edited, not just the repo copy
535
+
2. the deploy script is actually starting from `ecosystem.config.js`
536
+
3. `pm2 save` ran after the fresh start
537
+
538
+
If you are changing env manually outside the deploy flow, `pm2 restart <app> --update-env && pm2 save` is still a valid operator command.
500
539
501
540
## Validation
502
541
@@ -530,5 +569,7 @@ Use `pm2 restart <app> --update-env && pm2 save`. Without `--update-env`, PM2 re
530
569
- forgetting `--mkpath` on rsync in CI workflows — first deploys fail because the remote directory does not exist
531
570
- keeping stale Nginx configs pointing at old deploy paths after migrating to a new directory structure
532
571
- mixing up `path` (remote destination) and `source` (local directory) — they serve different purposes
533
-
- using `pm2 restart` without `--update-env` after changing ecosystem file variables
572
+
- treating the root workspace id as the deployable app id
573
+
- forgetting to add `frontend_app_id` on `[[projects]]` entries once the API exposes it
574
+
- using `pm2 restart` without `--update-env` after changing ecosystem file variables in older restart-in-place workflows
534
575
- assuming the CLI generates Nginx configs — it does not; Nginx is always configured manually on the server
Copy file name to clipboardExpand all lines: .agents/skills/smbcloud-deploy-nextjs/SKILL.md
+52-18Lines changed: 52 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,7 +9,7 @@ Use this skill when work touches Next.js deployment on smbCloud.
9
9
10
10
Applies to:
11
11
12
-
-`kind = "nextjs-ssr"`projects
12
+
-`kind = "nextjs-ssr"`deploy targets
13
13
-`.smb/config.toml` deploy configuration
14
14
-`process_deploy_nextjs_ssr.rs`
15
15
- PM2 process management for standalone builds
@@ -18,6 +18,15 @@ Applies to:
18
18
19
19
## Deployment model
20
20
21
+
Keep the deploy hierarchy straight:
22
+
23
+
-`Project` = umbrella workspace in smbCloud (not deployable)
24
+
-`DeployRepo` = the git repository inside that workspace
25
+
-`FrontendApp` = the deployable app unit, identified by `frontend_app_id` in config
26
+
-`Deployment` = one release event, linked to a FrontendApp via `frontend_app_id`
27
+
28
+
The canonical chain is: Deployment → FrontendApp → DeployRepo → Project
29
+
21
30
For `nextjs-ssr`, smbCloud does not use git-push deploy.
22
31
23
32
The CLI route in `process_deploy.rs` short-circuits on:
@@ -62,20 +71,28 @@ Minimum `.smb/config.toml` for SSR:
62
71
63
72
```toml
64
73
[project]
74
+
id = 28# workspace id (for API routing)
75
+
frontend_app_id = "uuid"# FrontendApp id (for deployment tracking)
76
+
deploy_repo_id = 123# DeployRepo id (links to git repository record)
65
77
deployment_method = 1
66
78
kind = "nextjs-ssr"
67
79
source = "."
68
80
package_manager = "pnpm"
69
81
pm2_app = "my-app"
70
82
path = "apps/web/my-app"
83
+
port = 3028
71
84
```
72
85
73
86
Important rules:
74
87
75
88
-`kind = "nextjs-ssr"` is what activates the SSR deploy path
89
+
-`id` is the umbrella workspace ID, used for auth and API routing
90
+
-`frontend_app_id` identifies the FrontendApp record for this deploy target — include it so deployments are attributed to the correct app, not just the workspace
91
+
-`deploy_repo_id` identifies the DeployRepo record backing this app — include it when available
76
92
-`source` is the local Next.js app directory
77
93
-`path` is the remote destination directory on the server
78
94
-`pm2_app` is mandatory because the CLI restarts PM2 by name
95
+
-`port` should be set explicitly and must match nginx
79
96
-`deployment_method = 1` may still be present, but the `kind` routing is what matters most
80
97
81
98
## Expected remote layout
@@ -90,15 +107,23 @@ Note that `server.js` is expected at the remote root because the CLI uploads the
90
107
91
108
## PM2 behavior
92
109
93
-
The CLI's deploy path runs logic equivalent to:
110
+
The CLI's deploy path now deletes and starts fresh, preferring the server's
111
+
`ecosystem.config.js` when it exists.
112
+
113
+
Conceptually it behaves like:
94
114
95
115
```sh
96
116
cd"$APP_PATH"
117
+
mkdir -p logs
97
118
98
119
if pm2 describe "$PM2_APP"> /dev/null 2>&1;then
99
-
pm2 restart "$PM2_APP"
120
+
pm2 delete "$PM2_APP"
121
+
fi
122
+
123
+
if [ -f ecosystem.config.js ];then
124
+
pm2 start ecosystem.config.js --only "$PM2_APP" --env production
2. Every subsequent CLI deploy runs `pm2 restart <pm2_app>`. Because `pm2 save` already persisted the env, PM2 restarts with the same environment â **the CLI does not need to know about the ecosystem file at all**.
170
+
2. Every subsequent CLI deploy deletes the PM2 process and starts it fresh. If the server has `ecosystem.config.js`, the CLI starts PM2 from that file again. If not, it falls back to `node server.js` with inline `NODE_ENV`, `PORT`, and `HOSTNAME`.
145
171
146
172
3. To change or add env vars, SSH in, edit `ecosystem.config.js`, then:
147
173
@@ -150,23 +176,26 @@ The flow works like this:
150
176
pm2 save
151
177
```
152
178
153
-
The ecosystem file is the server-side source of truth for each appâs runtime config. Future versions of the smbCloud web console will provide a UI to manage these vars per app, which will write to this file and trigger the restart remotely.
179
+
The ecosystem file is the server-side source of truth for each app's runtime config. The CLI preserves the server copy during rsync and must not delete it.
@@ -181,9 +210,11 @@ If an older `ecosystem.config.js` exists and contains both:
181
210
182
211
that is a broken configuration. Standardize on one port value.
183
212
184
-
For the current SSR deploy code, the real runtime is controlled by the environment passed to `node server.js`, not by `next start` or an ecosystem file.
213
+
Current rules:
185
214
186
-
If the app must run on a port other than `3010`, patch the CLI or restart PM2 manually with the correct port.
215
+
- fallback fresh-start path uses `port` from `.smb/config.toml`
216
+
- ecosystem-managed apps should set the same port in `env_production.PORT`
217
+
- nginx upstream must match that port
187
218
188
219
## Nginx for SSR
189
220
@@ -253,12 +284,12 @@ If the project has no `public/` directory, deploy may fail. Either:
253
284
254
285
Cause:
255
286
256
-
- CLI hardcodes `PORT=3010` for fresh starts
287
+
- `port` in `.smb/config.toml`, server `ecosystem.config.js`, and nginx upstream disagree
257
288
258
289
Fix:
259
290
260
-
- manually restart with the correct port
261
-
- or patch the CLI to read a configurable port from `.smb/config.toml`
291
+
- standardize the same port in all three places
292
+
- if using ecosystem config, make sure PM2 is actually starting from that file
262
293
263
294
### Misleading deploy output
264
295
@@ -325,6 +356,9 @@ Use the smallest checks that prove the contract.
325
356
- forgetting `kind = "nextjs-ssr"`
326
357
- keeping an old git `post-receive` hook and expecting it to manage SSR deploys
327
358
- using static-file Nginx config for an SSR app
328
-
- editing `ecosystem.config.js` but forgetting `pm2 restart <app> --update-env && pm2 save` â PM2 keeps the old env until explicitly refreshed
329
-
- leaving port values inconsistent across PM2, Nginx, and CLI
359
+
- editing the repo copy of `ecosystem.config.js` and expecting a normal CLI deploy to overwrite the server copy — it is preserved intentionally
360
+
- editing the server `ecosystem.config.js` but the deploy script falling back to inline `node server.js` because the file path check is wrong
361
+
- leaving port values inconsistent across PM2, Nginx, and `.smb/config.toml`
362
+
- forgetting to set `frontend_app_id` on the deploy target once app-level deployment tracking is available
330
363
- treating browser CORS failures as real internet outages
364
+
- deploying without `frontend_app_id` in config — the API will try to infer the app, but explicit is better than implicit
0 commit comments