@dforge-core/dforge-mcp 0.2.33 → 0.2.35
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/CHANGELOG.md +65 -1
- package/dist/server.js +219 -147
- package/package.json +3 -3
- package/resources/docs/conventions.md +20 -0
- package/resources/docs/dsl-reference.md +7 -3
- package/resources/schemas/deps.schema.json +7 -2
- package/resources/schemas/domains.schema.json +1 -1
- package/resources/schemas/entity.schema.json +29 -2
- package/resources/schemas/registers.schema.json +429 -0
- package/resources/schemas/reports.schema.json +69 -4
- package/resources/schemas/seed-data.schema.json +12 -1
- package/resources/schemas/settings.schema.json +24 -1
- package/resources/schemas/stored-procedures.schema.json +24 -1
- package/resources/schemas/traits.schema.json +26 -1
- package/resources/schemas/translations.schema.json +7 -0
- package/skills/dforge-mcp-author/references/action-dsl.md +1 -1
- package/skills/dforge-mcp-author/references/conventions.md +4 -3
- package/skills/dforge-mcp-author/references/flags.md +2 -2
- package/skills/dforge-mcp-author/references/manifest.md +21 -3
- package/skills/dforge-mcp-author/references/reports.md +10 -2
- package/skills/dforge-mcp-author/references/traits.md +2 -2
- package/skills/dforge-module-build/SKILL.md +4 -0
- package/skills/dforge-module-ship/SKILL.md +5 -0
|
@@ -12,9 +12,13 @@
|
|
|
12
12
|
"type": "object",
|
|
13
13
|
"required": ["description", "layout", "datasets"],
|
|
14
14
|
"properties": {
|
|
15
|
+
"label": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Report name: the page title, breadcrumb and parameter dialog. Recommended: without it the description is the name, and module pack, validate and install warn"
|
|
18
|
+
},
|
|
15
19
|
"description": {
|
|
16
20
|
"type": "string",
|
|
17
|
-
"description": "
|
|
21
|
+
"description": "What the report shows, under its name on the page. The name too when label is omitted"
|
|
18
22
|
},
|
|
19
23
|
"layout": {
|
|
20
24
|
"$ref": "#/$defs/layout"
|
|
@@ -242,8 +246,8 @@
|
|
|
242
246
|
},
|
|
243
247
|
"datasetType": {
|
|
244
248
|
"type": "string",
|
|
245
|
-
"enum": ["Q", "S"],
|
|
246
|
-
"description": "Q = SQL/entity query, S = stored procedure"
|
|
249
|
+
"enum": ["Q", "S", "R"],
|
|
250
|
+
"description": "Q = SQL/entity query, S = stored procedure, R = an accounting register read over an interval"
|
|
247
251
|
},
|
|
248
252
|
"query": {
|
|
249
253
|
"$ref": "#/$defs/query",
|
|
@@ -253,6 +257,10 @@
|
|
|
253
257
|
"type": "string",
|
|
254
258
|
"description": "Used when datasetType is 'S': the stored-procedure code, as `logic/stored_procedures.json` keys it — NOT the PostgreSQL function name and never schema-qualified. `module.spCd` binds a dependency's procedure. Resolved to `report_ds.sp_id` at install. A role granting `report:<code>` must also grant `sp:<spCd>`, which no admin UI can add afterwards."
|
|
255
259
|
},
|
|
260
|
+
"register": {
|
|
261
|
+
"$ref": "#/$defs/registerSource",
|
|
262
|
+
"description": "Used when datasetType is 'R'"
|
|
263
|
+
},
|
|
256
264
|
"columnsDef": {
|
|
257
265
|
"type": "object",
|
|
258
266
|
"description": "Optional column metadata overrides: field code → { label, visible, ... }",
|
|
@@ -294,6 +302,63 @@
|
|
|
294
302
|
"additionalProperties": false
|
|
295
303
|
},
|
|
296
304
|
|
|
305
|
+
"registerSource": {
|
|
306
|
+
"type": "object",
|
|
307
|
+
"description": "An accounting register read over an interval: one row per account of the register's chart, with opening_debit, opening_credit, turnover_debit, turnover_credit, closing_debit and closing_credit for one resource. Balances are netted per account — shown on the side they fall on. Whole periods are read from the register's totals cache, the part-periods at the edges from its postings. Needs Select on the register's posting entity and on the chart.",
|
|
308
|
+
"required": ["name", "resource", "interval"],
|
|
309
|
+
"properties": {
|
|
310
|
+
"name": {
|
|
311
|
+
"type": "string",
|
|
312
|
+
"pattern": "^[^.]+\\.[^.]+$",
|
|
313
|
+
"description": "The register, `module_cd.register_cd`. This module's own, or a declared dependency's. It must be an accounting register."
|
|
314
|
+
},
|
|
315
|
+
"resource": {
|
|
316
|
+
"type": "string",
|
|
317
|
+
"description": "The one resource the six balance columns are about."
|
|
318
|
+
},
|
|
319
|
+
"interval": {
|
|
320
|
+
"type": "object",
|
|
321
|
+
"description": "The days read between, both inclusive: two date params (`from` / `to` as `@param`), or the record of `entity` a key param finds (`key` as `@param`) with `from` / `to` naming its two date columns.",
|
|
322
|
+
"required": ["from", "to"],
|
|
323
|
+
"properties": {
|
|
324
|
+
"entity": { "type": "string", "description": "Entity holding the interval, e.g. an accounting period." },
|
|
325
|
+
"key": { "type": "string", "pattern": "^@.+", "description": "Param holding that entity's key." },
|
|
326
|
+
"from": { "type": "string", "description": "`@param`, or the entity's first-day column." },
|
|
327
|
+
"to": { "type": "string", "description": "`@param`, or the entity's last-day column." }
|
|
328
|
+
},
|
|
329
|
+
"additionalProperties": false
|
|
330
|
+
},
|
|
331
|
+
"columns": {
|
|
332
|
+
"type": "array",
|
|
333
|
+
"items": { "type": "string" },
|
|
334
|
+
"description": "Columns to show, in order: chart columns in nav notation, `<chart>.<column>` (e.g. 'account.account_code'), and any of the six balance columns, bare. Naming no balance column shows all six; a rollup always emits all six."
|
|
335
|
+
},
|
|
336
|
+
"filter": {
|
|
337
|
+
"$ref": "#/$defs/filter",
|
|
338
|
+
"description": "A filter over the chart, in the same nav notation; `@param` values allowed."
|
|
339
|
+
},
|
|
340
|
+
"sort": {
|
|
341
|
+
"type": "array",
|
|
342
|
+
"items": { "$ref": "#/$defs/sortClause" },
|
|
343
|
+
"description": "Chart columns to sort by, in nav notation. Ignored under a rollup, which sorts by its tree."
|
|
344
|
+
},
|
|
345
|
+
"rollup": {
|
|
346
|
+
"type": "object",
|
|
347
|
+
"description": "The query rollup without 'leafKey' and 'measures': the rows are accounts and the six balance columns are the measures.",
|
|
348
|
+
"required": ["tree", "treeKey", "parentField", "labels"],
|
|
349
|
+
"properties": {
|
|
350
|
+
"tree": { "type": "string" },
|
|
351
|
+
"treeKey": { "type": "string" },
|
|
352
|
+
"parentField": { "type": "string" },
|
|
353
|
+
"labels": { "type": "array", "minItems": 1, "items": { "type": "string" } },
|
|
354
|
+
"order": { "type": "string" }
|
|
355
|
+
},
|
|
356
|
+
"additionalProperties": false
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"additionalProperties": false
|
|
360
|
+
},
|
|
361
|
+
|
|
297
362
|
"rollup": {
|
|
298
363
|
"type": "object",
|
|
299
364
|
"description": "Hierarchy rollup: roll the flat leaf result up a self-referencing tree so parent rows carry the SUM of their descendants. Emits one row per tree node (leaf + ancestor), plus '_level' (depth from root) and '_isLeaf'. Measures must be additively-rollable (physical additive columns or LINEAR formulas of them, e.g. closing = opening + turnover); non-linear measures (ratios, products) are not valid and need a computed-row feature instead.",
|
|
@@ -354,7 +419,7 @@
|
|
|
354
419
|
},
|
|
355
420
|
"domain": {
|
|
356
421
|
"type": "string",
|
|
357
|
-
"description": "Column domain
|
|
422
|
+
"description": "Column domain the parameter borrows its control and option list from. A bare `domain_cd` means this module's own domain, then a tenant-created one, and never another module's, even one with the same code. `module_cd.domain_cd` names a domain of any installed module; declare that module as a dependency. The options and their translations stay on the domain, so a list shared with an entity column is authored once. The DSL equivalent for action params is `paramCd: domain <domainCd>`.",
|
|
358
423
|
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)?$"
|
|
359
424
|
},
|
|
360
425
|
"label": { "type": "string" },
|
|
@@ -12,11 +12,22 @@
|
|
|
12
12
|
},
|
|
13
13
|
"records": {
|
|
14
14
|
"type": "array",
|
|
15
|
-
"description": "Array of records, each record is an object with column_code → value",
|
|
15
|
+
"description": "Array of records, each record is an object with column_code → value. In demo-data/ a value may be a formula: { \"$f\": \"DATEADD(@yearStart, 42, 'DAY')\" }",
|
|
16
16
|
"items": {
|
|
17
17
|
"type": "object",
|
|
18
18
|
"additionalProperties": true
|
|
19
19
|
}
|
|
20
|
+
},
|
|
21
|
+
"repeat": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"description": "demo-data/ only: insert every record once per value of @var, from..to inclusive",
|
|
24
|
+
"required": ["to"],
|
|
25
|
+
"properties": {
|
|
26
|
+
"var": { "type": "string", "default": "i" },
|
|
27
|
+
"from": { "type": "integer", "default": 1 },
|
|
28
|
+
"to": { "type": "integer" }
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": false
|
|
20
31
|
}
|
|
21
32
|
},
|
|
22
33
|
"additionalProperties": false
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
"$defs": {
|
|
11
11
|
"setting": {
|
|
12
12
|
"type": "object",
|
|
13
|
-
"required": ["fieldTypeCd"],
|
|
14
13
|
"properties": {
|
|
15
14
|
"fieldTypeCd": {
|
|
16
15
|
"type": "string",
|
|
@@ -47,8 +46,32 @@
|
|
|
47
46
|
"params": {
|
|
48
47
|
"type": "object",
|
|
49
48
|
"description": "Field-type-specific parameters. Examples: dropdown → { options: [...] }; number → { min, max }; lookup → { link: { entity, otherKey } }."
|
|
49
|
+
},
|
|
50
|
+
"domain": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"description": "Reference to a reusable column domain. A bare 'domain_cd' means this module's own domain, then a tenant-created one, and never another module's, even one with the same code. 'module_cd.domain_cd' names a domain of any installed module; declare that module as a dependency. The domain supplies fieldTypeCd, baseDatatypeCd and params; declaring any of those alongside 'domain' is rejected at install. The setting keeps its own label, defaultValue, formula and required flag."
|
|
50
53
|
}
|
|
51
54
|
},
|
|
55
|
+
"oneOf": [
|
|
56
|
+
{
|
|
57
|
+
"title": "Domain-backed setting",
|
|
58
|
+
"description": "Setting whose control and option list come from a reusable column domain. Requires 'domain' and must NOT restate what the domain owns.",
|
|
59
|
+
"required": ["domain"],
|
|
60
|
+
"properties": {
|
|
61
|
+
"fieldTypeCd": false,
|
|
62
|
+
"baseDatatypeCd": false,
|
|
63
|
+
"params": false
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"title": "Inline setting",
|
|
68
|
+
"description": "Setting that declares its own control and parameters. Requires 'fieldTypeCd'.",
|
|
69
|
+
"required": ["fieldTypeCd"],
|
|
70
|
+
"properties": {
|
|
71
|
+
"domain": false
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
],
|
|
52
75
|
"additionalProperties": false
|
|
53
76
|
}
|
|
54
77
|
}
|
|
@@ -117,9 +117,32 @@
|
|
|
117
117
|
"type": "object",
|
|
118
118
|
"description": "Control parameters, the same shape an entity column's `params` takes — `options` for a dropdown or flags, `currency`, `align`, and so on.",
|
|
119
119
|
"additionalProperties": true
|
|
120
|
+
},
|
|
121
|
+
"domain": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"description": "Reference to a reusable column domain. Unqualified resolves within this module, then tenant-created domains; 'module_cd.domain_cd' binds to that module. The domain supplies the control, datatype and option list — and its options are translated once, for every consumer."
|
|
120
124
|
}
|
|
121
125
|
},
|
|
122
|
-
"additionalProperties": false
|
|
126
|
+
"additionalProperties": false,
|
|
127
|
+
"oneOf": [
|
|
128
|
+
{
|
|
129
|
+
"title": "Domain-backed result column",
|
|
130
|
+
"description": "Defers to a column domain. Must not restate what the domain owns.",
|
|
131
|
+
"required": ["domain"],
|
|
132
|
+
"properties": {
|
|
133
|
+
"fieldTypeCd": false,
|
|
134
|
+
"baseDatatypeCd": false,
|
|
135
|
+
"params": false
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"title": "Inline result column",
|
|
140
|
+
"description": "Declares its own control and datatype.",
|
|
141
|
+
"properties": {
|
|
142
|
+
"domain": false
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
]
|
|
123
146
|
}
|
|
124
147
|
}
|
|
125
148
|
}
|
|
@@ -79,9 +79,34 @@
|
|
|
79
79
|
"serverDefault": { "$ref": "#/$defs/serverDefault" }
|
|
80
80
|
},
|
|
81
81
|
"additionalProperties": true
|
|
82
|
+
},
|
|
83
|
+
"domain": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"description": "Reference to a reusable column domain. A bare 'domain_cd' resolves in the module of the entity taking the trait, then tenant-created domains, so one generic trait gives each module its own list; 'module_cd.domain_cd' pins one module's domain for every entity. A module's own traits.json must qualify a domain the module itself defines: written bare, it would bind to a same-named domain of whichever module takes the trait, and pack rejects it. The domain supplies the type, control, sizing and options."
|
|
82
86
|
}
|
|
83
87
|
},
|
|
84
|
-
"additionalProperties": false
|
|
88
|
+
"additionalProperties": false,
|
|
89
|
+
"oneOf": [
|
|
90
|
+
{
|
|
91
|
+
"title": "Domain-backed trait field",
|
|
92
|
+
"description": "Defers to a column domain. Must not restate what the domain owns, and takes no 'link' — it is a plain scalar column.",
|
|
93
|
+
"required": ["domain"],
|
|
94
|
+
"properties": {
|
|
95
|
+
"link": false,
|
|
96
|
+
"dbDatatype": false,
|
|
97
|
+
"fieldTypeCd": false,
|
|
98
|
+
"maxLen": false,
|
|
99
|
+
"params": false
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"title": "Inline trait field",
|
|
104
|
+
"description": "Declares its own type and control, as trait fields always have.",
|
|
105
|
+
"properties": {
|
|
106
|
+
"domain": false
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
]
|
|
85
110
|
},
|
|
86
111
|
"serverDefault": {
|
|
87
112
|
"type": "object",
|
|
@@ -58,6 +58,13 @@
|
|
|
58
58
|
"$ref": "#/$defs/labelOnly"
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
|
+
"registers": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"description": "Register code (as registers.json keys it) → label and description.",
|
|
64
|
+
"additionalProperties": {
|
|
65
|
+
"$ref": "#/$defs/labelDesc"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
61
68
|
"reports": {
|
|
62
69
|
"type": "object",
|
|
63
70
|
"description": "Report code → label, dataset captions and parameter labels.",
|
|
@@ -348,7 +348,7 @@ error('Insufficient stock. Available: {available}, requested: {requested}',
|
|
|
348
348
|
| Function | Returns | Description |
|
|
349
349
|
|---|---|---|
|
|
350
350
|
| `now()` | DateTime | Current date/time. Use for `date`, `datetime`, and `timestamp` fields. **Lowercase** — this is the execute-block date function. |
|
|
351
|
-
| `addDays(date, n)` |
|
|
351
|
+
| `addDays(date, n)` | Same as `date` | Add `n` days to a date field, a `Date` or an ISO string, e.g. `addDays([order_date], 3)`. Null stays null; anything else is an error. |
|
|
352
352
|
| `addMinutes(date, n)` | DateTime | Add `n` minutes, e.g. `addMinutes(now(), 15)`. |
|
|
353
353
|
| `addSeconds(date, n)` | DateTime | Add `n` seconds. |
|
|
354
354
|
| `currentUserId()` | Long | The acting user's tenant user ID. |
|
|
@@ -42,8 +42,7 @@ my_module/
|
|
|
42
42
|
│ ├── menus.json
|
|
43
43
|
│ ├── actions.json
|
|
44
44
|
│ ├── folders.json
|
|
45
|
-
│ └── reports
|
|
46
|
-
│ └── <report>.json
|
|
45
|
+
│ └── reports.json
|
|
47
46
|
├── security/
|
|
48
47
|
│ └── roles.json
|
|
49
48
|
├── settings.json
|
|
@@ -54,6 +53,7 @@ my_module/
|
|
|
54
53
|
│ └── de-DE.json # IETF tags, one file per non-English locale
|
|
55
54
|
├── print_templates/
|
|
56
55
|
│ └── <template>.scriban
|
|
56
|
+
├── migrations/ # upgrade data scripts, <version>.sql
|
|
57
57
|
├── files/ # static assets
|
|
58
58
|
└── webhooks.json # optional
|
|
59
59
|
```
|
|
@@ -144,7 +144,8 @@ Both use **semver** (`MAJOR.MINOR.PATCH`).
|
|
|
144
144
|
- If you added a new entity or column → bump both `version` and `dbSchemaVersion`.
|
|
145
145
|
- If you changed a view or menu → bump `version` only.
|
|
146
146
|
- If you changed translations only → bump `version` only.
|
|
147
|
-
- The installer uses `dbSchemaVersion` to decide whether to
|
|
147
|
+
- The installer uses `dbSchemaVersion` to decide whether to apply schema changes. Wrong version = skipped DDL.
|
|
148
|
+
- Data a new version reshapes (backfill, move rows, drop a table it no longer declares) goes in `migrations/<version>.sql`, named by `version`, run once on an upgrade from below it. See `manifest.md` § Upgrade migrations.
|
|
148
149
|
- **Never ship a package without bumping at least `version`** from the previous release. The installer may reject or silently skip a re-install with the same version.
|
|
149
150
|
- For brand-new modules, start at `version: "0.1.0"` and `dbSchemaVersion: "0.0.1"`.
|
|
150
151
|
|
|
@@ -118,12 +118,12 @@ These are **NOT** flag letters. They're separate properties on the column defini
|
|
|
118
118
|
| Need | How to declare | NOT this |
|
|
119
119
|
|---|---|---|
|
|
120
120
|
| Primary key | `"isPk": true` (or use `identity` trait) | NOT a `P` flag |
|
|
121
|
-
| Unique column |
|
|
121
|
+
| Unique column | A `unique` constraint in the entity's `constraints` block: `"ux_code": { "type": "unique", "fields": ["code"] }` | NOT a `U` flag, NOT an index |
|
|
122
122
|
| Searchable | Configure in data view columns or search settings | NOT an `S` flag |
|
|
123
123
|
|
|
124
124
|
## Mistakes to avoid
|
|
125
125
|
|
|
126
|
-
- Using `"U"` for unique — **not a valid flag**. Use `
|
|
126
|
+
- Using `"U"` for unique — **not a valid flag**. Use a `unique` constraint. There is no `isUnique` property, and an entry in `indexes` is never unique.
|
|
127
127
|
- Using `"S"` for searchable — **not a valid flag**.
|
|
128
128
|
- Using `"P"` for primary key — **not a valid flag**. Use `"isPk": true` or the `identity` trait.
|
|
129
129
|
- Declaring `M` **and** `"isNullable": true` on the same field — a contradiction that fails the pack.
|
|
@@ -111,7 +111,7 @@ Dependencies are a map of module codes to semver ranges. The installer checks th
|
|
|
111
111
|
|
|
112
112
|
**Declare a dependency only on a module you actually consume something from** — an entity you reference with a link column, extend, grant rights on, or read in a view, report, formula or action. Every entry you write here obliges you to write a matching `deps/<module>.json` contract (below), so a speculative dependency is not free.
|
|
113
113
|
|
|
114
|
-
**Do not depend on `admin`.** It — like `metadata` and `
|
|
114
|
+
**Do not depend on `admin`.** It — like `metadata`, `workspace` and `sys-billing` — is a system module, provisioned into every tenant before any other module installs. Depending on it buys nothing. The one legitimate reason to name a system module is to require a **minimum platform version** for a feature you use, e.g. `"metadata": ">=1.5.0"` for record-report attachments. Its contract names the entity the feature introduced, or declares `"entities": {}` when the feature introduced none (`"admin": ">=1.21.0"` for upgrade migrations).
|
|
115
115
|
|
|
116
116
|
**For bridge modules** (`crm-fin`, `wms-fin`, etc.), depend on both sides:
|
|
117
117
|
|
|
@@ -143,7 +143,7 @@ Every entry in `dependencies` needs a contract file at `deps/<module_code>.json`
|
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
- `version` must be the same range as the manifest's dependency entry.
|
|
146
|
-
- `entities` needs at least one entry
|
|
146
|
+
- `entities` needs at least one entry, except against a system module, where `{}` is a pure platform-version gate. Each entry needs a `pk` and a non-empty `use`.
|
|
147
147
|
- `columns` is optional — omit it when you touch no specific column of that entity. Declare only real storage columns you read, write or join on, at their **storage class** (`int8`, `varchar`, `numeric`, `bool`, `date`, `timestamptz`, …; a `cuid` PK is `int8`). Never declare a virtual column (`R`/`S`/`F`) or a column your own extension adds.
|
|
148
148
|
- `use` tokens are `<kind>:<symbol>` where kind is `ref`, `extends`, `formula`, `action`, `view`, `report`, `print` or `role`. `extends` must be fully qualified: `extends:parties.party`.
|
|
149
149
|
|
|
@@ -174,4 +174,22 @@ The extension file has `"extends": "fin.invoice"` inside. See MODULE_CONVENTIONS
|
|
|
174
174
|
|
|
175
175
|
- Bump `version` on every release (bug fix, feature add, etc.).
|
|
176
176
|
- Bump `dbSchemaVersion` **only** when the DB schema changes. If you added an action but no new columns, `version` goes up but `dbSchemaVersion` stays the same.
|
|
177
|
-
- The installer uses `dbSchemaVersion` to decide whether to
|
|
177
|
+
- The installer uses `dbSchemaVersion` to decide whether to apply schema changes. Upgrade **data** scripts under `migrations/` are keyed by `version` instead — see below.
|
|
178
|
+
|
|
179
|
+
## Upgrade migrations (`migrations/`)
|
|
180
|
+
|
|
181
|
+
A table or column change needs no script: the installer generates the DDL. A script is for the DATA a new version reshapes — filling a new column from an old one, moving rows to a new table, dropping a table the new version no longer declares (the platform never drops one on its own).
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
migrations/
|
|
185
|
+
└── 0.11.0.sql # runs on an upgrade from below 0.11.0 to 0.11.0 or later
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
- **Name** — the module `version` the file upgrades to, `MAJOR.MINOR.PATCH.sql`. Keyed by `version`, not `dbSchemaVersion`. A misnamed file, or one newer than the manifest `version`, fails the package at load.
|
|
189
|
+
- **When** — on an upgrade only: every file above the installed version and no higher than the package's, in ascending order. A fresh install or a same-version reinstall runs none.
|
|
190
|
+
- **Where** — inside the install transaction, after the new tables and columns exist and before `NOT NULL` is applied or a register's `totals` cache is rebuilt. A table the new version removed is still there to read. A failing script rolls the upgrade back and the module stays on the old version; refuse unconvertible data with `RAISE EXCEPTION '…'`, which the operator sees.
|
|
191
|
+
- **Ids** — `"dForge".next_id()` mints a row id in SQL. Declare `"admin": ">=1.21.0"` in `dependencies`; that is also what guarantees a platform that runs migrations.
|
|
192
|
+
- **Locks** — a script writing a posted document or its register journal wraps the writes in `SELECT set_config('registry.posting', 'true', true);` … `'false'`, so the post locks stand aside. Period locks do not; reopen a closed period and close it again.
|
|
193
|
+
- A `kind: "pack"` module cannot carry migrations.
|
|
194
|
+
|
|
195
|
+
Reference: `modules/gl/migrations/0.11.0.sql` in dForge-core.
|
|
@@ -7,11 +7,14 @@ SP files: `logic/reports/rpt_*.sql`
|
|
|
7
7
|
|
|
8
8
|
## Structure
|
|
9
9
|
|
|
10
|
-
A report has `description`, a `datasets` map, a `layout` object (`{ panels: [...] }`), optional per-dataset `params`, and an optional `entities` array (record-report attachments). Panels reference datasets by code via `datasetCd`.
|
|
10
|
+
A report has a `label`, a `description`, a `datasets` map, a `layout` object (`{ panels: [...] }`), optional per-dataset `params`, and an optional `entities` array (record-report attachments). Panels reference datasets by code via `datasetCd`.
|
|
11
|
+
|
|
12
|
+
**Name it with `label`, describe it with `description`.** `label` is the report's name: page title, breadcrumb and parameter dialog. `description` says what it shows and appears under the label, as a data view's does. Without a `label` the description becomes the name, so a sentence ends up as the page title. `dforge_module_validate`, `module pack` and install warn about it; install does not refuse it. Translate the name as `reports.<cd>.label`.
|
|
11
13
|
|
|
12
14
|
```json
|
|
13
15
|
{
|
|
14
16
|
"sales_pipeline": {
|
|
17
|
+
"label": "Sales Pipeline",
|
|
15
18
|
"description": "Open opportunities by stage",
|
|
16
19
|
"datasets": {
|
|
17
20
|
"pipeline": {
|
|
@@ -191,6 +194,10 @@ granted on. Keyed by stored-procedure code, which may not contain a dot.
|
|
|
191
194
|
- **`params`** is the call signature, in order — omit it for a zero-argument function.
|
|
192
195
|
- **`columns`** is optional; without it install derives the result columns from the
|
|
193
196
|
function's `RETURNS TABLE (…)`.
|
|
197
|
+
- A result column may name a **`domain`** (`domain_cd` or `module_cd.domain_cd`) instead of
|
|
198
|
+
`fieldTypeCd` / `baseDatatypeCd` / `params`: a status the function returns then shows its
|
|
199
|
+
labels without restating the entity's option list. Naming a domain and restating any of
|
|
200
|
+
the three is refused.
|
|
194
201
|
- Schema: `stored_procedures.schema.json`.
|
|
195
202
|
|
|
196
203
|
## Parameters
|
|
@@ -341,7 +348,8 @@ A report can be **attached to an entity** so it opens from a record — the way
|
|
|
341
348
|
|
|
342
349
|
```json
|
|
343
350
|
"credit_check": {
|
|
344
|
-
"
|
|
351
|
+
"label": "Credit Check",
|
|
352
|
+
"description": "Credit limit against outstanding AR and open quotes",
|
|
345
353
|
"entities": [
|
|
346
354
|
{ "entityCd": "parties.party", "params": { "customer_id": "party_id" }, "orderNum": 45 },
|
|
347
355
|
{ "entityCd": "crm.quote", "params": { "customer_id": "customer_id" }, "orderNum": 45 }
|
|
@@ -104,13 +104,13 @@ Use in combination with `accumulation` or `ledger` traits for accounting/registr
|
|
|
104
104
|
|
|
105
105
|
### `accumulation`
|
|
106
106
|
|
|
107
|
-
**Marker trait — adds no columns.** Indicates the entity is an accumulation register.
|
|
107
|
+
**Marker trait — adds no columns.** Indicates the entity is an accumulation register. The register itself is declared once in the module's `registers.json`; an `A`-type column only binds to it (`register`, `map`, `dateField`, …). Schema: `dforge://schema/registers`.
|
|
108
108
|
|
|
109
109
|
Advanced feature for accounting/registry modules.
|
|
110
110
|
|
|
111
111
|
### `ledger`
|
|
112
112
|
|
|
113
|
-
**Marker trait — adds no columns.** Indicates the entity uses double-entry bookkeeping.
|
|
113
|
+
**Marker trait — adds no columns.** Indicates the entity uses double-entry bookkeeping. The `accounting` register is declared in `registers.json`; an `L`-type column binds to it.
|
|
114
114
|
|
|
115
115
|
Advanced feature for accounting modules.
|
|
116
116
|
|
|
@@ -237,6 +237,10 @@ If none fire, skip specialized views for that entity.
|
|
|
237
237
|
**3c. Reports** only when aggregation/grouping isn't covered by views — or when
|
|
238
238
|
Phase 2a sent you here because the "action" only wanted to show a number.
|
|
239
239
|
|
|
240
|
+
Give each report a short `label` (its name: page title, breadcrumb, parameter
|
|
241
|
+
dialog) and a `description` of what it shows, which appears under the label.
|
|
242
|
+
Without a label the description becomes the title, and validate/pack warn.
|
|
243
|
+
|
|
240
244
|
Params are **report-scoped**: declare them in the report-level `parameters`
|
|
241
245
|
block, or as shorthand under `datasets.<cd>.params` when exactly one dataset uses
|
|
242
246
|
the param. The installer merges both into the report's one param set, report level
|
|
@@ -101,6 +101,11 @@ role / trigger / job counts. Then confirm both version strings with the user:
|
|
|
101
101
|
- **`version`** — always bump (semver) before packing.
|
|
102
102
|
- **`dbSchemaVersion`** — bump only if entity fields were added, removed, or
|
|
103
103
|
type-changed since the last install.
|
|
104
|
+
- **Data on upgrade** — if the new version moves or reshapes existing rows, or
|
|
105
|
+
removes an entity whose table must go, ship `migrations/<version>.sql` named by
|
|
106
|
+
the new `version` and declare `"admin": ">=1.21.0"`. The installer generates the
|
|
107
|
+
DDL; it never moves data or drops a table on its own. See
|
|
108
|
+
`dforge://docs/conventions` § Upgrade Migrations.
|
|
104
109
|
|
|
105
110
|
Get explicit confirmation on both before packing. This version confirmation
|
|
106
111
|
applies only to the initial pack. During the install-fix loop, re-pack without
|