@dforge-core/dforge-mcp 0.2.43 → 0.2.45
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 +77 -0
- package/README.md +1 -1
- package/dist/server.js +130 -86
- package/package.json +3 -3
- package/resources/docs/conventions.md +17 -14
- package/resources/docs/dsl-reference.md +34 -6
- package/resources/schemas/entity.schema.json +14 -4
- package/resources/schemas/registers.schema.json +8 -3
- package/resources/schemas/reports.schema.json +6 -2
- package/resources/schemas/translations.schema.json +21 -0
- package/skills/dforge-mcp-author/SKILL.md +3 -2
- package/skills/dforge-mcp-author/examples/column-security/entities/product.json +1 -1
- package/skills/dforge-mcp-author/examples/column-security/manifest.json +0 -1
- package/skills/dforge-mcp-author/examples/column-security/security/roles.json +2 -2
- package/skills/dforge-mcp-author/references/action-dsl.md +38 -8
- package/skills/dforge-mcp-author/references/conventions.md +7 -1
- package/skills/dforge-mcp-author/references/field-types.md +3 -2
- package/skills/dforge-mcp-author/references/filters.md +2 -0
- package/skills/dforge-mcp-author/references/formulas.md +5 -1
- package/skills/dforge-mcp-author/references/print-templates.md +13 -2
- package/skills/dforge-mcp-author/references/queries.md +1 -1
- package/skills/dforge-mcp-author/references/registers.md +18 -3
- package/skills/dforge-mcp-author/references/reports.md +8 -2
- package/skills/dforge-mcp-author/references/schema-import.md +1 -1
- package/skills/dforge-mcp-author/references/security.md +1 -1
- package/skills/dforge-mcp-author/references/translations.md +44 -16
- package/skills/dforge-mcp-author/references/validation-checklist.md +2 -3
- package/skills/dforge-module-build/SKILL.md +10 -1
- package/skills/dforge-module-ship/SKILL.md +31 -3
- package/skills/dforge-mcp-author/examples/column-security/translations/en-US.json +0 -35
|
@@ -78,7 +78,7 @@ A report has a `label`, a `description`, a `datasets` map, a `layout` object (`{
|
|
|
78
78
|
- `query.columns` — column codes; supports dot navigation (`customer.name`).
|
|
79
79
|
- `query.filter` — canonical filter (`{c,o,v}` or `{g,i:[...]}`); use `@param_code` to reference a parameter.
|
|
80
80
|
- `query.sort` — `[{ c, d }]` where `d` ∈ `asc | desc`.
|
|
81
|
-
- `columnsDef` — optional per-column display overrides (`{ label,
|
|
81
|
+
- `columnsDef` — optional per-column display overrides (`{ label, fieldTypeCd, format, width }`; each key replaces the projected value). `label` is a literal and wins over a translated header. `visible` is accepted but read by nothing. `baseDatatypeCd` is read only where the dataset projects no columns of its own.
|
|
82
82
|
|
|
83
83
|
### Stored procedure dataset (developer path)
|
|
84
84
|
|
|
@@ -110,6 +110,9 @@ Key differences from entity datasets:
|
|
|
110
110
|
**override** — `report.run` projects `dForge.sp_column`, and `columnsDef` only restyles it.
|
|
111
111
|
A function returning an unnamed `SETOF <composite>` or a bare scalar declares no column
|
|
112
112
|
names, so that one needs an explicit `columns` block in `logic/stored_procedures.json`.
|
|
113
|
+
Leave `label` out of `columnsDef` to keep the column's translated header: result-column headers
|
|
114
|
+
translate under the procedure, `storedProcedures.<sp_cd>.columns.<column_cd>.label`
|
|
115
|
+
(see `references/translations.md`), and every dataset bound to the procedure shows it.
|
|
113
116
|
- Params work exactly as they do for an entity dataset, and `datasetType` makes no difference: declare them at report level (`parameters`) or on the dataset (`params`). Report level wins on a code collision.
|
|
114
117
|
- **The parameter code must match the procedure's declared `paramCd` exactly.** `report.run`
|
|
115
118
|
resolves each argument by that code alone — no prefix is added or stripped — so a report
|
|
@@ -159,8 +162,10 @@ $$;
|
|
|
159
162
|
- `paramCd` is capped at 50 characters, and a declared `fieldTypeCd` must be a real one —
|
|
160
163
|
both are checked at install, because binding the SP in the report editor copies them
|
|
161
164
|
into report params.
|
|
162
|
-
- `RETURNS TABLE (...)`.
|
|
165
|
+
- `RETURNS TABLE (...)`. In `LANGUAGE plpgsql` with `RETURN QUERY`, each selected column must match its declared type exactly: a `varchar` column returned as `text` fails with "structure of query does not match function result type". Cast in the select (`c.account_name::text`).
|
|
163
166
|
- Use the module's schema prefix (`crm.rpt_*`) and `STABLE` volatility.
|
|
167
|
+
- **A function that returns one row: declare `ROWS 1`.** Install adds `SET search_path` to the function, which stops Postgres from inlining it, so the planner falls back to its default estimate of 1000 rows and a join on the function can turn a 5-second report into a 20-minute one. `ROWS 1` (or a realistic estimate) on each table function the report calls restores the plan.
|
|
168
|
+
- **Every `logic/reports/*.sql` runs at every install**, as the install's database user. Don't create or replace the function by hand under another user while experimenting: the next install fails with "must be owner of function". Try SQL in a transaction you roll back, and let install own the functions.
|
|
164
169
|
- **Security is your responsibility, and the function has no context to work from**: it is not
|
|
165
170
|
told the folder or the user, so an SP dataset cannot be row-level scoped the way a `"Q"`
|
|
166
171
|
dataset is. Use `"Q"` for anything that must be filtered per user, and keep `"S"` for
|
|
@@ -194,6 +199,7 @@ granted on. Keyed by stored-procedure code, which may not contain a dot.
|
|
|
194
199
|
- **`params`** is the call signature, in order — omit it for a zero-argument function.
|
|
195
200
|
- **`columns`** is optional; without it install derives the result columns from the
|
|
196
201
|
function's `RETURNS TABLE (…)`.
|
|
202
|
+
- A result column's `baseDatatypeCd` is a platform base type code: `string`, `number`, `bool`, `date`, `timestamp`, `time`, `guid`, `json`, `link`, `set`, `binary`, `xml`, `culture`. Not `datetime`, `boolean`, `integer` or `text`: an unknown code fails install with a bare foreign-key error on `sp_column`, which validate does not catch yet.
|
|
197
203
|
- A result column may name a **`domain`** (`domain_cd` or `module_cd.domain_cd`) instead of
|
|
198
204
|
`fieldTypeCd` / `baseDatatypeCd` / `params`: a status the function returns then shows its
|
|
199
205
|
labels without restating the entity's option list. Naming a domain and restating any of
|
|
@@ -111,7 +111,7 @@ Using the converted entities, generate the full module package:
|
|
|
111
111
|
4. **`ui/menus.json`** — grouped logically (group related entities under section nodes)
|
|
112
112
|
5. **`ui/folders.json`** — root folder with all entities listed
|
|
113
113
|
6. **`security/roles.json`** — at least `module.admin` (SIUDC on everything) and `module.user` (SIU on main entities)
|
|
114
|
-
7.
|
|
114
|
+
7. **English labels in the definitions** — a short `description` on every entity, field and role, a `label` on every view, menu and action. No `translations/en-US.json`: install skips it. Translation files only for the locales in `supportedLocales` (`dforge_translation_sync`)
|
|
115
115
|
8. **`seed-data/`** — if the source had enum/lookup tables converted to entities, generate seed data for them
|
|
116
116
|
|
|
117
117
|
### Step 8: Generate IMPORT_NOTES.md
|
|
@@ -16,7 +16,7 @@ Lives in: `security/roles.json`
|
|
|
16
16
|
|
|
17
17
|
Role codes use a `module.role` naming pattern (e.g. `crm.admin`, `crm.sales-rep`).
|
|
18
18
|
|
|
19
|
-
> **Role display name & translations.** Each role has exactly two keys: `description` and `rights` (`roles.schema.json` is `additionalProperties: false` — **do not** add a `label` here). `description` is the English
|
|
19
|
+
> **Role display name & translations.** Each role has exactly two keys: `description` and `rights` (`roles.schema.json` is `additionalProperties: false` — **do not** add a `label` here). `description` is the English display name — keep it a short label ("Storekeeper"), not an explanation, since it is what the English UI shows. The **localized** display name lives in the translation files as `roles.<code>.label`, keyed by the module-qualified role code, and is **completeness-enforced**: every role must have a `roles.<code>.label` in every non-English `translations/<locale>.json` or install fails. There is no English translation file. See `translations.md`.
|
|
20
20
|
|
|
21
21
|
Example:
|
|
22
22
|
|
|
@@ -2,9 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
dForge modules support multi-language translations for user-facing labels — entity names, field labels, view titles, folder names, menu items, action labels and params, and report params/dataset captions.
|
|
4
4
|
|
|
5
|
-
Lives in: `translations/<locale>.json` (e.g. `translations/
|
|
5
|
+
Lives in: `translations/<locale>.json` for each **non-English** locale (e.g. `translations/de-DE.json`, `translations/uk-UA.json`)
|
|
6
6
|
|
|
7
|
-
Locale codes use the `ll-CC` format (language-country): `
|
|
7
|
+
Locale codes use the `ll-CC` format (language-country): `de-DE`, `uk-UA`, `fr-FR`, `es-ES`, etc.
|
|
8
|
+
|
|
9
|
+
## English is the base — and it lives in the definitions
|
|
10
|
+
|
|
11
|
+
Install **never reads** `translations/en.json` or `translations/en-*.json` (`ModulePackage.ReadTranslationFiles` skips them). The English UI shows the text written in the definitions themselves, so an English-only module ships **no** `translations/` folder, and a translated module ships one file per locale in `supportedLocales` and nothing for English. An `en-US.json` is dead weight: its labels are never applied, and the English UI keeps showing whatever the definitions say — which is how a module ends up displaying long service descriptions as labels. `dforge_module_validate` warns about such a file; `dforge_translation_sync` refuses to write one.
|
|
12
|
+
|
|
13
|
+
Where each object's English text lives (what install shows, `label ?? description ?? code` where both exist):
|
|
14
|
+
|
|
15
|
+
| Object | English text | Notes |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| Entity | `description` in `entities/<e>.json` | |
|
|
18
|
+
| Field | `description` on the field | trait columns take theirs from the trait |
|
|
19
|
+
| Data view | `label`, else `description` | with both, `description` is the tooltip |
|
|
20
|
+
| Folder | `label`, else `description` | |
|
|
21
|
+
| Menu / menu item | `label`, else `description` | |
|
|
22
|
+
| Action | `label`, else `description` | an action param: its `description` |
|
|
23
|
+
| Report | `label`, else `description` | |
|
|
24
|
+
| Stored procedure | `description`; a result column: its `label` | |
|
|
25
|
+
| Print template | `description` | `label` is rejected by the schema |
|
|
26
|
+
| Setting | `description` | |
|
|
27
|
+
| Role | `description` | `label` is rejected by the schema |
|
|
28
|
+
| Column domain | `description` | |
|
|
29
|
+
| Register | `label` | |
|
|
30
|
+
|
|
31
|
+
Keep these short **labels** — "Product", "Storekeeper" — not explanations. Notes such as a legacy table name or "(in Ukrainian)" belong in docs or comments: whatever the field holds is the UI text.
|
|
8
32
|
|
|
9
33
|
## Structure
|
|
10
34
|
|
|
@@ -83,7 +107,8 @@ Translation files mirror the module's content structure. Each translatable objec
|
|
|
83
107
|
| `views` | Data view labels and descriptions (`label`, `desc`) | View codes (keys from `ui/data_views.json`) → `{ label, desc }` |
|
|
84
108
|
| `menus` | Menu node labels (root + nested items) | Menu root key → `{ label, items: { item_code: { label } } }` matching `ui/menus.json` structure |
|
|
85
109
|
| `actions` | Action labels, descriptions, param labels **and param dropdown option labels** | Action codes (keys from `ui/actions.json`) → `{ label, desc, params: { param_cd: { label, options: { value: … } } } }` |
|
|
86
|
-
| `reports` | Report dataset captions, param labels **and param dropdown option labels** | Report codes → `{ datasets: { ds_cd: { caption } }, params: { param_cd: { label, options: { value: … } } } }` |
|
|
110
|
+
| `reports` | Report `label`, `desc`, dataset captions, param labels **and param dropdown option labels** | Report codes → `{ datasets: { ds_cd: { caption } }, params: { param_cd: { label, options: { value: … } } } }` |
|
|
111
|
+
| `storedProcedures` | Result-column headers of a stored procedure (`logic/stored_procedures.json`), shared by every report bound to it | Procedure codes → `{ columns: { column_cd: { label } } }` |
|
|
87
112
|
| `entities.<e>.constraints` | Check/unique constraint violation messages (opt-in — warned, not enforced) | Constraint codes → `{ message }` under the owning entity |
|
|
88
113
|
| `messages` | DSL `info` / `warn` / `error` / `exit` texts (opt-in — warned, not enforced) | Exact English text → translated text |
|
|
89
114
|
| `entities.<e>.fields.<f>.options` | Dropdown/radio/flags **option labels** (opt-in) | Option `value` → localized label (string) or `{ label, icon, color }` |
|
|
@@ -110,7 +135,7 @@ A check/unique constraint declares a user-facing `message` in the entity JSON (`
|
|
|
110
135
|
|
|
111
136
|
### Dropdown option labels ARE translatable (opt-in)
|
|
112
137
|
|
|
113
|
-
The `options` on a `dropdown`/`radio`/`flags` column are the **base (fallback) labels
|
|
138
|
+
The `options` on a `dropdown`/`radio`/`flags` column are the **base (fallback) labels**, and they are the English UI — write plain English there (`"Active"`), never a bilingual `"Active (Актив)"`. To translate the labels a user actually sees, add an `options` map next to the field's `label`, keyed by the option's **value** (the stored code). Prefer the **string** form (`"active": "Активний"`): the `{ label, … }` form is valid, but the VS Code extension's translation panel counts it as missing, and `module validate` does not check option translations at all. An option list several columns share belongs in a column domain, translated once under `domains.<code>.options`.
|
|
114
139
|
|
|
115
140
|
```json
|
|
116
141
|
"entities": {
|
|
@@ -203,15 +228,14 @@ Role labels are **required and localized** (this changed — older docs said rol
|
|
|
203
228
|
```
|
|
204
229
|
|
|
205
230
|
- **Keys are the role codes** from `security/roles.json` — already module-qualified (e.g. `crm.admin`, `crm.sales-rep`). They match `module_role.name`.
|
|
206
|
-
- **Value is `{ "label": ... }`** — the localized display name. It supersedes the `description` from `roles.json`
|
|
207
|
-
- **Completeness is enforced.** `TranslationCompletenessValidator` requires `roles.<code>.label` for **every** role in `security/roles.json`, in **every** translation file —
|
|
231
|
+
- **Value is `{ "label": ... }`** — the localized display name. It supersedes the `description` from `roles.json` in that locale; `description` is the English text.
|
|
232
|
+
- **Completeness is enforced.** `TranslationCompletenessValidator` requires `roles.<code>.label` for **every** role in `security/roles.json`, in **every** translation file install reads — each locale in `supportedLocales`. A missing role label fails install with `Label for role '<code>'.` English needs nothing here: it is the role's `description`.
|
|
208
233
|
|
|
209
234
|
### Sections that are NOT translated (write-time only)
|
|
210
235
|
|
|
211
|
-
- `
|
|
212
|
-
- `print_templates` — not currently consumed by the registrar. Template labels come from `ui/print_templates.json`.
|
|
236
|
+
- `print_templates` — not consumed by the registrar: a template row has no translatable resource. Its name is the `description` in `ui/print_templates.json` in every language. If you include the section, install succeeds and ignores it.
|
|
213
237
|
|
|
214
|
-
|
|
238
|
+
`settings` **is** translated: completeness is checked for each declared locale (ship `settings.<cd>.label`), and the setting's English text is its `description` in `settings.json` — the registrar never reads a `label` there.
|
|
215
239
|
|
|
216
240
|
## German example (de-DE)
|
|
217
241
|
|
|
@@ -261,7 +285,7 @@ If you include these sections, the install succeeds (they're silently ignored)
|
|
|
261
285
|
|
|
262
286
|
## Manifest declaration
|
|
263
287
|
|
|
264
|
-
Non-English locales are declared in `supportedLocales` (an array of `ll-CC` tags) — **not** a `translations` object. The manifest schema has no `translations` key and rejects it (`additionalProperties: false`). Translation files are auto-discovered at `translations/<locale>.json`.
|
|
288
|
+
Non-English locales are declared in `supportedLocales` (an array of `ll-CC` tags) — **not** a `translations` object. The manifest schema has no `translations` key and rejects it (`additionalProperties: false`). Translation files are auto-discovered at `translations/<locale>.json`. Do **not** list `en`/`en-US` in `supportedLocales` and do not ship an English file — English is the definitions' own text (see above); the schema rejects `en`/`en-US` entries.
|
|
265
289
|
|
|
266
290
|
```json
|
|
267
291
|
"supportedLocales": ["de-DE", "fr-FR"]
|
|
@@ -269,20 +293,24 @@ Non-English locales are declared in `supportedLocales` (an array of `ll-CC` tags
|
|
|
269
293
|
|
|
270
294
|
Every listed locale MUST have a matching `translations/<locale>.json` with a label for each translatable resource, or install fails completeness validation.
|
|
271
295
|
|
|
296
|
+
### Stored-procedure column headers
|
|
297
|
+
|
|
298
|
+
A result column's header belongs to the procedure, not to a report. `module pack` / `module validate` require one `storedProcedures.<sp_cd>.columns.<column_cd>.label` per declared column for each non-English supported locale; install only warns (also when a translation names a column the module lacks). A dataset's `columnsDef` label is a literal and overrides it, so leave the label out to keep the column translated.
|
|
299
|
+
|
|
272
300
|
## Rules
|
|
273
301
|
|
|
274
|
-
1. **
|
|
275
|
-
2. **Locale format is `ll-CC`** (e.g. `
|
|
276
|
-
3. **Translate everything user-visible**: entity labels, every field label (including trait-provided fields like `created_date`, `last_updated`), view names, menu items, action labels, **role labels (required — completeness-enforced, `roles.<code>.label` for every role in every locale
|
|
302
|
+
1. **English is the definitions' text** — no `en-US.json`. Write a short English label into each definition (see the table above); other languages fall back to it for missing keys.
|
|
303
|
+
2. **Locale format is `ll-CC`** (e.g. `de-DE`, `uk-UA`, `fr-FR`) — language code + country code, hyphen-separated.
|
|
304
|
+
3. **Translate everything user-visible**: entity labels, every field label (including trait-provided fields like `created_date`, `last_updated`), view names, menu items, action labels, **role labels (required — completeness-enforced, `roles.<code>.label` for every role in every declared locale)**, setting labels, folder names.
|
|
277
305
|
4. **Include virtual columns** (references, sets, formulas) in field translations — they appear in the UI just like physical columns.
|
|
278
306
|
5. **Menu translations mirror the `ui/menus.json` structure** — root key → `items` → nested items.
|
|
279
|
-
6. **Missing keys fall back** to the
|
|
307
|
+
6. **Missing keys fall back** to the definition's English text, then to the raw code name. So it's safe to ship partial translations — untranslated items show in English rather than breaking.
|
|
280
308
|
7. **Don't translate column codes** — only the `label` values. Codes stay as-is in all languages.
|
|
281
309
|
8. **File naming**: `translations/<locale>.json` (e.g. `de-DE.json`) — each non-English file must match a locale listed in `supportedLocales`.
|
|
282
310
|
9. **Constraint messages are opt-in** — localize them under `entities.<e>.constraints.<c>.message` when you want a per-locale violation message; otherwise the base `message` from the entity JSON is used. Missing overrides warn (non-fatal), they don't fail install. See "Constraint violation messages ARE translatable" above.
|
|
283
311
|
|
|
284
312
|
## When to create translations
|
|
285
313
|
|
|
286
|
-
- **
|
|
287
|
-
- **On request** create additional languages
|
|
314
|
+
- **Never** create `translations/en-US.json` — install skips it. Give every definition a short English label instead, so nothing falls back to a column code.
|
|
315
|
+
- **On request** create additional languages: declare them in `supportedLocales` and run `dforge_translation_sync`, which seeds each file from the definitions' English text for you to translate in place.
|
|
288
316
|
- **Include all fields** in each language file, including trait-provided fields (`created_date`, `last_updated`, `created_by`, etc.) — users see these columns and they need labels.
|
|
@@ -162,8 +162,8 @@ For each action:
|
|
|
162
162
|
|
|
163
163
|
## Translations
|
|
164
164
|
|
|
165
|
-
- [ ] `translations/en
|
|
166
|
-
- [ ]
|
|
165
|
+
- [ ] **No** `translations/en.json` / `en-*.json` — install skips them. English is each definition's own short label (entity/field/role/setting `description`, view/menu/action/report `label`)
|
|
166
|
+
- [ ] Each `translations/<locale>.json` (one per `supportedLocales` entry) has an `entities` section with `label`, `desc`, and `fields` for every entity
|
|
167
167
|
- [ ] Every field (including trait-provided: `created_date`, `last_updated`, etc.) has a `label`
|
|
168
168
|
- [ ] Has `views` section with labels for every data view
|
|
169
169
|
- [ ] Has `menus` section matching the `ui/menus.json` structure
|
|
@@ -172,7 +172,6 @@ For each action:
|
|
|
172
172
|
- [ ] (Optional) Constraint messages localized under `entities.<e>.constraints.<c>.message` — opt-in; a missing override for a declared `supportedLocales` entry warns (surfaced by `dforge_module_validate` and at install) but does not fail install
|
|
173
173
|
- [ ] Has `settings` section with labels for every setting (if settings exist)
|
|
174
174
|
- [ ] Has `folders` section with label for the root folder
|
|
175
|
-
- [ ] Additional language files (if any) have the same structure as `en-US.json`
|
|
176
175
|
- [ ] Manifest `supportedLocales` lists every non-English locale that has a `translations/<locale>.json` file (English is not listed)
|
|
177
176
|
|
|
178
177
|
## Versioning
|
|
@@ -36,12 +36,15 @@ flags, or column patterns.
|
|
|
36
36
|
| Suggest a value when another field is edited (a reaction), incl. from a bridge module | `dforge://reference/reactions` | `dforge://schema/entity`, `dforge://schema/deps` |
|
|
37
37
|
| Add a trait | `dforge://reference/traits` | — |
|
|
38
38
|
| Add a number sequence | `dforge://reference/number-sequences` | — |
|
|
39
|
+
| Add an accumulation register (`A` column, `registers.json`) | `dforge://reference/registers` | `dforge://schema/registers` |
|
|
40
|
+
| Edit the manifest (version, `supportedLocales`, dependencies, `entities` map) | `dforge://reference/manifest` | `dforge://schema/manifest` |
|
|
39
41
|
| Add a grid / list view | `dforge://reference/data-views`, `dforge://example/ui/data_views.json` | — |
|
|
40
42
|
| Add a matrix (pivot) view | `dforge://reference/data-views` (§Matrix), `dforge://example/matrix-budget/ui/data_views.json`, `dforge://example/matrix-budget/entities/budget_line.json` | — |
|
|
41
43
|
| Add kanban / calendar / tree-grid / master-detail | `dforge://reference/data-views` | `dforge://schema/data-views` |
|
|
42
44
|
| Hide columns from a user type (column-level security) | `dforge://reference/security` (§Column-level security), `dforge://example/column-security/entities/product.json`, `dforge://example/column-security/ui/folders.json` | — |
|
|
43
45
|
| Add a menu | `dforge://reference/menus`, `dforge://example/ui/menus.json` | — |
|
|
44
46
|
| Add an action | `dforge://reference/action-dsl`, `dforge://example/logic/actions/mark_done.dsl`, `dforge://example/ui/actions.json` | `dforge://docs/dsl` |
|
|
47
|
+
| Email a file the script builds, or ship saved values / a PDF preview for an action's dialog | `dforge://reference/action-dsl` (§Email and §PDF and file output: `sendEmail` attachments, `attachText`, `attachBase64`; §Registering the action: `paramSets`, `previewTemplate`) | `dforge://docs/dsl` |
|
|
45
48
|
| Share helpers between actions, or call another module's functions | `dforge://reference/action-dsl` (§Function libraries): `logic/functions/*.dsl`, imports in `deps/<module>.json` | `dforge://schema/deps` |
|
|
46
49
|
| Add a trigger | — | `dforge://schema/triggers`; condition syntax in `dforge://docs/dsl` |
|
|
47
50
|
| Add a scheduled job | `dforge://reference/jobs` | `dforge://schema/jobs` |
|
|
@@ -115,6 +118,10 @@ Enough to author inline; load the linked reference for the full detail.
|
|
|
115
118
|
- **Manifest:** non-English locales go in `supportedLocales` (`ll-CC`, never
|
|
116
119
|
`en`/`en-US`); there is no `translations` manifest key. `security` has both
|
|
117
120
|
`roles` and `folders`. → `manifest`
|
|
121
|
+
- **English is the definitions' text:** install skips `translations/en*.json`, so
|
|
122
|
+
never create one. Give every entity, field, role and setting a short
|
|
123
|
+
`description` and every view, menu, action and report a short `label` — that
|
|
124
|
+
is what the English UI shows. → `translations`
|
|
118
125
|
- **Seed data:** explicit numeric PKs under `{entity}_id`; parents before
|
|
119
126
|
children via the `NN-` prefix. Use `dforge_seed_add`.
|
|
120
127
|
|
|
@@ -160,6 +167,7 @@ approval, then patch. Reach for the **composite tools first**:
|
|
|
160
167
|
- roll-up total → `dforge_entity_rollup_add`
|
|
161
168
|
- status column → `dforge_entity_status_add`
|
|
162
169
|
- plain scalar → `dforge_entity_field_add`
|
|
170
|
+
- change an existing field (label, flags, type, …) → `dforge_entity_field_modify`
|
|
163
171
|
|
|
164
172
|
**Field batching rule** — the only Phase 1 exception to one-at-a-time. A field
|
|
165
173
|
is batchable only if ALL of: scalar primitive (string/integer/decimal/boolean/
|
|
@@ -285,7 +293,8 @@ stated trigger; every report's params sit on a dataset.
|
|
|
285
293
|
## Phase 4 — Polish (mostly optional)
|
|
286
294
|
|
|
287
295
|
- **Settings** — `dforge_setting_add` per configurable value the user asked for.
|
|
288
|
-
- **Translations** —
|
|
296
|
+
- **Translations** — only for the locales in `supportedLocales`; English needs
|
|
297
|
+
no file. Run **`dforge_translation_sync`**. It generates every
|
|
289
298
|
required key from the module's own contents, never overwrites existing
|
|
290
299
|
translated text, and fills the **role labels that are completeness-enforced at
|
|
291
300
|
install**. Run it after any entity/view/role change, and always before Phase 6.
|
|
@@ -78,9 +78,9 @@ formula column shape; flags letters (`V I E M H` only); every entity has a
|
|
|
78
78
|
default grid and `dataSources` at root with `"order"` as a string array; menu
|
|
79
79
|
leaves use `dataViewCode` and bare icon names; every entity in at least one
|
|
80
80
|
role's rights; action `script` values are bare filenames; seed PKs numeric with
|
|
81
|
-
parents first; a `translations/<locale>.json` for every `supportedLocales` entry
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
parents first; a `translations/<locale>.json` for every `supportedLocales` entry,
|
|
82
|
+
each carrying a label for every trait-provided field and every role. No English
|
|
83
|
+
file — install skips `en*.json`; English is the definitions' own short labels.
|
|
84
84
|
|
|
85
85
|
If translations are thin, run **`dforge_translation_sync`** now rather than
|
|
86
86
|
hand-patching — it fills exactly the keys install requires.
|
|
@@ -156,6 +156,34 @@ package — fix the referenced files, report what changed, and immediately re-ru
|
|
|
156
156
|
validate → pack → install. Keep sign-off for product/design choices or genuinely
|
|
157
157
|
ambiguous fixes.
|
|
158
158
|
|
|
159
|
+
**If install hangs, or fails with a bare HTTP 500 or 400 "deadlock":** look for
|
|
160
|
+
a lock before touching the module. An install's `ALTER TABLE` waits behind any
|
|
161
|
+
open transaction on the module's tables — an idle `psql` session, an ad hoc
|
|
162
|
+
read left open, a script that never commits — and waits without a message,
|
|
163
|
+
for an hour or more. Check `pg_stat_activity` for a blocked `ALTER` and the
|
|
164
|
+
session holding it. Never install while scripts hold transactions on the
|
|
165
|
+
module's tables; run ad hoc scripts in autocommit.
|
|
166
|
+
|
|
167
|
+
**If install times out on the client while rebuilding a register cache:** the
|
|
168
|
+
server goes on and finishes (an analytic cache over 1.5 million postings took
|
|
169
|
+
about 18 minutes). Check the server log or the cache before installing again.
|
|
170
|
+
|
|
171
|
+
**Same version installed "successfully" but nothing changed:** a re-install of
|
|
172
|
+
the same `version` is skipped (`isEmpty: true`). Bump the version, or pass
|
|
173
|
+
`--force` on a dev tenant.
|
|
174
|
+
|
|
175
|
+
**Local dev stack pitfalls:**
|
|
176
|
+
- After installing into a local docker setup, restart `dforge-api` if the UI
|
|
177
|
+
still shows the old metadata; its cache can stay stale.
|
|
178
|
+
- The tenant URL is `http://<tenant>._.localhost:5179`. `<tenant>.localhost`
|
|
179
|
+
and `<tenant>_.localhost` sign into **another** tenant.
|
|
180
|
+
- "no token for tenant X": the CLI session expired (a token lasts about an
|
|
181
|
+
hour). Run `dforge-cli auth login --url <tenant url>`.
|
|
182
|
+
- "tenant at db_schema_version … is ahead of this binary" after rebuilding the
|
|
183
|
+
platform: install through the server with `--url`.
|
|
184
|
+
- Don't keep scaffold copies of a module (same `code`, another `moduleId`)
|
|
185
|
+
anywhere a folder publish can pick them up.
|
|
186
|
+
|
|
159
187
|
**If install fails on auth (401/403) or connectivity (refused):** that is
|
|
160
188
|
credentials/connectivity, NOT a module defect. Tell the user to verify
|
|
161
189
|
`DFORGE_URL` and `DFORGE_TOKEN`. **Do not backtrack** to earlier phases.
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"entities": {
|
|
3
|
-
"product": {
|
|
4
|
-
"label": "Product",
|
|
5
|
-
"fields": {
|
|
6
|
-
"name": { "label": "Product Name" },
|
|
7
|
-
"sku": { "label": "SKU" },
|
|
8
|
-
"quantity": { "label": "Quantity On Hand" },
|
|
9
|
-
"cost_price": { "label": "Cost Price" },
|
|
10
|
-
"sale_price": { "label": "Sale Price" },
|
|
11
|
-
"margin": { "label": "Margin" }
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"folders": {
|
|
16
|
-
"warehouse": { "label": "Warehouse" },
|
|
17
|
-
"finance": { "label": "Finance" }
|
|
18
|
-
},
|
|
19
|
-
"roles": {
|
|
20
|
-
"column_security.storekeeper": { "label": "Storekeeper" },
|
|
21
|
-
"column_security.accountant": { "label": "Accountant" }
|
|
22
|
-
},
|
|
23
|
-
"views": {
|
|
24
|
-
"product_grid": { "label": "Products" }
|
|
25
|
-
},
|
|
26
|
-
"menus": {
|
|
27
|
-
"product_menu": {
|
|
28
|
-
"label": "Products",
|
|
29
|
-
"items": {
|
|
30
|
-
"catalog": { "label": "Catalog" },
|
|
31
|
-
"all_products": { "label": "Products" }
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|