@awesomate/hosting-mcp 0.8.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +19 -5
- package/package.json +1 -1
- package/skill/awesomate-app-builder/SKILL.md +22 -6
- package/skill/awesomate-app-builder/references/node-recipes.md +83 -0
- package/skill/awesomate-app-builder/references/security-checklist.md +57 -0
- package/skill/awesomate-app-builder/references/stack-decision.md +16 -4
- package/skill/awesomate-app-builder/references/wp-migrate.md +60 -0
package/dist/index.js
CHANGED
|
@@ -40108,7 +40108,7 @@ readTool(
|
|
|
40108
40108
|
);
|
|
40109
40109
|
readTool(
|
|
40110
40110
|
"awesomate_get_limits",
|
|
40111
|
-
"Usage vs plan limits across every dimension (sites, custom domains, workflow credits, AI-editor credits) plus a nudges[] array. Call BEFORE any create action; when a nudge has severity 'approaching' or 'exceeded', surface it to the user with the recommended plan \u2014 never execute an upgrade without preview + explicit confirmation (upgrade tools ship in a later release; for now deep-link to the hub billing page).",
|
|
40111
|
+
"Usage vs plan limits across every dimension (sites, custom domains, apps, database provisions today, workflow credits, AI-editor credits) plus a nudges[] array. Call BEFORE any create action; when a nudge has severity 'approaching' or 'exceeded', surface it to the user with the recommended plan \u2014 never execute an upgrade without preview + explicit confirmation (upgrade tools ship in a later release; for now deep-link to the hub billing page). pgProvisionsToday is a flat daily cap that resets within 24h \u2014 no plan raises it, so don't pitch an upgrade for it.",
|
|
40112
40112
|
"/api/client-hosting/limits"
|
|
40113
40113
|
);
|
|
40114
40114
|
server.registerTool(
|
|
@@ -40207,12 +40207,12 @@ server.registerTool(
|
|
|
40207
40207
|
server.registerTool(
|
|
40208
40208
|
"awesomate_app_create",
|
|
40209
40209
|
{
|
|
40210
|
-
description: "Provision a new app on the client's cPanel account. Choose the stack deliberately (see the awesomate-app-builder skill): kind 'static' = a single fast landing/lead page served straight from the docroot (no DB, no server process \u2014 pick this for brochure/landing/lead-capture); kind 'node' = a dynamic app with a backend + database (logins, custom logic, an API).
|
|
40210
|
+
description: "Provision a new app on the client's cPanel account. Choose the stack deliberately (see the awesomate-app-builder skill): kind 'static' = a single fast landing/lead page served straight from the docroot (no DB, no server process \u2014 pick this for brochure/landing/lead-capture); kind 'node' = a dynamic app with a backend + database (logins, custom logic, an API). Pick the template by job \u2014 'node-auth-sync' (user accounts/logins, MySQL), 'node-crud-postgres' (structured data without logins: trackers/dashboards \u2014 ready-made CRUD + UI, Postgres), 'node-api-only' (webhooks/integrations/glue, no DB wiring), 'static-landing' (marketing/lead page). If dbEngine is omitted the template's native engine is used (node-crud-postgres \u2192 postgres). Returns 202 immediately with an appId + subdomain(s); poll awesomate_app_get until status=active, then fetch the starter files with awesomate_app_scaffold. Requires apps:write (Support Plus+) \u2014 a 403 means offer an upgrade. Get the user's confirmation on the stack + name before calling.",
|
|
40211
40211
|
inputSchema: {
|
|
40212
40212
|
appSlug: external_exports.string().regex(/^[a-z][a-z0-9]{1,15}$/).describe("2-16 chars, starts with a letter, lowercase alphanumeric \u2014 used for subdomains + db names"),
|
|
40213
40213
|
kind: external_exports.enum(["node", "static"]).default("node").describe("'static' for a landing/lead page (no DB); 'node' for a dynamic app"),
|
|
40214
|
-
dbEngine: external_exports.enum(["mysql", "postgres"]).
|
|
40215
|
-
template: external_exports.string().optional().describe("Starter template (defaults: node \u2192 'node-auth-sync', static \u2192 'static-landing')")
|
|
40214
|
+
dbEngine: external_exports.enum(["mysql", "postgres"]).optional().describe("node only \u2014 omit to use the template's native engine"),
|
|
40215
|
+
template: external_exports.string().optional().describe("Starter template: node-auth-sync | node-crud-postgres | node-api-only | static-landing (defaults: node \u2192 'node-auth-sync', static \u2192 'static-landing'; full catalog in awesomate_app_context.templates)")
|
|
40216
40216
|
}
|
|
40217
40217
|
},
|
|
40218
40218
|
async ({ appSlug, kind, dbEngine, template }) => {
|
|
@@ -40225,10 +40225,24 @@ server.registerTool(
|
|
|
40225
40225
|
}
|
|
40226
40226
|
}
|
|
40227
40227
|
);
|
|
40228
|
+
server.registerTool(
|
|
40229
|
+
"awesomate_app_scaffold",
|
|
40230
|
+
{
|
|
40231
|
+
description: "Fetch the app's starter files (its template rendered against the live app metadata \u2014 subdomains, control-plane URL, repo \u2014 with placeholders already substituted). Call after awesomate_app_create reaches status=active: write each returned file into a fresh local project folder at its relative path, then run npm install (Node apps) and follow the bundled CLAUDE.md. This is how the starter code gets onto the user's machine \u2014 don't reconstruct templates by hand.",
|
|
40232
|
+
inputSchema: { appId: external_exports.number().int().positive().describe("The app id from awesomate_app_create / _list") }
|
|
40233
|
+
},
|
|
40234
|
+
async ({ appId }) => {
|
|
40235
|
+
try {
|
|
40236
|
+
return textResult(await hubGet(requireConfig(), `/api/my-apps/apps/${appId}/scaffold`));
|
|
40237
|
+
} catch (err) {
|
|
40238
|
+
return errorResult(err);
|
|
40239
|
+
}
|
|
40240
|
+
}
|
|
40241
|
+
);
|
|
40228
40242
|
server.registerTool(
|
|
40229
40243
|
"awesomate_app_deploy",
|
|
40230
40244
|
{
|
|
40231
|
-
description: "Report how to deploy an app
|
|
40245
|
+
description: "Report how to deploy an app, its per-env targets, last-deploy/health state, and how to promote (dev\u2192staging\u2192main) or roll back (git revert + push). Node apps deploy via git push (dev/staging/main \u2192 GitHub Actions \u2192 cPanel). Use the awesomate-github skill to wire push-to-deploy the first time.",
|
|
40232
40246
|
inputSchema: { appId: external_exports.number().int().positive().describe("The app id") }
|
|
40233
40247
|
},
|
|
40234
40248
|
async ({ appId }) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awesomate/hosting-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -70,21 +70,37 @@ target; never touch prod without an explicit ask.**
|
|
|
70
70
|
you recommend. Get a yes.
|
|
71
71
|
3. **Confirmation gate** — confirm the **name** (2–16 lowercase letters/digits,
|
|
72
72
|
starts with a letter — becomes the subdomain + db names) and the **stack**,
|
|
73
|
-
then call `awesomate_app_create` (`appSlug`, `kind`, and for
|
|
73
|
+
then call `awesomate_app_create` (`appSlug`, `kind`, `template`, and for
|
|
74
|
+
node optionally `dbEngine` — omit it to use the template's native engine).
|
|
75
|
+
Pick the template by job (stack-decision.md has the table): logins →
|
|
76
|
+
`node-auth-sync`; structured data, no logins → `node-crud-postgres`;
|
|
77
|
+
webhooks/integrations → `node-api-only`; landing page → `static-landing`.
|
|
74
78
|
It returns **202** with an `appId` + subdomain(s); poll `awesomate_app_get`
|
|
75
79
|
until `status` is `active` (or `failed` — read `provision_error`, explain
|
|
76
80
|
plainly).
|
|
77
|
-
4. **
|
|
78
|
-
|
|
81
|
+
4. **Scaffold** — call `awesomate_app_scaffold` and write each returned file
|
|
82
|
+
into a fresh local project folder at its relative path (placeholders are
|
|
83
|
+
already substituted), then `npm install` (Node) and read the bundled
|
|
84
|
+
`CLAUDE.md` — it's the app's own manual. Never reconstruct the starter by
|
|
85
|
+
hand.
|
|
86
|
+
5. **Implementation** — build the actual code/content on top of the scaffold.
|
|
87
|
+
[references/node-recipes.md](references/node-recipes.md) has the recipes
|
|
88
|
+
(add a table/endpoint, env vars, connection strings, promote/rollback).
|
|
89
|
+
Handle **secrets** only via the **awesomate-credentials** skill
|
|
79
90
|
(encrypted + injected, never committed/echoed). Wire **version control**
|
|
80
91
|
from the first commit via **awesomate-github**. If it needs email/lookup/AI,
|
|
81
92
|
attach n8n (§"when to use n8n").
|
|
82
|
-
|
|
93
|
+
6. **Testing** — deploy to **dev** (`git push` to `dev`), then
|
|
83
94
|
`awesomate_app_health` to confirm it came up (Node: `/api/ready`). Show the
|
|
84
95
|
user the live dev URL and let them try it. Iterate on dev until they're happy.
|
|
85
|
-
|
|
96
|
+
7. **Wrap-up / promote** — only when the user approves, promote **dev → staging
|
|
86
97
|
→ main** (merge + push per branch). `awesomate_app_deploy` reports the
|
|
87
|
-
branch→env map. Prod is `main`.
|
|
98
|
+
branch→env map + last-deploy state. Prod is `main`. **Before merging to
|
|
99
|
+
main**, walk [references/security-checklist.md](references/security-checklist.md)
|
|
100
|
+
— the deploy workflow's automated gate blocks prod on high-severity
|
|
101
|
+
findings (secrets, injectable SQL, eval…), and the checklist covers what
|
|
102
|
+
a scanner can't (authorization, webhook secrets, data minimization).
|
|
103
|
+
Never remove the gate step to make a deploy pass — fix the finding.
|
|
88
104
|
|
|
89
105
|
**Promote / rollback (git-based):** promoting is merging the tested branch
|
|
90
106
|
forward (`dev`→`staging`→`main`); rolling back is `git revert` of the bad
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Node app recipes — the moves you'll make over and over
|
|
2
|
+
|
|
3
|
+
Every scaffolded app carries its own `CLAUDE.md` (the authoritative manual for
|
|
4
|
+
THAT app — read it first). These are the cross-app recipes, kept in the user's
|
|
5
|
+
plain language.
|
|
6
|
+
|
|
7
|
+
## Add a table / change the schema
|
|
8
|
+
|
|
9
|
+
Never edit an already-deployed migration. Add a new file:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
migrations/002_add_customers.sql
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```sql
|
|
16
|
+
CREATE TABLE IF NOT EXISTS customers (...);
|
|
17
|
+
-- or: ALTER TABLE records ADD COLUMN amount NUMERIC NOT NULL DEFAULT 0;
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Push it — the deploy workflow runs `npm run migrate` before restarting the
|
|
21
|
+
app. Postgres templates apply each file in a transaction (a failure rolls
|
|
22
|
+
back and retries next deploy); MySQL applies statement-by-statement, so keep
|
|
23
|
+
MySQL migrations small.
|
|
24
|
+
|
|
25
|
+
## Add an endpoint
|
|
26
|
+
|
|
27
|
+
Copy the closest existing route in `src/index.ts` and keep its three habits:
|
|
28
|
+
|
|
29
|
+
1. **zod-validate the input** before touching the DB or doing work.
|
|
30
|
+
2. **Parameterized SQL only** — `$1`/`$2` (Postgres) or `?` (MySQL). Never
|
|
31
|
+
template user input into a SQL string.
|
|
32
|
+
3. **Escape on render** — `textContent` in browser code, never `innerHTML`
|
|
33
|
+
with user data.
|
|
34
|
+
|
|
35
|
+
## Connection strings / DB access
|
|
36
|
+
|
|
37
|
+
Provisioning writes the server-side `.env` per env: `DATABASE_URL` +
|
|
38
|
+
`DB_ENGINE`/`DB_HOST`/`DB_PORT`/`DB_NAME`/`DB_USER`/`DB_PASS`. The starters'
|
|
39
|
+
lazy pool means local dev works with a blank `.env` (DB routes return 503
|
|
40
|
+
with a clear reason). Postgres code should prefer `DATABASE_URL`.
|
|
41
|
+
|
|
42
|
+
## Env vars & secrets
|
|
43
|
+
|
|
44
|
+
- Runtime secret for the app → `awesomate_app_set_env` (encrypted in the hub,
|
|
45
|
+
injected into the server `.env`, pm2 restarted). Per-env; `dev` default.
|
|
46
|
+
- Never commit `.env`, never echo a stored value, and per the
|
|
47
|
+
awesomate-credentials skill: a key pasted in chat gets stored AND flagged
|
|
48
|
+
for rotation.
|
|
49
|
+
|
|
50
|
+
## Attach n8n as the backend
|
|
51
|
+
|
|
52
|
+
Job needs email / a lookup in their connected apps / AI → build the webhook
|
|
53
|
+
workflow with the awesomate-n8n skill, then `awesomate_n8n_attach_to_app`
|
|
54
|
+
(stores `N8N_WEBHOOK_URL` + secret; returns the secret ONCE — add the
|
|
55
|
+
matching `X-Awesomate-Webhook-Secret` header check to the workflow). The app
|
|
56
|
+
calls `callWorkflow(payload)` from `src/lib/n8n.ts`; it no-ops when unset and
|
|
57
|
+
never throws — check `result.ok` and degrade gracefully.
|
|
58
|
+
|
|
59
|
+
## Deploy, promote, roll back
|
|
60
|
+
|
|
61
|
+
- **Deploy** = `git push origin dev` (that's the whole mechanism). Watch with
|
|
62
|
+
`gh run watch`; verify with `awesomate_app_health`.
|
|
63
|
+
- **Promote** = merge forward: `dev → staging → main`. Prod is `main`; go
|
|
64
|
+
through a PR from staging.
|
|
65
|
+
- **Roll back** = `git revert <bad-sha>` on the affected branch + push — the
|
|
66
|
+
workflow redeploys the previous good state. Re-check health after.
|
|
67
|
+
- `awesomate_app_deploy` reports the branch→env map, last-deploy SHA/time,
|
|
68
|
+
and last health per env.
|
|
69
|
+
|
|
70
|
+
## Health semantics (don't mix these up)
|
|
71
|
+
|
|
72
|
+
- `/api/health` — lenient, always 200, DB state in the body. For humans.
|
|
73
|
+
- `/api/ready` — strict; 503 until the DB is reachable AND migrations ran
|
|
74
|
+
(DB templates). CI's post-deploy gate and what `awesomate_app_health`
|
|
75
|
+
probes. An app that was created but never pushed reports unreachable —
|
|
76
|
+
that's expected, not broken.
|
|
77
|
+
|
|
78
|
+
## When something's off
|
|
79
|
+
|
|
80
|
+
1. `gh run view --log-failed` — the deploy step that broke.
|
|
81
|
+
2. `awesomate_app_health` — live per-env probe with a plain reason.
|
|
82
|
+
3. The app's own `CLAUDE.md` troubleshooting section — engine-specific
|
|
83
|
+
diagnostics live there.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Security checklist — walk this before promoting to prod
|
|
2
|
+
|
|
3
|
+
Two layers guard prod. The **automated gate** runs in every app's deploy
|
|
4
|
+
workflow (`scripts/security-check.mjs` — report-only on dev/staging,
|
|
5
|
+
BLOCKING on `main`, plus `npm audit --audit-level=critical`). This checklist
|
|
6
|
+
is the **human layer**: the things a scanner cannot see. Walk it with the
|
|
7
|
+
user in plain language before merging staging → main.
|
|
8
|
+
|
|
9
|
+
## What the automated gate already catches (don't re-litigate)
|
|
10
|
+
|
|
11
|
+
Committed secrets / a tracked `.env` / private keys · SQL built by
|
|
12
|
+
interpolation or concatenation · `eval` / `new Function` · shell exec with
|
|
13
|
+
interpolated input · critical dependency advisories. If the prod deploy
|
|
14
|
+
fails on the gate, read the Actions log — every finding prints its fix.
|
|
15
|
+
**Never remove or bypass the gate step to make a deploy pass.**
|
|
16
|
+
|
|
17
|
+
## The human checks (scanner-blind spots)
|
|
18
|
+
|
|
19
|
+
1. **Authorization, not just authentication.** Logged-in is not allowed.
|
|
20
|
+
For every route that reads/writes data: could user A pass user B's id and
|
|
21
|
+
touch B's data? Filter by the session's user id server-side, never trust
|
|
22
|
+
an id from the request body.
|
|
23
|
+
2. **Every input validated at the edge.** Each POST/PATCH handler starts
|
|
24
|
+
with a zod `safeParse`, with sane max lengths. No handler touches
|
|
25
|
+
`await c.req.json()` raw.
|
|
26
|
+
3. **Secrets flow one way.** Values live in env vars (set via
|
|
27
|
+
`awesomate_app_set_env`), are never logged, never echoed in responses,
|
|
28
|
+
never sent to the browser.
|
|
29
|
+
4. **Rendering is escape-safe.** Browser code uses `textContent` /
|
|
30
|
+
`createElement` for user data; server HTML never string-interpolates
|
|
31
|
+
user input without escaping.
|
|
32
|
+
5. **The n8n webhook is not world-callable.** If n8n is attached, the
|
|
33
|
+
workflow checks the `X-Awesomate-Webhook-Secret` header (set during
|
|
34
|
+
attach). Test: call the webhook without the header — it must refuse.
|
|
35
|
+
6. **Public API surface is intentional.** api-only starter: is `API_KEY`
|
|
36
|
+
set for prod, or is a public API genuinely intended? CORS open on
|
|
37
|
+
purpose?
|
|
38
|
+
7. **Sensitive data is minimized.** Only collect what the app needs; if it
|
|
39
|
+
stores personal data, tell the user plainly: connections are TLS and
|
|
40
|
+
secrets are encrypted, but the DATABASE is not blanket-encrypted at
|
|
41
|
+
rest — sensitive fields deserve app-level encryption (ask before adding).
|
|
42
|
+
8. **Errors don't leak.** 500 responses return a generic message, not stack
|
|
43
|
+
traces or SQL (the starters already do this — keep it).
|
|
44
|
+
|
|
45
|
+
## Static sites
|
|
46
|
+
|
|
47
|
+
No server code, so the gate doesn't run — the risks are the lead form's
|
|
48
|
+
webhook (point 5) and third-party scripts (don't add any that aren't
|
|
49
|
+
needed). Never put an API key in page JavaScript: anything in a static page
|
|
50
|
+
is public.
|
|
51
|
+
|
|
52
|
+
## How to talk about it
|
|
53
|
+
|
|
54
|
+
Non-technical user — say what you checked, not the jargon: *"Before making
|
|
55
|
+
it live I checked that people can only see their own data, that the contact
|
|
56
|
+
form can't be abused, and that your API key never appears anywhere public.
|
|
57
|
+
The deploy pipeline also scans every release automatically."*
|
|
@@ -8,18 +8,30 @@ confirm before building. **Never default to WordPress.**
|
|
|
8
8
|
|
|
9
9
|
| What the user is really trying to do | Stack | Why / how |
|
|
10
10
|
|---|---|---|
|
|
11
|
-
| "I already have a WordPress site" / a blog / publishes content regularly / **wants to rank on Google & AI** | **WordPress** | Best CMS for indexable content, sitemaps, schema. Hand to the awesomate-hosting skill to provision, then run **awesomate-seo**. |
|
|
11
|
+
| "I already have a WordPress site" / a blog / publishes content regularly / **wants to rank on Google & AI** | **WordPress** | Best CMS for indexable content, sitemaps, schema. Hand to the awesomate-hosting skill to provision, then run **awesomate-seo**. Existing WP elsewhere → migrate it, don't rebuild: [wp-migrate.md](wp-migrate.md) (also covers WP ↔ app coexistence on subdomains). |
|
|
12
12
|
| Sell products / online shop | **WordPress + WooCommerce** | Reuse the `woo-agent-storefront` (AI-shopping feeds + `llms.txt`) and `woo-catalog-perfection` skills. |
|
|
13
13
|
| A landing page / capture leads / a one-pager / "just needs to look good and be found" | **static site** (`kind: 'static'`) | Served straight from the cPanel docroot — no database, no server process, fastest load. Add SEO + a lead form (below). The right default for marketing pages. |
|
|
14
14
|
| A tool/app with **logins, custom logic, a dashboard, or an API** | **Node app** (`kind: 'node'`) | A real backend + database. |
|
|
15
15
|
|
|
16
|
+
### Within a Node app: which starter template?
|
|
17
|
+
Pick by the job (full catalog with descriptions: `awesomate_app_context.templates`):
|
|
18
|
+
|
|
19
|
+
| Job | `template` | Ships with |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| People **sign in** / per-user data | `node-auth-sync` | signup/login (JWT + bcrypt), MySQL migrations |
|
|
22
|
+
| Stores **structured data, no logins** — trackers, dashboards, internal tools | `node-crud-postgres` | ready-made records CRUD API + tiny UI, Postgres migrations (transactional) |
|
|
23
|
+
| **Webhooks / integrations / glue** — receives or serves JSON, little state | `node-api-only` | versioned `/api/v1` routes, CORS, optional `x-api-key` gate, no DB wiring |
|
|
24
|
+
|
|
25
|
+
All three include `src/lib/n8n.ts` and the same push-to-deploy workflow.
|
|
26
|
+
|
|
16
27
|
### Within a Node app: which database?
|
|
17
28
|
- **postgres** — relational data with relationships, concurrency, JSON columns,
|
|
18
29
|
or analytics/AI features. The modern default for a real app.
|
|
19
30
|
- **mysql** — simple/legacy needs, or when they already know MySQL.
|
|
20
|
-
-
|
|
21
|
-
`
|
|
22
|
-
ready-to-use
|
|
31
|
+
- Omit `dbEngine` and `awesomate_app_create` uses the template's native engine
|
|
32
|
+
(`node-crud-postgres` → postgres). The app's `.env` gets `DB_ENGINE`,
|
|
33
|
+
`DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASS`, and a ready-to-use
|
|
34
|
+
`DATABASE_URL` — even `node-api-only` gets one, sitting idle until wired.
|
|
23
35
|
|
|
24
36
|
## Questions that resolve the choice fast
|
|
25
37
|
1. "Is this mainly a **page people read** (marketing, blog, shop) or a **tool
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Moving an existing WordPress site to Awesomate (and WP ↔ app coexistence)
|
|
2
|
+
|
|
3
|
+
When the stack decision lands on WordPress **and the user already has a WP
|
|
4
|
+
site elsewhere**, don't rebuild it — migrate it. Plain-language framing:
|
|
5
|
+
*"We'll make an exact copy of your current site on your Awesomate hosting,
|
|
6
|
+
check it works, then point your domain at it. Your old site stays untouched
|
|
7
|
+
until you're happy."*
|
|
8
|
+
|
|
9
|
+
## The migration path
|
|
10
|
+
|
|
11
|
+
1. **Provision WP on Awesomate first** — the awesomate-hosting skill's
|
|
12
|
+
normal WP install (their plan's site limit applies; check
|
|
13
|
+
`awesomate_get_limits`). This gives a working target with SSL.
|
|
14
|
+
2. **Export from the old host.** Preference order:
|
|
15
|
+
- **A full-copy plugin** (Duplicator / All-in-One WP Migration): the user
|
|
16
|
+
installs it on their OLD site and downloads the archive — the only step
|
|
17
|
+
that happens outside Awesomate, so give them click-by-click guidance.
|
|
18
|
+
- **Host export**: many hosts offer a backup download (files + a `.sql`).
|
|
19
|
+
- **WP admin export (XML)**: last resort — content only (posts/pages/
|
|
20
|
+
media), loses theme/plugins/settings; expect to reassemble the look.
|
|
21
|
+
3. **Import on Awesomate.** With shell access (Support Plus+) prefer
|
|
22
|
+
`wp-cli` over the target install: unpack files into the docroot, import
|
|
23
|
+
the DB, then `wp search-replace 'https://old-domain.com'
|
|
24
|
+
'https://new-domain.com' --all-tables` (serialized-data-safe — never do
|
|
25
|
+
this with raw SQL). Plugin archives restore through the same plugin
|
|
26
|
+
installed on the new site.
|
|
27
|
+
4. **Verify before DNS.** Browse the copy on its Awesomate URL: pages,
|
|
28
|
+
images, forms, admin login, HTTPS. Run **awesomate-seo** (sitemap,
|
|
29
|
+
robots, meta) and offer the **wp-security-review** skill — a migrated
|
|
30
|
+
site imports its old plugins, and stale plugins are the top WP risk.
|
|
31
|
+
5. **Cut over DNS** — point the domain at Awesomate (add it as a custom
|
|
32
|
+
domain first; plan limits apply). Old site stays live as the fallback
|
|
33
|
+
until the user confirms; propagation can take up to a day and both
|
|
34
|
+
copies serve during it (avoid content edits that day).
|
|
35
|
+
6. **After cutover:** confirm SSL issued for the domain, re-run the SEO
|
|
36
|
+
check on the final URL, and remind them to cancel the old hosting only
|
|
37
|
+
once everything's verified.
|
|
38
|
+
|
|
39
|
+
## WP ↔ app coexistence (they want both)
|
|
40
|
+
|
|
41
|
+
The platform already separates them cleanly — **WordPress owns the main
|
|
42
|
+
domain; every app lives on its own subdomain** (`app.domain.com`,
|
|
43
|
+
`dev-app.domain.com`, …). No conflict: Apache routes the main site to WP's
|
|
44
|
+
docroot and each subdomain to its app.
|
|
45
|
+
|
|
46
|
+
- Marketing/blog/shop stays in WP; the tool their customers log into is the
|
|
47
|
+
Node app on a subdomain. Link between them with plain links.
|
|
48
|
+
- Don't try to serve an app *under a WP path* (`domain.com/app`) — that
|
|
49
|
+
fights WP's rewrites. A subdomain is the supported shape.
|
|
50
|
+
- Shared look: reuse the WP site's colors/logo in the app's UI rather than
|
|
51
|
+
loading WP themes into the app.
|
|
52
|
+
- Shared backend jobs (a form on either side emailing/CRM-ing): both can
|
|
53
|
+
call the same n8n webhook — one workflow, two callers.
|
|
54
|
+
|
|
55
|
+
## When NOT to migrate
|
|
56
|
+
|
|
57
|
+
If the old "WP site" is really one landing page and they don't blog or
|
|
58
|
+
sell: recommend rebuilding it as a **static site** on Awesomate instead
|
|
59
|
+
(faster, nothing to update) — see stack-decision.md. Migration is for sites
|
|
60
|
+
with real content, plugins, or a shop.
|