@dforge-core/dforge-mcp 0.1.0-rc.1 → 0.1.0-rc.10
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 +177 -50
- package/dist/server.js +13191 -2585
- package/docs/creating-modules.md +148 -0
- package/package.json +5 -4
- package/resources/docs/dsl-reference.md +767 -0
- package/resources/schemas/{data-view.schema.json → data-views.schema.json} +52 -1
- package/resources/schemas/entity.schema.json +1 -2
- package/resources/schemas/folders.schema.json +108 -0
- package/resources/schemas/jobs.schema.json +83 -0
- package/resources/schemas/manifest.schema.json +49 -3
- package/resources/schemas/menus.schema.json +86 -0
- package/resources/schemas/reports.schema.json +221 -0
- package/resources/schemas/roles.schema.json +32 -0
- package/resources/schemas/seed-data.schema.json +23 -0
- package/resources/schemas/settings.schema.json +55 -0
- package/resources/schemas/traits.schema.json +99 -0
- package/resources/schemas/webhooks.schema.json +73 -0
- package/skills/dforge-mcp-author/SKILL.md +260 -66
|
@@ -1,107 +1,301 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dforge-mcp-author
|
|
3
|
-
description:
|
|
3
|
+
description: Co-pilot for authoring dForge modules via the dforge-mcp tool surface. Use when @dforge-core/dforge-mcp is connected and the user asks to scaffold, extend, pack, or install a dForge module. Drafts and proposes; the user approves at named gates. Walks the user through six phases with explicit gates for confirmation, a deterministic backtrack protocol, a tool-failure protocol, and resume-from-partial-state support.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# dForge Module Author
|
|
6
|
+
# dForge Module Author — Co-pilot
|
|
7
7
|
|
|
8
|
-
You
|
|
8
|
+
You are a co-pilot: you **draft**, **propose**, and **call tools**; the **user approves** at named gates. Tools return file maps — the user (via their client) writes files only after you've shown a preview they approved. Never write without confirmation.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Tool reference
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## Tool surface
|
|
12
|
+
The phase column below indicates the **typical** use. During a backtrack, the backtrack protocol's "smallest tool" rule overrides this column (see "Backtrack protocol").
|
|
15
13
|
|
|
16
|
-
| Tool | What it does |
|
|
14
|
+
| Tool | Typical phase | What it does |
|
|
17
15
|
|---|---|---|
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
16
|
+
| `dforge_module_inspect` | any | Read current module state. **Read-only** — output does NOT require user confirmation. The one-line `summary` is for the user; the full structured state lives in `files["_inspect.json"]` (entities + their fields, views + their data sources, roles + rights matrix, actions, reports, settings, folders tree). Parse `_inspect.json` before planning patches — don't rely on summary text alone. |
|
|
17
|
+
| `dforge_module_create` | 1 | Scaffold a new module (returns file map; user writes) |
|
|
18
|
+
| `dforge_entity_add` | 1 | Add a whole entity to an existing module |
|
|
19
|
+
| `dforge_entity_field_add` | 1 | Patch one field onto an existing entity |
|
|
20
|
+
| `dforge_entity_field_modify` | 1 | Replace one field's spec |
|
|
21
|
+
| `dforge_entity_field_remove` | 1 | Drop one field (warns about dependents) |
|
|
22
|
+
| `dforge_action_add` | 2 | DSL action + ui/actions.json entry |
|
|
23
|
+
| `dforge_view_add` | 3 | Data view in ui/data_views.json |
|
|
24
|
+
| `dforge_view_modify` | 3 | Replace a view's spec |
|
|
25
|
+
| `dforge_report_add` | 3 | Report in ui/reports.json |
|
|
26
|
+
| `dforge_setting_add` | 4 | Configurable module setting |
|
|
27
|
+
| `dforge_role_add` | 5 | Role with rights matrix |
|
|
28
|
+
| `dforge_role_right_set` | 5 | Grant / revoke one right on one object |
|
|
29
|
+
| `dforge_folder_add` | 5 | Security folder (optional) |
|
|
30
|
+
| `dforge_dependency_add` | any | Add a dep on another module |
|
|
31
|
+
| `dforge_module_pack` | 6 | Produce .dforge tarball (needs dforge-cli on PATH) |
|
|
32
|
+
| `dforge_module_install` | 6 | Install to tenant — the real validator |
|
|
33
|
+
|
|
34
|
+
## Resources to load once per session
|
|
23
35
|
|
|
24
|
-
|
|
36
|
+
- `dforge://docs/conventions` — naming, FK+Reference pattern, traits, security model
|
|
37
|
+
- `dforge://schema/manifest`, `entity`, `data-views`, `folders`, `menus`, `roles`, `reports`, `settings`, `jobs`, `seed-data` — consult before emitting each file kind
|
|
25
38
|
|
|
26
|
-
|
|
39
|
+
**If a resource fails to load, halt and notify the user.** Do not invent conventions or schemas from memory.
|
|
27
40
|
|
|
28
|
-
|
|
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
|
|
41
|
+
## Hard rules
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
These are absolute. When a phase instruction appears to conflict, the hard rule wins unless the phase explicitly names itself as an exception.
|
|
34
44
|
|
|
35
|
-
|
|
45
|
+
1. **Co-pilot stance.** Draft → propose → user approves → tool call → file write. Never write without confirmation.
|
|
46
|
+
2. **Inspect before patching.** Run `dforge_module_inspect` at session start and after every backtrack. Inspect output is read-only; show a summary and continue without asking confirmation for the inspect itself — confirmation applies only to **write** tools.
|
|
47
|
+
3. **One thing at a time when interacting with the user.** Applies to:
|
|
48
|
+
- **Questions.** Ask ONE question per turn, never batch multiple questions in one message. Each subsequent question is informed by prior answers. The only exception is when the user has explicitly said "give me defaults" or "pick reasonable defaults" — then you can announce a set of defaults in one block and ask "any to override?".
|
|
49
|
+
- **Entities / views / roles / actions / reports.** Propose ONE per turn. Never batch these. (Field batching inside an entity has a narrow exception in Phase 1.)
|
|
50
|
+
4. **Validate-and-reflect every step.** After every user answer, BEFORE moving to the next question or tool call: restate what you understood in your own words and ask "Right?" or "Does that capture it?". Only proceed once the user confirms. If they correct, repeat the restate-and-confirm loop until aligned. **Goal: zero ambiguity going into the next step.** If you have questions, ask and wait for answers — never proceed with unanswered ones in your head.
|
|
51
|
+
5. **Tabs in JSON, trailing newline** — tools already emit this; don't reformat.
|
|
52
|
+
6. **Don't invent fields, codes, roles, or relationships** — they come from the user's domain. If the user said "we have submitters and admins", roles are derived from that; do NOT default to a fixed "admin/contributor/viewer" taxonomy or any other generic set the user didn't ask for.
|
|
36
53
|
|
|
37
|
-
##
|
|
54
|
+
## Tool failure protocol
|
|
38
55
|
|
|
39
|
-
|
|
56
|
+
If any MCP tool returns an error at any time:
|
|
40
57
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
4. **Greenfield or extending an existing module?** If extending, ask which.
|
|
58
|
+
1. **Surface the raw error verbatim** to the user. Do not paraphrase.
|
|
59
|
+
2. **Do not attempt a workaround** with a different tool or hand-crafted JSON.
|
|
60
|
+
3. **Ask the user to resolve the tool-level issue** (missing dep, bad path, schema validation, etc.) before continuing.
|
|
61
|
+
4. **Do not advance the phase** until the failing tool succeeds.
|
|
46
62
|
|
|
47
|
-
|
|
63
|
+
Two specific tool errors have known causes worth distinguishing:
|
|
48
64
|
|
|
49
|
-
|
|
65
|
+
- **`dforge_module_pack` / `_install` reports "command not found" or PATH error**: dforge-cli isn't installed. Tell the user: "dforge-cli is not on your PATH. Install with `npm install -g @dforge-core/dforge-cli`, then re-run. Do not continue Phase 6 until resolved."
|
|
66
|
+
- **`dforge_module_install` reports HTTP 401/403 or connection refused**: this is auth/connectivity, NOT a module defect. Tell the user: "This appears to be a credentials or connectivity issue, not a module defect. Verify `DFORGE_URL` and `DFORGE_TOKEN` before re-running install." Do not backtrack to earlier phases.
|
|
50
67
|
|
|
51
|
-
|
|
68
|
+
## Resume-from-partial-state
|
|
52
69
|
|
|
53
|
-
|
|
70
|
+
At every session start, call `dforge_module_inspect` on the module dir (if it exists).
|
|
54
71
|
|
|
55
|
-
|
|
56
|
-
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
|
|
72
|
+
- If the dir doesn't exist or has no `manifest.json` → start fresh from Phase 0.
|
|
73
|
+
- If it does exist:
|
|
74
|
+
1. Read `_brief/00-intake.md` and `_brief/changelog.md` if present.
|
|
75
|
+
2. Cross-reference the inspect output against the brief to infer the last completed phase (e.g. entities exist + views exist + roles missing → last completed = Phase 3).
|
|
76
|
+
3. Summarize: "Found module `<code>` v`<version>`. Looks like Phase N was the last completed phase. Resume from Phase N+1, or revisit an earlier phase?"
|
|
77
|
+
4. Wait for the user's answer before proceeding.
|
|
60
78
|
|
|
61
|
-
|
|
79
|
+
## Phase 0 — Intake (required)
|
|
62
80
|
|
|
63
|
-
|
|
81
|
+
**Preconditions:** none.
|
|
64
82
|
|
|
65
|
-
|
|
83
|
+
**Action:** Walk through the questions below **one at a time, in sequence**. After each answer, apply the validate-and-reflect rule (hard rule #4): restate what you understood, confirm, then proceed to the next question. Each subsequent question is informed by prior answers — don't ask Q2 in a way that contradicts what Q1 established. Don't batch.
|
|
66
84
|
|
|
67
|
-
|
|
85
|
+
**Interaction style — free-form prose only.** Every question in Phase 0 is asked as a plain-language sentence in your conversation message. Do **NOT** use `AskUserQuestion`, picker UIs, multiple-choice tabs, structured forms, or any tool that presents the user with predefined options to choose from. The whole point of Phase 0 is to elicit the user's own words about purpose, user types, and verbs — predefined buckets bias the answer into your taxonomy and lose the verbs we need for Phase 5. If your client offers a picker tool, suppress it for Phase 0; resume normal tool use in Phase 1+.
|
|
68
86
|
|
|
69
|
-
|
|
87
|
+
**Forbidden picker examples that have leaked in past sessions** (do not present any variant of these):
|
|
88
|
+
- "Single role / Two roles / Three+ roles" — predetermines security shape before entities exist
|
|
89
|
+
- "admin / manager / user / viewer" or "admin / contributor / viewer" — imposes a generic taxonomy
|
|
90
|
+
- "English only / Multilingual" — answer in plain text instead
|
|
70
91
|
|
|
71
|
-
|
|
92
|
+
**Exception:** if the user explicitly says "give me defaults" / "pick reasonable defaults" / similar, you may propose a default brief in one block, restate it, and ask "any to override?". Otherwise, sequential free-form text only.
|
|
72
93
|
|
|
73
|
-
|
|
94
|
+
**Question order** (use the wording in your own voice):
|
|
74
95
|
|
|
75
|
-
|
|
96
|
+
1. **Purpose.** "In one sentence, what does this module do?"
|
|
97
|
+
Reflect: "OK — so it's a `<paraphrase>`. Right?" → wait.
|
|
76
98
|
|
|
77
|
-
|
|
99
|
+
2. **User types and verbs** — capture in plain language. "Who'll use this, and what does each type DO with it?" Listen for verbs that imply actions on data: submits, approves, reviews, issues, receives, matches, closes, etc.
|
|
78
100
|
|
|
79
|
-
|
|
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.
|
|
101
|
+
**Capture format — full verb-form sentences, not role labels.** Write each as `<descriptor of the person> <verb phrase>`. Never use role-noun labels (Requester, Manager, Buyer, Admin, Approver, Viewer, Contributor, AP Clerk, etc.) as the bullet head — those are role NAMES which prematurely commit to a security taxonomy.
|
|
82
102
|
|
|
83
|
-
|
|
103
|
+
✅ Good:
|
|
104
|
+
```
|
|
105
|
+
- Anyone in the company submits purchase requests and tracks their own.
|
|
106
|
+
- Department managers approve or reject pending requests for their team.
|
|
107
|
+
- Buyers in the procurement team manage suppliers, collect quotes, and issue purchase orders.
|
|
108
|
+
- Warehouse staff confirm what physically arrived against the PO.
|
|
109
|
+
- Accounts payable staff match supplier bills against the PO and receipt, then approve for payment.
|
|
110
|
+
```
|
|
84
111
|
|
|
85
|
-
|
|
112
|
+
❌ Bad (role labels as headings):
|
|
113
|
+
```
|
|
114
|
+
- **Requester** — submits purchase requests
|
|
115
|
+
- **Approver** — approves pending requests
|
|
116
|
+
- **Buyer** — manages suppliers
|
|
117
|
+
- **AP Clerk** — matches bills
|
|
118
|
+
```
|
|
119
|
+
The bad form trades situational verbs for fixed nouns and biases Phase 5 toward exactly those roles. Phase 5 might consolidate (e.g. one role covers both warehouse and AP) or split — that's Phase 5's job.
|
|
86
120
|
|
|
87
|
-
|
|
88
|
-
|
|
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.
|
|
121
|
+
Example missing verbs: "admins and users" — push back: "What does an admin do that a user can't?"
|
|
122
|
+
Reflect: "So users are: `<bullets>`. Right?" → wait.
|
|
92
123
|
|
|
93
|
-
|
|
124
|
+
**Hard forbidden in Phase 0:** do NOT emit role codes (`<code>.admin`, `<code>.requester`, etc.), do NOT use role-noun labels as bullet heads, do NOT propose a rights matrix, do NOT add a "Target user roles" section to the brief. Roles are derived from entities + verbs in Phase 5, and **entities don't exist yet**.
|
|
94
125
|
|
|
95
|
-
|
|
126
|
+
3. **Existing dForge modules to depend on.** "Are you building this on top of other dForge modules — e.g. needing entities from `crm` or `parties`?" (`admin` and `metadata` are platform-implicit. Don't ask about them. Don't even MENTION them in the brief — every module depends on them, so listing them in a per-module brief is pure noise.) If the user names actual deps, capture those; if not, the brief's Dependencies section should read literally `None.` or be omitted.
|
|
127
|
+
Reflect → wait.
|
|
96
128
|
|
|
97
|
-
|
|
98
|
-
|
|
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.
|
|
129
|
+
4. **Language scope.** "English only, or any other locales the module needs to ship with translations for?"
|
|
130
|
+
Reflect → wait.
|
|
100
131
|
|
|
101
|
-
|
|
132
|
+
5. **Optional follow-up — domain ambiguities.** If anything in answers 1-4 left an open question (e.g. "what counts as a 'closed' feedback item?", "is the submitter always a logged-in user or also anonymous?"), ask that question now, one at a time. Continue until you can describe how the module should work without any open questions in your head. **Goal of Phase 0: you understand the module well enough to design entities in Phase 1 without further clarification.**
|
|
133
|
+
|
|
134
|
+
**Write:** `_brief/00-intake.md` after the final reflection. **Allowed sections (exhaustive):**
|
|
135
|
+
- `# <module-name> — intake`
|
|
136
|
+
- `## Purpose` (one paragraph)
|
|
137
|
+
- `## Module identity` (code, display name, target path)
|
|
138
|
+
- `## User types` (bullet list — `<type> — <verbs>`. NO role codes, NO rights, NO "Target user roles" table.)
|
|
139
|
+
- `## Dependencies` (which dForge modules)
|
|
140
|
+
- `## Languages`
|
|
141
|
+
- `## Scope / success criteria` (only if mentioned by user)
|
|
142
|
+
- `## Open assumptions` (anything you flagged + need to revisit in Phase 1)
|
|
143
|
+
|
|
144
|
+
**Forbidden sections in the brief:** any roles table, any entity proposal (entities are Phase 1's deliverable, not Phase 0's). If you find yourself drafting a "Target user roles" table — stop and replace it with the verb-only bullet list.
|
|
145
|
+
|
|
146
|
+
**Final gate:** Show the brief verbatim, ask "Does this capture everything? Anything to fix or add?". Proceed only on explicit confirmation. The next message you send after confirmation should be the start of Phase 1 — proposing the entity inventory.
|
|
147
|
+
|
|
148
|
+
## Phase 1 — Domain (required)
|
|
149
|
+
|
|
150
|
+
**Preconditions:** intake brief written and confirmed.
|
|
151
|
+
|
|
152
|
+
**This phase's FIRST deliverable — before any tool call — is the proposed entity inventory.** Show it. Get explicit sign-off. Then scaffold. The user needs to see "the module will have these N things in it" before files exist, because entities are the spine the rest of the module hangs from (views, actions, roles all reference entity codes).
|
|
153
|
+
|
|
154
|
+
**Sub-steps:**
|
|
155
|
+
|
|
156
|
+
1. **Propose the entity inventory.** Re-read `_brief/00-intake.md`'s purpose and user-verbs sections. Derive an entity list: each meaningful "thing the user verbs against" tends to become an entity. Present as:
|
|
157
|
+
```
|
|
158
|
+
Proposed entities (N):
|
|
159
|
+
- <entity_code> — <one-line description, ties to a verb / use case from intake>
|
|
160
|
+
- ...
|
|
161
|
+
```
|
|
162
|
+
Apply the validate-and-reflect rule: "Here's what I think the module needs. Right shape and scope? Add / remove / merge?" Loop with the user until they explicitly approve the list.
|
|
163
|
+
|
|
164
|
+
Write the approved inventory to `_brief/01-domain.md`.
|
|
165
|
+
|
|
166
|
+
2. **Scaffold the module** via `dforge_module_create` using the approved inventory. Preview the file map, get approval, then user writes.
|
|
167
|
+
|
|
168
|
+
3. **Per-entity loop.** For each entity in order, propose fields + traits + references. **Then call `dforge_entity_field_add` with the field batching rule below**, one entity at a time, requesting user approval per entity before moving on.
|
|
169
|
+
|
|
170
|
+
4. **Extension entities last.** If extending another module's entity, use `extends: "module.entity"`, `toString: null` (inherits base), and a dotted manifest key. **Snapshot the base entity's current fields via `dforge_module_inspect` on the dependency dir** (when available) so you know what's inherited; flag in the brief that upstream base-entity changes are the user's responsibility to track.
|
|
171
|
+
|
|
172
|
+
**Field batching rule** (the only Phase-1 exception to the hard rule):
|
|
173
|
+
|
|
174
|
+
A field is **batchable** only if ALL of these are true: scalar primitive (string / integer / decimal / boolean / date), no FK or Reference, no `formula`, and the nullability is unambiguous (e.g. required-not-null per intake context). Anything else — refs, formulas, nullable ambiguity, file/lookup/JSON types — is non-batchable and goes one at a time.
|
|
175
|
+
|
|
176
|
+
**Exit criteria:** every entity has at least PK + audit traits + 1 user-visible field; FK references resolve; manifest's `entities` map reflects reality.
|
|
177
|
+
|
|
178
|
+
## Phase 2 — Actions (optional, skip-able)
|
|
179
|
+
|
|
180
|
+
**Preconditions:** Phase 1 complete.
|
|
181
|
+
|
|
182
|
+
Skip entirely if the module is pure CRUD. Do **not** fabricate actions to fill the phase.
|
|
183
|
+
|
|
184
|
+
When the user has a real business operation: **load `dforge://docs/dsl`** (the full action DSL reference — block structure, all 30 built-in functions, field-access syntax, batch-mode rules, JS subset, pitfalls), then call `dforge_action_add` per action — one at a time — with the full DSL body. `dforge://docs/conventions` is broader module-level guidance and does NOT cover the DSL grammar — load `docs/dsl` specifically.
|
|
185
|
+
|
|
186
|
+
**Exit criteria:** every action you added is intended, named, and has params/canExecute/execute blocks. Compilation is validated in Phase 6.
|
|
187
|
+
|
|
188
|
+
## Phase 3 — Views (required) + Reports (optional)
|
|
189
|
+
|
|
190
|
+
**Preconditions:** Phase 1 complete.
|
|
191
|
+
|
|
192
|
+
### 3a. Default grids (required, do FIRST)
|
|
193
|
+
|
|
194
|
+
For every entity in the manifest, call `dforge_view_add` with `viewType: "grid"` and `dataSources: [{ entityCode: <entity>, columns: [...] }]`.
|
|
195
|
+
|
|
196
|
+
**View naming.** View codes in `ui/data_views.json` are semantic — convention is the entity name (`feedback_item`), the plural (`invoices`), or descriptive (`invoices_kanban`, `feedback_by_status`). Do NOT use the literal code `default`. When `ui/folders.json` entities reference `viewName: "default"`, the platform resolves that to the entity's first view declared in `data_views.json` — it's a fallback alias, not a required view code. (The scaffolder already wrote a default grid keyed by entity code in Phase 1, so often you'll `view_modify` it rather than `view_add`.)
|
|
197
|
+
|
|
198
|
+
**Do not propose any specialized view until every entity has its default grid.**
|
|
199
|
+
|
|
200
|
+
### 3b. Specialized views (optional, only after 3a complete)
|
|
201
|
+
|
|
202
|
+
Propose a specialized view (kanban / calendar / list-with-levels / tree-grid / master-detail) **only when one of these objective triggers fires**:
|
|
203
|
+
|
|
204
|
+
- The user explicitly mentioned the visualization ("show leads as a kanban", "we need a calendar for tasks").
|
|
205
|
+
- The entity has a status / stage / kind field with **3 or more discrete values** in a dropdown — kanban candidate.
|
|
206
|
+
- The entity has a required date/time field intended for scheduling — calendar candidate.
|
|
207
|
+
- The entity self-references (parent FK to itself) — tree-grid candidate.
|
|
208
|
+
- The entity has a 1:N detail child with `parentSetField` declared — list-with-levels or master-detail candidate.
|
|
209
|
+
|
|
210
|
+
If none of these fire, skip specialized views for that entity. Read `dforge://schema/data-views` for the `viewConfig` shape of the type you're proposing before calling `dforge_view_add`.
|
|
211
|
+
|
|
212
|
+
### 3c. Reports (optional)
|
|
213
|
+
|
|
214
|
+
Add reports only when management aggregation/grouping isn't covered by views. `dforge_report_add` with layout + datasets (Query type with entityCd + filter + sort, or Stored Procedure). Pull `dforge://schema/reports` first.
|
|
215
|
+
|
|
216
|
+
**Exit criteria:** every entity has a default grid; every specialized view has a stated trigger; reports cover the stated reporting use cases.
|
|
217
|
+
|
|
218
|
+
## Phase 4 — Polish: settings, translations, seed (mostly optional)
|
|
219
|
+
|
|
220
|
+
**Preconditions:** Phase 3 complete.
|
|
221
|
+
|
|
222
|
+
- **Settings**: `dforge_setting_add` per configurable value the user requested.
|
|
223
|
+
- **Translations** (required if intake declared non-English locales): files under `translations/<locale>.json`. **If the user defers translation authoring, append to `_brief/changelog.md`: "Translation files for [locales] are incomplete. Phase 6 install will fail translation completeness validation until added." Remind the user before calling `dforge_module_pack`.**
|
|
224
|
+
- **Seed data**: only when the module needs reference data on install.
|
|
225
|
+
|
|
226
|
+
**Exit criteria:** any configurable value the user requested is exposed as a setting; if non-English locales were declared, translations exist OR the deferral warning is logged.
|
|
227
|
+
|
|
228
|
+
## Phase 5 — Security
|
|
229
|
+
|
|
230
|
+
**Preconditions:** Phases 1, 3 complete (you need entity/view/action/report codes to grant rights on).
|
|
231
|
+
|
|
232
|
+
### 5a. Roles + rights matrix (required)
|
|
233
|
+
|
|
234
|
+
1. **Inspect first.** Run `dforge_module_inspect` and read the `roles` array. The scaffolder pre-creates `<code>.admin` with `SIUDC` on every entity declared at scaffold time. That role exists already — don't try to re-create it.
|
|
235
|
+
2. **Derive role inventory FROM the intake's user types and verbs — never default to a fixed taxonomy.** Re-read `_brief/00-intake.md`'s "users" section. For each distinct user type, propose ONE role named `<code>.<user-type>` (e.g. intake said "any signed-in user submits + admins triage" → `<code>.user` (covers the "submits" verb) + the existing scaffolded `<code>.admin` (covers triage). If intake mentioned "approvers" or "auditors" or "managers" or any other group, derive roles for those too.) **Forbidden:** spinning up a generic `admin/contributor/viewer` matrix when the user didn't ask for it. The rights set should map to the verbs each user type does, not to a textbook role hierarchy.
|
|
236
|
+
3. Reflect the proposed role list back to the user before computing rights: "Based on intake, I see these user types → these roles: `<list>`. Right?" Get explicit confirmation. If the user clarifies / adds / removes, re-list and re-confirm.
|
|
237
|
+
4. Show the rights matrix as a table (rows = entities/actions/reports, columns = the confirmed roles, cells = rights string). Each cell explained by the verb-to-right mapping you derived. Get user sign-off on the matrix.
|
|
238
|
+
5. **For new roles**: call `dforge_role_add`. **For amending existing roles** (the scaffolded admin, or grants on actions/reports added in Phases 2-3 that aren't yet in any role): call `dforge_role_right_set` per grant — it's the smallest tool and doesn't conflict with the scaffolded admin role. Calling `dforge_role_add` against an existing role code fails — use `role_right_set` to amend instead.
|
|
239
|
+
|
|
240
|
+
**Rights semantics** (additive — multiple roles UNION, never revoke):
|
|
241
|
+
- Entities: any subset of `SIUDC` (Select / Insert / Update / Delete / Clone)
|
|
242
|
+
- Actions / reports: `E` (Execute), or omit to deny
|
|
243
|
+
|
|
244
|
+
### 5b. Security folders (optional)
|
|
245
|
+
|
|
246
|
+
Only if intake said data must be partitioned per folder (multi-warehouse, multi-region, multi-tenant-like). Default: root only.
|
|
247
|
+
|
|
248
|
+
If needed: `dforge_folder_add` per sub-folder, passing `entities` with `rowFilter` (SQL string OR canonical `{c,o,v}` / `{g,i:[]}` filter).
|
|
249
|
+
|
|
250
|
+
**Exit criteria:** every entity is reachable to at least one role; if folders declared, every folder has security mapped.
|
|
251
|
+
|
|
252
|
+
## Phase 6 — Verify (required, non-skippable)
|
|
253
|
+
|
|
254
|
+
**Preconditions:** all **required** prior phases complete. Optional phases (2, 3c reports, 4 settings/seed, 5b folders) are not preconditions — explicitly skipped optional phases do not block Phase 6.
|
|
255
|
+
|
|
256
|
+
**Steps:**
|
|
257
|
+
|
|
258
|
+
1. `dforge_module_pack` → produces `.dforge` tarball.
|
|
259
|
+
2. `dforge_module_install` with `DFORGE_URL` / `DFORGE_TOKEN`. Runs the full server-side validator.
|
|
260
|
+
3. **If install fails on a module defect** (schema, FK, missing translation, etc.), the error message tells you which phase to backtrack to. Use the backtrack protocol.
|
|
261
|
+
4. **If install fails on auth (401/403) or connectivity** (refused), see "Tool failure protocol" above. Do not backtrack — fix credentials.
|
|
262
|
+
|
|
263
|
+
**Exit criteria:** install exits 0 against a real tenant.
|
|
264
|
+
|
|
265
|
+
## Backtrack protocol
|
|
266
|
+
|
|
267
|
+
When a later phase exposes a problem in an earlier phase, follow steps 1–6 IN ORDER:
|
|
268
|
+
|
|
269
|
+
**Multi-trigger rule (deterministic):** If multiple phases simultaneously expose gaps in earlier phases (e.g. Phase 3 needs a field; Phase 5 needs an action), resolve the **earliest-phase gap first**, complete its full backtrack, run `dforge_module_inspect`, then evaluate remaining gaps.
|
|
270
|
+
|
|
271
|
+
1. **Stop the current phase.** Don't paper over or improvise.
|
|
272
|
+
2. **Name the issue precisely.** "Phase 3 wants a kanban grouped by `lead_status`, but Phase 1 didn't define `lead_status` on entity `lead`."
|
|
273
|
+
3. **Identify the target phase + decision.** "Backtrack to Phase 1: add field `lead_status` to entity `lead`."
|
|
274
|
+
4. **Get user sign-off.** Describe the change including any cascading impacts.
|
|
275
|
+
5. **Apply the smallest tool that fits.** This rule overrides the "typical phase" labels in the tool reference table. Prefer `entity_field_add` over `entity_add`; `role_right_set` over `role_add`; `view_modify` over `view_add` + remove.
|
|
276
|
+
6. **Run `dforge_module_inspect` again** to surface knock-on impacts. Fix in order. Resume the original phase.
|
|
277
|
+
|
|
278
|
+
**Entity rename or deletion specifically requires cascade discovery:**
|
|
279
|
+
|
|
280
|
+
Before applying:
|
|
281
|
+
1. Run `dforge_module_inspect` to enumerate every reference: views' `dataSources.entityCode`, role `rights` keys, action `entity`, report dataset `entityCd`, seed-data files, formula/DSL bodies.
|
|
282
|
+
2. List every affected artifact to the user. Require explicit confirmation.
|
|
283
|
+
3. Apply in **reverse dependency order**: roles → reports → views → actions → entity itself.
|
|
284
|
+
4. Re-inspect; verify no dangling references remain.
|
|
285
|
+
|
|
286
|
+
**After every backtrack** append to `_brief/changelog.md`:
|
|
287
|
+
|
|
288
|
+
```markdown
|
|
289
|
+
## <YYYY-MM-DD> — Phase N → Phase M backtrack
|
|
290
|
+
- Trigger: <what later phase tried to do>
|
|
291
|
+
- Change: <what was patched>
|
|
292
|
+
- Affected files: <list>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Final hygiene
|
|
296
|
+
|
|
297
|
+
After Phase 6 install succeeds:
|
|
102
298
|
|
|
103
|
-
|
|
299
|
+
**Ask the user**: "Delete `_brief/` (session scratch) or move it to `docs/` for committed design rationale?". Wait for their answer; do not act unilaterally.
|
|
104
300
|
|
|
105
|
-
|
|
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)
|
|
301
|
+
Suggest a `git commit` summarizing the module. Do not commit unless the user asks.
|