@dforge-core/dforge-mcp 0.1.0-rc.1
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/README.md +119 -0
- package/dist/server.js +21626 -0
- package/package.json +39 -0
- package/resources/docs/conventions.md +939 -0
- package/resources/schemas/data-view.schema.json +299 -0
- package/resources/schemas/entity.schema.json +444 -0
- package/resources/schemas/manifest.schema.json +100 -0
- package/skills/dforge-mcp-author/SKILL.md +107 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://dforge.dev/schemas/entity.schema.json",
|
|
4
|
+
"title": "dForge Entity Definition",
|
|
5
|
+
"description": "Defines an entity (table/view mapping) for a dForge module",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["fields"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"extends": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"pattern": "^[a-z][a-z0-9_]*\\.[a-z][a-z0-9_]*$",
|
|
12
|
+
"description": "Qualified entity code of the target entity to extend (e.g. 'fin.invoice'). When set, this entity definition adds columns to an existing entity owned by another module instead of creating a new entity. Physical columns are stored in a 1:1 extension table."
|
|
13
|
+
},
|
|
14
|
+
"description": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Human-readable description of the entity"
|
|
17
|
+
},
|
|
18
|
+
"schema": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Database schema name override (defaults to module schema)"
|
|
21
|
+
},
|
|
22
|
+
"dbObject": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Database table or view name (defaults to entity code)"
|
|
25
|
+
},
|
|
26
|
+
"isView": {
|
|
27
|
+
"type": "boolean",
|
|
28
|
+
"description": "When true, entity maps to a SQL view (read-only, no DDL generation). Default: false (table-backed).",
|
|
29
|
+
"default": false
|
|
30
|
+
},
|
|
31
|
+
"viewSql": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "SQL SELECT statement for view-backed entities (isView=true). Executed as CREATE OR REPLACE VIEW during module install."
|
|
34
|
+
},
|
|
35
|
+
"toString": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "Display pattern using column placeholders, e.g. \"{first_name} {last_name}\""
|
|
38
|
+
},
|
|
39
|
+
"traits": {
|
|
40
|
+
"type": "array",
|
|
41
|
+
"description": "Entity traits expanded during module install (authoring shortcut). Trait definitions loaded from DB (seeded by metadata module).",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"enum": ["identity", "audit", "audit-full", "soft-delete", "sorting", "postable", "accumulation", "ledger", "period", "file-library"]
|
|
45
|
+
},
|
|
46
|
+
"uniqueItems": true
|
|
47
|
+
},
|
|
48
|
+
"fields": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"description": "Column definitions keyed by column code",
|
|
51
|
+
"additionalProperties": {
|
|
52
|
+
"$ref": "#/$defs/field"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"constraints": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"description": "Database constraints (unique, check, etc.)"
|
|
58
|
+
},
|
|
59
|
+
"references": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"description": "Foreign key reference definitions (legacy format, prefer 'link' on field)",
|
|
62
|
+
"additionalProperties": {
|
|
63
|
+
"$ref": "#/$defs/entityReference"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"indexes": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"description": "Database index definitions"
|
|
69
|
+
},
|
|
70
|
+
"numberSequence": {
|
|
71
|
+
"$ref": "#/$defs/numberSequence",
|
|
72
|
+
"description": "Automatic document numbering configuration for this entity"
|
|
73
|
+
},
|
|
74
|
+
"period": {
|
|
75
|
+
"$ref": "#/$defs/periodConfig",
|
|
76
|
+
"description": "Period entity configuration. Requires 'period' trait."
|
|
77
|
+
},
|
|
78
|
+
"accumulation": {
|
|
79
|
+
"$ref": "#/$defs/accumulationConfig",
|
|
80
|
+
"description": "Accumulation registry configuration (simple document without lines). Requires 'accumulation' trait."
|
|
81
|
+
},
|
|
82
|
+
"params": {
|
|
83
|
+
"type": "object",
|
|
84
|
+
"description": "Entity-level parameters for platform behavior flags",
|
|
85
|
+
"properties": {
|
|
86
|
+
"restricted": {
|
|
87
|
+
"type": "boolean",
|
|
88
|
+
"description": "When true, blocks generic data.get/data.set access. Entity must be accessed via dedicated API methods.",
|
|
89
|
+
"default": false
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"additionalProperties": true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"additionalProperties": false,
|
|
96
|
+
"$defs": {
|
|
97
|
+
"field": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"description": "Entity column/field definition",
|
|
100
|
+
"properties": {
|
|
101
|
+
"dbDatatype": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"description": "PostgreSQL data type (e.g. uuid, varchar, int4, bool, text, json, numeric, date, timestamp, timestamptz, bpchar)"
|
|
104
|
+
},
|
|
105
|
+
"baseDatatypeCd": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"enum": ["binary", "bool", "cuid", "culture", "date", "guid", "link", "number", "project", "string", "time", "timestamp", "xml", "json"],
|
|
108
|
+
"description": "Base data type code from field_type table (e.g. string, number, boolean, date, time, timestamp, json, binary)"
|
|
109
|
+
},
|
|
110
|
+
"columnType": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"enum": ["D", "R", "S", "F", "A", "L", "G"],
|
|
113
|
+
"description": "Column type: D=Data (physical column), R=Reference (N:1 lookup), S=Set (1:N collection), F=Formula (virtual calculated), G=Generated/Computed (physical, auto-maintained), A=Accumulation registry, L=Ledger registry"
|
|
114
|
+
},
|
|
115
|
+
"fieldTypeCd": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"enum": [
|
|
118
|
+
"text", "email", "phone", "url", "textarea", "number", "currency", "percent",
|
|
119
|
+
"checkbox", "date", "datetime", "time",
|
|
120
|
+
"dropdown", "flags", "tags", "json", "hidden", "color", "image", "file",
|
|
121
|
+
"richtext", "lookup", "user", "grid", "entitylink", "code"
|
|
122
|
+
],
|
|
123
|
+
"description": "UI field type code from field_type table"
|
|
124
|
+
},
|
|
125
|
+
"flags": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"pattern": "^[VIEMH]*$",
|
|
128
|
+
"description": "Display flags: V=Visible, I=Identity, E=Editable, M=Mandatory, H=Hidden"
|
|
129
|
+
},
|
|
130
|
+
"isPk": {
|
|
131
|
+
"type": "boolean",
|
|
132
|
+
"description": "Whether this column is part of the primary key"
|
|
133
|
+
},
|
|
134
|
+
"isNullable": {
|
|
135
|
+
"type": "boolean",
|
|
136
|
+
"description": "Whether the column allows NULL values"
|
|
137
|
+
},
|
|
138
|
+
"isIdentity": {
|
|
139
|
+
"type": "boolean",
|
|
140
|
+
"description": "Whether the column value is auto-generated (e.g. CUID primary key). Identity columns are not editable and excluded from required validation."
|
|
141
|
+
},
|
|
142
|
+
"formula": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"description": "Formula expression (for columnType 'F' or default values)"
|
|
145
|
+
},
|
|
146
|
+
"orderNum": {
|
|
147
|
+
"type": "integer",
|
|
148
|
+
"description": "Display order number"
|
|
149
|
+
},
|
|
150
|
+
"description": {
|
|
151
|
+
"type": "string",
|
|
152
|
+
"description": "Human-readable column description"
|
|
153
|
+
},
|
|
154
|
+
"maxLen": {
|
|
155
|
+
"type": "integer",
|
|
156
|
+
"description": "Maximum length for varchar/text columns"
|
|
157
|
+
},
|
|
158
|
+
"precision": {
|
|
159
|
+
"type": "integer",
|
|
160
|
+
"description": "Numeric precision for decimal/currency columns"
|
|
161
|
+
},
|
|
162
|
+
"editMask": {
|
|
163
|
+
"type": "string",
|
|
164
|
+
"description": "Input mask pattern for editing"
|
|
165
|
+
},
|
|
166
|
+
"displayFmt": {
|
|
167
|
+
"type": "string",
|
|
168
|
+
"description": "Display format pattern"
|
|
169
|
+
},
|
|
170
|
+
"params": {
|
|
171
|
+
"type": "object",
|
|
172
|
+
"description": "Field-type-specific configuration (e.g. dropdown options, currency settings)",
|
|
173
|
+
"properties": {
|
|
174
|
+
"options": {
|
|
175
|
+
"type": "array",
|
|
176
|
+
"items": {
|
|
177
|
+
"oneOf": [
|
|
178
|
+
{ "type": "string" },
|
|
179
|
+
{
|
|
180
|
+
"type": "object",
|
|
181
|
+
"required": ["value", "label"],
|
|
182
|
+
"properties": {
|
|
183
|
+
"value": { "type": "string" },
|
|
184
|
+
"label": { "type": "string" },
|
|
185
|
+
"icon": { "type": "string" },
|
|
186
|
+
"color": { "type": "string" }
|
|
187
|
+
},
|
|
188
|
+
"additionalProperties": false
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
"description": "Options for dropdown/flags field types"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"link": {
|
|
197
|
+
"$ref": "#/$defs/fieldLink",
|
|
198
|
+
"description": "Relationship link for Reference (R) and Set (S) columns"
|
|
199
|
+
},
|
|
200
|
+
"refFilter": {
|
|
201
|
+
"description": "Filter criteria for reference lookups"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"oneOf": [
|
|
205
|
+
{
|
|
206
|
+
"title": "Data column",
|
|
207
|
+
"description": "Physical DB column (columnType 'D' or unspecified). Requires 'dbDatatype'. Must NOT have 'link'.",
|
|
208
|
+
"required": ["dbDatatype"],
|
|
209
|
+
"properties": {
|
|
210
|
+
"columnType": { "enum": ["D"] },
|
|
211
|
+
"link": false
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"title": "Inferred-type column",
|
|
216
|
+
"description": "Physical column where dbDatatype is inferred from fieldTypeCd (e.g. user, color)",
|
|
217
|
+
"required": ["fieldTypeCd"],
|
|
218
|
+
"properties": {
|
|
219
|
+
"columnType": { "enum": ["D"] },
|
|
220
|
+
"link": false,
|
|
221
|
+
"dbDatatype": false
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"title": "Reference column (R)",
|
|
226
|
+
"description": "N:1 lookup (columnType 'R'). Requires 'link' and 'fieldTypeCd'. Must NOT have 'dbDatatype'.",
|
|
227
|
+
"required": ["columnType", "fieldTypeCd", "link"],
|
|
228
|
+
"properties": {
|
|
229
|
+
"columnType": { "const": "R" },
|
|
230
|
+
"dbDatatype": false
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"title": "Set column (S)",
|
|
235
|
+
"description": "1:N collection (columnType 'S'). Requires 'link' and 'fieldTypeCd'. Must NOT have 'dbDatatype'.",
|
|
236
|
+
"required": ["columnType", "fieldTypeCd", "link"],
|
|
237
|
+
"properties": {
|
|
238
|
+
"columnType": { "const": "S" },
|
|
239
|
+
"dbDatatype": false
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"title": "Formula column (F)",
|
|
244
|
+
"description": "Calculated virtual column (columnType 'F'). Requires 'formula'. Must NOT have 'link' or 'dbDatatype'.",
|
|
245
|
+
"required": ["columnType", "formula", "baseDatatypeCd"],
|
|
246
|
+
"properties": {
|
|
247
|
+
"columnType": { "const": "F" },
|
|
248
|
+
"link": false,
|
|
249
|
+
"baseDatatypeCd": true,
|
|
250
|
+
"dbDatatype": false
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"title": "Accumulation registry column (A)",
|
|
255
|
+
"description": "Accumulation registry state (bool) + config. Physical column storing posted state. Config in params defines balance entity, dimensions, resources.",
|
|
256
|
+
"required": ["columnType", "dbDatatype", "params"],
|
|
257
|
+
"properties": {
|
|
258
|
+
"columnType": { "const": "A" },
|
|
259
|
+
"dbDatatype": { "const": "bool" },
|
|
260
|
+
"link": false
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"title": "Ledger registry column (L)",
|
|
265
|
+
"description": "Ledger registry state (bool) + config. Physical column storing posted state. Config in params defines lines, movement entity, balance entity.",
|
|
266
|
+
"required": ["columnType", "dbDatatype", "params"],
|
|
267
|
+
"properties": {
|
|
268
|
+
"columnType": { "const": "L" },
|
|
269
|
+
"dbDatatype": { "const": "bool" },
|
|
270
|
+
"link": false
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"title": "Generated/Computed column (G)",
|
|
275
|
+
"description": "Physical column auto-computed by DB trigger (aggregate over child set) or PostgreSQL GENERATED ALWAYS AS (same-row expression). Requires 'dbDatatype' and 'formula'. Formula syntax: SUM([setCol].[childField]) for aggregates, or plain SQL expression for same-row generated columns.",
|
|
276
|
+
"required": ["columnType", "dbDatatype", "formula"],
|
|
277
|
+
"properties": {
|
|
278
|
+
"columnType": { "const": "G" },
|
|
279
|
+
"link": false
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
],
|
|
283
|
+
"required": ["orderNum", "description"],
|
|
284
|
+
"additionalProperties": false
|
|
285
|
+
},
|
|
286
|
+
"fieldLink": {
|
|
287
|
+
"type": "object",
|
|
288
|
+
"description": "Relationship definition for Reference and Set columns",
|
|
289
|
+
"required": ["entity", "thisKey", "otherKey"],
|
|
290
|
+
"properties": {
|
|
291
|
+
"entity": {
|
|
292
|
+
"type": "string",
|
|
293
|
+
"description": "Target entity code (the entity being referenced or collected)"
|
|
294
|
+
},
|
|
295
|
+
"thisKey": {
|
|
296
|
+
"type": "string",
|
|
297
|
+
"description": "Column(s) in this entity (comma-separated for compound keys)"
|
|
298
|
+
},
|
|
299
|
+
"otherKey": {
|
|
300
|
+
"type": "string",
|
|
301
|
+
"description": "Column(s) in the target entity (comma-separated for compound keys)"
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
"additionalProperties": false
|
|
305
|
+
},
|
|
306
|
+
"numberSequence": {
|
|
307
|
+
"type": "object",
|
|
308
|
+
"description": "Automatic document numbering. Auto-generates a formatted number on INSERT when the target column is empty.",
|
|
309
|
+
"required": ["column", "defaultPrefix"],
|
|
310
|
+
"properties": {
|
|
311
|
+
"column": {
|
|
312
|
+
"type": "string",
|
|
313
|
+
"description": "Column code that receives the auto-generated number"
|
|
314
|
+
},
|
|
315
|
+
"prefixSettingCd": {
|
|
316
|
+
"type": "string",
|
|
317
|
+
"description": "Module setting code to resolve the prefix from (folder-scoped inheritance)"
|
|
318
|
+
},
|
|
319
|
+
"defaultPrefix": {
|
|
320
|
+
"type": "string",
|
|
321
|
+
"description": "Fallback prefix when no setting is configured"
|
|
322
|
+
},
|
|
323
|
+
"pattern": {
|
|
324
|
+
"type": "string",
|
|
325
|
+
"description": "Number format pattern. Placeholders: {prefix}, {yyyy}, {yy}, {mm}, {dd}, {seq:N}",
|
|
326
|
+
"default": "{prefix}{yyyy}-{seq:3}"
|
|
327
|
+
},
|
|
328
|
+
"resetPeriod": {
|
|
329
|
+
"type": "string",
|
|
330
|
+
"enum": ["year", "month", "day", "never"],
|
|
331
|
+
"description": "Counter reset period",
|
|
332
|
+
"default": "year"
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
"additionalProperties": false
|
|
336
|
+
},
|
|
337
|
+
"periodConfig": {
|
|
338
|
+
"type": "object",
|
|
339
|
+
"description": "Configuration for entities with the 'period' trait. Defines how date values map to period keys.",
|
|
340
|
+
"required": ["keyFormat"],
|
|
341
|
+
"properties": {
|
|
342
|
+
"keyFormat": {
|
|
343
|
+
"type": "string",
|
|
344
|
+
"description": "Format string for deriving period key from a date. Placeholders: {yyyy}, {yy}, {MM}, {dd}, {q} (quarter 1-4).",
|
|
345
|
+
"examples": ["{yyyy}-{MM}", "{yyyy}-Q{q}", "FY{yyyy}"]
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
"additionalProperties": false
|
|
349
|
+
},
|
|
350
|
+
"accumulationConfig": {
|
|
351
|
+
"type": "object",
|
|
352
|
+
"description": "Configuration for simple accumulation (document without lines, e.g. receipt → stock).",
|
|
353
|
+
"required": ["balanceEntity", "dimensions", "resources"],
|
|
354
|
+
"properties": {
|
|
355
|
+
"balanceEntity": { "type": "string", "description": "Balance entity code (e.g. 'stock')" },
|
|
356
|
+
"dimensions": {
|
|
357
|
+
"description": "Balance row lookup dimensions. Array of field names (same name on both entities) or object mapping balance_field → document_field.",
|
|
358
|
+
"oneOf": [
|
|
359
|
+
{ "type": "array", "items": { "type": "string" } },
|
|
360
|
+
{ "type": "object", "additionalProperties": { "type": "string" } }
|
|
361
|
+
]
|
|
362
|
+
},
|
|
363
|
+
"resources": {
|
|
364
|
+
"type": "object",
|
|
365
|
+
"description": "Document field → balance field resource mappings",
|
|
366
|
+
"additionalProperties": {
|
|
367
|
+
"type": "object",
|
|
368
|
+
"required": ["balanceField"],
|
|
369
|
+
"properties": {
|
|
370
|
+
"balanceField": { "type": "string" }
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
"direction": { "type": "string", "enum": ["increase", "decrease"], "description": "Fixed direction for all postings" },
|
|
375
|
+
"sign": { "$ref": "#/$defs/signConfig", "description": "Dynamic sign based on a field value (alternative to direction)" },
|
|
376
|
+
"autoCreateBalance": { "type": "boolean", "default": true },
|
|
377
|
+
"allowNegative": { "type": "boolean", "default": true },
|
|
378
|
+
"lockedFields": { "type": "array", "items": { "type": "string" }, "description": "Document fields locked when posted" }
|
|
379
|
+
},
|
|
380
|
+
"additionalProperties": false
|
|
381
|
+
},
|
|
382
|
+
"signConfig": {
|
|
383
|
+
"type": "object",
|
|
384
|
+
"description": "Dynamic sign determination based on a field value",
|
|
385
|
+
"required": ["field", "positive", "negative"],
|
|
386
|
+
"properties": {
|
|
387
|
+
"field": { "type": "string", "description": "Field code that determines direction" },
|
|
388
|
+
"positive": { "type": "array", "items": { "type": "string" }, "description": "Values that mean increase" },
|
|
389
|
+
"negative": { "type": "array", "items": { "type": "string" }, "description": "Values that mean decrease" }
|
|
390
|
+
},
|
|
391
|
+
"additionalProperties": false
|
|
392
|
+
},
|
|
393
|
+
"ledgerRegistryEntry": {
|
|
394
|
+
"type": "object",
|
|
395
|
+
"description": "Single registry target within an L-column's registries array",
|
|
396
|
+
"required": ["movementEntity", "movementMapping", "balanceEntity", "balanceMapping"],
|
|
397
|
+
"properties": {
|
|
398
|
+
"movementEntity": { "type": "string", "description": "Movement entity code (e.g. 'posting_record')" },
|
|
399
|
+
"movementMapping": {
|
|
400
|
+
"type": "object",
|
|
401
|
+
"description": "Line field → movement field mapping",
|
|
402
|
+
"additionalProperties": { "type": "string" }
|
|
403
|
+
},
|
|
404
|
+
"balanceEntity": { "type": "string", "description": "Balance entity code (e.g. 'balance_register')" },
|
|
405
|
+
"balanceMapping": {
|
|
406
|
+
"type": "object",
|
|
407
|
+
"required": ["dimensions", "debitResource", "creditResource"],
|
|
408
|
+
"properties": {
|
|
409
|
+
"dimensions": { "type": "array", "items": { "type": "string" }, "description": "Balance row dimension columns" },
|
|
410
|
+
"debitResource": { "type": "string", "description": "Balance column for debit turnover" },
|
|
411
|
+
"creditResource": { "type": "string", "description": "Balance column for credit turnover" }
|
|
412
|
+
},
|
|
413
|
+
"additionalProperties": false
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
"additionalProperties": false
|
|
417
|
+
},
|
|
418
|
+
"entityReference": {
|
|
419
|
+
"type": "object",
|
|
420
|
+
"description": "Foreign key reference definition (legacy format)",
|
|
421
|
+
"required": ["from", "to"],
|
|
422
|
+
"properties": {
|
|
423
|
+
"from": {
|
|
424
|
+
"type": "object",
|
|
425
|
+
"required": ["field"],
|
|
426
|
+
"properties": {
|
|
427
|
+
"field": { "type": "string" }
|
|
428
|
+
},
|
|
429
|
+
"additionalProperties": false
|
|
430
|
+
},
|
|
431
|
+
"to": {
|
|
432
|
+
"type": "object",
|
|
433
|
+
"required": ["entity", "field"],
|
|
434
|
+
"properties": {
|
|
435
|
+
"entity": { "type": "string" },
|
|
436
|
+
"field": { "type": "string" }
|
|
437
|
+
},
|
|
438
|
+
"additionalProperties": false
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
"additionalProperties": false
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://dforge.dev/schemas/manifest.schema.json",
|
|
4
|
+
"title": "dForge Module Manifest",
|
|
5
|
+
"description": "Module package manifest defining metadata, dependencies, and entity references",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["packageFormat", "moduleId", "code", "version", "dbSchemaVersion", "displayName"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"packageFormat": {
|
|
10
|
+
"type": "integer",
|
|
11
|
+
"minimum": 1,
|
|
12
|
+
"description": "Package format version (currently 1)"
|
|
13
|
+
},
|
|
14
|
+
"moduleId": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
|
|
17
|
+
"description": "Globally unique module UUID"
|
|
18
|
+
},
|
|
19
|
+
"code": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"pattern": "^[a-z][a-z0-9_-]*$",
|
|
22
|
+
"description": "Human-readable module code (becomes schema name and module_cd in DB)"
|
|
23
|
+
},
|
|
24
|
+
"version": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+",
|
|
27
|
+
"description": "Module version (semver)"
|
|
28
|
+
},
|
|
29
|
+
"dbSchemaVersion": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+",
|
|
32
|
+
"description": "Database schema version (semver)"
|
|
33
|
+
},
|
|
34
|
+
"displayName": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"description": "Human-readable module name"
|
|
37
|
+
},
|
|
38
|
+
"description": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "Module description"
|
|
41
|
+
},
|
|
42
|
+
"schemaName": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"description": "Database schema name override (defaults to module code, system modules use 'dForge')"
|
|
45
|
+
},
|
|
46
|
+
"system": {
|
|
47
|
+
"type": "boolean",
|
|
48
|
+
"description": "System module flag (cannot be uninstalled, admin-only). Omit for regular modules."
|
|
49
|
+
},
|
|
50
|
+
"author": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {
|
|
53
|
+
"name": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"description": "Author name"
|
|
56
|
+
},
|
|
57
|
+
"url": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"description": "Author URL"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"required": ["name"],
|
|
63
|
+
"additionalProperties": false
|
|
64
|
+
},
|
|
65
|
+
"license": {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"description": "License identifier (e.g. 'proprietary', 'MIT')"
|
|
68
|
+
},
|
|
69
|
+
"dependencies": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"description": "Module dependencies: module code → semver range",
|
|
72
|
+
"additionalProperties": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"description": "Semver version range (e.g. '>=1.0.0')"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"entities": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"description": "Entity definitions and extensions: entity code → relative path to entity JSON file. Dotted keys (e.g. 'fin.invoice') indicate extensions of other modules' entities (the entity file must have an 'extends' property).",
|
|
80
|
+
"additionalProperties": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"pattern": "^(\\./)?entities/.+\\.json$"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"category": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"description": "Module category for display (e.g. 'Integration', 'Finance')"
|
|
88
|
+
},
|
|
89
|
+
"icon": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"description": "Bootstrap icon class (e.g. 'bi-link-45deg')"
|
|
92
|
+
},
|
|
93
|
+
"supportedLocales": {
|
|
94
|
+
"type": "array",
|
|
95
|
+
"items": { "type": "string", "pattern": "^[a-z]{2,3}(-[A-Z]{2})?$" },
|
|
96
|
+
"description": "Non-English locales the package promises to translate. Each entry MUST match a translations/<locale>.json file, and every translatable resource (entity/field labels, folders, views, menus + items, actions + params, reports + datasets + params, settings) MUST have a label in that file. English is the default — don't list 'en' or 'en-US'."
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"additionalProperties": false
|
|
100
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dforge-mcp-author
|
|
3
|
+
description: Author dForge modules using the dforge-mcp tool surface. Use when the user has the @dforge-core/dforge-mcp MCP server connected and asks to scaffold, extend, pack, or install a dForge module. Replaces hand-writing JSON files with structured tool calls that produce schema-valid output on the first try.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dForge Module Author (MCP-driven)
|
|
7
|
+
|
|
8
|
+
You're authoring a dForge module via the `dforge-mcp` MCP server. dForge is a metadata-driven, multi-tenant business platform — modules are JSON metadata + DSL scripts.
|
|
9
|
+
|
|
10
|
+
**Your edge here** is that you have *tools*, not just text generation. Always prefer a tool call over writing a file by hand. Every tool either returns a file map (so the user can preview before commit) or shells out to the validated native CLI.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Tool surface
|
|
15
|
+
|
|
16
|
+
| Tool | What it does | Returns |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| `dforge_module_create` | Build a brand-new module's file map | `{ files: {...} }` — client writes |
|
|
19
|
+
| `dforge_entity_add` | Add an entity to an existing module | `{ files: {...}, warning?: ... }` — client writes |
|
|
20
|
+
| `dforge_module_pack` | Pack a module dir into a `.dforge` tarball | `{ tarballPath, sizeBytes }` (writes the tarball) |
|
|
21
|
+
| `dforge_module_install` | Install a module to a tenant | `{ ok, output }` (live action) |
|
|
22
|
+
| `dforge_dbml_import` | Generate from DBML (stub) | not yet implemented |
|
|
23
|
+
|
|
24
|
+
## Resources
|
|
25
|
+
|
|
26
|
+
Read these *before* generating any module content so your output matches the canonical schema:
|
|
27
|
+
|
|
28
|
+
- `dforge://schema/manifest` — manifest.json shape (required fields, patterns)
|
|
29
|
+
- `dforge://schema/entity` — entity JSON shape (fields, traits, refs)
|
|
30
|
+
- `dforge://schema/data-view` — data view shape (viewType, dataSources)
|
|
31
|
+
- `dforge://docs/conventions` — naming, FK+Reference pattern, traits, security model
|
|
32
|
+
|
|
33
|
+
Load them when you start a session, not after a wrong guess.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Standard workflow
|
|
38
|
+
|
|
39
|
+
### 1. Gather requirements (one short turn)
|
|
40
|
+
|
|
41
|
+
Ask the user, in order:
|
|
42
|
+
1. **What's the module for?** One sentence is enough.
|
|
43
|
+
2. **What's the module code?** Lowercase, hyphen-or-underscore, e.g. `crm`, `pm`, `hr-admin`.
|
|
44
|
+
3. **What entities does it own?** Rough list with one-line descriptions each.
|
|
45
|
+
4. **Greenfield or extending an existing module?** If extending, ask which.
|
|
46
|
+
|
|
47
|
+
Don't ask about field types, view layouts, or DSL actions yet — those come *after* a working skeleton.
|
|
48
|
+
|
|
49
|
+
### 2. Read the schemas + conventions
|
|
50
|
+
|
|
51
|
+
Pull `dforge://schema/manifest`, `dforge://schema/entity`, and `dforge://docs/conventions` into context. Skim, don't memorise.
|
|
52
|
+
|
|
53
|
+
### 3. Call `dforge_module_create`
|
|
54
|
+
|
|
55
|
+
Pass:
|
|
56
|
+
- `code`, `displayName`, `description` from the user's answers
|
|
57
|
+
- `entities`: array of `{ name, label, traits }` — default traits to `"identity+audit"`
|
|
58
|
+
- `preset`: `"minimal"` unless the user wants full template (settings/translations/seed)
|
|
59
|
+
- `dependencies`: usually `["admin", "metadata"]` — both are required for typical modules
|
|
60
|
+
|
|
61
|
+
You'll get back `{ summary, files: { "<relPath>": "<contents>", ... } }`.
|
|
62
|
+
|
|
63
|
+
### 4. Preview the file map with the user
|
|
64
|
+
|
|
65
|
+
Show the file list (paths only) + the manifest contents. Ask "write these to `./<code>`?". Don't write without confirmation.
|
|
66
|
+
|
|
67
|
+
### 5. Write the files
|
|
68
|
+
|
|
69
|
+
Use your filesystem tool (Write / bash heredoc / fs.writeFileSync, whatever your client offers). Each value in `files` is the literal file contents — including JSON indentation. Don't re-format.
|
|
70
|
+
|
|
71
|
+
### 6. Iterate
|
|
72
|
+
|
|
73
|
+
Use `dforge_entity_add` to add more entities incrementally — it reads the existing manifest, regenerates the dependent UI/security files, and returns ONLY the files that change. Re-preview each time before writing.
|
|
74
|
+
|
|
75
|
+
For fields, ref columns, actions, formulas, settings, reports — write those directly into the entity JSON / new files under `logic/`, `ui/`, etc. The schemas are your guide; the tools don't (yet) cover field-level changes.
|
|
76
|
+
|
|
77
|
+
### 7. Pack + install
|
|
78
|
+
|
|
79
|
+
Once the module is shaped right:
|
|
80
|
+
1. `dforge_module_pack` with `moduleDir: "./<code>"` → returns the tarball path.
|
|
81
|
+
2. (Optional) `dforge_module_install` with `pathOrTarball: <tarballPath or moduleDir>` and a `tenantUrl` + `token` (or rely on `DFORGE_URL`/`DFORGE_TOKEN` env). This runs the *full* server-side validator — the only validator available. Surface its output verbatim; if it fails, fix and re-pack.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Hard rules
|
|
86
|
+
|
|
87
|
+
- **Always preview file maps before writing.** Tools return — the user decides.
|
|
88
|
+
- **Use `dforge_entity_add`, not regenerate-from-scratch.** It preserves the existing manifest's UUID, version, dependencies, etc.
|
|
89
|
+
- **Tabs in JSON.** All emitted files use `\t` indentation. Don't re-pretty-print with spaces.
|
|
90
|
+
- **Don't invent `code` or `moduleId`.** `code` comes from the user; `moduleId` is auto-generated by the tool (UUID). Never hand-write a UUID.
|
|
91
|
+
- **Refer to the conventions doc for FK+Reference, traits, flags.** The MCP server doesn't enforce these — your output does. The first install will catch violations, but a clean first install is the goal.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## When NOT to use the tools
|
|
96
|
+
|
|
97
|
+
- **Modifying a single existing field in an entity JSON.** Just edit the file.
|
|
98
|
+
- **Writing an action DSL script.** No tool for that — write to `logic/actions/<name>.dsl` directly. Reference the `dforge://docs/conventions` doc for DSL syntax.
|
|
99
|
+
- **Querying live tenant state.** No tool for that either — shell out to `dforge-cli` via your bash tool if the user has it installed.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Sanity check before declaring done
|
|
104
|
+
|
|
105
|
+
- `dforge_module_pack` succeeded → archive size is non-trivial (>100 KB usually)
|
|
106
|
+
- `dforge_module_install --code <tenant>` exited 0 → server validated everything
|
|
107
|
+
- The user confirms the install log looks right (entities created, no warnings about missing translations / orphan rights)
|