prizmkit 1.1.51 → 1.1.53
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/bundled/VERSION.json +3 -3
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/prizmkit-deploy/SKILL.md +139 -167
- package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +115 -0
- package/bundled/skills/prizmkit-deploy/references/database-setup.md +46 -0
- package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +1 -0
- package/bundled/skills/prizmkit-deploy/references/deployment-modes.md +50 -0
- package/bundled/skills/prizmkit-deploy/references/direct-upload.md +26 -0
- package/bundled/skills/prizmkit-deploy/references/dns-setup.md +42 -0
- package/bundled/skills/prizmkit-deploy/references/firewall-setup.md +37 -0
- package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +21 -0
- package/bundled/skills/prizmkit-deploy/references/ssl-setup.md +56 -0
- package/package.json +1 -1
package/bundled/VERSION.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "prizmkit-deploy"
|
|
3
|
-
description: "Universal deployment gateway for any PrizmKit project. Discovers project type and target (SSH server, Vercel, Docker, etc.), then routes: full automation for SSH Linux with PM2 + Nginx + blue/green switching, guided setup for cloud platforms, or safe documentation fallback for unsupported targets. Also operates existing deployments: status, logs, restart, rollback, health checks, history.
|
|
3
|
+
description: "Universal deployment gateway for any PrizmKit project. Discovers project type and target (SSH server, Vercel, Docker, etc.), then routes: full automation for SSH Linux with PM2 + Nginx + blue/green switching, guided setup for cloud platforms, or safe documentation fallback for unsupported targets. Also operates existing deployments: status, logs, restart, rollback, health checks, history, validate. Use this skill whenever the user asks about deployment, hosting, going live, or server operations. Triggers on: 'deploy', 'ship it', 'take this live', 'deploy to Vercel', 'deploy to my server', 'check deploy status', 'view logs', 'restart app', 'rollback', 'how do I deploy this', any deployment or hosting question."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# PrizmKit Deploy — Universal Deployment Gateway
|
|
@@ -73,26 +73,12 @@ If headless mode and no target can be determined, exit with `NEEDS_INPUT` listin
|
|
|
73
73
|
|
|
74
74
|
Based on detected target, route the rest of the session:
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Vercel / Netlify → §Cloud Platform Deployment Path (guided)
|
|
82
|
-
detect CLI tools, walk through deploy commands,
|
|
83
|
-
generate deploy.md with platform-specific steps
|
|
84
|
-
|
|
85
|
-
Docker → §Docker Deployment Path (guided)
|
|
86
|
-
detect Dockerfile/Compose, build image,
|
|
87
|
-
container lifecycle (run, stop, logs, restart)
|
|
88
|
-
|
|
89
|
-
Unsupported → §Unsupported Deployment Fallback
|
|
90
|
-
generate deploy.md with detected info,
|
|
91
|
-
record missing adapter gap,
|
|
92
|
-
provide manual deployment checklist
|
|
93
|
-
```
|
|
76
|
+
1. **SSH Linux server** → §SSH Deployment Path — full automation: bootstrap, configure, deploy, operate. First-version adapter: PM2 + Nginx + blue/green.
|
|
77
|
+
2. **Vercel / Netlify** → §Cloud Platform Deployment Path — guided: detect CLI tools, walk through deploy commands, generate deploy.md. Details in `references/cloud-platform-deploy.md`.
|
|
78
|
+
3. **Docker** → §Docker Deployment Path — guided: detect Dockerfile/Compose, build image, container lifecycle. Details in `references/docker-deploy.md`.
|
|
79
|
+
4. **Unsupported** → §Unsupported Deployment Fallback — generate deploy.md, record adapter gap, provide manual checklist.
|
|
94
80
|
|
|
95
|
-
|
|
81
|
+
Cloud and Docker paths follow the same discovery and documentation patterns but use platform CLIs instead of SSH + PM2.
|
|
96
82
|
|
|
97
83
|
**Compatibility check before routing to SSH**: The SSH adapter (PM2 + Nginx + blue/green) requires a Node.js project — verify `package.json` exists. Non-Node.js projects (Go, Rust, Python) targeting a Linux server route to Unsupported Fallback with a note: "Adapter gap: PM2 adapter requires Node.js."
|
|
98
84
|
|
|
@@ -101,18 +87,11 @@ The SSH path is fully documented in the sections below. Cloud and Docker paths f
|
|
|
101
87
|
When the deployment target or project type isn't covered by any adapter, don't fail silently. Instead:
|
|
102
88
|
|
|
103
89
|
1. **Detect what you can**: project language, framework, build/start commands, env vars, port usage, database dependencies.
|
|
104
|
-
2. **Generate `.prizmkit/deploy/deploy.md`**: human-readable deployment guide with
|
|
105
|
-
|
|
106
|
-
- Environment variables table (detected from code scan)
|
|
107
|
-
- Build and start instructions
|
|
108
|
-
- Health check suggestions
|
|
109
|
-
- Platform-specific tips if the target is partially recognized
|
|
110
|
-
3. **Record the adapter gap**: write a note in deploy.md and deploy-history identifying what's missing (e.g., "Adapter needed: Python/FastAPI on systemd", "Adapter needed: Go binary deployment").
|
|
90
|
+
2. **Generate `.prizmkit/deploy/deploy.md`**: human-readable deployment guide with prerequisites, environment variables table, build/start instructions, health check suggestions.
|
|
91
|
+
3. **Record the adapter gap**: write a note in deploy.md and deploy-history identifying what's missing (e.g., "Adapter needed: Python/FastAPI on systemd").
|
|
111
92
|
4. **Provide a manual checklist**: concrete steps the user can follow to deploy manually.
|
|
112
93
|
5. **Offer to generate CI/CD config**: if `.github/workflows/` exists or the user wants one, generate a basic deploy workflow.
|
|
113
94
|
|
|
114
|
-
This ensures every deployment request produces useful output, even when full automation isn't available yet.
|
|
115
|
-
|
|
116
95
|
## Mode Detection
|
|
117
96
|
|
|
118
97
|
Detect invocation mode from the user's initial message. The mode determines what you're allowed to do:
|
|
@@ -124,9 +103,9 @@ Detect invocation mode from the user's initial message. The mode determines what
|
|
|
124
103
|
- Production requires explicit user confirmation before execution.
|
|
125
104
|
|
|
126
105
|
**Headless mode** (invoked via `--headless` flag, pipeline, or script):
|
|
127
|
-
-
|
|
106
|
+
- Never wait for user input — unattended shells that time out on a prompt block pipelines silently without visible errors, so exit with clear status codes instead.
|
|
128
107
|
- May ONLY target `dev` or `test` environments.
|
|
129
|
-
- If `--env production` in headless mode: exit immediately with `ENVIRONMENT_DENIED — production deployment requires interactive mode
|
|
108
|
+
- If `--env production` in headless mode: exit immediately with `ENVIRONMENT_DENIED — production deployment requires interactive mode`, because production deploys must never happen without human oversight.
|
|
130
109
|
- If required info is missing, exit with `NEEDS_INPUT` and write pending questions to `.prizmkit/deploy/pending-input.json`.
|
|
131
110
|
- May only perform actions already authorized by `deploy.config.json`.
|
|
132
111
|
|
|
@@ -164,16 +143,34 @@ All artifacts live under `.prizmkit/deploy/`:
|
|
|
164
143
|
pending-input.json # pending questions for headless mode resume
|
|
165
144
|
deploy-history/
|
|
166
145
|
<deployment-id>.json # one per deploy/rollback/event
|
|
167
|
-
deploy-scripts/ # future —
|
|
146
|
+
deploy-scripts/ # future — PrizmKit-managed deploy scripts
|
|
168
147
|
secrets.enc.json # optional, encrypted local secrets
|
|
169
148
|
secrets.local.json # optional, plaintext secrets (must be gitignored)
|
|
170
149
|
```
|
|
171
150
|
|
|
172
|
-
|
|
151
|
+
Read `references/deploy-config-schema.md` when writing or validating `deploy.config.json`. Read `references/deploy-history-schema.md` when writing history records.
|
|
152
|
+
|
|
153
|
+
## SSH Deployment Path
|
|
154
|
+
|
|
155
|
+
The following sections define the SSH deployment adapter — the only fully-automated path. Route here when Discovery determines the target is a Linux server with SSH access.
|
|
156
|
+
|
|
157
|
+
### SSH: Deployment Mode Selection
|
|
173
158
|
|
|
174
|
-
|
|
159
|
+
After Discovery routes to SSH, **before** entering the configuration wizard, ask the user how they want to deploy.
|
|
175
160
|
|
|
176
|
-
|
|
161
|
+
**First question:**
|
|
162
|
+
> "你想怎么部署到服务器?"
|
|
163
|
+
> - **A. 直接上传(快速上手)** — 本地构建,传到服务器启动。适合第一次部署。
|
|
164
|
+
> - **B. CI/CD 自动部署(推荐)** — 配置 GitHub Actions,以后 `git push` 自动部署。
|
|
165
|
+
|
|
166
|
+
**If user chooses CI/CD, second question:**
|
|
167
|
+
> "CI/CD 有两种模式:"
|
|
168
|
+
> - **Push 模式** — GitHub Actions runner 编译,SCP 传到服务器。服务器压力小。
|
|
169
|
+
> - **Pull 模式** — 服务器自己拉代码编译。配置更简单但需 Deploy Key。
|
|
170
|
+
|
|
171
|
+
For detailed mode descriptions and the full Push/Pull comparison table, read `references/deployment-modes.md`.
|
|
172
|
+
|
|
173
|
+
**Config field:** `deployStrategy` in `deploy.config.json` — `"direct-upload"`, `"ci-cd-push"`, or `"ci-cd-pull"`. Existing configs without this field default to `"ci-cd-pull"` for backward compatibility.
|
|
177
174
|
|
|
178
175
|
### SSH: Server Model
|
|
179
176
|
|
|
@@ -181,7 +178,7 @@ Servers are generic SSH targets. A server is valid if it:
|
|
|
181
178
|
- Can be reached over SSH.
|
|
182
179
|
- Provides a Linux shell.
|
|
183
180
|
- Can install or has Node.js, npm, PM2, Nginx, Git.
|
|
184
|
-
- Can access the configured Git repository.
|
|
181
|
+
- Can access the configured Git repository (Pull mode only).
|
|
185
182
|
|
|
186
183
|
Server-side directory layout:
|
|
187
184
|
```
|
|
@@ -199,48 +196,46 @@ SSH roles: `bootstrapUser` (usually root, for initial setup) and `runtimeUser` (
|
|
|
199
196
|
|
|
200
197
|
### SSH: First-Run Configuration Wizard
|
|
201
198
|
|
|
202
|
-
When `.prizmkit/deploy/deploy.config.json` does not exist, enter configuration wizard.
|
|
199
|
+
When `.prizmkit/deploy/deploy.config.json` does not exist, enter configuration wizard. Flow: **deployment mode → collect → validate → confirm → persist**.
|
|
200
|
+
|
|
201
|
+
**Before any questions:** ask deployment mode (see §SSH: Deployment Mode Selection). This determines required steps:
|
|
202
|
+
|
|
203
|
+
| Step | Direct Upload | CI/CD Push | CI/CD Pull |
|
|
204
|
+
|------|:---:|:---:|:---:|
|
|
205
|
+
| SSH Server Discovery | Required | Required | Required |
|
|
206
|
+
| Repository Access | Skipped | Skipped | Required |
|
|
207
|
+
| Application Configuration | Required | Required | Required |
|
|
208
|
+
| Environment Variables | Required | Required | Required |
|
|
209
|
+
| Persist Configuration | Required | Required | Required |
|
|
203
210
|
|
|
204
211
|
#### Step 1: SSH Server Discovery
|
|
205
212
|
|
|
206
213
|
Ask for and validate:
|
|
207
214
|
- **Server host and port** (e.g., `43.161.221.171:22`)
|
|
208
|
-
- **Bootstrap user** (usually `root`) —
|
|
215
|
+
- **Bootstrap user** (usually `root`) — for initial package install and user creation
|
|
209
216
|
- **Runtime user** (recommend `deploy`) — app runs as this user, never root
|
|
210
217
|
- **Auth method** — SSH key path or agent
|
|
211
218
|
|
|
212
219
|
Validate immediately: `ssh <bootstrapUser>@<host> 'echo OK'`. If that fails, nothing else matters — stop and fix connectivity first.
|
|
213
220
|
|
|
214
|
-
#### Step 2: Repository Access
|
|
221
|
+
#### Step 2: Repository Access (CI/CD Pull mode only)
|
|
215
222
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
- **Auth strategy** — prefer read-only Deploy Key
|
|
223
|
+
Only needed when `deployStrategy` is `"ci-cd-pull"` — the server needs to `git pull` code. Skip for `"direct-upload"` (no Git on server) and `"ci-cd-push"` (GitHub Actions handles checkout).
|
|
224
|
+
|
|
225
|
+
Ask for: Git URL, branch, auth strategy (prefer read-only Deploy Key).
|
|
220
226
|
|
|
221
227
|
If using Deploy Key:
|
|
222
228
|
1. Generate ed25519 key on server: `sudo -u <runtimeUser> ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""`
|
|
223
|
-
2. Show
|
|
224
|
-
3. Wait for
|
|
229
|
+
2. Show public key to user: "Add this to GitHub Deploy Keys (read-only)"
|
|
230
|
+
3. Wait for confirmation, then verify: attempt a git clone as runtime user
|
|
225
231
|
|
|
226
232
|
#### Step 3: Application Configuration
|
|
227
233
|
|
|
228
|
-
For each app, collect:
|
|
229
|
-
- **id** — short name (e.g., `web`)
|
|
230
|
-
- **path** — relative path within repo
|
|
231
|
-
- **packageManager** — npm / yarn / pnpm
|
|
232
|
-
- **installCommand** — `npm ci` / `yarn install` etc.
|
|
233
|
-
- **buildCommand** — `npm run build` etc.
|
|
234
|
-
- **startCommand** — `npm run start` etc.
|
|
235
|
-
- **ports** — blue/green port pair (default 3101/3102)
|
|
236
|
-
- **healthChecks** — list of `{ name, url, expectedStatus[] }`
|
|
234
|
+
For each app, collect: id, path, packageManager, installCommand, buildCommand, startCommand, blue/green port pair (default 3101/3102), healthChecks.
|
|
237
235
|
|
|
238
236
|
#### Step 4: Environment Variables
|
|
239
237
|
|
|
240
|
-
|
|
241
|
-
- Ask user for each required value.
|
|
242
|
-
- Identify which are secrets (API keys, tokens) vs. non-secrets (URLs, anon keys).
|
|
243
|
-
- Ask about secret storage strategy (see Secrets Management below).
|
|
238
|
+
Scan source code for `process.env.<VAR>` references. Ask user for each required value. Identify secrets vs non-secrets. Ask about secret storage strategy (see §Secrets Management).
|
|
244
239
|
|
|
245
240
|
#### Step 5: Persist Configuration
|
|
246
241
|
|
|
@@ -248,7 +243,7 @@ Write `deploy.config.json` with all collected values and `validated: {}` stubs f
|
|
|
248
243
|
|
|
249
244
|
### SSH: Bootstrap Flow
|
|
250
245
|
|
|
251
|
-
Before first deployment, bootstrap the server. Present a plan
|
|
246
|
+
Before first deployment, bootstrap the server. Present a plan showing every privileged action before executing anything.
|
|
252
247
|
|
|
253
248
|
**Always-run preflight:**
|
|
254
249
|
```
|
|
@@ -256,18 +251,9 @@ locale-gen en_US.UTF-8 # fix locale warnings on bare Ubuntu
|
|
|
256
251
|
apt-get update -qq # refresh package list
|
|
257
252
|
```
|
|
258
253
|
|
|
259
|
-
**Check-and-install (idempotent):**
|
|
260
|
-
- **Node.js**: check `node --version`. If missing or too old, install via NodeSource. Use v22 LTS if v25 not available — that's fine for most projects.
|
|
261
|
-
- **npm**: verify separately from node (`which npm`). On minimal installs, npm may be a separate package.
|
|
262
|
-
- **PM2**: `npm install -g pm2` if missing.
|
|
263
|
-
- **Nginx**: `apt-get install -y nginx` if missing.
|
|
264
|
-
- **Git**: `apt-get install -y git` if missing.
|
|
254
|
+
**Check-and-install (idempotent):** Node.js, npm, PM2, Nginx, Git. Use v22 LTS if v25 not available.
|
|
265
255
|
|
|
266
|
-
**Detect port conflicts
|
|
267
|
-
```
|
|
268
|
-
ss -tlnp | grep :80 || true
|
|
269
|
-
```
|
|
270
|
-
If port 80/443 is occupied, report what's using it and ask how to resolve.
|
|
256
|
+
**Detect port conflicts:** `ss -tlnp | grep :80 || true`. If port 80/443 is occupied, report and ask how to resolve.
|
|
271
257
|
|
|
272
258
|
**User and directory setup:**
|
|
273
259
|
```
|
|
@@ -281,104 +267,119 @@ chown -R <runtimeUser>:<runtimeUser> /var/www/<project>
|
|
|
281
267
|
env PATH=$PATH:/usr/bin pm2 startup systemd -u <runtimeUser> --hp /home/<runtimeUser>
|
|
282
268
|
```
|
|
283
269
|
|
|
284
|
-
**Deploy key (
|
|
270
|
+
**Deploy key (Pull mode only):**
|
|
285
271
|
```
|
|
286
272
|
sudo -u <runtimeUser> ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
|
|
287
273
|
sudo -u <runtimeUser> ssh-keyscan -H github.com >> ~/.ssh/known_hosts
|
|
288
274
|
```
|
|
289
275
|
|
|
276
|
+
**Security baseline (firewall):** After core tools are installed, ask whether to configure ufw. If user agrees, read `references/firewall-setup.md` for the full interactive flow and rule templates.
|
|
277
|
+
|
|
278
|
+
**Database setup:** If Discovery detected database drivers, ask whether to install the database on the server. If user agrees, read `references/database-setup.md` for platform-specific setup commands and security notes.
|
|
279
|
+
|
|
290
280
|
After each bootstrap step, record the result. Bootstrap operations must be idempotent. Back up any existing config files before modifying them.
|
|
291
281
|
|
|
282
|
+
### SSH: Direct Upload Deployment
|
|
283
|
+
|
|
284
|
+
When `deployStrategy` is `"direct-upload"`, the AI builds locally and transfers artifacts to the server. No Git operations on the server. Full procedure in `references/direct-upload.md`.
|
|
285
|
+
|
|
286
|
+
### SSH: CI/CD Pipeline Configuration
|
|
287
|
+
|
|
288
|
+
When `deployStrategy` is `"ci-cd-push"` or `"ci-cd-pull"`, generate `.github/workflows/deploy.yml` with the appropriate workflow template. Both modes share the same trigger and secrets. Full YAML templates in `references/ci-cd-workflows.md`.
|
|
289
|
+
|
|
290
|
+
After generating the workflow, verify: the first `git push` to the configured branch will trigger the first deployment. Monitor the GitHub Actions run and report results.
|
|
291
|
+
|
|
292
|
+
### SSH: DNS Guidance
|
|
293
|
+
|
|
294
|
+
Before SSL, check if the user has a domain pointing to the server.
|
|
295
|
+
|
|
296
|
+
1. Ask: "你有没有域名要绑定到这个项目?" If no domain → skip DNS + SSL, note in deploy.md.
|
|
297
|
+
2. Check DNS: `dig +short <domain> A`. If resolved → proceed to SSL.
|
|
298
|
+
3. If not resolved: show the user DNS setup instructions. Full procedure in `references/dns-setup.md`.
|
|
299
|
+
|
|
300
|
+
### SSH: SSL/HTTPS Configuration
|
|
301
|
+
|
|
302
|
+
Once DNS is confirmed pointing to the server, configure HTTPS via Let's Encrypt.
|
|
303
|
+
|
|
304
|
+
1. Detect cloud vendor via metadata endpoints.
|
|
305
|
+
2. If cloud vendor detected, ask: Let's Encrypt (recommended) or cloud vendor certificate.
|
|
306
|
+
3. Install certbot and request certificate.
|
|
307
|
+
4. Verify auto-renewal with `certbot renew --dry-run`.
|
|
308
|
+
|
|
309
|
+
Full procedure in `references/ssl-setup.md`.
|
|
310
|
+
|
|
292
311
|
### SSH: Deployment Execution Flow
|
|
293
312
|
|
|
294
313
|
Pipeline runs in strict order. Each group must complete before the next begins. If any step before traffic switch fails, STOP — do not touch the live version.
|
|
295
314
|
|
|
315
|
+
**Pre-flight — Change Summary:** Show what will be deployed using `git log --oneline <last-deployed-commit>..HEAD`. If first deployment, show last 5 commits. If no new commits, warn "没有新的代码变更。确定要重新部署吗?"
|
|
316
|
+
|
|
296
317
|
**Group 1 — Pre-flight & Prepare:**
|
|
297
318
|
- Verify SSH, runtime user, tools, deploy key, port availability.
|
|
298
319
|
- Generate `releaseId`: `YYYYMMDD-<short-commit-sha>`. Create `releases/<releaseId>`.
|
|
299
320
|
- Determine target color: read `activeColor` from `shared/deploy-metadata.json` and use the opposite. If first deploy (no metadata, no `current` symlink), default to blue (port 3101).
|
|
300
321
|
|
|
301
322
|
**Group 2 — Fetch & Build:**
|
|
302
|
-
|
|
303
|
-
- `
|
|
304
|
-
-
|
|
305
|
-
-
|
|
323
|
+
|
|
324
|
+
- **CI/CD Pull mode** (server-side build): git clone → install → copy `.env.production` before build (NEXT_PUBLIC_* vars are baked at build time) → build. If build fails: STOP.
|
|
325
|
+
- **CI/CD Push mode** (runner-side build): extract tarball, skip install/build.
|
|
326
|
+
- **Direct-upload mode**: build was already done locally and SCP'd. Skip this group.
|
|
306
327
|
|
|
307
328
|
**Group 3 — Stage & Health Check:**
|
|
308
|
-
- Start new version on
|
|
329
|
+
- Start new version on inactive port via PM2: `pm2 start npm --name <project>-<app>-<color> -- run start -- -p <inactivePort>`.
|
|
309
330
|
- PM2 process naming: `<project>-<app>-<color>` (e.g., `prizm-ideas-web-green`).
|
|
310
|
-
- Wait 3-5 seconds, run health checks against new port. If any fails: STOP
|
|
331
|
+
- Wait 3-5 seconds, run health checks against new port. If any fails: STOP, do NOT switch traffic.
|
|
311
332
|
|
|
312
333
|
**Group 4 — Switch & Verify:**
|
|
313
334
|
- Update Nginx upstream to new port. Run `nginx -t` — abort on failure.
|
|
314
335
|
- `systemctl reload nginx`. Update `current` symlink to new release.
|
|
315
336
|
- Write `shared/deploy-metadata.json` with new `activeColor`, `activePort`, `lastReleaseId`.
|
|
316
|
-
- Run health checks against public endpoint. If any fails: rollback immediately
|
|
337
|
+
- Run health checks against public endpoint. If any fails: rollback immediately.
|
|
317
338
|
|
|
318
339
|
**Group 5 — Cleanup & Record:**
|
|
319
340
|
- Stop old PM2 process. Remove oldest releases beyond `releaseRetention` count. `pm2 save`.
|
|
320
|
-
- Write deploy-history JSON
|
|
321
|
-
|
|
341
|
+
- Write deploy-history JSON. Update `deploy.config.json` validation status.
|
|
342
|
+
|
|
343
|
+
**Post-deploy — Completion Summary:** Output a summary (project, URL, version, duration, health status) and append to deploy.md. If `deployStrategy` is `"direct-upload"`, offer CI/CD upgrade (see §SSH: Post-Deploy CI/CD Upgrade).
|
|
322
344
|
|
|
323
345
|
### SSH: Blue/Green PM2 + Nginx Strategy
|
|
324
346
|
|
|
325
|
-
|
|
326
|
-
-
|
|
327
|
-
-
|
|
347
|
+
- Blue: port 3101 (default), Green: port 3102 (default).
|
|
348
|
+
- Active color persisted in `/var/www/<project>/shared/deploy-metadata.json`.
|
|
349
|
+
- PM2 process naming: `<project>-<app>-<color>` (deterministic, never reuse old release IDs).
|
|
350
|
+
- Nginx config must include: `# PrizmKit Managed: <project> — DO NOT EDIT MANUALLY`.
|
|
351
|
+
- Before modifying any Nginx config lacking this marker, ask for user confirmation.
|
|
352
|
+
- Always `nginx -t` before `systemctl reload nginx`.
|
|
328
353
|
|
|
329
|
-
|
|
354
|
+
See `references/nginx-blue-green.md` for the full Nginx config template and traffic switch procedure.
|
|
330
355
|
|
|
331
|
-
|
|
356
|
+
### SSH: Rollback
|
|
332
357
|
|
|
333
|
-
|
|
334
|
-
```
|
|
335
|
-
# PrizmKit Managed: <project> — DO NOT EDIT MANUALLY
|
|
336
|
-
```
|
|
358
|
+
Two triggers: **automatic** (health check failure after traffic switch) and **manual** (`/prizmkit-deploy rollback --app <id> [--to <releaseId>]`).
|
|
337
359
|
|
|
338
|
-
|
|
360
|
+
Steps: identify target release → verify build exists → start PM2 on its port → update Nginx upstream → `nginx -t` → reload → health checks → write rollback event. Do NOT delete the failed release or its logs — preserve for debugging.
|
|
339
361
|
|
|
340
|
-
|
|
362
|
+
If no previous release exists, rollback is not possible — state this clearly.
|
|
341
363
|
|
|
342
|
-
### SSH:
|
|
364
|
+
### SSH: Operations Commands
|
|
343
365
|
|
|
344
|
-
|
|
345
|
-
1. **Automatic**: health check failure after traffic switch → roll back immediately.
|
|
346
|
-
2. **Manual**: `/prizmkit-deploy rollback --app <id> [--to <releaseId>]`
|
|
366
|
+
**status:** `pm2 list` as runtime user + active release, active color/port, last deploy timestamp.
|
|
347
367
|
|
|
348
|
-
|
|
349
|
-
1. Identify target release: `--to <releaseId>` or discover previous release from deploy history.
|
|
350
|
-
2. Verify target release directory exists and has a valid build.
|
|
351
|
-
3. Determine which port the target release used (from deploy history or release metadata).
|
|
352
|
-
4. Start the target PM2 process on its port (if not already running).
|
|
353
|
-
5. Update Nginx upstream to target port, run `nginx -t`, reload.
|
|
354
|
-
6. Run health checks against the restored version.
|
|
355
|
-
7. Write a rollback event to deploy history.
|
|
356
|
-
8. Do NOT delete the failed release or its logs — preserve for debugging.
|
|
368
|
+
**logs --app \<id\>:** `pm2 logs <process-name> --lines 100` as runtime user.
|
|
357
369
|
|
|
358
|
-
|
|
370
|
+
**restart --app \<id\>:** identify active PM2 process → `pm2 restart` → wait → health checks.
|
|
359
371
|
|
|
360
|
-
|
|
372
|
+
**health --app \<id\>:** run all configured health checks, report pass/fail for each.
|
|
361
373
|
|
|
362
|
-
|
|
363
|
-
SSH to server and run `pm2 list` as runtime user. Also show:
|
|
364
|
-
- Active release (from `current` symlink target)
|
|
365
|
-
- Active color/port (from `deploy-metadata.json`)
|
|
366
|
-
- Last deploy timestamp
|
|
374
|
+
**history:** list `.prizmkit/deploy/deploy-history/` events chronologically.
|
|
367
375
|
|
|
368
|
-
|
|
369
|
-
SSH to server and run `pm2 logs <process-name> --lines 100` as runtime user.
|
|
376
|
+
### SSH: Post-Deploy CI/CD Upgrade
|
|
370
377
|
|
|
371
|
-
|
|
372
|
-
1. Identify the active PM2 process for the app.
|
|
373
|
-
2. Run `pm2 restart <process-name>` as runtime user.
|
|
374
|
-
3. Wait for process to come online.
|
|
375
|
-
4. Run health checks to verify recovery.
|
|
378
|
+
After a successful direct-upload deployment, proactively offer CI/CD setup:
|
|
376
379
|
|
|
377
|
-
|
|
378
|
-
Run all configured health checks for the app against the public endpoint. Report pass/fail for each.
|
|
380
|
+
> "部署成功。要不要顺手帮你配置 CI/CD 自动部署?以后 `git push` 就自动上线。"
|
|
379
381
|
|
|
380
|
-
|
|
381
|
-
Read `.prizmkit/deploy/deploy-history/` directory, list events chronologically. Show event type, release ID, commit SHA, timestamp, status.
|
|
382
|
+
If user agrees, ask push vs pull, then configure accordingly. If Pull mode: set up deploy key. If Push mode: add GitHub Actions secrets. Generate `deploy.yml` from `references/ci-cd-workflows.md`, update `deployStrategy` in config, write upgrade event to history.
|
|
382
383
|
|
|
383
384
|
## Environment Policy
|
|
384
385
|
|
|
@@ -387,7 +388,7 @@ Read `.prizmkit/deploy/deploy-history/` directory, list events chronologically.
|
|
|
387
388
|
| Interactive | Allowed | Allowed | Allowed (requires confirmation) |
|
|
388
389
|
| Headless | Allowed | Allowed | **REJECTED** — exits with ENVIRONMENT_DENIED |
|
|
389
390
|
|
|
390
|
-
|
|
391
|
+
Headless must reject production because production deploys require human oversight — an unattended pipeline timing out mid-deploy can leave the site in a broken state with no one monitoring.
|
|
391
392
|
|
|
392
393
|
## Secrets Management
|
|
393
394
|
|
|
@@ -407,7 +408,7 @@ Deploy history records secret presence metadata only (e.g., `{"SUPABASE_SERVICE_
|
|
|
407
408
|
When deploying to a server that already has deployment assets:
|
|
408
409
|
|
|
409
410
|
1. Detect: existing `/var/www/<project>` directory, existing PM2 processes with similar names, Nginx config referencing the same domain/IP, port conflicts.
|
|
410
|
-
2. Report findings
|
|
411
|
+
2. Report findings and ask for takeover decision:
|
|
411
412
|
- **Take over and backup**: Back up existing config, then proceed.
|
|
412
413
|
- **Coexist**: Use different directory/ports/process names.
|
|
413
414
|
- **Manual resolve**: Stop and let the user handle it.
|
|
@@ -417,23 +418,15 @@ When deploying to a server that already has deployment assets:
|
|
|
417
418
|
|
|
418
419
|
- First Nginx config creation or update of a non-PrizmKit block requires user confirmation.
|
|
419
420
|
- Subsequent updates to PrizmKit-managed blocks (`# PrizmKit Managed:` marker) may proceed automatically.
|
|
420
|
-
-
|
|
421
|
-
- Always run `nginx -t` before reload.
|
|
422
|
-
- If a server block exists without the managed marker, ask before modifying.
|
|
421
|
+
- Always `nginx -t` before reload.
|
|
423
422
|
|
|
424
|
-
See `references/nginx-blue-green.md` for the full Nginx config template
|
|
423
|
+
See `references/nginx-blue-green.md` for the full Nginx config template.
|
|
425
424
|
|
|
426
425
|
### SSH: Bootstrap Safety Rules
|
|
427
426
|
|
|
428
|
-
Before executing privileged bootstrap work, generate an action plan listing:
|
|
429
|
-
- Packages to install/upgrade
|
|
430
|
-
- Users/groups to create/modify
|
|
431
|
-
- SSH keys to create
|
|
432
|
-
- Nginx config to create/modify
|
|
433
|
-
- Directories and permissions to change
|
|
434
|
-
- Services that may be restarted
|
|
427
|
+
Before executing privileged bootstrap work, generate an action plan listing: packages, users/groups, SSH keys, Nginx config, directories/permissions, services that may be restarted.
|
|
435
428
|
|
|
436
|
-
|
|
429
|
+
Rules:
|
|
437
430
|
- User gives one explicit approval for the entire bootstrap plan.
|
|
438
431
|
- If the plan changes during execution, pause and ask again.
|
|
439
432
|
- Bootstrap operations must be idempotent.
|
|
@@ -444,53 +437,32 @@ Execution rules:
|
|
|
444
437
|
### SSH: Multi-App Coordination
|
|
445
438
|
|
|
446
439
|
An all-app deploy creates one release group. Rules:
|
|
447
|
-
- Pre-traffic phases
|
|
448
|
-
- If any app fails before traffic switch, NO app switches traffic. Staged processes
|
|
449
|
-
- If any app fails after traffic switch, default: group rollback
|
|
440
|
+
- Pre-traffic phases must complete for ALL selected apps before ANY app switches traffic.
|
|
441
|
+
- If any app fails before traffic switch, NO app switches traffic. Staged processes stopped, live system unchanged.
|
|
442
|
+
- If any app fails after traffic switch, default: group rollback.
|
|
450
443
|
- Single-app deploys (`--app <id>`) do not affect unrelated apps.
|
|
451
444
|
|
|
452
445
|
## Validation
|
|
453
446
|
|
|
454
|
-
Validation is mandatory before production deploy. Check:
|
|
455
|
-
- SSH connectivity and user permissions
|
|
456
|
-
- Required tools present (node, npm, git, pm2, nginx)
|
|
457
|
-
- Repository reachability and branch existence
|
|
458
|
-
- Ports availability
|
|
459
|
-
- Required env vars present
|
|
460
|
-
- Nginx config syntax
|
|
461
|
-
- Health check routes accessible
|
|
447
|
+
Validation is mandatory before production deploy. Check: SSH connectivity, required tools (node, npm, git, pm2, nginx), repository reachability, port availability, required env vars, Nginx config syntax, health check routes accessible.
|
|
462
448
|
|
|
463
449
|
Persist validation in `deploy.config.json` under each section's `validated` field.
|
|
464
450
|
|
|
465
451
|
## Adapter Paths
|
|
466
452
|
|
|
467
|
-
After Discovery routes to a deployment target, read the corresponding reference
|
|
453
|
+
After Discovery routes to a deployment target, read the corresponding reference:
|
|
468
454
|
|
|
469
455
|
| Target | Reference | Mode |
|
|
470
456
|
|--------|-----------|------|
|
|
471
|
-
| SSH Linux server | SSH sections
|
|
457
|
+
| SSH Linux server | SSH sections in this file | Full automation |
|
|
472
458
|
| Vercel, Netlify, Fly.io | `references/cloud-platform-deploy.md` | Guided CLI |
|
|
473
459
|
| Docker / Docker Compose | `references/docker-deploy.md` | Guided build + run |
|
|
474
|
-
| Unrecognized target | Deployment Discovery Step 4 | Documented fallback |
|
|
475
|
-
|
|
476
|
-
The SSH path is documented inline below because it is the fully-automated adapter and the model needs its instructions in every SSH deployment session. Cloud and Docker paths are in references because they're loaded only when Discovery routes to them.
|
|
460
|
+
| Unrecognized target | §Deployment Discovery Step 4 | Documented fallback |
|
|
477
461
|
|
|
478
462
|
## Deploy History Record Schema
|
|
479
463
|
|
|
480
|
-
Each deployment, rollback, or significant event writes a record to `.prizmkit/deploy/deploy-history/<id>.json`.
|
|
481
|
-
|
|
482
|
-
Never record raw secret values in history — presence metadata only.
|
|
483
|
-
|
|
484
|
-
## Implementation Notes from Live Validation
|
|
464
|
+
Each deployment, rollback, or significant event writes a record to `.prizmkit/deploy/deploy-history/<id>.json`. Full schema in `references/deploy-history-schema.md`. Never record raw secret values in history — presence metadata only.
|
|
485
465
|
|
|
486
|
-
|
|
466
|
+
## Implementation Notes
|
|
487
467
|
|
|
488
|
-
|
|
489
|
-
2. **Verify npm separately from node.** Minimal Node installs may not bundle npm.
|
|
490
|
-
3. **Fix locale on bare Ubuntu.** Run `locale-gen en_US.UTF-8` early to avoid perl warnings in apt.
|
|
491
|
-
4. **Deploy key workflow is inherently interactive.** Generate key → wait for user to add to GitHub → verify. Headless mode cannot complete this.
|
|
492
|
-
5. **`pm2 startup` needs explicit PATH.** Always use `env PATH=$PATH:/usr/bin pm2 startup ...`.
|
|
493
|
-
6. **Persist deploy metadata on server.** Write `activeColor`, `activePort`, `lastReleaseId`, `lastDeployTimestamp` to `shared/deploy-metadata.json`.
|
|
494
|
-
7. **Detect first deployment.** If no `current` symlink and no PM2 process for the app, skip rollback safety checks and use blue (3101) as initial color.
|
|
495
|
-
8. **Build-time env vars.** Copy `.env.production` before `npm run build`, not after. `NEXT_PUBLIC_*` vars are baked at build time.
|
|
496
|
-
9. **Node.js version flexibility.** Default to v22 LTS if v25 is unavailable. Most frameworks tolerate a minor version diff.
|
|
468
|
+
Live validation findings from the first PrizmKit deployment are in `references/live-validation-notes.md`. Read when troubleshooting bootstrap or deploy issues — these cover port conflict detection, npm verification, locale fixes, deploy key interactivity, PM2 PATH handling, and build-time env var timing.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# CI/CD Workflow Templates
|
|
2
|
+
|
|
3
|
+
Read this file when `deployStrategy` is `ci-cd-push` or `ci-cd-pull`.
|
|
4
|
+
|
|
5
|
+
## Shared Configuration
|
|
6
|
+
|
|
7
|
+
**Secrets** (add to GitHub repository Settings → Secrets and variables → Actions):
|
|
8
|
+
- `SSH_HOST` — server IP/hostname
|
|
9
|
+
- `SSH_USER` — runtime user (e.g., `deploy`)
|
|
10
|
+
- `SSH_KEY` — SSH private key
|
|
11
|
+
- `SSH_PORT` — SSH port (default 22)
|
|
12
|
+
|
|
13
|
+
**Shared trigger:**
|
|
14
|
+
```yaml
|
|
15
|
+
on:
|
|
16
|
+
push:
|
|
17
|
+
branches: [<branch>]
|
|
18
|
+
paths-ignore:
|
|
19
|
+
- '.prizmkit/**'
|
|
20
|
+
- 'docs/**'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Push Mode Workflow (`ci-cd-push`)
|
|
26
|
+
|
|
27
|
+
Build happens on GitHub Actions runner. Only built artifacts are transferred to the server.
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
name: Deploy to Production (Push)
|
|
31
|
+
|
|
32
|
+
on:
|
|
33
|
+
push:
|
|
34
|
+
branches: [<branch>]
|
|
35
|
+
|
|
36
|
+
jobs:
|
|
37
|
+
deploy:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
|
|
42
|
+
- uses: actions/setup-node@v4
|
|
43
|
+
with:
|
|
44
|
+
node-version: 20
|
|
45
|
+
|
|
46
|
+
- name: Install & Build
|
|
47
|
+
run: |
|
|
48
|
+
npm ci
|
|
49
|
+
npm run build
|
|
50
|
+
|
|
51
|
+
- name: Package & Transfer
|
|
52
|
+
run: |
|
|
53
|
+
RELEASE_ID=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
|
|
54
|
+
tar czf deploy-$RELEASE_ID.tar.gz \
|
|
55
|
+
<build-output-dir>/ node_modules/ package.json package-lock.json
|
|
56
|
+
scp -P ${{ secrets.SSH_PORT }} deploy-$RELEASE_ID.tar.gz \
|
|
57
|
+
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/var/www/<project>/releases/
|
|
58
|
+
|
|
59
|
+
- name: Deploy on Server
|
|
60
|
+
uses: appleboy/ssh-action@v1
|
|
61
|
+
with:
|
|
62
|
+
host: ${{ secrets.SSH_HOST }}
|
|
63
|
+
username: ${{ secrets.SSH_USER }}
|
|
64
|
+
key: ${{ secrets.SSH_KEY }}
|
|
65
|
+
port: ${{ secrets.SSH_PORT }}
|
|
66
|
+
script: |
|
|
67
|
+
cd /var/www/<project>
|
|
68
|
+
RELEASE_ID=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
|
|
69
|
+
mkdir -p releases/$RELEASE_ID
|
|
70
|
+
tar xzf releases/deploy-$RELEASE_ID.tar.gz -C releases/$RELEASE_ID
|
|
71
|
+
rm releases/deploy-$RELEASE_ID.tar.gz
|
|
72
|
+
# PM2 start, health check, Nginx switch (same as manual flow)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Key difference from Pull:** the runner checks out code, installs, builds, and only transmits the result. The server doesn't need Git or build tools — just Node.js runtime and PM2.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Pull Mode Workflow (`ci-cd-pull`)
|
|
80
|
+
|
|
81
|
+
GitHub Actions runner only triggers the server. The server does all the work.
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
name: Deploy to Production (Pull)
|
|
85
|
+
|
|
86
|
+
on:
|
|
87
|
+
push:
|
|
88
|
+
branches: [<branch>]
|
|
89
|
+
|
|
90
|
+
jobs:
|
|
91
|
+
deploy:
|
|
92
|
+
runs-on: ubuntu-latest
|
|
93
|
+
steps:
|
|
94
|
+
- name: Trigger Server Deploy
|
|
95
|
+
uses: appleboy/ssh-action@v1
|
|
96
|
+
with:
|
|
97
|
+
host: ${{ secrets.SSH_HOST }}
|
|
98
|
+
username: ${{ secrets.SSH_USER }}
|
|
99
|
+
key: ${{ secrets.SSH_KEY }}
|
|
100
|
+
port: ${{ secrets.SSH_PORT }}
|
|
101
|
+
script: |
|
|
102
|
+
cd /var/www/<project>
|
|
103
|
+
RELEASE_ID=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
|
|
104
|
+
mkdir -p releases/$RELEASE_ID
|
|
105
|
+
git clone <repoUrl> --branch <branch> releases/$RELEASE_ID
|
|
106
|
+
cd releases/$RELEASE_ID
|
|
107
|
+
npm ci
|
|
108
|
+
cp ../shared/.env.production .
|
|
109
|
+
npm run build
|
|
110
|
+
# PM2 start, health check, Nginx switch
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Key difference from Push:** the workflow is simpler (one step: SSH + run script), but the server needs Git, full build toolchain, and must be able to reach the repo.
|
|
114
|
+
|
|
115
|
+
After generating the workflow, verify: the first `git push` to the configured branch will trigger the first deployment. Monitor the GitHub Actions run and report results.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Database Setup
|
|
2
|
+
|
|
3
|
+
Read this file when Discovery detected a database driver and the user wants AI-assisted database installation on the server.
|
|
4
|
+
|
|
5
|
+
## Entry condition
|
|
6
|
+
|
|
7
|
+
During Discovery Step 1 (Project Detection), database drivers were already scanned. If a driver was detected, ask after bootstrap tools are installed:
|
|
8
|
+
|
|
9
|
+
> "检测到项目使用了 <PostgreSQL/MySQL/Redis>,需要帮你在服务器上安装配置吗?"
|
|
10
|
+
> - **需要** → 继续数据库安装
|
|
11
|
+
> - **不需要** → 跳过,记录到 deploy.md,标注"数据库需用户自行配置"
|
|
12
|
+
|
|
13
|
+
## PostgreSQL setup
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
apt-get install -y postgresql postgresql-contrib
|
|
17
|
+
sudo -u postgres psql -c "CREATE DATABASE <project>;"
|
|
18
|
+
sudo -u postgres psql -c "CREATE USER <project> WITH PASSWORD '<random-password>';"
|
|
19
|
+
sudo -u postgres psql -c "GRANT ALL ON DATABASE <project> TO <project>;"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- Generate a secure random password (32 chars, alphanumeric + symbols).
|
|
23
|
+
- Write the connection string to `.prizmkit/deploy/secrets.local.json`: `DATABASE_URL=postgresql://<project>:<password>@localhost:5432/<project>`.
|
|
24
|
+
- In deploy.md, write: "PostgreSQL 已安装,连接信息已记录到 `.prizmkit/deploy/secrets.local.json`(不提交到 git)".
|
|
25
|
+
|
|
26
|
+
## MySQL setup (future)
|
|
27
|
+
|
|
28
|
+
Similar flow. Not implemented in first version — if project uses MySQL, direct user to documentation fallback.
|
|
29
|
+
|
|
30
|
+
## Redis setup
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
apt-get install -y redis-server
|
|
34
|
+
redis-cli CONFIG SET requirepass "<random-password>"
|
|
35
|
+
redis-cli CONFIG REWRITE
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Bind to localhost only (modify `/etc/redis/redis.conf` if needed).
|
|
39
|
+
- Write `REDIS_URL=redis://:<password>@localhost:6379` to `.prizmkit/deploy/secrets.local.json`.
|
|
40
|
+
|
|
41
|
+
## Security notes
|
|
42
|
+
|
|
43
|
+
- Never write database passwords to deploy.md, because deploy.md may be committed to git and passwords would leak.
|
|
44
|
+
- Passwords stored in `.prizmkit/deploy/secrets.local.json` (gitignored).
|
|
45
|
+
- Default: database binds to localhost, no external access, because most indie projects only need local connections.
|
|
46
|
+
- Record a `"database-setup"` event in deploy history (presence metadata only, no passwords).
|
|
@@ -9,6 +9,7 @@ This file is the machine-readable deployment configuration. Always read it befor
|
|
|
9
9
|
"version": 1,
|
|
10
10
|
"project": "project-name",
|
|
11
11
|
"deploymentMode": "ssh",
|
|
12
|
+
"deployStrategy": "direct-upload|ci-cd-push|ci-cd-pull",
|
|
12
13
|
"defaults": { ... },
|
|
13
14
|
"environments": { ... },
|
|
14
15
|
"servers": [ ... ],
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Deployment Mode Details
|
|
2
|
+
|
|
3
|
+
Read this file when the user needs a detailed comparison of deployment modes during mode selection. SKILL.md contains the routing logic; this file has the full descriptions.
|
|
4
|
+
|
|
5
|
+
## Mode A — Direct Upload
|
|
6
|
+
|
|
7
|
+
1. Local build on the user's machine.
|
|
8
|
+
2. SCP built output + `node_modules` + `.env.production` to server.
|
|
9
|
+
3. PM2 start → health check → Nginx switch.
|
|
10
|
+
4. After success: offer to upgrade to CI/CD.
|
|
11
|
+
5. Bypasses: deploy key, git clone on server, server-side build.
|
|
12
|
+
|
|
13
|
+
Best for: first-time deployment, getting something live fast, low-spec servers.
|
|
14
|
+
|
|
15
|
+
## Mode B1 — CI/CD Push
|
|
16
|
+
|
|
17
|
+
1. Generate `.github/workflows/deploy.yml`: checkout → install → build → SCP tarball → SSH restart.
|
|
18
|
+
2. Add GitHub Secrets: `SSH_HOST`, `SSH_USER`, `SSH_KEY`, `SSH_PORT`.
|
|
19
|
+
3. First deploy triggered by push to configured branch.
|
|
20
|
+
4. Server only needs Node.js runtime + PM2 — no git, no build tools needed.
|
|
21
|
+
5. GitHub Actions runner handles the heavy lifting.
|
|
22
|
+
|
|
23
|
+
Best for: low-spec servers, heavy build processes, projects with large dependencies.
|
|
24
|
+
|
|
25
|
+
## Mode B2 — CI/CD Pull
|
|
26
|
+
|
|
27
|
+
1. Configure deploy key on server → add to GitHub.
|
|
28
|
+
2. Generate `.github/workflows/deploy.yml`: triggers SSH command on server.
|
|
29
|
+
3. Server-side deploy script: `git pull` → install → build → PM2 restart → health check.
|
|
30
|
+
4. Server needs full build toolchain (Node.js, npm, git).
|
|
31
|
+
5. Simpler workflow file, heavier server load.
|
|
32
|
+
|
|
33
|
+
Best for: simple setup, servers with sufficient CPU/RAM, projects where build is fast.
|
|
34
|
+
|
|
35
|
+
## Comparison
|
|
36
|
+
|
|
37
|
+
| 对比 | Push 模式 | Pull 模式 |
|
|
38
|
+
|------|----------|----------|
|
|
39
|
+
| 构建位置 | GitHub Actions runner | 服务器本地 |
|
|
40
|
+
| 服务器压力 | 低(只运行应用) | 高(编译+运行) |
|
|
41
|
+
| 配置复杂度 | 中(需 SCP 传产物) | 低(只需 SSH 触发脚本) |
|
|
42
|
+
| 适合场景 | 服务器配置低、编译重 | 部署简单优先、服务器性能充裕 |
|
|
43
|
+
| Deploy Key 需要 | 不需要 | 需要 |
|
|
44
|
+
| 产物传输 | SCP tarball | git pull(仅增量) |
|
|
45
|
+
|
|
46
|
+
## Common ground between all modes
|
|
47
|
+
|
|
48
|
+
- Same PM2 + Nginx blue/green strategy.
|
|
49
|
+
- Same health check and traffic switch procedure.
|
|
50
|
+
- Same ops commands (status/logs/restart/rollback).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Direct Upload Deployment
|
|
2
|
+
|
|
3
|
+
Read this file when `deployStrategy` is `"direct-upload"`. The AI handles the build locally and transfers built artifacts to the server. No Git operations on the server.
|
|
4
|
+
|
|
5
|
+
## Build phase (local)
|
|
6
|
+
|
|
7
|
+
1. Run `<buildCommand>` locally (e.g., `npm run build`) in the project root.
|
|
8
|
+
2. Identify the build output directory: `.next/` for Next.js, `dist/` for Vite, `build/` for CRA.
|
|
9
|
+
3. Prepare a deployment tarball containing: build output + `node_modules/` + `package.json` + `package-lock.json` + any runtime config files.
|
|
10
|
+
|
|
11
|
+
## Transfer phase (SCP)
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
scp -P <port> deploy-<releaseId>.tar.gz <runtimeUser>@<host>:/var/www/<project>/releases/
|
|
15
|
+
ssh <runtimeUser>@<host> "cd /var/www/<project>/releases && mkdir <releaseId> && tar xzf deploy-<releaseId>.tar.gz -C <releaseId>"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Server-side setup
|
|
19
|
+
|
|
20
|
+
1. Copy `.env.production` from `shared/` into the release directory (or SCP it alongside the tarball if first deploy).
|
|
21
|
+
2. No `npm install` needed — `node_modules` was transferred directly.
|
|
22
|
+
3. Start PM2 on the inactive port. Health checks and traffic switch follow the standard flow (Groups 3-5 in SKILL.md).
|
|
23
|
+
|
|
24
|
+
## Why transfer node_modules
|
|
25
|
+
|
|
26
|
+
Direct upload is optimized for "fast first deploy." Re-running `npm ci` on a low-spec server can be slow. Transferring pre-built artifacts means the server only needs to run the app.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# DNS Setup Guidance
|
|
2
|
+
|
|
3
|
+
Read this file when the user has a domain for their project but DNS is not yet pointing to the server.
|
|
4
|
+
|
|
5
|
+
## Step 1 — Check DNS resolution
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
dig +short <domain> A
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
If it resolves to the server IP: DNS is already configured, proceed to SSL (`references/ssl-setup.md`).
|
|
12
|
+
If not: continue below.
|
|
13
|
+
|
|
14
|
+
## Step 2 — DNS setup guidance
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
域名 <example.com> 还未指向服务器 <服务器IP>。
|
|
18
|
+
|
|
19
|
+
请在 DNS 服务商(如阿里云、Cloudflare、Namecheap)添加以下记录:
|
|
20
|
+
|
|
21
|
+
Type: A
|
|
22
|
+
Name: @
|
|
23
|
+
Value: <服务器IP>
|
|
24
|
+
TTL: 600
|
|
25
|
+
|
|
26
|
+
如果要同时支持 www 子域名:
|
|
27
|
+
Type: A
|
|
28
|
+
Name: www
|
|
29
|
+
Value: <服务器IP>
|
|
30
|
+
|
|
31
|
+
配置完成后回复"好了",我继续检查并配 SSL 证书。
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Step 3 — Verify after user confirmation
|
|
35
|
+
|
|
36
|
+
- Re-run `dig +short <domain> A` to confirm resolution.
|
|
37
|
+
- If still not resolved: warn about DNS propagation delay (can take up to 48 hours, usually 5-30 minutes). Offer to wait or continue without SSL for now.
|
|
38
|
+
- Once confirmed: proceed to SSL (`references/ssl-setup.md`).
|
|
39
|
+
|
|
40
|
+
## Edge case — IP-only deployment
|
|
41
|
+
|
|
42
|
+
If user has no domain: skip DNS + SSL sections. Generate a note in deploy.md: "项目通过 IP 访问,未配置域名和 HTTPS。建议购买域名后运行 `/prizmkit-deploy setup-ssl`。"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Firewall Setup (UFW)
|
|
2
|
+
|
|
3
|
+
Read this file when the user wants AI-assisted firewall configuration during bootstrap.
|
|
4
|
+
|
|
5
|
+
## Flow
|
|
6
|
+
|
|
7
|
+
1. After core tools are installed, ask the user:
|
|
8
|
+
> "是否需要帮你配置防火墙(ufw)?只开放必要的端口,提高服务器安全性。"
|
|
9
|
+
|
|
10
|
+
2. If user declines: skip, record to deploy config.
|
|
11
|
+
|
|
12
|
+
3. If user agrees, ask which additional ports to open (beyond SSH/HTTP/HTTPS):
|
|
13
|
+
> "默认只开放 SSH(22)、HTTP(80)、HTTPS(443)。蓝绿部署预览端口(3101/3102)要不要也开放?如果需要其他端口(如数据库远程管理),可以一起列出来。"
|
|
14
|
+
|
|
15
|
+
4. Collect ports, then ask:
|
|
16
|
+
> "防火墙规则已整理好。是我直接上去改,还是你自己来?"
|
|
17
|
+
> - **A. 你帮我改** — AI 执行 ufw 命令
|
|
18
|
+
> - **B. 我自己改** — 输出规则清单,用户手工执行
|
|
19
|
+
|
|
20
|
+
## Planned rules (output before executing)
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
ufw default deny incoming
|
|
24
|
+
ufw default allow outgoing
|
|
25
|
+
ufw allow 22/tcp # SSH
|
|
26
|
+
ufw allow 80/tcp # HTTP
|
|
27
|
+
ufw allow 443/tcp # HTTPS
|
|
28
|
+
ufw allow 3101/tcp # blue preview (user-approved)
|
|
29
|
+
ufw allow 3102/tcp # green preview (user-approved)
|
|
30
|
+
ufw --force enable
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Rules for automatic execution
|
|
34
|
+
|
|
35
|
+
- Check `ufw status` first — if rules already exist, append only missing rules, don't overwrite.
|
|
36
|
+
- Never `ufw reset` unless explicitly asked, because it wipes custom rules the user may have configured manually.
|
|
37
|
+
- Record a `"security-baseline"` event in deploy history with the rule list, so future sessions can detect existing configuration.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Implementation Notes from Live Validation
|
|
2
|
+
|
|
3
|
+
These findings from the first PrizmKit deployment (PrizmIdeas) guide edge-case handling. Read when troubleshooting bootstrap or deploy issues.
|
|
4
|
+
|
|
5
|
+
1. **Detect port conflicts before installing Nginx.** Check what's on port 80/443 and ask before stopping anything, because overwriting an existing web server without confirmation can break unrelated services.
|
|
6
|
+
|
|
7
|
+
2. **Verify npm separately from node.** Minimal Node installs may not bundle npm. Run `which npm` after installing Node, because `node --version` succeeding doesn't guarantee npm is available.
|
|
8
|
+
|
|
9
|
+
3. **Fix locale on bare Ubuntu.** Run `locale-gen en_US.UTF-8` early to avoid perl warnings in apt. This is safe to run unconditionally even if locale is already configured.
|
|
10
|
+
|
|
11
|
+
4. **Deploy key workflow is inherently interactive.** Generate key → wait for user to add to GitHub → verify. Headless mode cannot complete this because it requires the user to paste the key into GitHub's UI.
|
|
12
|
+
|
|
13
|
+
5. **`pm2 startup` needs explicit PATH.** Always use `env PATH=$PATH:/usr/bin pm2 startup ...`, because the pm2 binary may not be on root's default PATH.
|
|
14
|
+
|
|
15
|
+
6. **Persist deploy metadata on server.** Write `activeColor`, `activePort`, `lastReleaseId`, `lastDeployTimestamp` to `shared/deploy-metadata.json`, because subsequent deploys and rollbacks depend on knowing the current active slot.
|
|
16
|
+
|
|
17
|
+
7. **Detect first deployment.** If no `current` symlink and no PM2 process for the app, skip rollback safety checks and use blue (3101) as initial color.
|
|
18
|
+
|
|
19
|
+
8. **Build-time env vars.** Copy `.env.production` before `npm run build`, not after. `NEXT_PUBLIC_*` vars are baked at build time and won't be picked up if the .env is added later.
|
|
20
|
+
|
|
21
|
+
9. **Node.js version flexibility.** Default to v22 LTS if v25 is unavailable. Most frameworks tolerate a minor version diff, and v22 has broader package compatibility.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# SSL/HTTPS Configuration (Let's Encrypt + Certbot)
|
|
2
|
+
|
|
3
|
+
Read this file when DNS is confirmed pointing to the server and SSL needs to be configured.
|
|
4
|
+
|
|
5
|
+
## Step 1 — Detect cloud vendor
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
# Try metadata endpoints to detect cloud vendor
|
|
9
|
+
curl -s --connect-timeout 2 http://100.100.100.200/latest/meta-data/ && echo "ALIBABA"
|
|
10
|
+
curl -s --connect-timeout 2 http://metadata.tencentyun.com/latest/meta-data/ && echo "TENCENT"
|
|
11
|
+
curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/ && echo "AWS/GCP/AZURE"
|
|
12
|
+
```
|
|
13
|
+
Also check `/etc/hostname` for vendor patterns.
|
|
14
|
+
|
|
15
|
+
## Step 2 — Choose SSL strategy
|
|
16
|
+
|
|
17
|
+
- **Cloud vendor detected** → ask user:
|
|
18
|
+
> "检测到服务器运行在 <云厂商>。用哪种 SSL 方案?"
|
|
19
|
+
> - **A. Let's Encrypt 免费证书(推荐)** — 一行命令永久自动续期,最省心
|
|
20
|
+
> - **B. <云厂商> 自有证书** — 需手动下载配置,1年有效期需手动续期
|
|
21
|
+
>
|
|
22
|
+
> 选 A 我直接帮你搞定;选 B 你需要在云控制台下载证书后告诉我路径。
|
|
23
|
+
- **No cloud vendor / unknown** → use certbot directly, no choice needed.
|
|
24
|
+
|
|
25
|
+
## Step 3 — Certbot install & certificate request
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
# Install certbot (idempotent)
|
|
29
|
+
which certbot || apt-get install -y certbot python3-certbot-nginx
|
|
30
|
+
|
|
31
|
+
# Request certificate
|
|
32
|
+
certbot --nginx -d <domain> -d www.<domain> --non-interactive --agree-tos --email <user-email>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Collect from user before running:**
|
|
36
|
+
- Email address (Let's Encrypt expiry notifications)
|
|
37
|
+
- Confirm domain list (e.g., `example.com, www.example.com`)
|
|
38
|
+
|
|
39
|
+
## Step 4 — Verify auto-renewal
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
systemctl status certbot.timer
|
|
43
|
+
certbot renew --dry-run
|
|
44
|
+
```
|
|
45
|
+
If timer is inactive, enable it: `systemctl enable --now certbot.timer`.
|
|
46
|
+
|
|
47
|
+
## Step 5 — Record
|
|
48
|
+
|
|
49
|
+
- Write SSL configuration summary to deploy.md: certificate paths, auto-renewal status, expiry date.
|
|
50
|
+
- Record a `"ssl-setup"` event in deploy history.
|
|
51
|
+
|
|
52
|
+
## Edge cases
|
|
53
|
+
|
|
54
|
+
- **DNS not yet propagated** → certbot challenge fails. Tell user to wait and retry: `/prizmkit-deploy setup-ssl`.
|
|
55
|
+
- **Existing certificate found** → check expiry date (`certbot certificates`). If expiring within 30 days, warn. Otherwise skip.
|
|
56
|
+
- **Port 80/443 occupied by non-Nginx process** → report and ask how to resolve before proceeding.
|