create-restforge-skills 1.0.0 → 1.0.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/cli/index.js +250 -250
- package/cli/mcp.js +103 -94
- package/package.json +2 -1
- package/skills/restforge/SKILL.md +230 -773
- package/skills/restforge/agents/openai.yaml +4 -4
- package/skills/restforge/references/auth.md +185 -145
- package/skills/restforge/references/backend-pipeline.md +388 -0
- package/skills/restforge/references/data-seeding.md +27 -0
- package/skills/restforge/references/dbschema-catalog.md +2 -2
- package/skills/restforge/references/field-validation.md +6 -4
- package/skills/restforge/references/frontend-pipeline.md +178 -0
- package/skills/restforge/references/rdf-advanced.md +1 -1
- package/skills/restforge/references/troubleshooting.md +144 -0
|
@@ -25,810 +25,267 @@ compatibility: >
|
|
|
25
25
|
|
|
26
26
|
RESTForge is a deterministic, definition-first generator with two output tracks:
|
|
27
27
|
|
|
28
|
-
- **Backend track** — SDF defines the database schema; RDF
|
|
29
|
-
|
|
30
|
-
identical endpoint module on every
|
|
31
|
-
- **Frontend track** — UDF
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
The
|
|
41
|
-
`
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
1. **The skill describes intent and order; the MCP server executes.** If the
|
|
45
|
-
RESTForge MCP server is not registered in the client, this skill cannot do
|
|
46
|
-
anything — there is nothing to call. Confirm the tools are available before
|
|
47
|
-
planning a multi-step operation.
|
|
48
|
-
2. **The catalog is the source of truth, not memory.** Field types, constraints,
|
|
49
|
-
validation rules, and plugin capabilities belong to the *installed* platform
|
|
50
|
-
version. Always ground against the catalog before proposing definition
|
|
51
|
-
content (see Grounding-First Rules, below).
|
|
28
|
+
- **Backend track** — SDF (`schema/<table>.js`) defines the database schema; RDF
|
|
29
|
+
(`payload/<name>.json`) defines a REST API resource. One SDF produces identical
|
|
30
|
+
DDL; one RDF produces an identical endpoint module on every run.
|
|
31
|
+
- **Frontend track** — UDF (`frontend/payload/`: `app-config.json`,
|
|
32
|
+
`pages/<pageId>.json`, and the aggregator `<appCode>.json`) defines the
|
|
33
|
+
frontend. `npx restforge-designer` turns it into HTML/JS/CSS, plugin-driven.
|
|
34
|
+
|
|
35
|
+
Because the generators are deterministic, speed and correctness depend on two
|
|
36
|
+
things only: turning the user's intent into the right tool, and running the
|
|
37
|
+
tools in the right order. This file is the router for both. Detail lives in
|
|
38
|
+
`references/`, read only when its branch is relevant.
|
|
39
|
+
|
|
40
|
+
The agent works **through MCP tools** (`health_*`, `setup_*`, `codegen_*`,
|
|
41
|
+
`runtime_*`, `designer_*`, `data_*`, `key_*`, `project_*`, `license_*`). It does
|
|
42
|
+
not hand-write generator output, does not edit generated files, and does not
|
|
43
|
+
guess options outside the catalog.
|
|
52
44
|
|
|
53
45
|
---
|
|
54
46
|
|
|
55
|
-
## Preflight
|
|
56
|
-
|
|
57
|
-
Verify readiness before planning or producing anything:
|
|
58
|
-
|
|
59
|
-
1. **Are the RESTForge MCP tools present?** Look for `codegen_*` / `designer_*`,
|
|
60
|
-
including client-prefixed names such as `mcp__restforge__codegen_*`. If the
|
|
61
|
-
client supports deferred tool discovery, search for RESTForge tools first.
|
|
62
|
-
If they remain unavailable, the MCP server is **not active**. Stop and tell the
|
|
63
|
-
user to register the RESTForge MCP server and restart the client. Do **not**
|
|
64
|
-
finish the task by hand-reading the bundled `references/` — that bypasses the
|
|
65
|
-
generator and yields slower, non-deterministic output.
|
|
66
|
-
2. **Backend work** → confirm the project and config are ready with
|
|
67
|
-
`runtime_detect_project`, list the candidate `.env` files in `config/` with
|
|
68
|
-
`runtime_detect_config` when the config to use is not obvious, then the
|
|
69
|
-
`setup_validate_config` gate.
|
|
70
|
-
3. **Before writing a launcher** → `runtime_validate_preflight`. It re-runs the
|
|
71
|
-
config validation and adds the two runtime-only checks the gate does not
|
|
72
|
-
cover: a possibly-running server (`.restforge/server.pid`) and availability
|
|
73
|
-
of the local port. Use it as the last check before `runtime_generate_launcher`,
|
|
74
|
-
not as a replacement for the `setup_validate_config` gate earlier in the run.
|
|
75
|
-
4. **License questions** → `license_info` reports the activation stored on this
|
|
76
|
-
machine (key, e-mail, type, machine id, last validation, expiry) and changes
|
|
77
|
-
nothing. Repeat the key, e-mail, or machine id back to the user only when
|
|
78
|
-
they asked for them. Activation and `license deactivate` are deliberately
|
|
79
|
-
**not** wrapped by MCP — deactivation frees a machine slot across machines,
|
|
80
|
-
so the user runs it in their own terminal.
|
|
81
|
-
5. **Frontend work** → the Designer tools pre-check that `npx restforge-designer`
|
|
82
|
-
can run (its binary is bundled in `@restforgejs/platform`, so it is available
|
|
83
|
-
once the project is created with `npx create-restforge-app` / the platform is
|
|
84
|
-
installed); if it cannot run, surface that before proceeding.
|
|
85
|
-
|
|
86
|
-
If a prerequisite is missing, report it as the next step — do not improvise around it.
|
|
47
|
+
## Preflight
|
|
87
48
|
|
|
88
|
-
|
|
49
|
+
1. **RESTForge MCP tools present?** Look for `codegen_*` / `designer_*`, including
|
|
50
|
+
client-prefixed names (`mcp__restforge__codegen_*`). Search deferred tools
|
|
51
|
+
first when the client supports it. If they stay unavailable, stop and tell the
|
|
52
|
+
user to register the RESTForge MCP server and restart the client. Do not finish
|
|
53
|
+
the task by hand from `references/`.
|
|
54
|
+
2. **Backend work that reads the config or the database** → the
|
|
55
|
+
`setup_validate_config` gate (Guardrail 3). `runtime_detect_project` and
|
|
56
|
+
`runtime_detect_config` help when the project or the `.env` file is not
|
|
57
|
+
obvious.
|
|
58
|
+
3. **Frontend work** → the designer tools pre-check that `npx restforge-designer`
|
|
59
|
+
can run; relay a failed pre-check as a setup step.
|
|
89
60
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
This is the canonical (golden) path. For state-dependent choices see Decision
|
|
93
|
-
Points; for failure handling see Guardrails and Common Errors.
|
|
94
|
-
|
|
95
|
-
The sequence below applies to a **new project from scratch**. For an existing
|
|
96
|
-
project, start from the step that matches the current state — do not re-run
|
|
97
|
-
earlier steps that already succeeded.
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
1. npx create-restforge-app <name> ── PRIMARY ── human-run scaffolder
|
|
101
|
-
One shot: creates the project folder, runs
|
|
102
|
-
npm install @restforgejs/platform (local), and bundles the designer
|
|
103
|
-
binary. This is the dominant way to start a new project.
|
|
104
|
-
Granular alternative (agent scaffolds step by step):
|
|
105
|
-
setup_create_folder → create the project folder.
|
|
106
|
-
|
|
107
|
-
2. setup_install_package (granular path only)
|
|
108
|
-
Install @restforgejs/platform into the folder. SKIP when the project
|
|
109
|
-
was created with create-restforge-app (already installed). Plain
|
|
110
|
-
'npm install @restforgejs/platform' stays valid but is not the
|
|
111
|
-
primary entry point.
|
|
112
|
-
|
|
113
|
-
3. setup_init_config
|
|
114
|
-
Write config/db-connection.env from the default template.
|
|
115
|
-
setup_get_init_template returns that same template WITHOUT writing a
|
|
116
|
-
file — use it to compare an edited config against the defaults.
|
|
117
|
-
|
|
118
|
-
4. setup_write_env / setup_update_env
|
|
119
|
-
Set values: LICENSE, SERVER_ADDRESS, SERVER_PORT, DB_TYPE,
|
|
120
|
-
DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME (9 required parameters).
|
|
121
|
-
Use setup_read_env to read existing values before overwriting.
|
|
122
|
-
Grounding for the full parameter set: setup_get_config_schema.
|
|
123
|
-
|
|
124
|
-
5. setup_validate_config
|
|
125
|
-
── GATE ── Must pass before any codegen_* operation starts.
|
|
126
|
-
Validates database connection and license. Running codegen before this
|
|
127
|
-
gate passes produces uninformative errors.
|
|
128
|
-
Read-only by default. Set autoCreateDb=true only when the target database
|
|
129
|
-
itself does not exist yet AND the user agreed to have it created: it runs
|
|
130
|
-
CREATE DATABASE on the server (postgres/mysql only, ignored for sqlite and
|
|
131
|
-
oracle), and validation has to be repeated afterwards.
|
|
132
|
-
|
|
133
|
-
6. codegen_get_dbschema_catalog
|
|
134
|
-
── GROUNDING ── Source of truth before defining SDF: field types,
|
|
135
|
-
constraints, shorthand syntax, relations, referential actions,
|
|
136
|
-
check operations, and the soft-delete contract.
|
|
137
|
-
→ references/dbschema-catalog.md
|
|
138
|
-
|
|
139
|
-
7a. codegen_dbschema_init (empty DB — scaffold SDF with audit columns)
|
|
140
|
-
codegen_dbschema_template (minimal template, no DB connection required)
|
|
141
|
-
7b. codegen_list_tables (existing DB — what is actually in there)
|
|
142
|
-
→ codegen_describe_table (columns, PK, FKs, indexes of one table)
|
|
143
|
-
→ codegen_dbschema_introspect (generate SDF from the actual schema)
|
|
144
|
-
list/describe are read-only catalog reads: they answer "what does this
|
|
145
|
-
database already hold?" without writing an SDF file. Use them before
|
|
146
|
-
introspecting a subset, and whenever a question about an existing table
|
|
147
|
-
would otherwise be answered from memory.
|
|
148
|
-
|
|
149
|
-
8. codegen_dbschema_validate
|
|
150
|
-
Validate SDF before any DDL is generated. Catch errors here, not at migrate.
|
|
151
|
-
File-only by default. With 'config' it also compares every model with the
|
|
152
|
-
database and gives one verdict per table: [OK], [DRIFT], or [ERROR] with
|
|
153
|
-
category table-missing or sdf-invalid. Exit code 1 in that mode is a
|
|
154
|
-
result (drift or error found), not a tool failure. SQLite is not
|
|
155
|
-
supported by the database mode.
|
|
156
|
-
codegen_dbschema_models (optional) lists the models already defined in the
|
|
157
|
-
SDF files with field count, primary key kind, indexes, uniques, relations.
|
|
158
|
-
|
|
159
|
-
9. codegen_dbschema_generate_ddl (optional — preview DDL without executing)
|
|
160
|
-
|
|
161
|
-
10a. codegen_dbschema_migrate (empty DB — apply DDL directly)
|
|
162
|
-
10b. codegen_dbschema_diff (existing DB — review the differences first)
|
|
163
|
-
→ codegen_dbschema_apply (apply only after confirming the drift)
|
|
164
|
-
|
|
165
|
-
11. codegen_get_field_validation_catalog
|
|
166
|
-
── GROUNDING ── before defining fieldValidation in a payload.
|
|
167
|
-
→ references/field-validation.md
|
|
168
|
-
|
|
169
|
-
12. codegen_get_query_declarative_catalog
|
|
170
|
-
── GROUNDING ── when the payload contains datatablesQuery, viewQuery,
|
|
171
|
-
viewName, exportQuery, or detailQuery.
|
|
172
|
-
codegen_validate_sql
|
|
173
|
-
Check the SELECT / WITH statement against the live database (EXPLAIN, no
|
|
174
|
-
rows executed) BEFORE pasting it into the payload: syntax, column
|
|
175
|
-
references, function existence, type compatibility, JOIN resolution.
|
|
176
|
-
|
|
177
|
-
13. codegen_generate_payload
|
|
178
|
-
Generate payload JSON from a table. Foundation for all subsequent
|
|
179
|
-
codegen operations. 'detail' (a detail table name) also writes the
|
|
180
|
-
masterDetail block, the detail query file, and the composite actions.
|
|
181
|
-
Re-running it on an existing payload keeps the customisations made to
|
|
182
|
-
generator-owned keys; commit payload/.meta/<name>.json together with the
|
|
183
|
-
payload (see Decision Points § RDF Payload).
|
|
184
|
-
|
|
185
|
-
14. codegen_validate_payload
|
|
186
|
-
Validate the payload before codegen. Catch errors here.
|
|
187
|
-
|
|
188
|
-
15. codegen_diff_payload (when a payload exists and the DB schema has changed)
|
|
189
|
-
→ codegen_sync_payload (apply the schema drift to the payload)
|
|
190
|
-
'expandFk' (with 'table') also writes query/<table>-join.sql so
|
|
191
|
-
datatablesQuery (and viewQuery) show columns of referenced tables.
|
|
192
|
-
|
|
193
|
-
16a. codegen_create_endpoint (standard CRUD module)
|
|
194
|
-
Leave 'database' UNSET unless the user named a database: the CLI then
|
|
195
|
-
auto-detects DB_TYPE from the active config (fallback postgres), so a
|
|
196
|
-
MySQL/Oracle/SQLite project generates for its own dialect. 'config'
|
|
197
|
-
selects that .env explicitly. createDemo (default true) writes the
|
|
198
|
-
curl / Postman / Insomnia examples. force defaults to true — an existing
|
|
199
|
-
module is overwritten and the previous files are moved to
|
|
200
|
-
.restforge/archive/<run>/<original relative path> (the 5 most recent runs
|
|
201
|
-
are kept); force=false stops without writing anything when the module
|
|
202
|
-
exists, which is the closest thing to a conflict dry run.
|
|
203
|
-
16b. codegen_get_dashboard_catalog
|
|
204
|
-
→ codegen_validate_dashboard_payload
|
|
205
|
-
── GATE ── structural check of a dashboard payload; writes nothing.
|
|
206
|
-
On a platform without 'dashboard create --validate-only' the tool
|
|
207
|
-
answers with an upgrade suggestion instead of a validation result — then
|
|
208
|
-
let the generator itself validate, since it runs the same validator
|
|
209
|
-
before it writes.
|
|
210
|
-
→ codegen_create_dashboard (analytic dashboard with SQL widgets)
|
|
211
|
-
No database auto-detection here: the dashboard command uses 'database'
|
|
212
|
-
when given and plain postgres otherwise, so pass it whenever the project
|
|
213
|
-
is not postgres. force defaults to true and then re-registers the project
|
|
214
|
-
under the database type carried by this call; force=false refuses cleanly
|
|
215
|
-
instead of writing.
|
|
216
|
-
16c. codegen_create_processor (background processing)
|
|
217
|
-
16d. codegen_create_kafka_consumer (Kafka event streaming)
|
|
218
|
-
→ runtime_generate_consumer_launcher
|
|
219
|
-
Prepare a way to RUN that consumer: mode=host writes the fixed
|
|
220
|
-
consumer-start/consumer-stop pair in the project root, mode=pm2 produces
|
|
221
|
-
ecosystem.config.js + consumer-manager.sh in ./deploy/. 'config' is
|
|
222
|
-
required and must end with .env.
|
|
223
|
-
→ (user runs the consumer) — the agent never starts it, same rule as the
|
|
224
|
-
server launcher below.
|
|
225
|
-
|
|
226
|
-
17. codegen_generate_test (optional)
|
|
227
|
-
Jest + Supertest integration test for an endpoint that ALREADY exists.
|
|
228
|
-
Natural follow-up once the module is generated.
|
|
229
|
-
|
|
230
|
-
18. project_sdk_generate (optional)
|
|
231
|
-
Write the JavaScript SDK source for the project (one resource file per
|
|
232
|
-
registered endpoint, plus client.auth when the backend auth extension is
|
|
233
|
-
installed) so a frontend calls client.<resource>.<verb>(payload). Source
|
|
234
|
-
only: the user runs install / build / deploy. Without force it refuses
|
|
235
|
-
when an SDK exists; with force=true it overwrites IN PLACE with no
|
|
236
|
-
archive, so local edits in the SDK folder are lost.
|
|
237
|
-
|
|
238
|
-
19. runtime_check_launcher_exists → runtime_validate_preflight
|
|
239
|
-
→ runtime_generate_launcher
|
|
240
|
-
Check what is already there (read-only), validate the runtime
|
|
241
|
-
prerequisites, then write the launcher script. The agent STOPS here. The
|
|
242
|
-
user executes the launcher — the server runs independently of the agent
|
|
243
|
-
session.
|
|
244
|
-
|
|
245
|
-
20. (user executes the launcher)
|
|
246
|
-
|
|
247
|
-
21. runtime_check_status
|
|
248
|
-
Verify the server is running and endpoints are reachable.
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Two hard checkpoints (see Guardrails): **step 5** is a gate — no `codegen_*` call
|
|
252
|
-
before `setup_validate_config` passes; **step 19** is where the agent stops (it
|
|
253
|
-
generates the launcher, never runs the server).
|
|
254
|
-
|
|
255
|
-
**Payload naming differs per generator** — the value is handed to the CLI and
|
|
256
|
-
each verb resolves it differently:
|
|
257
|
-
|
|
258
|
-
| Tool | Accepted form |
|
|
259
|
-
|---|---|
|
|
260
|
-
| `codegen_create_endpoint`, `codegen_create_processor` | bare name, with or without `.json`; lowercased by the CLI; path forms are rejected |
|
|
261
|
-
| `codegen_create_dashboard`, `codegen_validate_dashboard_payload` | name or relative path **with** the extension, used verbatim (`dash-sales.json`, `payload/dash-sales.json`) — nothing is appended |
|
|
262
|
-
| `codegen_create_kafka_consumer` | name or path |
|
|
263
|
-
|
|
264
|
-
**Config selection across calls.** Most backend tools take an optional `config`
|
|
265
|
-
and otherwise fall back to the default recorded per working directory in
|
|
266
|
-
`.restforge/defaults.json`. Manage that default instead of repeating the file
|
|
267
|
-
name on every call: `setup_list_configs` (which `.env` files exist),
|
|
268
|
-
`setup_set_default_config` (record one), `setup_get_default_config` (which one is
|
|
269
|
-
active), `setup_clear_default_config` (remove it — afterwards every call must
|
|
270
|
-
name its config explicitly).
|
|
61
|
+
If a prerequisite is missing, report it as the next step; do not improvise
|
|
62
|
+
around it.
|
|
271
63
|
|
|
272
64
|
---
|
|
273
65
|
|
|
274
|
-
##
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
7. designer_generate
|
|
323
|
-
Generate frontend HTML/JS/CSS from the aggregator. Writes output files.
|
|
324
|
-
The agent STOPS here — the user opens the output in a browser.
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
For plugin development (custom output plugins):
|
|
328
|
-
|
|
329
|
-
```
|
|
330
|
-
designer_scaffold_plugin → [develop plugin templates]
|
|
331
|
-
→ designer_inspect_plugin (verify plugin metadata and capabilities)
|
|
332
|
-
→ designer_generate (test generation with the custom plugin)
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
Two checkpoints (see Guardrails): **step 5** is a gate — never `designer_generate`
|
|
336
|
-
an unvalidated payload; **step 7** is where the agent stops (generates files, does
|
|
337
|
-
not serve or deploy).
|
|
338
|
-
|
|
339
|
-
Licensing note: the Designer tools (`designer_preview_files`, `designer_generate`,
|
|
340
|
-
etc.) do **not** require a RESTForge license, unlike the `codegen_*`, `runtime_*`,
|
|
341
|
-
and `setup_validate_config` tools. `codegen_migrate_payload` is a `codegen_*`
|
|
342
|
-
tool, so step 2a runs in the backend project folder.
|
|
66
|
+
## Intent Router
|
|
67
|
+
|
|
68
|
+
Find the row that matches the request, check the minimum information, and start
|
|
69
|
+
with the first action. When the minimum information is already in the request,
|
|
70
|
+
do not ask for it again. When it is missing, ask once, in one short message, for
|
|
71
|
+
everything missing, and say the user may leave the choice to the agent.
|
|
72
|
+
|
|
73
|
+
| User intent | Minimum information | First action | Tool chain |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| New table ("buatkan tabel product") | Fields and types, or the design handed over | Ask for the fields when not stated; write nothing while waiting | `codegen_get_dbschema_catalog` (needed sections) → write `schema/<table>.js` → `codegen_dbschema_validate` |
|
|
76
|
+
| Draft / skeleton table file (explicit) | Table name | `codegen_dbschema_init` | → user fills it in → `codegen_dbschema_validate` |
|
|
77
|
+
| Ready-made template (explicit) | Domain or table | `codegen_dbschema_template` | list → show → generate → `codegen_dbschema_validate` |
|
|
78
|
+
| Schema from a UI design (HTML, image) | The design | Confirm it is an entity, not a dashboard | references/design-to-sdf.md |
|
|
79
|
+
| SDF from an existing database | Config, table or schema | `setup_validate_config` | `codegen_list_tables` → `codegen_dbschema_introspect` |
|
|
80
|
+
| Apply schema to an empty database | Schema path, config | `setup_validate_config` | `codegen_dbschema_migrate` (dryRun first, then confirm) |
|
|
81
|
+
| Change an existing table (column, index, FK) | The change | Edit the SDF | `codegen_dbschema_validate` → `codegen_dbschema_diff` → `codegen_dbschema_apply` (dryRun, confirm) |
|
|
82
|
+
| New CRUD endpoint | Source table (exists in DB); master-detail or not | `setup_validate_config` | `codegen_generate_payload` → `codegen_validate_payload` → `codegen_create_endpoint` |
|
|
83
|
+
| Master-detail endpoint | Header table and detail table | `setup_validate_config` | `codegen_generate_payload` with `detail` → fill formulas → validate → create endpoint |
|
|
84
|
+
| Field validation rule | Field, rule, and layer (RDF or SDF) | Ask the layer only when DDL terms or "enforce" make it ambiguous | RDF: `codegen_get_field_validation_catalog` → edit payload → `codegen_validate_payload` → `codegen_create_endpoint`. SDF: edit schema → validate → diff → apply |
|
|
85
|
+
| Show columns of a referenced table | Table | `codegen_sync_payload` with `expandFk` | → `codegen_create_endpoint` |
|
|
86
|
+
| Custom query (list, view, export) | Columns to show and filter | `codegen_get_query_declarative_catalog` | `codegen_validate_sql` → edit payload → validate → create endpoint |
|
|
87
|
+
| Workflow / status transitions | Status field and transitions | Ground in references/rdf-advanced.md § Workflow | edit RDF (`action.workflow`, `workflow`) → validate → create endpoint; UDF `workflowActions` |
|
|
88
|
+
| Payload out of sync with the database | Table (optional) | `codegen_diff_payload` | → `codegen_sync_payload` → `codegen_create_endpoint` |
|
|
89
|
+
| Dashboard endpoint | Widgets (metrics, SQL), `dash-` name | `codegen_get_dashboard_catalog` | write payload → `codegen_validate_dashboard_payload` → `codegen_create_dashboard` |
|
|
90
|
+
| Background job / Kafka consumer | Name, topic for a consumer | `codegen_create_processor` / `codegen_create_kafka_consumer` | consumer → `runtime_generate_consumer_launcher` |
|
|
91
|
+
| Frontend page | Source RDF and plugin (the existing app's plugin when there is one) | `codegen_migrate_payload` when an RDF exists | `designer_get_udf_catalog` → edit page → `designer_validate_payload` → `designer_preview_files` → `designer_generate` |
|
|
92
|
+
| Bring UDF changes into an existing app | Aggregator UDF, output folder | `designer_validate_payload` | `designer_generate` without `overwrite` (merge); exit 1 = conflicts to resolve → generate again |
|
|
93
|
+
| Auth | Backend, frontend, or both; RBAC or not | references/auth.md § Choosing the mechanism | `project_auth` / plugin auth / `designer_auth_create` / `designer_auth_attach` |
|
|
94
|
+
| JavaScript SDK | Project (endpoints already generated) | `project_sdk_generate` | user runs install / build / deploy |
|
|
95
|
+
| Seed, export, or move rows | Tables or schema, config | references/data-seeding.md | `data_pull` / `data_push` |
|
|
96
|
+
| Integration test | Existing endpoint | `codegen_generate_test` | user runs the tests |
|
|
97
|
+
| Run, stop, or restart the server | Project, config | `runtime_validate_preflight` | `runtime_generate_launcher` → the user runs it |
|
|
98
|
+
| Configure the project | Target parameters | `setup_read_env` | `setup_write_env` / `setup_update_env` → `setup_validate_config` |
|
|
99
|
+
| License question | — | `license_info` | `license deactivate` is the user's command |
|
|
100
|
+
| New project | Project name | Suggest `npx create-restforge-app <name>` | granular: `setup_create_folder` → `setup_install_package` → `setup_init_config` |
|
|
101
|
+
|
|
102
|
+
Detail per track:
|
|
103
|
+
|
|
104
|
+
- Backend pipeline, schema / payload / module decisions → references/backend-pipeline.md
|
|
105
|
+
- Frontend pipeline, UDF / page type / plugin decisions → references/frontend-pipeline.md
|
|
106
|
+
- Errors, prerequisites, commands outside MCP, runtime lifecycle → references/troubleshooting.md
|
|
107
|
+
|
|
108
|
+
### Continue, do not stop halfway
|
|
109
|
+
|
|
110
|
+
A tool response often names the next step. When the user's request already
|
|
111
|
+
covers that step ("buat tabel product sampai endpoint-nya jadi"), continue
|
|
112
|
+
without asking. When it does not, finish with one sentence that offers the next
|
|
113
|
+
step. A destructive step still needs its confirmation (Guardrail 1).
|
|
343
114
|
|
|
344
115
|
---
|
|
345
116
|
|
|
346
|
-
##
|
|
117
|
+
## Layers
|
|
347
118
|
|
|
348
|
-
|
|
349
|
-
right one; never describe one as the other, and never claim the extension does RBAC.
|
|
119
|
+
Three layers co-exist and must not be conflated:
|
|
350
120
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
```
|
|
368
|
-
project_auth (wraps: npx restforge project auth --create --project=<name>)
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
Installs auth SDF (`rfx`), DB tables, middleware, router, six processors
|
|
372
|
-
(register/login/refresh/logout/me/reset-password), a random `JWT_SECRET`, and
|
|
373
|
-
`bcrypt`+`jsonwebtoken`. Idempotent. → references/auth.md § Backend
|
|
374
|
-
|
|
375
|
-
### Frontend auth — `designer_auth_create` / `designer_auth_remove`
|
|
376
|
-
|
|
377
|
-
Adds (or removes) an **embedded** login / signup / forget-password overlay
|
|
378
|
-
(`rfx_auth`) on an existing frontend project, at route
|
|
379
|
-
`/api/<project>/rfx_auth`. This is independent of the `vanilla-js-auth` plugin.
|
|
380
|
-
|
|
381
|
-
```
|
|
382
|
-
designer_auth_create (wraps: npx restforge-designer auth --create --project=<name>)
|
|
383
|
-
designer_auth_remove (wraps: npx restforge-designer auth --remove --project=<name> --force)
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
`create` writes the auth pages + `js/rfx_auth.js` and injects a guard into existing
|
|
387
|
-
pages; `remove` deletes them. Idempotent. Runs via `npx restforge-designer`
|
|
388
|
-
(bundled in `@restforgejs/platform`; available once the project was created with
|
|
389
|
-
`npx create-restforge-app` / the platform is installed).
|
|
390
|
-
→ references/auth.md § Frontend
|
|
391
|
-
|
|
392
|
-
### Retrofit on a generated app — `designer_auth_attach`
|
|
393
|
-
|
|
394
|
-
```
|
|
395
|
-
designer_auth_attach (wraps: npx restforge-designer auth --attach --project=<name>)
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
The "turn auth on afterwards" path for an app whose pages already exist. It
|
|
399
|
-
installs `js/rfx_auth.js`, injects the script tag into the existing pages (except
|
|
400
|
-
the login page), and writes the `embeddedAuth` marker — **page files themselves
|
|
401
|
-
are never touched**, so customisations survive. When the project payload has an
|
|
402
|
-
auth block on an auth-capable plugin (`vanilla-js-auth` / `vanilla-js-custom`) it
|
|
403
|
-
additionally renders the plugin login artifacts (`js/auth.js`, `login.html`,
|
|
404
|
-
`js/login.js`) and extends `js/config.js` with a marked block; in that mode the
|
|
405
|
-
`rfx_auth` login/signup pages are not written, and the storage key is aligned with
|
|
406
|
-
the plugin login so both sides read the same session. Idempotent — existing files
|
|
407
|
-
are skipped unless `overwrite` is set.
|
|
408
|
-
|
|
409
|
-
Pick between the two: `designer_auth_create` when the app just needs a standalone
|
|
410
|
-
login/signup overlay and no auth-capable plugin is in play;
|
|
411
|
-
`designer_auth_attach` when the pages already exist, the plugin is
|
|
412
|
-
`vanilla-js-auth` / `vanilla-js-custom`, or `designer_generate` reported missing
|
|
413
|
-
auth artifacts. The CLI accepts exactly one of `--create` / `--attach` /
|
|
414
|
-
`--remove` per invocation.
|
|
415
|
-
|
|
416
|
-
Do not combine the two mechanisms on one app: if an app already has plugin auth
|
|
417
|
-
(`vanilla-js-auth` / `vanilla-js-custom`), do not also add embedded `rfx_auth`.
|
|
121
|
+
- **SDF** — database structure: tables, columns, indexes, foreign keys, CHECK and
|
|
122
|
+
UNIQUE. Changed in `schema/<table>.js`, applied with migrate (empty database)
|
|
123
|
+
or diff → apply (existing database).
|
|
124
|
+
- **RDF** — backend API behaviour on that structure: `fieldValidation`, queries,
|
|
125
|
+
actions, workflow, master-detail. Changed in `payload/<name>.json`, applied by
|
|
126
|
+
regenerating the endpoint.
|
|
127
|
+
- **UDF** — the frontend consuming the API. Derived from the RDF with
|
|
128
|
+
`codegen_migrate_payload`, refined by hand, generated with `designer_generate`.
|
|
129
|
+
Re-generating merges into the existing app files, so edits there survive.
|
|
130
|
+
|
|
131
|
+
When the user uses DDL terms (NOT NULL, UNIQUE, CHECK, REFERENCES, ALTER TABLE,
|
|
132
|
+
CREATE INDEX), do not map them to payload validation automatically. Ask which
|
|
133
|
+
layer they want: RDF validation answers HTTP 400 with a custom message before the
|
|
134
|
+
request reaches the database; SDF enforcement rejects at storage level. Both can
|
|
135
|
+
exist for the same field. A request about "schema" can mean SDF or RDF; ask when
|
|
136
|
+
the context does not decide it.
|
|
418
137
|
|
|
419
138
|
---
|
|
420
139
|
|
|
421
140
|
## Grounding-First Rules
|
|
422
141
|
|
|
423
|
-
Before
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
definition content from memory.
|
|
142
|
+
Before writing any definition **syntax** (SDF fields, `fieldValidation`, queries,
|
|
143
|
+
dashboard widgets, UDF pages), call the matching catalog tool and use only what
|
|
144
|
+
it returns. Ask only for the sections the task needs, once per session.
|
|
427
145
|
|
|
428
146
|
| Context | Grounding tool | Reference |
|
|
429
147
|
|---|---|---|
|
|
430
|
-
|
|
|
431
|
-
|
|
|
432
|
-
|
|
|
433
|
-
|
|
|
434
|
-
|
|
|
435
|
-
|
|
|
436
|
-
|
|
|
437
|
-
|
|
|
438
|
-
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
constraint, not RDF `fieldValidation`. Grounding surfaces this distinction
|
|
455
|
-
before the agent commits to the wrong one.
|
|
456
|
-
|
|
457
|
-
The reference files help you *understand* the catalog; they do **not** replace
|
|
458
|
-
the tool. Call the tool to ground, produce, and validate — do not hand-produce
|
|
459
|
-
output a tool would generate. The live tool is authoritative; when a reference and
|
|
460
|
-
the tool disagree, trust the tool.
|
|
148
|
+
| SDF | `codegen_get_dbschema_catalog` | references/dbschema-catalog.md |
|
|
149
|
+
| SDF from a UI design | `codegen_get_dbschema_catalog` | references/design-to-sdf.md |
|
|
150
|
+
| RDF `fieldValidation` | `codegen_get_field_validation_catalog` | references/field-validation.md |
|
|
151
|
+
| RDF queries | `codegen_get_query_declarative_catalog` | — |
|
|
152
|
+
| RDF action, workflow, master-detail, aggregate, import | — (no catalog tool) | references/rdf-advanced.md |
|
|
153
|
+
| Dashboard payload | `codegen_get_dashboard_catalog` | — |
|
|
154
|
+
| UDF | `designer_get_udf_catalog` | references/udf-catalog.md |
|
|
155
|
+
| Frontend plugins | `designer_list_plugins` | references/udf-catalog.md § Plugins |
|
|
156
|
+
| `db-connection.env` parameters | `setup_get_config_schema` | references/config-schema.md |
|
|
157
|
+
|
|
158
|
+
The catalog decides **how** a field is written, not **what** a table holds. When
|
|
159
|
+
the user hands the design over, the agent chooses the business fields from domain
|
|
160
|
+
knowledge of the entity.
|
|
161
|
+
|
|
162
|
+
A constraint can mean something other than its plain-English name. `uppercase`
|
|
163
|
+
on a string is a normalization transform (it stores the value in upper case), not
|
|
164
|
+
a validator that rejects lowercase input; rejection is `pattern`, and database
|
|
165
|
+
enforcement is an SDF check. Confirm which one is meant before editing.
|
|
166
|
+
|
|
167
|
+
The live tool is authoritative; when a reference and the tool disagree, trust the
|
|
168
|
+
tool. For RESTForge behaviour that no catalog or reference covers, say so and
|
|
169
|
+
point to the handbook at https://github.com/restforge/handbook (not
|
|
170
|
+
restforge.dev/docs, which is outdated). Never borrow syntax from Express, NestJS,
|
|
171
|
+
Strapi, Hasura, or similar frameworks.
|
|
461
172
|
|
|
462
173
|
---
|
|
463
174
|
|
|
464
|
-
##
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
→ references/design-to-sdf.md
|
|
486
|
-
- **"Is my schema valid and in sync with the database?"** →
|
|
487
|
-
`codegen_dbschema_validate` with `config` (optionally `table`): one verdict per
|
|
488
|
-
table, `[OK]`, `[DRIFT]`, or `[ERROR]` (`table-missing` → migrate/apply fixes
|
|
489
|
-
it; `sdf-invalid` → fix the file). Exit code 1 means drift or an error was
|
|
490
|
-
found, not that the tool failed. Not available for SQLite.
|
|
491
|
-
- **DB exists with drift** → `codegen_dbschema_diff` to review the per-column
|
|
492
|
-
differences, then `codegen_dbschema_apply`. Not `codegen_dbschema_migrate` —
|
|
493
|
-
that is for empty DBs only.
|
|
494
|
-
|
|
495
|
-
### RDF Payload
|
|
496
|
-
|
|
497
|
-
- **No payload yet** → `codegen_generate_payload`.
|
|
498
|
-
- **Payload exists, edit is API-layer only** (e.g. add/adjust `fieldValidation`,
|
|
499
|
-
messages, or a query — no column added or dropped) → ground via the matching
|
|
500
|
-
catalog, edit `payload/<name>.json`, run `codegen_validate_payload`, then regenerate
|
|
501
|
-
with `codegen_create_endpoint`. No DB migration: the schema (SDF) is unchanged.
|
|
502
|
-
- **Payload exists, DB schema changed** → `codegen_diff_payload` first, then
|
|
503
|
-
`codegen_sync_payload`. Turning the RDF into a frontend UDF is a separate
|
|
504
|
-
frontend step (Frontend Pipeline step 2a), not part of this branch.
|
|
505
|
-
- **Customisations survive regeneration.** `codegen_generate_payload` and
|
|
506
|
-
`codegen_sync_payload` keep edits made to generator-owned keys (`action`,
|
|
507
|
-
`fieldValidation`, inline SQL, `auditColumns`, the datatables query file).
|
|
508
|
-
A column deliberately removed from `fieldName` stays removed because generate
|
|
509
|
-
records the known columns in `payload/.meta/<name>.json`; commit that snapshot
|
|
510
|
-
with the payload and never edit it.
|
|
511
|
-
- **Show columns of a referenced table in the list** (e.g. `supplier_name` next
|
|
512
|
-
to `supplier_id`) → `codegen_sync_payload` with `table` and `expandFk`
|
|
513
|
-
(`"both"`, or `"datatables-only"` to leave a custom `viewQuery` alone). It
|
|
514
|
-
writes `query/<table>-join.sql` and points `datatablesQuery` (and `viewQuery`)
|
|
515
|
-
at it; `FK_AUTO_JOIN` picks LEFT or INNER JOIN. The display column per FK is
|
|
516
|
-
chosen automatically and is never the primary key. Use `fkColumns`
|
|
517
|
-
(`ref_table.column`, or `local_fk:ref_table.column`) to override it and
|
|
518
|
-
`expandFkSkip` to leave a relation out. When the CLI reports "No natural
|
|
519
|
-
display column found", **ask the user** which column to show or whether to
|
|
520
|
-
skip that relation — do not pick one yourself.
|
|
521
|
-
- **Custom query needed** → ground via `codegen_get_query_declarative_catalog`,
|
|
522
|
-
check the statement with `codegen_validate_sql` against the live database, then
|
|
523
|
-
set `datatablesQuery`, `viewQuery`, or `exportQuery` in the payload. External
|
|
524
|
-
SQL files use the `file:` prefix
|
|
525
|
-
(e.g. `"datatablesQuery": "file:sql/orders.sql"`). Validating first turns a
|
|
526
|
-
runtime 500 into an error message before the payload is even written.
|
|
527
|
-
|
|
528
|
-
> **"Add an uppercase / case constraint" is ambiguous — disambiguate first.**
|
|
529
|
-
> In RESTForge `uppercase` is an RDF `fieldValidation` *normalization transform*
|
|
530
|
-
> (forces the stored value to upper case), not a reject-if-not-uppercase
|
|
531
|
-
> validator. If the user wants rejection, use `pattern`. If the user wants the
|
|
532
|
-
> database to enforce it, that is an SDF check constraint, not RDF. Confirm which
|
|
533
|
-
> one is meant before editing — see Grounding-First Rules § Misreading semantics.
|
|
534
|
-
|
|
535
|
-
### Backend module type
|
|
536
|
-
|
|
537
|
-
- **Standard CRUD** → `codegen_create_endpoint`. One payload = one module.
|
|
538
|
-
- **Analytic dashboard** → `codegen_validate_dashboard_payload`, then
|
|
539
|
-
`codegen_create_dashboard`. Payload must have `widgets` (not `tableName`); page
|
|
540
|
-
name must be prefixed `dash-`; the payload argument keeps its `.json`
|
|
541
|
-
extension.
|
|
542
|
-
- **Background job** → `codegen_create_processor`.
|
|
543
|
-
- **Kafka event consumer** → `codegen_create_kafka_consumer`; requires
|
|
544
|
-
`KAFKA_ENABLED=true` in config. The consumer runtime is a separate process:
|
|
545
|
-
`runtime_generate_consumer_launcher` prepares it (host scripts or PM2 deploy
|
|
546
|
-
files) and the user starts it.
|
|
547
|
-
- **JavaScript client for a generated project** → `project_sdk_generate`. Run it
|
|
548
|
-
after the endpoints exist, and after `project_auth` when the project needs
|
|
549
|
-
auth, so `client.auth` is included.
|
|
550
|
-
- **Integration test for an existing endpoint** → `codegen_generate_test`.
|
|
551
|
-
- **Every feature endpoint needs its `action` flag.** A feature block without
|
|
552
|
-
the matching flag in `action` produces no endpoint.
|
|
553
|
-
→ references/rdf-advanced.md § The `action` Block
|
|
554
|
-
- **Workflow (status transitions)** → set `action.workflow: true` and add a
|
|
555
|
-
`workflow` block (`statusField`, `transitions` as a map `status → [targets]`,
|
|
556
|
-
optional `hooks` keyed by target status) to the RDF; generates
|
|
557
|
-
`/change-status`. The buttons are UDF `workflowActions` — a frontend key that
|
|
558
|
-
never goes into the RDF.
|
|
559
|
-
→ references/rdf-advanced.md § Workflow
|
|
560
|
-
- **Master-detail (composite CRUD)** → run `codegen_generate_payload` with
|
|
561
|
-
`detail: "<detail table>"`. It writes the `masterDetail` block, the detail
|
|
562
|
-
query file, and `action.createComposite` / `updateComposite` /
|
|
563
|
-
`readComposite`; then fill `headerCalculations` and `calculated` formulas by
|
|
564
|
-
hand. Generates `/create-composite`, `/update-composite`, `/read-composite`.
|
|
565
|
-
→ references/rdf-advanced.md § Master-Detail
|
|
566
|
-
- **Summary numbers per resource** (count, sum, avg, min, max, optionally
|
|
567
|
-
grouped) → `action.aggregate: true`; the request body carries the operations,
|
|
568
|
-
and `aggregateConfig.joins` only whitelists JOINs. For charts or KPIs across
|
|
569
|
-
several tables, prefer a backend dashboard (`codegen_create_dashboard`).
|
|
570
|
-
→ references/rdf-advanced.md § Aggregate Config
|
|
571
|
-
- **Excel export** → `/export` works by default (falls back to
|
|
572
|
-
`SELECT {fields} FROM tableName`); customise the columns/filter with
|
|
573
|
-
`exportQuery` in the RDF payload. Tune `EXPORT_FILE_EXPIRY` / `EXPORT_CHUNK_SIZE`
|
|
574
|
-
in config. Ground `exportQuery` via `codegen_get_query_declarative_catalog`.
|
|
575
|
-
→ references/rdf-advanced.md § Data Source Resolution
|
|
576
|
-
- **Excel import (.xlsx)** → set `action.import: true` and add `importConfig`
|
|
577
|
-
with `enabled: true` (`upsertKeys`, `upsertStrategy`, `requiredFields`,
|
|
578
|
-
optional `lookupFields`) to the RDF payload; generates `/import-upload`,
|
|
579
|
-
`/import-preview`, `/import-commit`, and `/import-status`.
|
|
580
|
-
→ references/rdf-advanced.md § Import Config
|
|
581
|
-
- Activate on an existing project: edit the payload to add `importConfig`
|
|
582
|
-
(and/or `exportQuery`) → `codegen_validate_payload` → `codegen_create_endpoint`.
|
|
583
|
-
|
|
584
|
-
### Soft-delete vs hard-delete
|
|
585
|
-
|
|
586
|
-
- Use soft-delete when deleted rows must be audited or recoverable. Declare
|
|
587
|
-
`softDelete: { enabled: true }` in SDF and add the three contract columns
|
|
588
|
-
(`is_deleted`, `deleted_at`, `deleted_by`).
|
|
589
|
-
- Soft-delete is supported on PostgreSQL only (Phase 1).
|
|
590
|
-
- Tables with composite UNIQUE constraints are incompatible with soft-delete.
|
|
591
|
-
|
|
592
|
-
### Data seeding / migration (rows, not schema)
|
|
593
|
-
|
|
594
|
-
Move table **rows** through SDF-driven envelope files. This is for data, never
|
|
595
|
-
for schema — use the dbschema tools for structure.
|
|
596
|
-
|
|
597
|
-
**Default output location:** `data-storage/<schema>/<table>.json`, relative to the
|
|
598
|
-
project cwd. The `data-storage` folder is the default of the `storagePath` param
|
|
599
|
-
(CLI `--storage-path <folder>`); override it to write elsewhere. The SDF read from
|
|
600
|
-
is `schemaPath` (CLI `--schema-path`, default `schema`).
|
|
601
|
-
|
|
602
|
-
- **Export / dump / snapshot / back up rows** → `data_pull`. Scope is exactly one
|
|
603
|
-
of `table`, `schema`, or `allSchemas`. Only tables registered in the SDF can be
|
|
604
|
-
pulled. `force: true` overwrites existing envelope files. Optional `limit`,
|
|
605
|
-
`batchSize`, `config` (falls back to the default set via `config set-default`,
|
|
606
|
-
i.e. `.restforge/defaults.json`), `schemaPath`, `storagePath`.
|
|
607
|
-
- **Import / load / seed / restore rows** → `data_push`. Same file names as
|
|
608
|
-
`data_pull`, so pulled files push back directly. Scope is exactly one of `table`,
|
|
609
|
-
`schema`, or `allSchemas`; for `schema`/`allSchemas` tables load in FK
|
|
610
|
-
parent→child order.
|
|
611
|
-
- **Move data between databases** → `data_pull` from the source, then `data_push`
|
|
612
|
-
into the target (`config` selects the env per side).
|
|
613
|
-
- ⚠ `data_push` is **APPEND-ONLY** (batch INSERT, no upsert/replace). Running it
|
|
614
|
-
twice inserts the rows twice. Confirm with the user before pushing into a
|
|
615
|
-
database that may already hold those rows.
|
|
616
|
-
|
|
617
|
-
### Frontend UDF
|
|
618
|
-
|
|
619
|
-
- **A backend RDF exists** → `codegen_migrate_payload`; do not write the page by
|
|
620
|
-
hand. Run it once per RDF into the same output folder to build one app.
|
|
621
|
-
- **Re-running migrate** (RDF changed, or a page must pick up new columns) →
|
|
622
|
-
run it again **without** `overwrite`. Existing pages are merged: user edits
|
|
623
|
-
(labels, layout, removed fields, blocks) are kept and RDF changes to untouched
|
|
624
|
-
values are applied. Backend contract values (`apiPath`, `primaryKey`, `type`,
|
|
625
|
-
`required`, `maxlength`, `decimalPlaces`, `tableField`, lookup source, option
|
|
626
|
-
values) follow the RDF when both sides changed, with a warning. The merge uses
|
|
627
|
-
the snapshots in `<output>/.meta/pages/<pageId>.json`; commit them with the
|
|
628
|
-
pages and never edit them. The aggregator (`navigation`, `homepage`) and
|
|
629
|
-
`app-config.json` are merged too.
|
|
630
|
-
- **`overwrite: true`** recreates the page from the RDF and discards every
|
|
631
|
-
customisation (the old file goes to `.restforge/archive/`). Confirm with the
|
|
632
|
-
user before using it.
|
|
633
|
-
- **Date patterns** → `appConfig.dateFormat` / `dateTimeFormat` are rewritten
|
|
634
|
-
from the backend `DATEFORMAT` / `DATETIMEFORMAT` on every migrate. After the
|
|
635
|
-
backend changes them, re-run migrate and `designer_generate`; never edit the
|
|
636
|
-
frontend values to differ from the backend.
|
|
637
|
-
|
|
638
|
-
### Frontend page type
|
|
639
|
-
|
|
640
|
-
- **Standard CRUD page** → `pageType: "crud"` (default) with `apiPath`,
|
|
641
|
-
`primaryKey`, `displayField`, and `fields[]`.
|
|
642
|
-
- **Dashboard page** → `pageType: "dashboard"` with a `dataSources` object
|
|
643
|
-
(`name → { url, method, body }`) and `rows[]` → `columns[]` → `widgets[]`.
|
|
644
|
-
→ references/udf-catalog.md § Dashboard Page
|
|
645
|
-
- **Page with approval workflow** → add `workflow` (`statusField` and
|
|
646
|
-
`transitions`, identical to the RDF) and `workflowActions[]` whose `actionId`
|
|
647
|
-
equals the target status. Add `fieldStates` to lock rows in final statuses.
|
|
648
|
-
→ references/udf-catalog.md § Workflow Actions
|
|
649
|
-
|
|
650
|
-
### Frontend plugin choice
|
|
651
|
-
|
|
652
|
-
- **No auth** → `vanilla-js-basic`.
|
|
653
|
-
- **Auth WITH RBAC, built into the app** → `vanilla-js-auth` or
|
|
654
|
-
`vanilla-js-custom` at `designer_init_project`. Use `noAuth: true` (`--no-auth`)
|
|
655
|
-
to get the plugin's UI without its auth.
|
|
656
|
-
- **Custom branding / new plugin** → `designer_scaffold_plugin`.
|
|
657
|
-
- **Bolt-on auth WITHOUT RBAC** → not a plugin; see Authentication below.
|
|
658
|
-
→ references/udf-catalog.md § Plugins
|
|
659
|
-
|
|
660
|
-
### Authentication
|
|
661
|
-
|
|
662
|
-
- **Needs RBAC** → plugin auth (`vanilla-js-auth` / `vanilla-js-custom`) at
|
|
663
|
-
`designer_init_project`. The extension below does **not** do RBAC.
|
|
664
|
-
- **Backend auth on an existing project (no RBAC)** → `project_auth` (after the
|
|
665
|
-
project and its endpoint exist, with an active DB).
|
|
666
|
-
- **Frontend auth on an app built WITHOUT plugin auth (no RBAC)** →
|
|
667
|
-
`designer_auth_create` (embedded `rfx_auth`).
|
|
668
|
-
- **Remove embedded frontend auth** → `designer_auth_remove` — destructive,
|
|
669
|
-
confirm first (see Guardrails).
|
|
175
|
+
## New Table Conventions
|
|
176
|
+
|
|
177
|
+
Apply to every authored table; take the syntax from the catalog.
|
|
178
|
+
|
|
179
|
+
- Table name snake_case, singular (`product`, `stock_inbound_item`).
|
|
180
|
+
- Primary key `<table>_id` as `string:36 pk`, or the PK style the other SDF files
|
|
181
|
+
of the project already use.
|
|
182
|
+
- Foreign key named after the target PK (`category_id` →
|
|
183
|
+
`fk:category.category_id`), only to a table in the schema folder
|
|
184
|
+
(`codegen_dbschema_models`) or one the user asked for; otherwise ask.
|
|
185
|
+
- Business code `string:<n> unique notnull`, display name `notnull`,
|
|
186
|
+
money/quantity `decimal:15,2 default:0` with a `gte: 0` check, active flag
|
|
187
|
+
`is_active` as `boolean default:true`, an index on columns used for search.
|
|
188
|
+
- The 4 audit columns exactly as the catalog `auditColumns` section gives them
|
|
189
|
+
(`created_at`, `created_by`, `updated_at`, `updated_by`); the RDF generator
|
|
190
|
+
assumes they exist.
|
|
191
|
+
- Fields stated by the user → use them; choose missing types from the names and
|
|
192
|
+
ask only when a type is genuinely ambiguous. Do not add business fields the user
|
|
193
|
+
did not list, apart from the PK and audit columns.
|
|
194
|
+
- Design handed over ("terserah", "tentukan sendiri") → design the fields, write
|
|
195
|
+
the file, validate, then report the chosen structure briefly.
|
|
670
196
|
|
|
671
197
|
---
|
|
672
198
|
|
|
673
199
|
## Guardrails
|
|
674
200
|
|
|
675
|
-
These are hard rules.
|
|
676
|
-
the user's request. When a guardrail conflicts with finishing faster, the
|
|
201
|
+
These are hard rules. When a guardrail conflicts with finishing faster, the
|
|
677
202
|
guardrail wins.
|
|
678
203
|
|
|
679
|
-
**1. Confirm before destructive operations.**
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
- `codegen_dbschema_migrate`
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
- `
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
- `setup_validate_config` with `autoCreateDb: true`
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
**
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
**
|
|
748
|
-
|
|
749
|
-
or
|
|
750
|
-
|
|
751
|
-
output by reading a reference. Emulating the generator is slower, loses
|
|
752
|
-
determinism, and drifts from what the installed version emits. If the tool is not
|
|
753
|
-
available, stop (see Preflight) rather than improvising from the references.
|
|
754
|
-
|
|
755
|
-
---
|
|
756
|
-
|
|
757
|
-
## Tools outside this skill's workflows
|
|
758
|
-
|
|
759
|
-
These MCP tools exist and are callable, but they are not steps of the backend or
|
|
760
|
-
frontend pipeline. They are listed here so their absence from the pipelines reads
|
|
761
|
-
as a decision, not an omission — call them when the user asks for exactly that,
|
|
762
|
-
not as part of a generation run.
|
|
763
|
-
|
|
764
|
-
| Tool | Why it is outside the pipeline |
|
|
765
|
-
|---|---|
|
|
766
|
-
| `health_ping` | Transport smoke test — answers "is the MCP server itself responsive", touches nothing in RESTForge |
|
|
767
|
-
| `key_generate`, `key_list`, `key_revoke` | API key bookkeeping inside `.env` files; independent of definition files and code generation |
|
|
768
|
-
| `project_list` | Registry inventory (endpoint count, database type, creation date) — useful for orientation, never a prerequisite of a later step |
|
|
769
|
-
|
|
770
|
-
`license deactivate` has no MCP tool at all, on purpose: it frees a machine slot
|
|
771
|
-
across machines, so the user runs it manually. `license_info` (read-only) is the
|
|
772
|
-
wrapped half of that pair.
|
|
204
|
+
**1. Confirm before destructive operations.** Tool descriptions mark them
|
|
205
|
+
DESTRUCTIVE. Ask before:
|
|
206
|
+
|
|
207
|
+
- `codegen_dbschema_migrate` (always with `dryRun: false`; with `drop: true` all
|
|
208
|
+
data in the affected tables is lost) and `codegen_dbschema_apply` with
|
|
209
|
+
`dryRun: false`, `allowDrop`, or `allowModify`.
|
|
210
|
+
- `project_delete`, `key_revoke`, `designer_auth_remove`, and `data_push`
|
|
211
|
+
(append-only, a second run duplicates rows).
|
|
212
|
+
- `project_sdk_generate` with `force: true` (rewritten in place, no archive).
|
|
213
|
+
- `setup_validate_config` with `autoCreateDb: true` (runs CREATE DATABASE).
|
|
214
|
+
- `codegen_migrate_payload` with `overwrite: true` (page customisations are
|
|
215
|
+
discarded; without it pages are merged).
|
|
216
|
+
- `designer_generate` with `overwrite: true` (every app file is recreated and
|
|
217
|
+
its customisations are discarded; without it files are merged).
|
|
218
|
+
- `codegen_create_endpoint` and `codegen_create_dashboard` overwrite by default
|
|
219
|
+
but archive the previous files to `.restforge/archive/<run>/` (5 most recent
|
|
220
|
+
runs kept), so a plain intent confirmation is enough. `force: false` finds out
|
|
221
|
+
whether the module exists without writing.
|
|
222
|
+
|
|
223
|
+
For schema changes, present the destructive parts of the diff (dropped tables or
|
|
224
|
+
columns, type narrowing) and wait. "Update the schema" is not consent to drop a
|
|
225
|
+
column.
|
|
226
|
+
|
|
227
|
+
**2. The agent does not run the server.** The last backend step is
|
|
228
|
+
`runtime_generate_launcher`; the user runs it. Never start, stop, or restart the
|
|
229
|
+
server or a Kafka consumer from a shell, and never assume it is running; check
|
|
230
|
+
with `runtime_check_status`. → references/troubleshooting.md § Runtime lifecycle
|
|
231
|
+
|
|
232
|
+
**3. The `setup_validate_config` gate.** It must pass once per session before the
|
|
233
|
+
first tool that takes a `config` parameter: `codegen_list_tables`,
|
|
234
|
+
`codegen_describe_table`, `codegen_dbschema_introspect`,
|
|
235
|
+
`codegen_dbschema_validate` with `config`, `codegen_dbschema_diff`,
|
|
236
|
+
`codegen_dbschema_apply`, `codegen_dbschema_migrate`, `codegen_validate_sql`,
|
|
237
|
+
`codegen_generate_payload`, `codegen_validate_payload`, `codegen_diff_payload`,
|
|
238
|
+
`codegen_sync_payload`, `codegen_migrate_payload`, `codegen_create_endpoint`,
|
|
239
|
+
`data_pull`, and `data_push`. Do not run it for file-only work (catalog lookups,
|
|
240
|
+
authoring SDF, file-only validate, DDL preview, templates). Repeat it only when
|
|
241
|
+
the config changed.
|
|
242
|
+
|
|
243
|
+
**4. Validate before generating.** `codegen_validate_payload` before
|
|
244
|
+
`codegen_create_*`; `codegen_validate_dashboard_payload` for a dashboard payload;
|
|
245
|
+
`designer_validate_payload` before `designer_generate`.
|
|
246
|
+
|
|
247
|
+
**5. Stay inside the task scope.** Do not tidy up files the task did not ask
|
|
248
|
+
for. When a change crosses into another layer (an RDF edit that needs a new
|
|
249
|
+
column is an SDF change), report the cross-over and ask before expanding.
|
|
250
|
+
|
|
251
|
+
**6. Ground before defining.** Never write definition syntax from memory (see
|
|
252
|
+
Grounding-First Rules). This rule is about syntax; choosing the business fields
|
|
253
|
+
of a table the user handed over is allowed (Guardrail 9).
|
|
254
|
+
|
|
255
|
+
**7. Know which generated output survives a regenerate.** Backend output
|
|
256
|
+
(`src/modules/`, `src/models/`, metadata) is overwritten by
|
|
257
|
+
`codegen_create_*` (archived first), so change the RDF instead of the code.
|
|
258
|
+
Frontend app files may be edited: `designer_generate` merges the edits
|
|
259
|
+
(references/frontend-pipeline.md § Regenerating an existing app). Snapshots in
|
|
260
|
+
`payload/.meta/`, `frontend/payload/.meta/pages/`, and
|
|
261
|
+
`frontend/apps/.meta/<project>/` (except `conflicts/`) are committed with their
|
|
262
|
+
files and never edited.
|
|
263
|
+
|
|
264
|
+
**8. Execute through tools; never emulate them.** When a tool produces or
|
|
265
|
+
validates an artifact (`codegen_generate_payload`, `codegen_dbschema_introspect`,
|
|
266
|
+
`codegen_create_*`, `designer_generate`, any `*_validate_*`), call it. An SDF for
|
|
267
|
+
a new table is authored content, not generator output, so writing
|
|
268
|
+
`schema/<table>.js` with the file tools is the intended path.
|
|
269
|
+
`codegen_dbschema_init` and `codegen_dbschema_template` are only for explicit
|
|
270
|
+
draft or template requests.
|
|
271
|
+
|
|
272
|
+
**9. Settle the table structure before writing it.** A new table without its
|
|
273
|
+
fields goes through the clarify question in the Intent Router. Never answer it
|
|
274
|
+
with a skeleton, a dummy template, or a reference template, and never create a
|
|
275
|
+
file "to be filled in later" unless the user asked for a draft.
|
|
773
276
|
|
|
774
277
|
---
|
|
775
278
|
|
|
776
|
-
##
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
-
|
|
782
|
-
|
|
783
|
-
-
|
|
784
|
-
|
|
785
|
-
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
- Kafka if using a Kafka consumer (`KAFKA_ENABLED=true`).
|
|
790
|
-
|
|
791
|
-
### Required backend config parameters
|
|
792
|
-
|
|
793
|
-
Nine of the full parameter set are mandatory before `setup_validate_config` can
|
|
794
|
-
pass:
|
|
795
|
-
|
|
796
|
-
`LICENSE`, `SERVER_ADDRESS`, `SERVER_PORT`, `DB_TYPE`, `DB_HOST`, `DB_PORT`,
|
|
797
|
-
`DB_USER`, `DB_PASSWORD`, `DB_NAME`.
|
|
798
|
-
|
|
799
|
-
→ references/config-schema.md for the full parameter list, and
|
|
800
|
-
`setup_get_config_schema` for the live version of it.
|
|
801
|
-
|
|
802
|
-
### Tools that depend on the installed platform version
|
|
803
|
-
|
|
804
|
-
Two tools wrap CLI sub-commands that old platform releases do not have. Current
|
|
805
|
-
releases have both. On an old project they fail in a recognisable way, so treat
|
|
806
|
-
the failure as a version answer, not a payload problem:
|
|
807
|
-
|
|
808
|
-
| Tool | Requirement | Symptom on an older platform |
|
|
809
|
-
|---|---|---|
|
|
810
|
-
| `codegen_validate_sql` | a platform providing `query validate` | `Unknown command: query` |
|
|
811
|
-
| `codegen_validate_dashboard_payload` | a platform providing `dashboard create --validate-only` | `Unknown flag: --validate-only`; the tool reports it as an upgrade requirement |
|
|
812
|
-
|
|
813
|
-
When `codegen_validate_dashboard_payload` is unavailable, the fallback is
|
|
814
|
-
`codegen_create_dashboard` itself — it runs the same validator before writing.
|
|
815
|
-
|
|
816
|
-
### Common error patterns
|
|
817
|
-
|
|
818
|
-
| Symptom | Cause | Recovery |
|
|
819
|
-
|---|---|---|
|
|
820
|
-
| Tool not found / no `codegen_*` tools available | MCP server not registered in the client | Install `@restforgejs/mcp-server`, register it as the `restforge` MCP server, restart the client |
|
|
821
|
-
| "authenticity check failed" / HTTP 401 | License not active or expired | Set `LICENSE` in `config/db-connection.env`, run `setup_validate_config` |
|
|
822
|
-
| HTTP 429 from license server | Rate limit (10 req/min/IP) | Expected since v5.1.15 — the client falls back to cache; wait or retry |
|
|
823
|
-
| DB connection failed | Wrong DB config or DB not running | Check `DB_HOST`, `DB_PORT`, `DB_USER`, `DB_PASSWORD`, `DB_NAME`; verify the DB is running |
|
|
824
|
-
| "softDelete contract violation" | Contract columns missing or wrong type | Fix the SDF declaration, run `codegen_dbschema_validate` |
|
|
825
|
-
| "Widget uses undeclared placeholder" | `:paramName` in SQL not in `params` | Add the entry to `params` in the dashboard payload |
|
|
826
|
-
| "tableName and widgets conflict" | Payload contains both | Dashboard uses `widgets`; CRUD uses `tableName` — remove the wrong one |
|
|
827
|
-
| UDF validation error on field type | Field type not supported by the active plugin | Run `designer_list_plugins` + `designer_get_udf_catalog` to verify supported types |
|
|
828
|
-
| `constraints.format ... is not supported for type 'date'` (or `timestamp`) | Per-field date pattern in RDF | Remove `format`; the pattern comes from `DATEFORMAT` / `DATETIMEFORMAT` |
|
|
829
|
-
| Frontend shows a different date than the backend stored | `appConfig.dateFormat` / `dateTimeFormat` differ from the backend config | Re-run `codegen_migrate_payload`, then `designer_generate` |
|
|
830
|
-
| Hook rejection answered HTTP 400 with only the hook message | A component handler returned `{ success: false }` or threw | Expected behaviour; the handler name and path are in the server log |
|
|
831
|
-
|
|
832
|
-
When an error is not in this table, do not guess a fix. Re-run the relevant
|
|
833
|
-
`*_validate_*` tool, read its message, and ground against the catalog before
|
|
834
|
-
changing the definition.
|
|
279
|
+
## Talking to the User
|
|
280
|
+
|
|
281
|
+
- Reply in the user's language.
|
|
282
|
+
- Describe actions by what they do ("validate the payload", "generate the
|
|
283
|
+
endpoint"); do not name internal tools.
|
|
284
|
+
- Summarise results (counts, files, verdicts); do not paste raw CLI output or
|
|
285
|
+
JSON unless the user asks.
|
|
286
|
+
- Never repeat secrets: license keys, passwords, full connection URIs. Confirm
|
|
287
|
+
presence only.
|
|
288
|
+
- A precondition that is not met is a next step or a question, not an error.
|
|
289
|
+
- An exit code that the tool describes as a verdict (drift found, payload
|
|
290
|
+
invalid, items skipped, merge conflicts) is a result to relay, not a tool
|
|
291
|
+
failure.
|