@dforge-core/dforge-mcp 0.1.0-rc.11 → 0.1.0-rc.13

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +75 -21
  3. package/dist/server.js +2405 -272
  4. package/docs/creating-modules.md +7 -3
  5. package/package.json +11 -6
  6. package/resources/docs/conventions.md +20 -14
  7. package/resources/schemas/entity.schema.json +8 -1
  8. package/resources/schemas/reports.schema.json +4 -0
  9. package/skills/dforge-mcp-author/SKILL.md +227 -95
  10. package/skills/dforge-mcp-author/examples/simple-todo/README.md +38 -0
  11. package/skills/dforge-mcp-author/examples/simple-todo/entities/todo_item.json +83 -0
  12. package/skills/dforge-mcp-author/examples/simple-todo/entities/todo_list.json +43 -0
  13. package/skills/dforge-mcp-author/examples/simple-todo/logic/actions/mark_done.dsl +6 -0
  14. package/skills/dforge-mcp-author/examples/simple-todo/manifest.json +32 -0
  15. package/skills/dforge-mcp-author/examples/simple-todo/security/roles.json +10 -0
  16. package/skills/dforge-mcp-author/examples/simple-todo/seed-data/01-lists.json +17 -0
  17. package/skills/dforge-mcp-author/examples/simple-todo/ui/actions.json +11 -0
  18. package/skills/dforge-mcp-author/examples/simple-todo/ui/data_views.json +35 -0
  19. package/skills/dforge-mcp-author/examples/simple-todo/ui/menus.json +28 -0
  20. package/skills/dforge-mcp-author/references/action-dsl.md +397 -0
  21. package/skills/dforge-mcp-author/references/column-types.md +168 -0
  22. package/skills/dforge-mcp-author/references/conventions.md +177 -0
  23. package/skills/dforge-mcp-author/references/data-migration.md +270 -0
  24. package/skills/dforge-mcp-author/references/data-views.md +192 -0
  25. package/skills/dforge-mcp-author/references/excel-import.md +61 -0
  26. package/skills/dforge-mcp-author/references/field-types.md +144 -0
  27. package/skills/dforge-mcp-author/references/filters.md +326 -0
  28. package/skills/dforge-mcp-author/references/flags.md +73 -0
  29. package/skills/dforge-mcp-author/references/formulas.md +206 -0
  30. package/skills/dforge-mcp-author/references/jobs.md +149 -0
  31. package/skills/dforge-mcp-author/references/manifest.md +123 -0
  32. package/skills/dforge-mcp-author/references/menus.md +164 -0
  33. package/skills/dforge-mcp-author/references/number-sequences.md +117 -0
  34. package/skills/dforge-mcp-author/references/print-templates.md +159 -0
  35. package/skills/dforge-mcp-author/references/queries.md +312 -0
  36. package/skills/dforge-mcp-author/references/reports.md +398 -0
  37. package/skills/dforge-mcp-author/references/schema-import.md +331 -0
  38. package/skills/dforge-mcp-author/references/security.md +244 -0
  39. package/skills/dforge-mcp-author/references/settings.md +120 -0
  40. package/skills/dforge-mcp-author/references/traits.md +153 -0
  41. package/skills/dforge-mcp-author/references/translations.md +158 -0
  42. package/skills/dforge-mcp-author/references/validation-checklist.md +182 -0
  43. package/skills/dforge-mcp-author/scripts/xlsx_to_model.py +198 -0
@@ -0,0 +1,192 @@
1
+ # Data Views Reference
2
+
3
+ Data views define how users see and interact with entity data. One entity can have many data views (grid, kanban, gallery, tree-grid, list, card).
4
+
5
+ Lives in: `ui/data_views.json`
6
+
7
+ ## Structure
8
+
9
+ ```json
10
+ {
11
+ "contact_list": {
12
+ "label": "All Contacts",
13
+ "description": "Primary list of contacts",
14
+ "viewType": "grid",
15
+ "icon": "bi-people",
16
+ "dataSources": [{
17
+ "entityCode": "contact",
18
+ "label": "Contacts",
19
+ "columns": [
20
+ { "column_cd": "first_name", "width": 150 },
21
+ { "column_cd": "last_name", "width": 150 },
22
+ { "column_cd": "email", "width": 220 },
23
+ { "column_cd": "phone", "width": 130 },
24
+ { "column_cd": "account", "width": 200 }
25
+ ],
26
+ "filter": null
27
+ }],
28
+ "order": ["last_name"]
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## Critical rule — `dataSources` array
34
+
35
+ **Always** put `entityCode`, `columns`, and per-source `filter` inside a `dataSources` array. Never at the root. The view-level `order` and `filter` sit at the view-def root, alongside `viewType`.
36
+
37
+ ```json
38
+ // WRONG — will fail validation
39
+ {
40
+ "contact_list": {
41
+ "label": "Contacts",
42
+ "viewType": "grid",
43
+ "entityCode": "contact", // WRONG — should be inside dataSources
44
+ "columns": [ /* ... */ ] // WRONG — should be inside dataSources
45
+ }
46
+ }
47
+
48
+ // RIGHT
49
+ {
50
+ "contact_list": {
51
+ "label": "Contacts",
52
+ "viewType": "grid",
53
+ "dataSources": [{
54
+ "entityCode": "contact",
55
+ "columns": [ /* ... */ ]
56
+ }]
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## View types
62
+
63
+ | `viewType` | Description | `viewConfig` | When to use |
64
+ |---|---|---|---|
65
+ | `grid` | Spreadsheet-style table with sortable columns | — | Default for most entities; bulk data |
66
+ | `list` | Compact list view | — | Mobile-friendly, card-sized items |
67
+ | `kanban` | Columns grouped by a status field | `groupByField` | Workflow entities with stages (deals, tickets) |
68
+ | `gallery` | Image-forward card grid | — | Image-heavy entities (products, real estate) |
69
+ | `tree-grid` | Hierarchical grid with expand/collapse | — | Tree structures (folders, categories, org charts) |
70
+ | `calendar` | Calendar display of date-based records | `dateField`, `titleField` | Schedules, due dates, events |
71
+ | `card` | Single-record detail view | — | Record detail pages (implicit — every entity has one) |
72
+
73
+ ## View config (`viewConfig`)
74
+
75
+ Some view types need additional configuration via the `viewConfig` property:
76
+
77
+ ### Kanban
78
+
79
+ ```json
80
+ {
81
+ "opportunities_kanban": {
82
+ "viewType": "kanban",
83
+ "label": "Sales Pipeline",
84
+ "dataSources": [{
85
+ "entityCode": "opportunity",
86
+ "columns": ["opportunity_name", "account", "total_amount", "owner_id"]
87
+ }],
88
+ "viewConfig": {
89
+ "groupByField": "stage"
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ `groupByField` — the dropdown/status column to group cards by. Each distinct value becomes a kanban column.
96
+
97
+ ### Calendar
98
+
99
+ ```json
100
+ {
101
+ "invoices_calendar": {
102
+ "viewType": "calendar",
103
+ "label": "Invoice Calendar",
104
+ "dataSources": [{
105
+ "entityCode": "invoice",
106
+ "columns": ["invoice_number", "customer", "total_amount", "due_date"]
107
+ }],
108
+ "viewConfig": {
109
+ "dateField": "due_date",
110
+ "titleField": "invoice_number"
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ - `dateField` — the date column that determines where records appear on the calendar
117
+ - `titleField` — the column whose value is shown as the calendar event title
118
+
119
+ ## Columns
120
+
121
+ Each column is either a simple string or an object:
122
+
123
+ ```json
124
+ "columns": [
125
+ "first_name", // just column code, default width
126
+ { "column_cd": "email", "width": 220 }, // with width override
127
+ { "column_cd": "account", "width": 200, "visible": true }
128
+ ]
129
+ ```
130
+
131
+ ## Filters
132
+
133
+ Filters use dForge's canonical JSON filter format — see [filters.md](filters.md) for the full grammar. Keys are `c` (column), `o` (operator), `v` (value) for conditions, and `g` (group operator), `i` (items) for groups.
134
+
135
+ Single condition:
136
+
137
+ ```json
138
+ "filter": { "c": "status", "o": "=", "v": "active" }
139
+ ```
140
+
141
+ Group:
142
+
143
+ ```json
144
+ "filter": {
145
+ "g": "and",
146
+ "i": [
147
+ { "c": "status", "o": "=", "v": "active" },
148
+ { "c": "created_date", "o": ">", "v": "2026-01-01" }
149
+ ]
150
+ }
151
+ ```
152
+
153
+ Do **not** use `op`/`args`/`column`/`value` — that format is rejected.
154
+
155
+ ## Sort (`order`)
156
+
157
+ Sort lives at the **view-def root** (not inside `dataSources[]`) under the key **`order`** — a `string[]` of column codes. Direction is encoded in the string itself:
158
+
159
+ - Bare column code → **ascending** (the default; no prefix needed)
160
+ - Leading `-` → **descending**
161
+
162
+ ```json
163
+ "order": ["last_name", "first_name"] // both ascending
164
+ "order": ["-created_date"] // descending (audit trait provides created_date)
165
+ "order": ["-created_date", "last_name"] // primary desc, then asc tiebreak
166
+ ```
167
+
168
+ The array order is the sort precedence: the first entry is the primary sort key, subsequent entries are tiebreakers.
169
+
170
+ This matches the shape the runtime persists and `data.get` accepts. **Do not** use `"sort"`, `[{ column_cd, direction }]`, or `[{ c, d }]` here — those shapes belong to `query.run` and `report.run` (see [queries.md](queries.md)), not `data_views.json`.
171
+
172
+ ## Multi-source views
173
+
174
+ A view can show data from multiple entities (e.g. a dashboard-style view mixing contacts and activities). Each entry in `dataSources` is independent with its own columns/filter.
175
+
176
+ ```json
177
+ "dataSources": [
178
+ { "entityCode": "contact", "columns": [ /* ... */ ] },
179
+ { "entityCode": "activity", "columns": [ /* ... */ ] }
180
+ ]
181
+ ```
182
+
183
+ Most views only have one source. Order is view-level and applies to the primary (level 0) source.
184
+
185
+ ## Common mistakes
186
+
187
+ - Putting `entityCode` or `columns` at the root — **wrong**. They go inside `dataSources[]`.
188
+ - Using `viewCode` or `view_cd` — **wrong**. The code is the dictionary key.
189
+ - Using `"sort"` for data view ordering — **wrong**. The field is `"order"` and it lives at view-def root (not inside `dataSources[]`).
190
+ - Object-array order like `[{ column_cd: "...", direction: "asc" }]` — **wrong shape for data views**. Use `string[]` with leading `-` for descending.
191
+ - Forgetting `viewType` — **required**, defaults don't apply.
192
+ - Inventing view types like `"spreadsheet"` or `"table"` — **wrong**. Use `grid`.
@@ -0,0 +1,61 @@
1
+ # Importing a data model from a spreadsheet (.xlsx / .csv)
2
+
3
+ When the user gives you a spreadsheet to turn into a module, you can't read a
4
+ binary `.xlsx` directly — decode it first, then reason over the result.
5
+
6
+ ## Flow
7
+
8
+ 1. **Extract the sheets to a JSON model.** Load the bundled extractor resource
9
+ `dforge://script/xlsx-to-model`, write it to a temp file, and run it:
10
+
11
+ ```bash
12
+ python3 /tmp/xlsx_to_model.py "<path/to/file.xlsx>"
13
+ ```
14
+
15
+ It needs only Python 3 (pure standard library — no `pip install`). It prints
16
+ `{"sheets":[{"name":..,"headers":[..],"rows":[[..],..]}]}`. If it prints
17
+ `{"error":..}` (e.g. Python missing), fall back: ask the user to export each
18
+ sheet as **CSV** (CSV is plain text — read it directly).
19
+
20
+ 2. **Turn the model into a table-spec.** For each sheet:
21
+ - `name` = the sheet name, snake_cased (`"Order Lines"` → `order_lines`).
22
+ - One **column** per header: `name` = header snake_cased; `sampleValues` =
23
+ that column's values from `rows` (a few are enough). Don't set `fieldTypeCd`
24
+ unless you're sure — let the import infer it. Add a `sqlType` hint only when
25
+ the values make the type obvious (all integers → `int`, decimals → `numeric`,
26
+ `YYYY-MM-DD` strings → `date`; remember xlsx **dates arrive as numbers**, so
27
+ lean on the header name, e.g. `*_date`, to spot them).
28
+ - **References (FKs):** when a column looks like a foreign key — header
29
+ `<thing>_id` (or `<thing> id`) where `<thing>` matches another sheet — put it
30
+ in `references: [{ column, toTable }]` instead of as a plain column.
31
+ - Skip an `id` / primary-key column — the `identity` trait provides `{entity}_id`.
32
+
33
+ 3. **Show the proposed entity inventory for sign-off** (same gate as any Phase 1
34
+ scaffold), then call **`dforge_module_import`**:
35
+ - existing module → `{ moduleDir, tables }`
36
+ - new module → add `module: { code, displayName }` (greenfield).
37
+
38
+ 4. **Run `dforge_module_validate`** and refine the generated default grids to
39
+ surface the imported columns.
40
+
41
+ ## With data or empty — both work
42
+
43
+ A sheet may be **populated** (headers + rows) or **structure-only** (headers, no
44
+ data rows). Both produce a valid entity:
45
+
46
+ - **Populated** → use the `sampleValues` for type inference (numbers, dates,
47
+ dropdowns). Best results.
48
+ - **Empty (headers only)** → the extractor returns `"rows": []`. You still get
49
+ one column per header, but with no samples the import defaults most columns to
50
+ `text` — so lean on the **header name** (`email`, `phone`, `*_date`, `*_id` →
51
+ FK) and add `sqlType` hints where the user can tell you the type. Consider
52
+ confirming the inferred types with the user before importing.
53
+
54
+ ## Notes
55
+
56
+ - One worksheet (or one Excel table object) = one entity. Ignore obviously
57
+ non-tabular sheets (dashboards, notes).
58
+ - The extractor returns the first non-empty row as `headers`; if a sheet has
59
+ title rows above the real header, tell the user or adjust the spec by hand.
60
+ - Type inference + the FK+Reference pattern are handled by `dforge_module_import`
61
+ against the `@dforge-core/metadata` registry — you only produce the table-spec.
@@ -0,0 +1,144 @@
1
+ # Field Types Reference
2
+
3
+ The canonical list of field types supported by dForge. **Do not invent new values — the set is fixed** and validated by the platform on module install.
4
+
5
+ Source of truth: `server/database/system-modules/metadata/seed-data/field_types.json` in the dForge repo.
6
+
7
+ > **You usually don't set `dbDatatype`.** For a plain data column, omit it — the field tools derive it from `fieldTypeCd` (the "Common `dbDatatype`" column below): `currency` → `numeric(18,2)`, `text` → `varchar`, `checkbox` → `bool`, etc. An explicit value is never overridden, so only set `dbDatatype` when you need to:
8
+ > - **a hidden FK column** — it has no `fieldTypeCd`, so derivation can't fire; set `dbDatatype: "cuid"` to match the target entity's `identity` PK (see `column-types.md`);
9
+ > - **override the size/precision** — e.g. `varchar(100)` via `maxLen`, or a specific numeric scale.
10
+ >
11
+ > Reference (`columnType: "R"`) and formula (`columnType: "F"`) columns never get a `dbDatatype` at all.
12
+
13
+ ## String-backed
14
+
15
+ | `fieldTypeCd` | `baseDatatypeCd` | Description | Common `dbDatatype` | Params |
16
+ |---|---|---|---|---|
17
+ | `text` | `string` | Single-line text | `varchar` (with `maxLen`) | `maxLen` |
18
+ | `email` | `string` | Email address. Client-side format validation. | `varchar` 250 | — |
19
+ | `phone` | `string` | Phone/telephone. | `varchar` 50 | — |
20
+ | `url` | `string` | Web URL. | `varchar` 500 | — |
21
+ | `textarea` | `string` | Multi-line plain text. | `text` | `defaultLines`, `maxLines` |
22
+ | `richtext` | `string` | Rich text editor (HTML). | `text` | — |
23
+ | `code` | `string` | Code editor with syntax highlighting. | `text` | `language` |
24
+ | `dropdown` | `string` | Fixed list of options. | `varchar` | `options: ["a","b",…]` or `[{value,label,icon,color}]` |
25
+ | `flags` | `string` | Multiple checkboxes with letter flags. | `varchar` | `optionSets`, `style: "buttons"` |
26
+ | `tags` | `string` | Free-form tag list. | `varchar` or `text` | — |
27
+ | `color` | `string` | Color picker. | `varchar(20)` | — |
28
+ | `hidden` | `string` | Internal, never shown in UI. | `varchar` | — |
29
+
30
+ ## Number-backed
31
+
32
+ | `fieldTypeCd` | `baseDatatypeCd` | Description | Common `dbDatatype` | Params |
33
+ |---|---|---|---|---|
34
+ | `number` | `number` | Numeric value. | `int`, `bigint`, `numeric` | `min`, `max`, `scale` |
35
+ | `currency` | `number` | Monetary value. Precision 2. | `numeric(18,2)` | `currency: "USD"`, `min`, `max` |
36
+ | `percent` | `number` | Percentage 0–100. Precision 2. | `numeric(5,2)` | `min`, `max` (default 0–100) |
37
+
38
+ ## Boolean-backed
39
+
40
+ | `fieldTypeCd` | `baseDatatypeCd` | Description | Common `dbDatatype` | Params |
41
+ |---|---|---|---|---|
42
+ | `checkbox` | `bool` | Boolean checkbox. | `bool` | — |
43
+
44
+ > **`checkbox` is the only valid `fieldTypeCd` for boolean fields.** Do not use `bool`, `boolean`, or `toggle` as `fieldTypeCd` — those are not valid field type codes. (`bool` IS the correct `dbDatatype` for this field, but `checkbox` is the only correct `fieldTypeCd`.)
45
+
46
+ ## Date/time-backed
47
+
48
+ | `fieldTypeCd` | `baseDatatypeCd` | Description | Common `dbDatatype` | Params |
49
+ |---|---|---|---|---|
50
+ | `date` | `date` | Calendar date only. | `date` | `min`, `max` (ISO strings or `TODAY()`) |
51
+ | `datetime` | `timestamp` | Date + time with timezone. | `timestamptz` | `min`, `max` |
52
+ | `time` | `time` | Time of day. | `time` | — |
53
+
54
+ ## Binary / file
55
+
56
+ | `fieldTypeCd` | `baseDatatypeCd` | Description | Params |
57
+ |---|---|---|---|
58
+ | `file` | `binary` | Arbitrary file upload. | `accept`, `maxSize` |
59
+ | `image` | `binary` | Image upload with preview. | `maxSize`, `dimensions` |
60
+
61
+ ## Reference / lookup / set
62
+
63
+ | `fieldTypeCd` | `baseDatatypeCd` | `columnType` | Description |
64
+ |---|---|---|---|
65
+ | `lookup` | `guid` | `R` | Reference to another entity (always paired with a hidden FK column — see SKILL.md "FK+Reference pattern") |
66
+ | `user` | `cuid` | `D` | User picker. Writes a user ID directly, no paired FK needed. |
67
+ | `grid` | `set` | `S` | Detail grid of related records (1:N backwards reference). Used with `link` declaring the relation. |
68
+ | `entitylink` | `json` | `D` | Polymorphic link to any entity (stores `{entity, id}` pair). |
69
+
70
+ ## JSON
71
+
72
+ | `fieldTypeCd` | `baseDatatypeCd` | Description |
73
+ |---|---|---|
74
+ | `json` | `json` | JSON editor. Stored in `jsonb`. |
75
+
76
+ ---
77
+
78
+ ## Default values
79
+
80
+ There is **no** `defaultValue` (or `default`) key on an entity data column — it fails schema
81
+ validation (`entity.schema.json` is `additionalProperties: false`). To give a column a default:
82
+
83
+ | Need | Do this |
84
+ |---|---|
85
+ | Literal / computed default (`'draft'`, `TODAY()`) | Carry a `formula` on the column (formula context — uppercase `TODAY()`/`NOW()`), e.g. `"formula": "'draft'"` or `"formula": "TODAY()"`. |
86
+ | Document number (PO-2026-0001) | Declare a `numberSequence` on the entity — auto-fills on insert. |
87
+ | Anything set at create time | Set it in an action/trigger DSL (`execute:` uses lowercase `now()`). |
88
+
89
+ > `defaultValue` **is** valid on **module settings** (`settings.json`) — that's the only place it
90
+ > belongs. Don't carry the settings habit over to entity fields.
91
+
92
+ ---
93
+
94
+ ## Common mistakes
95
+
96
+ > **Wrong key name:** `fieldType` is a C# navigation property on the server model — it is not a valid JSON key in entity definitions. Always use `fieldTypeCd` (the string code). Using `fieldType: { ... }` or `fieldType: "date"` causes the platform to silently ignore the field type, producing null constraint errors on save.
97
+
98
+ > **No `defaultValue` on entity fields:** `defaultValue` is a *settings* key, not a column key — on a field it fails schema validation. Set a column default with a `formula`, a `numberSequence`, or DSL logic (see "Default values" above).
99
+
100
+ ### Wrong `dbDatatype` values
101
+
102
+ These are SQL type names LLMs tend to use for `dbDatatype`. **They are all wrong.** The right values come from the tables above.
103
+
104
+ | Wrong `dbDatatype` | Right `dbDatatype` | Used with `fieldTypeCd` |
105
+ |---|---|---|
106
+ | `datetime` | `timestamptz` | `datetime` |
107
+ | `timestamp` | `timestamptz` | `datetime` |
108
+ | `boolean` | `bool` | `checkbox` |
109
+ | `string` | `varchar` (with `maxLen`) or `text` | `text`, `textarea`, `dropdown`, … |
110
+ | `integer` | `int` or `bigint` | `number` |
111
+ | `float`, `double`, `decimal` | `numeric` | `number`, `currency`, `percent` |
112
+ | `number` | `int`, `bigint`, or `numeric` | `number`, `currency`, `percent` |
113
+
114
+ ### Wrong `fieldTypeCd` values
115
+
116
+ These are the field type names LLMs tend to invent. **They are all wrong.**
117
+
118
+ | Wrong | Right |
119
+ |---|---|
120
+ | key `fieldType: { fieldTypeCd: "date", ... }` | key `fieldTypeCd: "date"` (plain string) |
121
+ | key `fieldType: "date"` | key `fieldTypeCd: "date"` |
122
+ | `bool`, `boolean` | `checkbox` |
123
+ | `integer` | `number` |
124
+ | `float` | `number` |
125
+ | `decimal` | `number` with `scale` param |
126
+ | `datePicker` | `date` |
127
+ | `timestamp` | `datetime` |
128
+ | `money` | `currency` |
129
+ | `select`, `enum` | `dropdown` |
130
+ | `multiselect` | `flags` or `tags` |
131
+ | `autocomplete` | `lookup` |
132
+ | `reference` | `lookup` |
133
+ | `relation` | `lookup` or `grid` |
134
+ | `link` | `url` |
135
+ | `picture`, `photo` | `image` |
136
+ | `attachment` | `file` |
137
+ | `multiline` | `textarea` |
138
+ | `richText`, `markdown` | `richtext` |
139
+ | `userPicker` | `user` |
140
+ | `phoneNumber` | `phone` |
141
+
142
+ ## When in doubt
143
+
144
+ If the user describes a field type that isn't in this list (e.g. "rating stars", "geo location", "signature pad"), those field types **do not currently exist**. Do not fabricate a `fieldTypeCd` value. Tell the user what's available and ask how they'd like to model it with existing types (e.g. rating as `number` with `min: 1, max: 5`, geo location as two `number` columns or a `json` column).