@cloudgrid-io/mcp 0.10.0 → 0.11.2
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/package.json +3 -1
- package/src/corpus/capability-map.md +72 -0
- package/src/corpus/cloudgrid-yaml.md +569 -0
- package/src/corpus/examples/app-with-data/index.md +24 -19
- package/src/corpus/templates/app-with-data/README.md +22 -19
- package/src/corpus/templates/app-with-data/cloudgrid.yaml +9 -9
- package/src/corpus/templates/app-with-data/index.md +38 -29
- package/src/corpus/templates/app-with-data/services/web/lib/db.js +10 -9
- package/src/corpus/templates/dashboard/cloudgrid.yaml +10 -0
- package/src/corpus/templates/dashboard/index.md +30 -0
- package/src/corpus/templates/deck/cloudgrid.yaml +10 -0
- package/src/corpus/templates/deck/index.md +30 -0
- package/src/corpus/templates/landing-page/cloudgrid.yaml +10 -0
- package/src/corpus/templates/landing-page/index.md +30 -0
- package/src/corpus/templates/report/cloudgrid.yaml +10 -0
- package/src/corpus/templates/report/index.md +30 -0
- package/src/corpus/templates/web-app/cloudgrid.yaml +10 -0
- package/src/corpus/templates/web-app/index.md +30 -0
- package/src/corpus/troubleshooting/persistent-apps.md +6 -6
- package/src/corpus/workflows/app-with-data.md +25 -18
- package/src/corpus/workflows/dashboard.md +5 -1
- package/src/corpus/workflows/landing-page.md +5 -1
- package/src/corpus/workflows/presentation.md +5 -1
- package/src/corpus/workflows/report.md +5 -1
- package/src/corpus/workflows/web-app.md +5 -1
- package/src/tools.js +2 -0
|
@@ -2,32 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
A filled reference imitating the `app-with-data` template: a persistent team
|
|
4
4
|
task board. Same stack (Next.js App Router + the `mongodb` driver, grid-shared
|
|
5
|
-
Mongo via `process.env.
|
|
6
|
-
template — tasks have an `assignee` and a `status` (todo / doing / done),
|
|
7
|
-
the API supports updating status via PATCH.
|
|
5
|
+
Mongo via `process.env.DATABASE_MONGODB_URL`), slightly richer than the bare
|
|
6
|
+
todo template — tasks have an `assignee` and a `status` (todo / doing / done),
|
|
7
|
+
and the API supports updating status via PATCH.
|
|
8
8
|
|
|
9
9
|
Data persists in the grid-shared Mongo, so the whole team sees the same board
|
|
10
10
|
across sessions and refresh.
|
|
11
11
|
|
|
12
12
|
**Same three proven rules as the template:** (1) app code lives under
|
|
13
13
|
**`services/web/`** (the service name, NOT the repo root — `path:` is the URL
|
|
14
|
-
mount); (2)
|
|
15
|
-
module top level (a top-level read fails `next build`); (3)
|
|
16
|
-
declared with **`
|
|
17
|
-
injects `
|
|
14
|
+
mount); (2) the DB connection string is read **lazily inside the `getDb`
|
|
15
|
+
getter**, never at module top level (a top-level read fails `next build`); (3)
|
|
16
|
+
the datastore is declared with the canonical **`needs: { database: true }`** —
|
|
17
|
+
the deployer provisions Mongo and injects `DATABASE_MONGODB_URL` (plus the
|
|
18
|
+
legacy `MONGODB_URL` alias). Don't use the deprecated `requires:` alias.
|
|
18
19
|
|
|
19
20
|
## cloudgrid.yaml
|
|
20
21
|
|
|
21
22
|
```yaml
|
|
22
|
-
#
|
|
23
|
-
#
|
|
23
|
+
# `needs: { database: true }` is canonical: the deployer provisions Mongo and
|
|
24
|
+
# injects DATABASE_MONGODB_URL (plus the legacy MONGODB_URL alias). `requires:`
|
|
25
|
+
# is the deprecated v1 alias — don't mix the two (the validator rejects it).
|
|
24
26
|
name: team-task-board
|
|
25
27
|
services:
|
|
26
28
|
web:
|
|
27
29
|
type: nextjs
|
|
28
30
|
path: /
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
needs:
|
|
32
|
+
database: true
|
|
31
33
|
```
|
|
32
34
|
|
|
33
35
|
## services/web/package.json
|
|
@@ -50,16 +52,18 @@ requires:
|
|
|
50
52
|
## services/web/lib/db.js
|
|
51
53
|
|
|
52
54
|
```js
|
|
53
|
-
// Cached Mongo client.
|
|
54
|
-
//
|
|
55
|
+
// Cached Mongo client. The grid injects DATABASE_MONGODB_URL (plus the legacy
|
|
56
|
+
// MONGODB_URL alias) at dev + runtime. Read the canonical var first, fall back to
|
|
57
|
+
// the legacy alias. Resolve it LAZILY inside the getter — a top-level read fails
|
|
58
|
+
// `next build`.
|
|
55
59
|
import { MongoClient } from "mongodb";
|
|
56
60
|
|
|
57
61
|
function clientPromise() {
|
|
58
|
-
const uri = process.env.MONGODB_URL;
|
|
62
|
+
const uri = process.env.DATABASE_MONGODB_URL || process.env.MONGODB_URL;
|
|
59
63
|
if (!uri) {
|
|
60
64
|
throw new Error(
|
|
61
|
-
"
|
|
62
|
-
"deploy with `grid plug`. Do not set it by hand.",
|
|
65
|
+
"DATABASE_MONGODB_URL is not set. The grid injects it — run `grid dev` " +
|
|
66
|
+
"locally or deploy with `grid plug`. Do not set it by hand.",
|
|
63
67
|
);
|
|
64
68
|
}
|
|
65
69
|
if (!globalThis.__mongoClientPromise) {
|
|
@@ -244,8 +248,9 @@ export default function Board({ initialTasks }) {
|
|
|
244
248
|
|
|
245
249
|
- Deploy the same way as the template: `grid dev` locally, `grid plug` to deploy
|
|
246
250
|
(async — poll status to a live URL). Re-plug the same entity to keep one URL.
|
|
247
|
-
- The only store this needs is Mongo (`
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
- The only store this needs is Mongo (`needs: { database: true }` — the deployer
|
|
252
|
+
provisions Mongo and injects `DATABASE_MONGODB_URL`, plus the legacy
|
|
253
|
+
`MONGODB_URL` alias). Add `cache: true` to `needs:` only for
|
|
254
|
+
caching/sessions/pubsub you actually use.
|
|
250
255
|
- All app code lives under `services/web/`; the connection is read lazily inside
|
|
251
256
|
`getDb`, never at module top level.
|
|
@@ -7,23 +7,26 @@ page whose state is in memory only.
|
|
|
7
7
|
## How the grid gives you a database
|
|
8
8
|
|
|
9
9
|
You do **not** provision a database or set a connection string. In
|
|
10
|
-
`cloudgrid.yaml` you declare `
|
|
10
|
+
`cloudgrid.yaml` you declare `needs: { database: true }`, and the grid:
|
|
11
11
|
|
|
12
12
|
- provisions shared Mongo for the app, and
|
|
13
|
-
- injects the connection string as the **`
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
>
|
|
26
|
-
>
|
|
13
|
+
- injects the connection string as the **`DATABASE_MONGODB_URL`** environment
|
|
14
|
+
variable (plus the legacy `MONGODB_URL` alias) — at dev-time (`grid dev`) and
|
|
15
|
+
at runtime (after `grid plug`).
|
|
16
|
+
|
|
17
|
+
The app reads it via `process.env.DATABASE_MONGODB_URL` (with a legacy
|
|
18
|
+
`process.env.MONGODB_URL` fallback) in `services/web/lib/db.js` — **lazily,
|
|
19
|
+
inside the `getDb` getter, never at module top level** (a top-level read fails
|
|
20
|
+
`next build`, which imports the module for route analysis before the grid injects
|
|
21
|
+
the var). Never hardcode a connection string; never commit a secret. (If you also
|
|
22
|
+
declare `cache: true`, the grid injects `CACHE_REDIS_URL` — and the legacy
|
|
23
|
+
`REDIS_URL` alias — the same way.)
|
|
24
|
+
|
|
25
|
+
> **Declare `needs: { database: true }` (the canonical shape).** The deployer
|
|
26
|
+
> provisions Mongo and injects `DATABASE_MONGODB_URL` (plus the legacy
|
|
27
|
+
> `MONGODB_URL` alias). `requires:` is the deprecated v1 alias — don't author new
|
|
28
|
+
> yaml with it, and never set `needs:` and `requires:` together (the validator
|
|
29
|
+
> rejects the combination).
|
|
27
30
|
|
|
28
31
|
## Service layout
|
|
29
32
|
|
|
@@ -36,7 +39,7 @@ App code lives under **`services/web/`**, not the template root. `path:` in
|
|
|
36
39
|
|
|
37
40
|
```bash
|
|
38
41
|
npm install
|
|
39
|
-
grid dev # runs Next.js with
|
|
42
|
+
grid dev # runs Next.js with DATABASE_MONGODB_URL injected against dev Mongo
|
|
40
43
|
```
|
|
41
44
|
|
|
42
45
|
## Deploy
|
|
@@ -52,9 +55,9 @@ to update the same URL.
|
|
|
52
55
|
## File tree
|
|
53
56
|
|
|
54
57
|
```
|
|
55
|
-
cloudgrid.yaml # name + services.web (nextjs) +
|
|
58
|
+
cloudgrid.yaml # name + services.web (nextjs) + needs: { database: true }
|
|
56
59
|
services/web/package.json # next, react, react-dom, mongodb driver only
|
|
57
|
-
services/web/lib/db.js # lazy Mongo client from
|
|
60
|
+
services/web/lib/db.js # lazy Mongo client from DATABASE_MONGODB_URL (legacy MONGODB_URL fallback)
|
|
58
61
|
services/web/app/layout.js # root layout + inline CSS
|
|
59
62
|
services/web/app/page.js # server component: reads todos from Mongo
|
|
60
63
|
services/web/app/todo-form.js # client form: POST/DELETE via the API
|
|
@@ -67,4 +70,4 @@ services/web/app/api/todos/route.js # GET (list) / POST (add) / DELETE (remove
|
|
|
67
70
|
`services/web/app/page.js` (e.g. `submissions`, `tasks`, `entries`).
|
|
68
71
|
- Change the document fields (add owners, timestamps, statuses).
|
|
69
72
|
- Add more routes/collections as the app grows.
|
|
70
|
-
- Add `
|
|
73
|
+
- Add `cache: true` to `needs:` only if you actually need Redis.
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# Rename this app. The grid injects
|
|
2
|
-
# as environment variables at runtime — do NOT set them
|
|
3
|
-
# a connection string or secret.
|
|
1
|
+
# Rename this app. The grid injects the DB connection string (and a Redis URL if
|
|
2
|
+
# you add a cache) as environment variables at runtime — do NOT set them
|
|
3
|
+
# yourself, and never commit a connection string or secret.
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# `
|
|
8
|
-
#
|
|
5
|
+
# `needs: { database: true }` is the canonical, recommended shape. The deployer
|
|
6
|
+
# provisions Mongo and injects DATABASE_MONGODB_URL (plus the legacy MONGODB_URL
|
|
7
|
+
# alias). `requires:` is the deprecated v1 alias — don't author new yaml with it,
|
|
8
|
+
# and never set `needs:` and `requires:` together (the validator rejects it).
|
|
9
9
|
name: my-app
|
|
10
10
|
services:
|
|
11
11
|
web:
|
|
12
12
|
type: nextjs
|
|
13
13
|
path: /
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
needs:
|
|
15
|
+
database: true
|
|
@@ -9,17 +9,19 @@ so it survives refresh and is shared across sessions — unlike a static page.
|
|
|
9
9
|
root.** `path:` in `cloudgrid.yaml` is the URL mount, NOT the filesystem path.
|
|
10
10
|
The service named `web` → the CLI looks for `services/web/`. App files at the
|
|
11
11
|
root fail with `Error: Service directory not found: …/services/web`.
|
|
12
|
-
2. **Read
|
|
13
|
-
The grid injects
|
|
14
|
-
variable at dev-time and runtime; the
|
|
15
|
-
|
|
12
|
+
2. **Read the DB connection string LAZILY (inside the getter), never at module
|
|
13
|
+
top level.** The grid injects it as the `DATABASE_MONGODB_URL` environment
|
|
14
|
+
variable (plus the legacy `MONGODB_URL` alias) at dev-time and runtime; the
|
|
15
|
+
app reads `process.env.DATABASE_MONGODB_URL || process.env.MONGODB_URL` inside
|
|
16
|
+
`getDb`. A top-level `const uri = process.env.DATABASE_MONGODB_URL; if (!uri)
|
|
16
17
|
throw` fails `next build` (the module is imported for route analysis before
|
|
17
18
|
the grid injects the var). Never hardcode a connection string; never commit a
|
|
18
19
|
secret.
|
|
19
|
-
3. **Declare the datastore with `
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
3. **Declare the datastore with `needs: { database: true }`.** This is the
|
|
21
|
+
canonical shape — the deployer provisions Mongo and injects
|
|
22
|
+
`DATABASE_MONGODB_URL` (plus the legacy `MONGODB_URL` alias). `requires:` is
|
|
23
|
+
the deprecated v1 alias; don't author new yaml with it, and never set `needs:`
|
|
24
|
+
and `requires:` together (the validator rejects the combination).
|
|
23
25
|
|
|
24
26
|
Write these files into the scaffolded app folder — the app code goes under
|
|
25
27
|
`services/web/` — adapt the collection/fields to the user's app, then `grid dev`
|
|
@@ -28,9 +30,9 @@ Write these files into the scaffolded app folder — the app code goes under
|
|
|
28
30
|
## File tree
|
|
29
31
|
|
|
30
32
|
```
|
|
31
|
-
cloudgrid.yaml # name + services.web (nextjs) +
|
|
33
|
+
cloudgrid.yaml # name + services.web (nextjs) + needs: { database: true }
|
|
32
34
|
services/web/package.json # next, react, react-dom, mongodb driver only
|
|
33
|
-
services/web/lib/db.js # lazy Mongo client from
|
|
35
|
+
services/web/lib/db.js # lazy Mongo client from DATABASE_MONGODB_URL (legacy MONGODB_URL fallback)
|
|
34
36
|
services/web/app/layout.js # root layout + inline CSS
|
|
35
37
|
services/web/app/page.js # server component: reads todos from Mongo
|
|
36
38
|
services/web/app/todo-form.js # client form: POST/DELETE via the API
|
|
@@ -40,23 +42,29 @@ services/web/app/api/todos/route.js # GET (list) / POST (add) / DELETE (remo
|
|
|
40
42
|
## cloudgrid.yaml
|
|
41
43
|
|
|
42
44
|
```yaml
|
|
43
|
-
# Rename this app. The grid injects
|
|
44
|
-
# as environment variables at runtime — do NOT set them
|
|
45
|
-
# a connection string or secret.
|
|
45
|
+
# Rename this app. The grid injects the DB connection string (and a Redis URL if
|
|
46
|
+
# you add a cache) as environment variables at runtime — do NOT set them
|
|
47
|
+
# yourself, and never commit a connection string or secret.
|
|
46
48
|
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
# `
|
|
50
|
-
#
|
|
49
|
+
# `needs: { database: true }` is the canonical, recommended shape. The deployer
|
|
50
|
+
# provisions Mongo and injects DATABASE_MONGODB_URL (plus the legacy MONGODB_URL
|
|
51
|
+
# alias). `requires:` is the deprecated v1 alias — don't author new yaml with it,
|
|
52
|
+
# and never set `needs:` and `requires:` together (the validator rejects it).
|
|
51
53
|
name: my-app
|
|
52
54
|
services:
|
|
53
55
|
web:
|
|
54
56
|
type: nextjs
|
|
55
57
|
path: /
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
needs:
|
|
59
|
+
database: true
|
|
58
60
|
```
|
|
59
61
|
|
|
62
|
+
> **Capability:** this template's need is `database: true`. The deployer
|
|
63
|
+
> provisions Mongo and injects `DATABASE_MONGODB_URL` (plus the legacy
|
|
64
|
+
> `MONGODB_URL` alias), so an app reading either var works. `requires:` is the
|
|
65
|
+
> deprecated v1 alias — don't mix it with `needs:` (the validator rejects the
|
|
66
|
+
> combination). See the capability-map for the full injection table.
|
|
67
|
+
|
|
60
68
|
## services/web/package.json
|
|
61
69
|
|
|
62
70
|
```json
|
|
@@ -83,22 +91,23 @@ requires:
|
|
|
83
91
|
```js
|
|
84
92
|
// Cached MongoDB client for the App Router.
|
|
85
93
|
//
|
|
86
|
-
// The grid injects the connection string as the
|
|
87
|
-
// at runtime (after `grid plug`) and
|
|
88
|
-
//
|
|
94
|
+
// The grid injects the connection string as the DATABASE_MONGODB_URL environment
|
|
95
|
+
// variable (plus the legacy MONGODB_URL alias) at runtime (after `grid plug`) and
|
|
96
|
+
// under `grid dev` locally. Read the canonical var first, fall back to the legacy
|
|
97
|
+
// alias. Never hardcode a connection string here and never commit a secret.
|
|
89
98
|
//
|
|
90
99
|
// The env var and client are resolved LAZILY (inside getDb), never at module top
|
|
91
100
|
// level — otherwise `next build` throws when it imports this module for route
|
|
92
|
-
// analysis, before the grid injects
|
|
101
|
+
// analysis, before the grid injects the var.
|
|
93
102
|
import { MongoClient } from "mongodb";
|
|
94
103
|
|
|
95
104
|
function clientPromise() {
|
|
96
|
-
const uri = process.env.MONGODB_URL;
|
|
105
|
+
const uri = process.env.DATABASE_MONGODB_URL || process.env.MONGODB_URL;
|
|
97
106
|
if (!uri) {
|
|
98
107
|
throw new Error(
|
|
99
|
-
"
|
|
100
|
-
"with `grid dev` locally, or deploy it with `grid plug` (the grid
|
|
101
|
-
"
|
|
108
|
+
"DATABASE_MONGODB_URL is not set. The grid injects it automatically — run " +
|
|
109
|
+
"this app with `grid dev` locally, or deploy it with `grid plug` (the grid " +
|
|
110
|
+
"injects the DB connection string at runtime). Do not set it by hand.",
|
|
102
111
|
);
|
|
103
112
|
}
|
|
104
113
|
if (!globalThis.__mongoClientPromise) {
|
|
@@ -109,7 +118,7 @@ function clientPromise() {
|
|
|
109
118
|
|
|
110
119
|
export async function getDb() {
|
|
111
120
|
const client = await clientPromise();
|
|
112
|
-
// The default DB comes from the
|
|
121
|
+
// The default DB comes from the connection-string path segment the grid injects.
|
|
113
122
|
return client.db();
|
|
114
123
|
}
|
|
115
124
|
```
|
|
@@ -257,5 +266,5 @@ export async function DELETE(request) {
|
|
|
257
266
|
|
|
258
267
|
- Rename the `todos` collection to your data (`submissions`, `tasks`, `entries`).
|
|
259
268
|
- Change the document fields; add owners/timestamps/statuses.
|
|
260
|
-
- Add `
|
|
269
|
+
- Add `cache: true` to `needs:` only if you actually need Redis.
|
|
261
270
|
- Run `grid dev` to test locally, `grid plug` to deploy (async — poll to live).
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
// Cached MongoDB client for the App Router.
|
|
2
2
|
//
|
|
3
|
-
// The grid injects the connection string as the
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// The grid injects the connection string as the DATABASE_MONGODB_URL environment
|
|
4
|
+
// variable (plus the legacy MONGODB_URL alias) at dev-time (`grid dev`) and
|
|
5
|
+
// runtime (after `grid plug`). Read the canonical var first, fall back to the
|
|
6
|
+
// legacy alias. Never hardcode a connection string here and never commit a secret.
|
|
6
7
|
//
|
|
7
8
|
// The env var and client are resolved LAZILY (inside getDb), never at module top
|
|
8
9
|
// level — otherwise `next build` throws when it imports this module for route
|
|
9
|
-
// analysis, before the grid injects
|
|
10
|
+
// analysis, before the grid injects the var.
|
|
10
11
|
import { MongoClient } from "mongodb";
|
|
11
12
|
|
|
12
13
|
function clientPromise() {
|
|
13
|
-
const uri = process.env.MONGODB_URL;
|
|
14
|
+
const uri = process.env.DATABASE_MONGODB_URL || process.env.MONGODB_URL;
|
|
14
15
|
if (!uri) {
|
|
15
16
|
throw new Error(
|
|
16
|
-
"
|
|
17
|
-
"with `grid dev` locally, or deploy it with `grid plug` (the grid
|
|
18
|
-
"
|
|
17
|
+
"DATABASE_MONGODB_URL is not set. The grid injects it automatically — run " +
|
|
18
|
+
"this app with `grid dev` locally, or deploy it with `grid plug` (the grid " +
|
|
19
|
+
"injects the DB connection string at runtime). Do not set it by hand.",
|
|
19
20
|
);
|
|
20
21
|
}
|
|
21
22
|
if (!globalThis.__mongoClientPromise) {
|
|
@@ -26,6 +27,6 @@ function clientPromise() {
|
|
|
26
27
|
|
|
27
28
|
export async function getDb() {
|
|
28
29
|
const client = await clientPromise();
|
|
29
|
-
// The default DB comes from the
|
|
30
|
+
// The default DB comes from the connection-string path segment the grid injects.
|
|
30
31
|
return client.db();
|
|
31
32
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
2
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
3
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
4
|
+
#
|
|
5
|
+
# needs: {} # none — static, no infrastructure
|
|
6
|
+
name: dashboard
|
|
7
|
+
services:
|
|
8
|
+
web:
|
|
9
|
+
type: static
|
|
10
|
+
path: /
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Template: dashboard (static)
|
|
2
|
+
|
|
3
|
+
A single self-contained HTML dashboard. **No infrastructure** — no database, no backend,
|
|
4
|
+
no `needs:`. State (if any) lives only in memory and is lost on refresh.
|
|
5
|
+
|
|
6
|
+
## How it deploys
|
|
7
|
+
|
|
8
|
+
To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
|
|
9
|
+
HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
|
|
10
|
+
edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
|
|
11
|
+
directory (`type: static`) is ONLY for plugging the page as an OWNED static
|
|
12
|
+
runtime (async, local edition only); the fast path is `gridctl_drop`.
|
|
13
|
+
|
|
14
|
+
The fillable HTML is the real template — fetch it with
|
|
15
|
+
`gridctl_fetch("template", "dashboard")` and fill in the user's content.
|
|
16
|
+
|
|
17
|
+
## cloudgrid.yaml (reference only)
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
21
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
22
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
23
|
+
#
|
|
24
|
+
# needs: {} # none — static, no infrastructure
|
|
25
|
+
name: dashboard
|
|
26
|
+
services:
|
|
27
|
+
web:
|
|
28
|
+
type: static
|
|
29
|
+
path: /
|
|
30
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
2
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
3
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
4
|
+
#
|
|
5
|
+
# needs: {} # none — static, no infrastructure
|
|
6
|
+
name: deck
|
|
7
|
+
services:
|
|
8
|
+
web:
|
|
9
|
+
type: static
|
|
10
|
+
path: /
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Template: deck (static)
|
|
2
|
+
|
|
3
|
+
A single self-contained HTML deck. **No infrastructure** — no database, no backend,
|
|
4
|
+
no `needs:`. State (if any) lives only in memory and is lost on refresh.
|
|
5
|
+
|
|
6
|
+
## How it deploys
|
|
7
|
+
|
|
8
|
+
To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
|
|
9
|
+
HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
|
|
10
|
+
edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
|
|
11
|
+
directory (`type: static`) is ONLY for plugging the page as an OWNED static
|
|
12
|
+
runtime (async, local edition only); the fast path is `gridctl_drop`.
|
|
13
|
+
|
|
14
|
+
The fillable HTML is the real template — fetch it with
|
|
15
|
+
`gridctl_fetch("template", "deck")` and fill in the user's content.
|
|
16
|
+
|
|
17
|
+
## cloudgrid.yaml (reference only)
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
21
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
22
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
23
|
+
#
|
|
24
|
+
# needs: {} # none — static, no infrastructure
|
|
25
|
+
name: deck
|
|
26
|
+
services:
|
|
27
|
+
web:
|
|
28
|
+
type: static
|
|
29
|
+
path: /
|
|
30
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
2
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
3
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
4
|
+
#
|
|
5
|
+
# needs: {} # none — static, no infrastructure
|
|
6
|
+
name: landing-page
|
|
7
|
+
services:
|
|
8
|
+
web:
|
|
9
|
+
type: static
|
|
10
|
+
path: /
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Template: landing-page (static)
|
|
2
|
+
|
|
3
|
+
A single self-contained HTML landing-page. **No infrastructure** — no database, no backend,
|
|
4
|
+
no `needs:`. State (if any) lives only in memory and is lost on refresh.
|
|
5
|
+
|
|
6
|
+
## How it deploys
|
|
7
|
+
|
|
8
|
+
To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
|
|
9
|
+
HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
|
|
10
|
+
edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
|
|
11
|
+
directory (`type: static`) is ONLY for plugging the page as an OWNED static
|
|
12
|
+
runtime (async, local edition only); the fast path is `gridctl_drop`.
|
|
13
|
+
|
|
14
|
+
The fillable HTML is the real template — fetch it with
|
|
15
|
+
`gridctl_fetch("template", "landing-page")` and fill in the user's content.
|
|
16
|
+
|
|
17
|
+
## cloudgrid.yaml (reference only)
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
21
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
22
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
23
|
+
#
|
|
24
|
+
# needs: {} # none — static, no infrastructure
|
|
25
|
+
name: landing-page
|
|
26
|
+
services:
|
|
27
|
+
web:
|
|
28
|
+
type: static
|
|
29
|
+
path: /
|
|
30
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
2
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
3
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
4
|
+
#
|
|
5
|
+
# needs: {} # none — static, no infrastructure
|
|
6
|
+
name: report
|
|
7
|
+
services:
|
|
8
|
+
web:
|
|
9
|
+
type: static
|
|
10
|
+
path: /
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Template: report (static)
|
|
2
|
+
|
|
3
|
+
A single self-contained HTML report. **No infrastructure** — no database, no backend,
|
|
4
|
+
no `needs:`. State (if any) lives only in memory and is lost on refresh.
|
|
5
|
+
|
|
6
|
+
## How it deploys
|
|
7
|
+
|
|
8
|
+
To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
|
|
9
|
+
HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
|
|
10
|
+
edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
|
|
11
|
+
directory (`type: static`) is ONLY for plugging the page as an OWNED static
|
|
12
|
+
runtime (async, local edition only); the fast path is `gridctl_drop`.
|
|
13
|
+
|
|
14
|
+
The fillable HTML is the real template — fetch it with
|
|
15
|
+
`gridctl_fetch("template", "report")` and fill in the user's content.
|
|
16
|
+
|
|
17
|
+
## cloudgrid.yaml (reference only)
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
21
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
22
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
23
|
+
#
|
|
24
|
+
# needs: {} # none — static, no infrastructure
|
|
25
|
+
name: report
|
|
26
|
+
services:
|
|
27
|
+
web:
|
|
28
|
+
type: static
|
|
29
|
+
path: /
|
|
30
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
2
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
3
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
4
|
+
#
|
|
5
|
+
# needs: {} # none — static, no infrastructure
|
|
6
|
+
name: web-app
|
|
7
|
+
services:
|
|
8
|
+
web:
|
|
9
|
+
type: static
|
|
10
|
+
path: /
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Template: web-app (static)
|
|
2
|
+
|
|
3
|
+
A single self-contained HTML web-app. **No infrastructure** — no database, no backend,
|
|
4
|
+
no `needs:`. State (if any) lives only in memory and is lost on refresh.
|
|
5
|
+
|
|
6
|
+
## How it deploys
|
|
7
|
+
|
|
8
|
+
To publish this page, use **`gridctl_drop`** (or `gridctl_plug` with the inline
|
|
9
|
+
HTML): it deploys as an **inspiration** — instant, and works on the **hosted**
|
|
10
|
+
edition (Claude Web) as well as local. The reference `cloudgrid.yaml` in this
|
|
11
|
+
directory (`type: static`) is ONLY for plugging the page as an OWNED static
|
|
12
|
+
runtime (async, local edition only); the fast path is `gridctl_drop`.
|
|
13
|
+
|
|
14
|
+
The fillable HTML is the real template — fetch it with
|
|
15
|
+
`gridctl_fetch("template", "web-app")` and fill in the user's content.
|
|
16
|
+
|
|
17
|
+
## cloudgrid.yaml (reference only)
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
# static — deploys as an inspiration (instant, works on hosted) via gridctl_drop;
|
|
21
|
+
# this yaml is only for plugging it as an OWNED static runtime (async, local
|
|
22
|
+
# edition only). To publish the page, prefer gridctl_drop, not grid plug.
|
|
23
|
+
#
|
|
24
|
+
# needs: {} # none — static, no infrastructure
|
|
25
|
+
name: web-app
|
|
26
|
+
services:
|
|
27
|
+
web:
|
|
28
|
+
type: static
|
|
29
|
+
path: /
|
|
30
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: persistent-apps
|
|
3
|
-
when: A persistent (Mongo-backed) app misbehaves — data doesn't survive refresh,
|
|
4
|
-
summary: Symptom, cause, and fix for the common app-with-data (runtime Mongo app) problems — in-memory vs persistent, injected MONGODB_URL, async deploys, and the hosted-edition gate.
|
|
3
|
+
when: A persistent (Mongo-backed) app misbehaves — data doesn't survive refresh, DATABASE_MONGODB_URL is undefined, a runtime deploy seems stuck, or it won't build on hosted.
|
|
4
|
+
summary: Symptom, cause, and fix for the common app-with-data (runtime Mongo app) problems — in-memory vs persistent, injected DATABASE_MONGODB_URL (+legacy MONGODB_URL), async deploys, and the hosted-edition gate.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Troubleshooting: persistent apps (app-with-data)
|
|
@@ -12,11 +12,11 @@ Match the symptom to the row, apply the fix, and stop.
|
|
|
12
12
|
| --- | --- | --- |
|
|
13
13
|
| Data doesn't persist / resets on refresh | You built a static inspiration (in-memory / localStorage), not a runtime app | Use the `app-with-data` workflow: a real Next.js + Mongo runtime that reads `process.env.MONGODB_URL`. Static templates keep state only in memory. |
|
|
14
14
|
| `Error: Service directory not found: …/services/web` | App code lives at the repo/template root, not under the service folder | App code must live under `services/<name>/` (e.g. `services/web/`). `path:` in `cloudgrid.yaml` is the URL mount, NOT the filesystem path — the service name is the folder the CLI looks for. |
|
|
15
|
-
| `next build` fails /
|
|
16
|
-
| App builds + deploys but every request 500s with `
|
|
17
|
-
| `
|
|
15
|
+
| `next build` fails / DB connection error at build time | The DB env var is read at module top level; `next build` imports the module for route analysis before the grid injects the var | Read `process.env.DATABASE_MONGODB_URL` (with a legacy `MONGODB_URL` fallback) LAZILY inside the getter (e.g. inside `getDb`), never at module load. Moving the check into the function lets the build pass. |
|
|
16
|
+
| App builds + deploys but every request 500s with `DATABASE_MONGODB_URL not set` | The datastore isn't declared, or you declared the deprecated `requires:` instead of `needs:` | Declare `needs: { database: true }` in `cloudgrid.yaml`. The deployer provisions Mongo and injects `DATABASE_MONGODB_URL` (plus the legacy `MONGODB_URL` alias). Never set `needs:` and `requires:` together (the validator rejects it). |
|
|
17
|
+
| `DATABASE_MONGODB_URL is undefined` (or the db.js guard throws) | The env var isn't present because you're not running under the grid | Run locally with `grid dev`, or deploy with `grid plug` — the grid injects `DATABASE_MONGODB_URL` (+legacy `MONGODB_URL`) at dev-time and runtime. Do NOT set it yourself and never hardcode a connection string. |
|
|
18
18
|
| Deploy seems stuck / no URL returned | Runtime deploys are asynchronous | `plug` returns `status: building`, not a URL. Poll `gridctl_status` (or the poll_url) until the app is live, then return the live URL. Don't treat the build/log link as the deliverable. |
|
|
19
19
|
| It won't build on the hosted edition | Hosted MCP is inline-only — it can't run the CLI or folder-plug | Runtime apps need the LOCAL edition (Claude Desktop/Code) or the CLI. On hosted, tell the user persistence isn't available there and offer a static version instead. |
|
|
20
|
-
| Redis not available | `
|
|
20
|
+
| Redis not available | `cache` wasn't declared | Add `cache: true` to `needs:` in `cloudgrid.yaml`; the grid then injects `CACHE_REDIS_URL` (plus the legacy `REDIS_URL` alias). Only add it if the app actually needs Redis. |
|
|
21
21
|
|
|
22
22
|
See the `app-with-data` workflow for the full recipe.
|