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.
@@ -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 defines REST API
29
- endpoints. One SDF produces identical DDL; one RDF payload produces an
30
- identical endpoint module on every execution.
31
- - **Frontend track** — UDF defines the frontend application. One UDF payload
32
- produces identical HTML/JS/CSS via `npx restforge-designer`, plugin-driven,
33
- no build step required.
34
-
35
- The agent interacts with the platform **exclusively through MCP tools**. The
36
- agent does not write generation code itself, does not modify generated output,
37
- and does not guess options outside the catalog. All valid options come from the
38
- catalog returned by grounding tools.
39
-
40
- The platform exposes its capabilities as MCP tools grouped by domain: `health_*`,
41
- `setup_*`, `codegen_*`, `runtime_*`, `designer_*`, `data_*`, `key_*`,
42
- `project_*`, `license_*`. Two facts follow from this and shape every task:
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 (run before any RESTForge task)
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
- ## Backend Pipeline (canonical)
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
- ## Frontend Pipeline (canonical)
275
-
276
- This is the canonical (golden) path for the frontend track. It runs
277
- **independently** from the backend pipeline. The backend API must be running and
278
- reachable at `apiBaseUrl` before the generated frontend is useful, but the
279
- frontend can be defined and generated without the backend live.
280
-
281
- ```
282
- 1. designer_list_plugins
283
- ── GROUNDING ── list available output plugins before creating the UDF.
284
- Built-in: vanilla-js-basic (no auth), vanilla-js-auth and
285
- vanilla-js-custom (JWT auth + RBAC).
286
- → references/udf-catalog.md § Plugins
287
-
288
- 2a. codegen_migrate_payload ── PRIMARY ── when a backend RDF payload exists
289
- Convert the RDF into a split UDF set in the output folder (default
290
- frontend/payload/): app-config.json, pages/<pageId>.json, the aggregator
291
- <appCode>.json, and snapshots in .meta/pages/. Run it once per RDF with
292
- the same output folder to add pages to one app. It derives fields, types,
293
- lookups, details[], status filters, and the date patterns from the
294
- backend, so start here instead of writing pages by hand.
295
- Needs a license and the backend config (like every codegen_* tool).
296
- 2b. [hand-write the UDF] only when there is no RDF to migrate from
297
- Ground every key with designer_get_udf_catalog first.
298
- designer_init_project (optional) scaffold a project folder with the
299
- assets of an auth-capable plugin (vanilla-js-auth / vanilla-js-custom).
300
- It writes no UDF payload file.
301
-
302
- 3. designer_get_udf_catalog
303
- ── GROUNDING ── call before editing any UDF page.
304
- Returns valid field types, enums, limits, and validation constants for
305
- the installed designer version.
306
- → references/udf-catalog.md
307
-
308
- 4. [edit the UDF pages]
309
- Edit pages/<pageId>.json (labels, layout, features, workflowActions) and
310
- the aggregator (navigation, homepage). One page entry = one CRUD page or
311
- one dashboard page. Re-running migrate later merges RDF changes into
312
- these files without losing the edits (Decision Points § Frontend UDF).
313
-
314
- 5. designer_validate_payload
315
- ── GATE ── validate the UDF (the aggregator file). Catches structural
316
- errors before generation. Run before preview or generate, every time.
317
-
318
- 6. designer_preview_files
319
- Dry-run: list files that would be generated, without writing to disk.
320
- Use to verify scope before an overwrite.
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
- ## Auth Extension
117
+ ## Layers
347
118
 
348
- RESTForge has **two different auth mechanisms — do not confuse them.** Pick the
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
- | Mechanism | RBAC? | How |
352
- |---|---|---|
353
- | **Plugin auth** — built into the frontend at generation time | **Yes (auth + RBAC)** | `vanilla-js-auth` or `vanilla-js-custom` plugin in `designer_init_project`; disable with `noAuth: true` (`--no-auth`) |
354
- | **Auth extension** — bolt-on added to an existing project | **No RBAC** | backend `project_auth`; frontend `designer_auth_create` (embedded `rfx_auth`) |
355
-
356
- Confirm which plugins provide auth with `designer_list_plugins` — do not hardcode
357
- it. The rest of this section covers the **extension** (the no-RBAC bolt-on); for
358
- plugin auth see Decision Points § Frontend plugin choice. Google Sign-In and
359
- `@restforgejs/auth` are out of scope for the extension.
360
-
361
- ### Backend auth — `project_auth`
362
-
363
- Adds the auth backend to an existing RESTForge project (run the standard backend
364
- pipeline first; the project and its endpoint must already exist, and the DB must
365
- be active).
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 reasoning about, proposing, or generating any **definition content** —
424
- SDF fields, RDF `fieldValidation`, queries, dashboard widgets, or UDF pages —
425
- call the matching grounding tool first and use only what it returns. Never write
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
- | Defining or reviewing SDF | `codegen_get_dbschema_catalog` | references/dbschema-catalog.md |
431
- | Deriving SDF from a UI design (HTML / image / screenshot) | `codegen_get_dbschema_catalog` | references/design-to-sdf.md |
432
- | Defining `fieldValidation` in an RDF payload | `codegen_get_field_validation_catalog` | references/field-validation.md |
433
- | Defining queries in an RDF payload | `codegen_get_query_declarative_catalog` | — |
434
- | Defining a dashboard payload | `codegen_get_dashboard_catalog` | — |
435
- | Defining `/aggregate` joins or requests | — (no catalog tool yet) | references/rdf-advanced.md § Aggregate Config |
436
- | Defining UDF (frontend) | `designer_get_udf_catalog` | references/udf-catalog.md |
437
- | Listing available frontend plugins | `designer_list_plugins` | references/udf-catalog.md § Plugins |
438
- | Setting `db-connection.env` parameters | `setup_get_config_schema` | references/config-schema.md |
439
-
440
- **Why this rule exists.** The catalog is the source of truth for valid options
441
- in the *installed* platform version. Reasoning without it produces confident but
442
- wrong output — field types that do not exist, constraints not applicable to a
443
- type, or wrong semantics. Two concrete failure modes this rule prevents:
444
-
445
- - **Inventing options.** Without grounding, an agent may write a made-up key
446
- (e.g. `"toUpper": true`) that the validator rejects. The catalog gives the
447
- exact key and value type.
448
- - **Misreading semantics.** A constraint can mean something different from its
449
- plain-English name. For example, `uppercase` on a `string` field is a
450
- *normalization transform* (it forces the stored value to upper case), grouped
451
- with `trim` and `lowercase` — it is **not** a validator that rejects
452
- non-uppercase input. If the user wants rejection, the answer is `pattern`, not
453
- `uppercase`; if they want database-level enforcement, that is an SDF check
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
- ## Decision Points
465
-
466
- Use these to pick the correct branch when the request is state-dependent. Each
467
- branch still obeys the Grounding-First Rules above.
468
-
469
- ### Schema (SDF)
470
-
471
- - **DB does not exist** → `codegen_dbschema_init` (scaffold with audit columns)
472
- or `codegen_dbschema_template` (minimal template, no DB connection required).
473
- - **DB already exists** → `codegen_dbschema_introspect` to generate SDF from the
474
- actual schema. Do not hand-write a schema that a real DB can describe.
475
- - **Question about what the DB already contains** → `codegen_list_tables` (tables
476
- and views) and `codegen_describe_table` (columns, primary key, foreign keys,
477
- indexes of one table). Both are read-only live introspection; they are the
478
- safe way to answer such a question without generating anything.
479
- - **Starting from a UI design** (HTML mockup, screenshot, image, Figma export)
480
- → first confirm the design is an entity to model, not a dashboard/analytics
481
- screen (those map to the Dashboard RDF branch below, not to a new SDF table).
482
- Then classify visible elements into stored / derived / relation / audit, draft
483
- the SDF, and run `codegen_dbschema_validate`. The design shows presentation,
484
- not storage — do not turn every visible label into a column.
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. They override convenience and override an eager reading of
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
- The following require explicit user confirmation before execution:
681
-
682
- - `codegen_dbschema_migrate` or `codegen_dbschema_apply` that drops a table or
683
- column, or alters a column in a way that loses data.
684
- - `project_delete` — permanent project deletion.
685
- - `project_sdk_generate` with `force: true` — the SDK files are rewritten in
686
- place with **no** archive backup, so hand edits inside the SDK folder are lost,
687
- and resource files of endpoints that no longer exist are left behind.
688
- - `setup_validate_config` with `autoCreateDb: true` — it runs CREATE DATABASE on
689
- the database server. The default call is read-only.
690
- - `codegen_migrate_payload` with `overwrite: true` — existing UDF pages are
691
- recreated and every customisation in them is discarded (the old files are
692
- archived). Without `overwrite`, pages are merged and nothing is lost.
693
-
694
- `codegen_create_endpoint` and `codegen_create_dashboard` overwrite by default
695
- (`force` is true) but first move the previous files to
696
- `.restforge/archive/<run>/<original relative path>` (the 5 most recent runs are
697
- kept), so they need a plain intent confirmation rather than a
698
- destructive-operation confirmation. Use `force: false` when the point is to find out whether the module
699
- already exists: the endpoint command then stops at its confirmation question
700
- without writing, and the dashboard command refuses with a clean error.
701
-
702
- For schema changes, run `codegen_dbschema_diff` first, present a summary of the
703
- destructive parts (dropped tables/columns, type narrowing), and wait for
704
- confirmation before calling `codegen_dbschema_apply`. Never infer approval from
705
- the original request — "update the schema" is not consent to drop a column.
706
-
707
- **2. The agent does not run the server.**
708
- The agent's last step on the backend track is `runtime_generate_launcher`. The
709
- user executes the launcher in their own terminal. The agent never calls shell
710
- commands to start, stop, or restart the server, and never assumes the server is
711
- running — verify with `runtime_check_status` instead. The same rule covers the
712
- Kafka consumer runtime: `runtime_generate_consumer_launcher` only writes the
713
- scripts or the PM2 deploy files; starting the consumer belongs to the user. A
714
- process spawned from an agent session dies with the session.
715
-
716
- **3. The `validate_config` gate is mandatory.**
717
- `setup_validate_config` must pass before any `codegen_*` operation starts. Do not
718
- skip it "to save a step" — running codegen against an invalid config produces
719
- uninformative errors that cost more time than the gate.
720
-
721
- **4. Validate before generating.**
722
- Always run `codegen_validate_payload` before `codegen_create_*`, and
723
- `designer_validate_payload` before `designer_generate`. For a dashboard payload
724
- the matching validator is `codegen_validate_dashboard_payload` — the general one
725
- does not understand the `widgets` shape. Generation on an invalid payload
726
- produces incomplete or broken output that looks like it succeeded.
727
-
728
- **5. Stay inside the task scope.**
729
- Do not modify files outside the requested task. If the change is a backend
730
- payload edit, do not also "tidy up" the SDF, the runtime, or the frontend. If a
731
- change genuinely requires touching another area (e.g. an RDF edit that needs a
732
- new column, which is an SDF change), stop and report the cross-over, then ask
733
- before expanding scope.
734
-
735
- **6. Ground before defining — repeated here because it is a guardrail, not a
736
- suggestion.** Never write SDF fields, `fieldValidation`, queries, dashboard
737
- widgets, or UDF content from memory. Call the matching catalog tool first (see
738
- Grounding-First Rules). Inventing an option that "should" exist is the most
739
- common way to produce confidently wrong output.
740
-
741
- **7. Confirm before removing embedded auth.**
742
- `designer_auth_remove` deletes the auth files (`login.html`, `signup.html`, the
743
- forget-password overlay, `js/rfx_auth.js`) and strips the guard from existing
744
- pages. Under MCP it runs with `--force` (no interactive prompt), so confirm the
745
- project name and intent with the user **before** calling it.
746
-
747
- **8. Execute through tools; never emulate them.** The bundled `references/` help
748
- you *understand* options — they do not replace the tools. When a tool can produce
749
- or validate an artifact (`codegen_dbschema_template`/`init`,
750
- `codegen_generate_payload`, any `*_validate_*`), **call it**; do not hand-write its
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
- ## Prerequisites and Common Errors
777
-
778
- ### Environment prerequisites
779
-
780
- - Node.js ≥ 18.
781
- - A reachable database matching the configured `DB_TYPE` (PostgreSQL, MySQL,
782
- Oracle, or SQLite).
783
- - A valid RESTForge license for `codegen_*`, `runtime_*`, and
784
- `setup_validate_config`. Designer tools do not require a license.
785
- - The RESTForge MCP server registered in the client
786
- (`npm install -g @restforgejs/mcp-server`, then registered as the `restforge`
787
- MCP server). Without it, none of the tools below exist.
788
- - Redis if using cache, distributed lock, or live sync.
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.