@shanyucoder/flowgrid 0.1.5 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +1 -1
  2. package/adapters/laravel/registries/codegen.registry.json +9 -9
  3. package/bin/flowgrid.mjs +326 -115
  4. package/bin/lib/agent-mcp.mjs +4 -0
  5. package/bin/lib/agent-profiles.mjs +30 -6
  6. package/bin/lib/audit-run.mjs +1 -1
  7. package/bin/lib/cli-update.mjs +48 -8
  8. package/bin/lib/doctor.mjs +90 -3
  9. package/bin/lib/harness-overlay.mjs +12 -5
  10. package/bin/lib/harness-sync.mjs +17 -3
  11. package/bin/lib/init-adapters.mjs +75 -0
  12. package/bin/lib/init-scaffold.mjs +9 -0
  13. package/bin/lib/inject-consumer-scripts.mjs +115 -0
  14. package/bin/lib/merge-stack-config.mjs +89 -0
  15. package/bin/lib/project-gitignore.mjs +1 -0
  16. package/bin/lib/repo-maps-align.mjs +203 -0
  17. package/dist/graph/config/load-config.js +7 -2
  18. package/dist/graph/config/load-config.js.map +1 -1
  19. package/dist/graph/mcp/tools.js +1 -1
  20. package/dist/graph/mcp/tools.js.map +1 -1
  21. package/dist/graph/registry/load-registries.d.ts +1 -0
  22. package/dist/graph/registry/load-registries.js +14 -1
  23. package/dist/graph/registry/load-registries.js.map +1 -1
  24. package/engines/cases/render-cases.mjs +67 -5
  25. package/engines/docs/lib/render-api-summary-markdown.mjs +28 -0
  26. package/engines/docs/lib/render-bundle-markdown.mjs +77 -2
  27. package/engines/docs/lib/render-data-model-markdown.mjs +171 -0
  28. package/engines/docs/lib/render-design-tables.mjs +89 -7
  29. package/engines/docs/lib/render-template.mjs +6 -0
  30. package/engines/docs/render-docs.mjs +6 -2
  31. package/engines/docs/vitepress/config.ts +7 -7
  32. package/engines/docs/vitepress/surfaces-nav.mjs +45 -14
  33. package/engines/openapi/check-backend-spec.mjs +2 -2
  34. package/engines/openapi/lib/markdown-table.mjs +8 -0
  35. package/engines/openapi/lib/render-backend-spec-markdown.mjs +78 -0
  36. package/engines/registry-sync/be-capabilities-sync.mjs +118 -0
  37. package/engines/registry-sync/fe-design-sync.mjs +258 -0
  38. package/engines/registry-sync/run-registry-sync.mjs +107 -0
  39. package/engines/shared/e2e-output-layout.mjs +68 -0
  40. package/engines/shared/flowgrid-e2e-root.mjs +19 -0
  41. package/engines/shared/resolve-flowgrid-context.mjs +176 -0
  42. package/engines/spec/lib/audit-api-gaps.mjs +1 -1
  43. package/engines/spec/lib/audit-bundle-gaps.mjs +92 -3
  44. package/engines/spec/lib/audit-db-tables.mjs +529 -0
  45. package/engines/spec/lib/audit-e2e-coverage.mjs +88 -30
  46. package/engines/spec/lib/bundle-schema.mjs +4 -1
  47. package/engines/spec/split-bundle.mjs +11 -1
  48. package/engines/testcase/runners/generate-api.mjs +23 -23
  49. package/engines/testcase/runners/generate.mjs +19 -17
  50. package/engines/testcase/runners/lib/bootstrap-context.mjs +44 -0
  51. package/engines/testcase/runners/lib/write-files.mjs +37 -9
  52. package/harness/agents/antigravity/rules/antigravity-mcp.mdc +12 -0
  53. package/harness/agents/gemini/rules/gemini-mcp.mdc +11 -0
  54. package/harness/agents/gemini_antigravity/rules/antigravity-mcp.mdc +8 -6
  55. package/harness/be/skills/{grill-api → audit-api}/SKILL.md +8 -7
  56. package/harness/common/extracts/artifact-graph.md +2 -2
  57. package/harness/common/extracts/artifactgraph-phase-hooks.md +2 -2
  58. package/harness/common/extracts/docs-mark-detect.md +2 -2
  59. package/harness/common/extracts/entity-relationship.md +23 -0
  60. package/harness/common/rules/flowgrid-ux-common.mdc +3 -3
  61. package/harness/common/skills/configure-repo-maps/SKILL.md +4 -2
  62. package/harness/docs/extracts/agent-execution-protocol.md +1 -1
  63. package/harness/docs/extracts/api-codegen-readiness.md +34 -0
  64. package/harness/docs/extracts/api-codegen-tags.md +30 -0
  65. package/harness/docs/extracts/api-contract.md +43 -0
  66. package/harness/docs/extracts/api-spec-sync.md +35 -0
  67. package/harness/docs/extracts/artifactgraph-hooks-docs.md +1 -1
  68. package/harness/docs/extracts/call-external.md +16 -0
  69. package/harness/docs/extracts/common-scope.md +9 -10
  70. package/harness/docs/extracts/db-audit-wizard.md +45 -0
  71. package/harness/docs/extracts/derived-data.md +18 -0
  72. package/harness/docs/extracts/design-leaf-signoff.md +16 -0
  73. package/harness/docs/extracts/extract-registry.docs.json +9 -1
  74. package/harness/docs/extracts/spec-core.md +7 -3
  75. package/harness/docs/extracts/spec-evolution.md +21 -0
  76. package/harness/docs/extracts/spec-prd-lite.md +19 -0
  77. package/harness/docs/extracts/spec-requirement.md +6 -2
  78. package/harness/docs/extracts/spec-ssot-prep.md +25 -0
  79. package/harness/docs/extracts/tpl-module.md +12 -0
  80. package/harness/docs/extracts/verify-gate.md +33 -0
  81. package/harness/docs/extracts/wire-spec-feedback.md +31 -0
  82. package/harness/docs/rules/agent-compliance.mdc +1 -1
  83. package/harness/docs/rules/team-flow-spec.mdc +3 -4
  84. package/harness/docs/skills/adopt/SKILL.md +2 -0
  85. package/harness/docs/skills/api/SKILL.md +4 -5
  86. package/harness/docs/skills/api-spec/SKILL.md +19 -6
  87. package/harness/docs/skills/api-update/SKILL.md +3 -3
  88. package/harness/docs/skills/architecture/SKILL.md +1 -1
  89. package/harness/docs/skills/business-process/SKILL.md +2 -0
  90. package/harness/docs/skills/common/SKILL.md +2 -2
  91. package/harness/docs/skills/common-spec/SKILL.md +10 -47
  92. package/harness/docs/skills/db-erd/SKILL.md +26 -0
  93. package/harness/docs/skills/grill/SKILL.md +28 -22
  94. package/harness/docs/skills/grill-api/SKILL.md +4 -6
  95. package/harness/docs/skills/grill-api-spec/SKILL.md +44 -24
  96. package/harness/docs/skills/grill-bqa/SKILL.md +28 -13
  97. package/harness/docs/skills/grill-common-spec/SKILL.md +10 -35
  98. package/harness/docs/skills/grill-dev/SKILL.md +7 -6
  99. package/harness/docs/skills/grill-docs/SKILL.md +10 -3
  100. package/harness/docs/skills/module/SKILL.md +3 -1
  101. package/harness/docs/skills/openapi/SKILL.md +2 -1
  102. package/harness/docs/skills/overview/SKILL.md +7 -1
  103. package/harness/docs/skills/spec/SKILL.md +42 -9
  104. package/harness/docs/skills/update-spec/SKILL.md +4 -1
  105. package/harness/fe/extracts/wire-audit-loop.md +72 -0
  106. package/harness/fe/extracts/wire-phase.md +45 -0
  107. package/harness/fe/rules/platform-design-vocabulary.mdc +1 -1
  108. package/harness/fe/rules/team-flow-prototype.mdc +8 -4
  109. package/harness/fe/skills/gen-common/SKILL.md +11 -84
  110. package/harness/fe/skills/grill-prototype/SKILL.md +51 -25
  111. package/harness/fe/skills/grill-test/SKILL.md +78 -20
  112. package/harness/fe/skills/grill-wire/SKILL.md +81 -0
  113. package/harness/fe/skills/prototype/SKILL.md +3 -2
  114. package/harness/fe/skills/wire/SKILL.md +7 -2
  115. package/harness/shared/AGENTS.md +3 -3
  116. package/harness/shared/SSOT_AGENT_PROTOCOL.md +3 -3
  117. package/harness/tests/extracts/grill-api-hook.md +69 -0
  118. package/harness/tests/extracts/grill-scenario-flow.md +39 -0
  119. package/harness/tests/extracts/grill-screen-tc.md +40 -0
  120. package/harness/tests/extracts/testcase-gen-cli.md +57 -0
  121. package/harness/tests/extracts/testcase-plan.md +29 -0
  122. package/harness/tests/extracts/tests-verify-gate.md +29 -0
  123. package/harness/tests/extracts/wire-test-handoff.md +37 -0
  124. package/harness/tests/skills/grill-testcase/SKILL.md +1 -0
  125. package/harness/tests/skills/test-api/SKILL.md +14 -6
  126. package/harness/tests/skills/testcase/SKILL.md +3 -1
  127. package/harness/tests/templates/TC.example-api.yaml +7 -1
  128. package/harness/tests/templates/TC.example.yaml +4 -1
  129. package/harness/tests/templates/tpl-testcase-plan.md +75 -0
  130. package/package.json +1 -1
  131. package/stacks/fastapi.json +1 -0
  132. package/stacks/laravel.json +1 -0
  133. package/stacks/nestjs.json +72 -0
  134. package/stacks/nextjs-nest.json +1 -0
  135. package/stacks/nuxt4-nest.json +1 -0
  136. package/templates/project-skeleton/architecture/03-business-process/FLOW-template.md +2 -0
  137. package/templates/project-skeleton/overview/index.md +68 -2
  138. package/templates/project-skeleton/overview/operational-areas/_template.md +37 -0
  139. package/templates/project-skeleton/surfaces/common/data-model/index.md +10 -2
  140. package/templates/shared/api-03-mock.stub.yaml +14 -0
  141. package/templates/shared/backend-api.bundle.yaml +3 -0
  142. package/templates/shared/backend-api.yaml +4 -0
  143. package/templates/shared/be-capabilities.registry.base.json +8 -0
  144. package/templates/shared/bundle-authoring.md +39 -3
  145. package/templates/shared/default-layout.ejs +131 -18
  146. package/templates/shared/design-spec.yaml +2 -3
  147. package/templates/shared/design.registry.base.json +38 -0
  148. package/templates/shared/feature.bundle.yaml +16 -9
  149. package/templates/shared/ir/generated/spec.md +281 -0
  150. package/templates/shared/qa-item.yaml +1 -1
  151. package/templates/shared/tpl-api-contract.md +133 -0
  152. package/templates/shared/tpl-screen-data-model.md +76 -0
  153. package/templates/tests-skeleton/cases/README.md +4 -0
  154. package/templates/tests-skeleton/catalog/locale.yaml +9 -0
  155. package/templates/tests-skeleton/tpl-testcase-plan.md +9 -0
  156. package/harness/docs/skills/api-integration/SKILL.md +0 -110
  157. package/harness/docs/skills/grill-integration-spec/SKILL.md +0 -51
@@ -1,5 +1,64 @@
1
+ <%
2
+ const pageId = spec['page-id'] || spec.id || '';
3
+ const docStatus = spec.status || 'draft';
4
+ const docOwner = spec.owner || '';
5
+ const hasMetrics = spec.successMetrics && String(spec.successMetrics).trim();
6
+ const hasNonGoals = spec.nonGoals && String(spec.nonGoals).trim();
7
+ const hasStories = !!spec.userStories;
8
+ const pageSections = spec.sections || spec.design?.sections || [];
9
+ const pageActions = spec.actions || spec.design?.actions || [];
10
+ const pageStateMatrix = spec.stateMatrix || spec.design?.stateMatrix;
11
+ const hasState = !!pageStateMatrix;
12
+ const listUi = spec.ui?.list || {};
13
+ const hasListColumns = !!(context.renderListColumnsTable && context.renderListColumnsTable(listUi));
14
+ const hasListFilters = !!(context.renderListFiltersTable && context.renderListFiltersTable(listUi));
15
+ const hasListPagination = !!(listUi.pagination && typeof listUi.pagination === 'object');
16
+ const hasListExtras = hasListFilters || hasListPagination;
17
+ const hasValidation = !!(context.renderValidationDictionaryTable && context.renderValidationDictionaryTable(pageSections));
18
+ const hasCustomWidget = !!(context.renderCustomWidgetSpecs && context.renderCustomWidgetSpecs(pageSections));
19
+ const hasActions = pageActions && pageActions.length;
20
+ const hasReview = spec.review && (spec.review.layoutNotes || spec.review.summary);
21
+ const hasLegacy = spec.legacy && (spec.legacy.behaviors?.length || spec.legacy.fields?.length || spec.legacy.evidence?.length);
22
+ const hasDebt = spec.pendingTechDebt && spec.pendingTechDebt.length;
23
+
24
+ const toc = [];
25
+ toc.push('1. [Tổng quan](#overview)');
26
+ if (hasMetrics) toc.push('2. [Chỉ số thành công](#success-metrics)');
27
+ if (hasNonGoals) toc.push('3. [Phạm vi không làm](#non-goals)');
28
+ if (hasStories) toc.push('4. [User stories và hành trình màn hình](#user-stories--screen-journey)');
29
+ if (hasState) toc.push('5. [Ma trận trạng thái và phân quyền](#state--permission-matrix)');
30
+ if (hasListColumns) toc.push('6. [Bảng cột danh sách](#list-columns)');
31
+ if (hasListExtras) toc.push('6b. [Bộ lọc & phân trang](#list-filters-pagination)');
32
+ if (hasValidation) toc.push(`${hasListColumns || hasListExtras ? '7' : '6'}. [Từ điển dữ liệu và validation](#data-dictionary--validation)`);
33
+ if (hasCustomWidget) toc.push(`${hasListColumns ? '8' : '7'}. [Widget tùy biến](#custom-widgets)`);
34
+ const actionNum = hasListColumns ? (hasCustomWidget ? '9' : '8') : (hasCustomWidget ? '8' : '7');
35
+ if (hasActions) toc.push(`${actionNum}. [Luồng hành động](#action-flows)`);
36
+ else if (pageSections.length) toc.push(`${actionNum}. [Bố cục màn hình](#page-composition)`);
37
+ if (hasReview) toc.push('9. [Ghi chú review](#review-notes)');
38
+ if (hasLegacy) toc.push('10. [Legacy evidence](#legacy-evidence)');
39
+ if (hasDebt) toc.push('11. [Tech debt](#pending-tech-debt)');
40
+ toc.push('- [API SSOT](#api-ssot)');
41
+
42
+ const route = spec.ui?.routes?.[0];
43
+ const routePath = route?.path || '';
44
+ const testId = route?.pageTestId || '';
45
+ %>
1
46
  # <%= spec.title || spec.id %>
2
47
 
48
+ ## Mục lục (Contents)
49
+
50
+ <%= toc.join('\n') %>
51
+
52
+ ---
53
+
54
+ ## Tổng quan {#overview}
55
+
56
+ | | |
57
+ | --- | --- |
58
+ | **Page ID** | `<%= pageId || '—' %>` |
59
+ | **Status** | <%= docStatus %> |
60
+ | **Owner** | <%= docOwner || '—' %> |
61
+
3
62
  <% if (context.testcases && context.testcases.length) { %>
4
63
  - **Testcase plans:** <%= context.testcases.map(tc => '`' + (tc.data.title || tc.data.id || tc.file) + '`').join(' · ') %> (hub: [base_test](https://github.com/raintr91/base_test))
5
64
  <% } else { %>
@@ -7,24 +66,45 @@
7
66
  <% } %>
8
67
 
9
68
  <%
10
- const route = spec.ui?.routes?.[0];
11
- const path = route?.path || '';
12
- const testId = route?.pageTestId || '';
13
69
  let screenLine = '- **Screen:** None';
14
- if (path) {
15
- const screen = context.renderScreenLink ? context.renderScreenLink(path) : '`' + path + '`';
70
+ if (routePath) {
71
+ const screen = context.renderScreenLink ? context.renderScreenLink(routePath) : '`' + routePath + '`';
16
72
  const suffix = testId ? ` · \`${testId}\`` : '';
17
73
  screenLine = `- **Screen:** ${screen}${suffix}`;
18
74
  }
19
75
  %>
20
76
  <%= screenLine %>
21
77
 
78
+ - **QA inbox:** [Danh sách câu hỏi treo](../../qa/index.md) (cùng function leaf)
79
+ - **Generated (VitePress):** [spec](./spec.md) · [data-model](./data-model.md) · [api](./api.md) _(khi có `01`)_
80
+
22
81
  <% if (spec.summary) { %>
23
82
  <%= spec.summary %>
24
83
  <% } %>
25
84
 
85
+ <% if (hasMetrics) { %>
86
+ ## Chỉ số thành công {#success-metrics}
87
+
88
+ <%= spec.successMetrics %>
89
+
90
+ <% } %>
91
+
92
+ <% if (hasNonGoals) { %>
93
+ ## Phạm vi không làm {#non-goals}
94
+
95
+ <%= spec.nonGoals %>
96
+
97
+ <% } %>
98
+
99
+ ## API SSOT {#api-ssot}
100
+
101
+ Hợp đồng backend: `api/<seq>/01-backend-spec.yaml` trong cùng function leaf (không gộp vào bundle). Sau split: `ir/design.yaml` chiếu endpoint; OpenAPI/mock theo stack.
102
+
103
+ - **Data model (review, multi-table):** [data-model.md](./data-model.md) — bảng/cột; SSOT codegen = `01` + `ir/design.yaml` `db`.
104
+ - **API (đọc trên site):** [api.md](./api.md) — tóm tắt endpoint từ `01-backend-spec.yaml` (khi có file).
105
+
26
106
  <% if (spec.userStories) { %>
27
- ## User Stories & Screen Journey
107
+ ## User Stories & Screen Journey {#user-stories--screen-journey}
28
108
 
29
109
  <% if (typeof spec.userStories === 'string') { %>
30
110
  <%= spec.userStories %>
@@ -114,11 +194,6 @@
114
194
  <% } %>
115
195
 
116
196
  <%
117
- // 1. Executive Summary & Screen Journey
118
- const pageSections = spec.sections || spec.design?.sections || [];
119
- const pageActions = spec.actions || spec.design?.actions || [];
120
- const pageStateMatrix = spec.stateMatrix || spec.design?.stateMatrix;
121
-
122
197
  const page = {
123
198
  nav: spec.nav || spec.design?.nav,
124
199
  sections: pageSections,
@@ -129,17 +204,51 @@
129
204
  %>
130
205
 
131
206
  <% if (pageStateMatrix) { %>
132
- ## Ma Trận Trạng Thái Giao Diện & Phân Quyền (State & Permission Matrix)
207
+ ## Ma Trận Trạng Thái Giao Diện & Phân Quyền (State & Permission Matrix) {#state--permission-matrix}
133
208
 
134
209
  <%- context.renderStateMatrixTable(pageStateMatrix) %>
135
210
 
136
211
  <% } %>
137
212
 
213
+ <%
214
+ const listColumnsMd = context.renderListColumnsTable && context.renderListColumnsTable(listUi);
215
+ if (listColumnsMd) {
216
+ %>
217
+ ## Bảng cột danh sách (List columns) {#list-columns}
218
+
219
+ <%- listColumnsMd %>
220
+
221
+ <p><strong>DB chi tiết / multi-table:</strong> <a href="./data-model.md">data-model.md</a> · SSOT ghi: <code>*.bundle.yaml</code> + <code>ir/design.yaml</code>.</p>
222
+
223
+ <% } %>
224
+
225
+ <%
226
+ const filtersMd = context.renderListFiltersTable && context.renderListFiltersTable(listUi);
227
+ const paginationMd = context.renderListPaginationBlock && context.renderListPaginationBlock(listUi);
228
+ if (filtersMd || paginationMd) {
229
+ %>
230
+ ## Bộ lọc & phân trang (List filters & pagination) {#list-filters-pagination}
231
+
232
+ <% if (filtersMd) { %>
233
+ ### Bộ lọc
234
+
235
+ <%- filtersMd %>
236
+
237
+ <% } %>
238
+ <% if (paginationMd) { %>
239
+ ### Phân trang
240
+
241
+ <%- paginationMd %>
242
+
243
+ <% } %>
244
+
245
+ <% } %>
246
+
138
247
  <%
139
248
  const validationTableMd = context.renderValidationDictionaryTable(pageSections);
140
249
  if (validationTableMd) {
141
250
  %>
142
- ## Danh Mục Trường Nhập Liệu & Quy Tắc Kiểm Tra Hợp Lệ (Data Dictionary & Validation)
251
+ ## Danh Mục Trường Nhập Liệu & Quy Tắc Kiểm Tra Hợp Lệ (Data Dictionary & Validation) {#data-dictionary--validation}
143
252
 
144
253
  <%- validationTableMd %>
145
254
 
@@ -149,6 +258,8 @@
149
258
  const customWidgetMd = context.renderCustomWidgetSpecs(pageSections);
150
259
  if (customWidgetMd) {
151
260
  %>
261
+ <div id="custom-widgets"></div>
262
+
152
263
  <%- customWidgetMd %>
153
264
 
154
265
  <% } %>
@@ -157,17 +268,19 @@
157
268
  const actionFlowsMd = context.renderActionFlowsDetailed(pageActions);
158
269
  if (actionFlowsMd) {
159
270
  %>
160
- ## Đặc Tả Quy Trình Hành Động (Action Flows)
271
+ ## Đặc Tả Quy Trình Hành Động (Action Flows) {#action-flows}
161
272
 
162
273
  <%- actionFlowsMd %>
163
274
 
164
275
  <% } else { %>
276
+ ## Bố cục màn hình {#page-composition}
277
+
165
278
  <%- context.renderPageComposition(page, { businessOnly: true }) %>
166
279
  <% } %>
167
280
 
168
281
  <%
169
282
  const skipKeys = new Set([
170
- 'id', 'page-id', 'title', 'summary', 'userStories', 'acceptance', 'ui', 'design', 'legacy', 'review', 'template',
283
+ 'id', 'page-id', 'title', 'summary', 'successMetrics', 'nonGoals', 'userStories', 'acceptance', 'ui', 'design', 'legacy', 'review', 'template',
171
284
  'nav', 'sections', 'zones', 'behavior', 'actions', 'stateMatrix', 'grillStatus', 'specOrigin',
172
285
  'status', 'owner', 'schema', 'qa', 'Q&A', 'pendingTechDebt', 'i18n', 'gen', '_meta'
173
286
  ]);
@@ -187,7 +300,7 @@
187
300
  <% }); %>
188
301
 
189
302
  <% if (spec.pendingTechDebt && spec.pendingTechDebt.length) { %>
190
- ## Pending tech debt
303
+ ## Pending tech debt {#pending-tech-debt}
191
304
 
192
305
  | ID | Status | Summary |
193
306
  | --- | --- | --- |
@@ -198,7 +311,7 @@
198
311
  <% } %>
199
312
 
200
313
  <% if (spec.review && (spec.review.layoutNotes || spec.review.summary)) { %>
201
- ## Review — layout notes
314
+ ## Review — layout notes {#review-notes}
202
315
 
203
316
  <% if (spec.review.layoutNotes) { %>
204
317
  <% if (Array.isArray(spec.review.layoutNotes)) { %>
@@ -210,7 +323,7 @@
210
323
  <% } %>
211
324
 
212
325
  <% if (spec.legacy && (spec.legacy.behaviors?.length || spec.legacy.fields?.length || spec.legacy.evidence?.length)) { %>
213
- ## Legacy evidence
326
+ ## Legacy evidence {#legacy-evidence}
214
327
 
215
328
  <% if (spec.legacy.behaviors && spec.legacy.behaviors.length) { %>
216
329
  ### Behaviors
@@ -1,6 +1,5 @@
1
- # Design spec v1 — /spec (round 1)
2
- # Do NOT add codegen, ui.filters, ui.columns, or portal-gen tags here.
3
- # After /grill-docs → see docs/templates/spec.yaml (portal-gen-ready).
1
+ # DEPRECATED — không author leaf mới. SSOT: feature.bundle.yaml + bundle-authoring.md
2
+ # File giữ cho repo cũ / tham chiếu shape spec (design v1). /spec skill → chỉ bundle.
4
3
 
5
4
  id: role-page-function
6
5
  title: Feature title
@@ -0,0 +1,38 @@
1
+ {
2
+ "version": 1,
3
+ "canonicalSystem": "flowgrid-fe",
4
+ "description": "Design DSL registry (UI shells, #ui, Mo*). Refresh with flowgrid registry:sync after base changes.",
5
+ "defaults": {
6
+ "shellByProfile": {
7
+ "list": "DataListPage",
8
+ "create": "DataFormPage",
9
+ "detail": "DataDetailPage",
10
+ "admin-crud": "DataListPage",
11
+ "auth": "AuthShell"
12
+ }
13
+ },
14
+ "shells": {
15
+ "DataListPage": {
16
+ "tag": "#shell: DataListPage",
17
+ "portal": { "status": "planned", "path": "components/organisms/DataListPage.vue" },
18
+ "portalGen": {
19
+ "templateStandard": "list/page-standard",
20
+ "templateCustom": "list/page-custom"
21
+ }
22
+ },
23
+ "DataFormPage": {
24
+ "tag": "#shell: DataFormPage",
25
+ "portal": { "status": "planned", "path": "components/organisms/DataFormPage.vue" }
26
+ },
27
+ "DataDetailPage": {
28
+ "tag": "#shell: DataDetailPage",
29
+ "portal": { "status": "planned", "path": "components/organisms/DataDetailPage.vue" }
30
+ }
31
+ },
32
+ "fieldWidgets": {},
33
+ "componentAliases": {},
34
+ "aliasIndex": {},
35
+ "components": {},
36
+ "composables": {},
37
+ "helpers": {}
38
+ }
@@ -1,6 +1,4 @@
1
- # SSOT — portal-feature-bundle/v1. Split: pnpm spec:split -- <path>
2
- # Authoring: docs/templates/bundle-authoring.md
3
- # /spec MUST fill inventory when information exists. grill-* only re-checks gaps/conflicts.
1
+ # portal-feature-bundle/v1 — Authoring: bundle-authoring.md · Split: flowgrid split <path>
4
2
 
5
3
  schema: portal-feature-bundle/v1
6
4
  page-id: role-domain-function
@@ -19,7 +17,14 @@ summary: |
19
17
  - output: [Kết quả đầu ra]
20
18
  - cách giải quyết (solution): [Tuỳ chọn. Ghi kỹ thuật phức tạp nếu có.]
21
19
 
22
- # 2. KHỐI USER STORIES CHI TIẾT CHO MÀN HÌNH (SCREEN USER STORIES & SCENARIOS)
20
+ successMetrics: |
21
+ - [Chỉ số đo được khi màn/feature đạt mục tiêu — VD: thời gian hoàn tất thao tác, tỷ lệ lỗi validation]
22
+ - [Bỏ bullet nếu chưa có số — ghi qualitative metric]
23
+
24
+ nonGoals: |
25
+ - [Phạm vi KHÔNG làm trên màn/phase này — tránh scope creep]
26
+ - [VD: không xử lý export Excel tại màn list — defer QA/debt]
27
+
23
28
  userStories:
24
29
  primary:
25
30
  asA: "[Persona / Role - vd: Nhân viên Vận hành / Khách hàng / Quản trị viên]"
@@ -27,10 +32,7 @@ userStories:
27
32
  soThat: "[Mục đích kinh doanh và giá trị thực tế đạt được]"
28
33
 
29
34
  contextAndHandoff:
30
- # 3 LOẠI CÁCH THỨC VÀO MÀN HÌNH (SCREEN ACCESS ENTRY MODE):
31
- # - directRoute: Dành cho Login, Register, Public/Guest Page (mô tả path router)
32
- # - sidebarMenu: Dành cho Dashboard, CRUD List, Admin Pages (mô tả menu đa cấp dropdown + label text)
33
- # - contextualAction: Dành cho Detail, Edit Modal, Settings (mô tả nút bấm xxx từ màn hình A)
35
+ # screenAccess: directRoute | sidebarMenu | contextualAction — xem bundle-authoring.md
34
36
  screenAccess:
35
37
  accessType: sidebarMenu # directRoute | sidebarMenu | contextualAction
36
38
  directRoute:
@@ -74,7 +76,6 @@ userStories:
74
76
  - "Hệ thống khóa nút và hiển thị loading để chống bấm đúp (double submit prevention)."
75
77
  - "Lưu dữ liệu thành công (không phải xóa): Toast hoặc inline alert; điều hướng theo Handoff. Thao tác xóa — xem scenario UX affordances bên dưới."
76
78
 
77
- # Thêm scenario này khi màn có delete/breadcrumb/filter/disabled reason / import CSV (sau audit UX_* hoặc DSL gap).
78
79
  - name: "Affordances UX chuẩn portal (UX — khi áp dụng)"
79
80
  steps:
80
81
  - "Breadcrumb / ngữ cảnh: Người dùng luôn biết đang ở module và bản ghi nào (trail hoặc back + title rõ)."
@@ -194,6 +195,12 @@ gen:
194
195
  testIds: null
195
196
 
196
197
  design:
198
+ # dataModel: # optional — multi-table review; xem tpl-screen-data-model.md
199
+ # erdRef: "<LCA>/common/db-erd.md"
200
+ # tables:
201
+ # - schema: records
202
+ # roleOnScreen: read-write
203
+ # summary: "Hồ sơ chính trên form"
197
204
  inherits: null
198
205
  shell:
199
206
  tag: "#shell: DataListPage" # AuthPage | AppShell
@@ -0,0 +1,281 @@
1
+
2
+ # Feature title
3
+
4
+ ## Mục lục (Contents)
5
+
6
+ 1. [Tổng quan](#overview)
7
+ 2. [Chỉ số thành công](#success-metrics)
8
+ 3. [Phạm vi không làm](#non-goals)
9
+ 4. [User stories và hành trình màn hình](#user-stories--screen-journey)
10
+ 5. [Ma trận trạng thái và phân quyền](#state--permission-matrix)
11
+ 6. [Bảng cột danh sách](#list-columns)
12
+ 7. [Từ điển dữ liệu và validation](#data-dictionary--validation)
13
+ 8. [Widget tùy biến](#custom-widgets)
14
+ 9. [Luồng hành động](#action-flows)
15
+ - [API SSOT](#api-ssot)
16
+
17
+ ---
18
+
19
+ ## Tổng quan {#overview}
20
+
21
+ | | |
22
+ | --- | --- |
23
+ | **Page ID** | `role-domain-function` |
24
+ | **Status** | draft |
25
+ | **Owner** | portal-team |
26
+
27
+
28
+ - **Testcase plans:** [base_test](https://github.com/raintr91/base_test) (`pnpm cases:render` on tests hub) — see docs-hub TESTS-HUB
29
+
30
+
31
+
32
+ - **Screen:** None
33
+
34
+
35
+ - mục tiêu nghiệp vụ (business_goals): [Nêu rõ vấn đề đang giải quyết và giá trị kinh tế/nghiệp vụ mang lại. Viết sâu sắc để Stakeholder hiểu rõ vì sao phải làm.]
36
+ - các bên liên quan (stakeholders): [Ai dùng, ai hưởng lợi, ai quản lý?]
37
+ - kịch bản người dùng (user_journey): [Kể câu chuyện người dùng trải qua các bước trên màn hình bằng ngôn ngữ đời thường.]
38
+ - bối cảnh (context):
39
+ - description: [Phân tích sâu luồng nghiệp vụ chi tiết]
40
+ - input: [Dữ liệu đầu vào. CHÚ Ý liên kết cross-page / cross-module nếu có]
41
+ - output: [Kết quả đầu ra]
42
+ - cách giải quyết (solution): [Tuỳ chọn. Ghi kỹ thuật phức tạp nếu có.]
43
+
44
+
45
+
46
+
47
+ ## Chỉ số thành công {#success-metrics}
48
+
49
+ - [Chỉ số đo được khi màn/feature đạt mục tiêu — VD: thời gian hoàn tất thao tác, tỷ lệ lỗi validation]
50
+ - [Bỏ bullet nếu chưa có số — ghi qualitative metric]
51
+
52
+
53
+
54
+
55
+
56
+ ## Phạm vi không làm {#non-goals}
57
+
58
+ - [Phạm vi KHÔNG làm trên màn/phase này — tránh scope creep]
59
+ - [VD: không xử lý export Excel tại màn list — defer QA/debt]
60
+
61
+
62
+
63
+
64
+ ## API SSOT {#api-ssot}
65
+
66
+ Hợp đồng backend: `api/<seq>/01-backend-spec.yaml` trong cùng function leaf (không gộp vào bundle). Sau split: `ir/design.yaml` chiếu endpoint; OpenAPI/mock theo stack.
67
+
68
+ - **Data model (review, multi-table):** [data-model.md](./data-model.md) — bảng/cột tách khỏi spec BA; SSOT codegen = `01` + `ir/design.yaml` `db`.
69
+
70
+
71
+ ## User Stories & Screen Journey {#user-stories--screen-journey}
72
+
73
+
74
+
75
+ ### User Story Chính
76
+ > **Là một** [Persona / Role - vd: Nhân viên Vận hành / Khách hàng / Quản trị viên],
77
+ > **Tôi muốn** [Hành động chính trên màn hình: xem danh sách, lọc, tạo mới, cập nhật, phê duyệt...],
78
+ > **Để** [Mục đích kinh doanh và giá trị thực tế đạt được].
79
+
80
+
81
+
82
+ ### Cách thức Truy cập & Chuyển giao Màn hình (Screen Access & Handoff)
83
+
84
+
85
+ - **Loại truy cập (Access Type):** `sidebarMenu`
86
+
87
+ - **Menu Sidebar:** Quản trị hệ thống &gt; Quản lý Người dùng > **Danh sách tài khoản**
88
+
89
+
90
+ - **Màn hình nguồn (Source Screen):** `W-ADM-LIST-01`
91
+
92
+ - **Dữ liệu tiếp nhận (Inputs):** customer_id · booking_id
93
+
94
+ - **Điều hướng tiếp theo (Next Screen):** `W-ADM-DETAIL-01`
95
+
96
+
97
+
98
+ ### Kịch bản Chi tiết trên Màn hình (Scenarios)
99
+
100
+ #### Khởi tạo &amp; Tải dữ liệu ban đầu (Initial Load)
101
+
102
+
103
+ - Kiểm tra quyền hạn người dùng (Role / Permissions) đối với màn hình.
104
+
105
+ - Tải danh sách dữ liệu theo bộ lọc mặc định hoặc bind thông tin bản ghi theo ID nhận được.
106
+
107
+ - Hiển thị trạng thái tải (Skeleton / Spinner), nếu không có dữ liệu hiển thị Empty State.
108
+
109
+
110
+
111
+ #### Tương tác Nhập liệu &amp; Thẩm định Dữ liệu (Input &amp; Validation)
112
+
113
+
114
+ - Người dùng nhập liệu các trường bắt buộc và tùy chọn trên form.
115
+
116
+ - Hệ thống validate trực tiếp trên giao diện (Inline error) khi nhập sai định dạng hoặc bỏ trống.
117
+
118
+ - Các trường có logic phụ thuộc tự động cập nhật hoặc mở thêm vùng nhập (Dynamic visibility / calculation).
119
+
120
+
121
+
122
+ #### Nộp dữ liệu &amp; Hoàn tất Thành công (Happy Path Submit)
123
+
124
+
125
+ - Người dùng nhấn nút thực thi chính (Primary Action Button).
126
+
127
+ - Hệ thống khóa nút và hiển thị loading để chống bấm đúp (double submit prevention).
128
+
129
+ - Lưu dữ liệu thành công (không phải xóa): Toast hoặc inline alert; điều hướng theo Handoff. Thao tác xóa — xem scenario UX affordances bên dưới.
130
+
131
+
132
+
133
+ #### Affordances UX chuẩn portal (UX — khi áp dụng)
134
+
135
+
136
+ - Breadcrumb / ngữ cảnh: Người dùng luôn biết đang ở module và bản ghi nào (trail hoặc back + title rõ).
137
+
138
+ - Danh sách: Tìm kiếm/lọc (nếu có) và phân trang; empty state khác &#39;không có kết quả filter&#39;.
139
+
140
+ - Cột trạng thái: Hiển thị chip/badge có chữ, không chỉ màu.
141
+
142
+ - Hành động trên dòng bị khóa: Có lý do hiển thị (tooltip/badge/chip), không chỉ nút disabled im lặng.
143
+
144
+ - Xóa / xóa hàng loạt: Hộp thoại xác nhận chặn → gọi API → hộp thoại kết quả (thành công/lỗi) bắt người dùng xác nhận — không chỉ toast.
145
+
146
+ - Import CSV (nếu có): Chọn file → kiểm tra → xác nhận → báo kết quả; lỗi theo dòng có thể tải log.
147
+
148
+
149
+
150
+ #### Xử lý Ngoại lệ &amp; Lỗi Giao diện (Exceptions &amp; Edge Cases)
151
+
152
+
153
+ - Xung đột dữ liệu / Đã bị sửa đổi bởi người khác (409 Conflict): Cảnh báo và tải lại.
154
+
155
+ - Lỗi kết nối / Máy chủ (Network / 5xx error): Giữ nguyên dữ liệu đã nhập trên form, không bắt nhập lại.
156
+
157
+ - Hết hạn phiên làm việc (Session timeout): Yêu cầu xác thực lại và bảo lưu tạm bản nháp.
158
+
159
+
160
+
161
+ #### Tác vụ Ngầm Kích hoạt từ Màn hình (Background / Async Logic - Tùy chọn)
162
+
163
+
164
+ - Nếu thao tác kích hoạt xử lý ngầm (gửi tin nhắn, tạo job đồng bộ): Hệ thống đẩy sự kiện vào hàng đợi.
165
+
166
+ - Cập nhật trạng thái hiển thị trên màn hình thành &#39;Đang xử lý ngầm&#39; (Processing) để người dùng theo dõi.
167
+
168
+
169
+
170
+
171
+
172
+
173
+ ### Tiêu chí Nghiệm thu (Acceptance Criteria)
174
+
175
+ - [ ] [ ] Người dùng có quyền truy cập xem được toàn bộ thông tin hợp lệ.
176
+
177
+ - [ ] [ ] Form chặn nộp khi thiếu các trường bắt buộc và thông báo lỗi rõ ràng.
178
+
179
+ - [ ] [ ] Khi nộp thành công (không phải delete), dữ liệu được lưu đúng và chuyển trang mượt mà.
180
+
181
+ - [ ] [ ] (Khi có delete) Confirm trước xóa và result dialog sau API — không toast-only.
182
+
183
+ - [ ] [ ] (Khi có action disabled theo rule) Người dùng hiểu lý do bị khóa (copy/badge/tooltip).
184
+
185
+ - [ ] [ ] (Khi list/detail drill-down) Breadcrumb hoặc ngữ cảnh điều hướng đủ cho deep link.
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+ ## Ma Trận Trạng Thái Giao Diện & Phân Quyền (State & Permission Matrix) {#state--permission-matrix}
196
+
197
+ | Trạng Thái Bản Ghi (Record Status) | Trạng Thái Trường Form (Fields State) | Nút Hành Động Khả Dụng (Visible Buttons) | Ghi Chú Phân Quyền RBAC (Role Overrides) |
198
+ | --- | --- | --- | --- |
199
+ | `DRAFT` | ✏️ Cho phép sửa (Editable) | `btn_save_draft`, `btn_submit_record`, `btn_cancel` | Áp dụng cho mọi vai trò |
200
+ | `PENDING_APPROVAL` | 🔒 Chỉ đọc (Readonly) | `btn_cancel_request` | **manager**: Nút khả dụng [`btn_approve`, `btn_reject`] |
201
+ | `APPROVED` | 🔒 Chỉ đọc (Readonly) | `btn_print`, `btn_export` | Áp dụng cho mọi vai trò |
202
+ | `REJECTED` | ✏️ Cho phép sửa (Editable) | `btn_resubmit`, `btn_delete` | Áp dụng cho mọi vai trò |
203
+
204
+
205
+
206
+
207
+ ## Bảng cột danh sách (List columns) {#list-columns}
208
+
209
+ | Nhãn cột | Key | Ý nghĩa nghiệp vụ | Mục đích UI | Widget / render | Sort | DB (schema.field) |
210
+ | --- | --- | --- | --- | --- | --- | --- |
211
+ | Trạng thái | `status` | Tình trạng hoạt động của tài khoản trong hệ thống để quản lý quyền đăng nhập và giao dịch | Cho user thấy tài khoản còn hoạt động hay đã bị tạm khóa | chip / custom | Không | — |
212
+
213
+ <p><strong>DB chi tiết / multi-table:</strong> <a href="./data-model.md">data-model.md</a> · SSOT ghi: <code>*.bundle.yaml</code> + <code>ir/design.yaml</code>.</p>
214
+
215
+
216
+
217
+
218
+ ## Danh Mục Trường Nhập Liệu & Quy Tắc Kiểm Tra Hợp Lệ (Data Dictionary & Validation) {#data-dictionary--validation}
219
+
220
+ | Tên Trường (Label) | Mã Kỹ Thuật (Key) | Kiểu (Type) | Bắt Buộc? | Ràng Buộc & Quy Tắc Hợp Lệ (Rules) | Thông Báo Lỗi Inline (Messages) |
221
+ | --- | --- | --- | --- | --- | --- |
222
+ | Mã hồ sơ | `N/A` | input | Bắt buộc | Kiểu: `slug_uppercase`<br>Regex: `^[A-Z0-9_-]{5,20}$`<br>Độ dài [5, 20]<br>Unique DB: `/api/v1/records/check-duplicate-code` | Required: "Vui lòng nhập mã hồ sơ."<br>"Mã hồ sơ chỉ được gồm chữ in hoa, chữ số và ký tự gạch (- _)"<br>"Độ dài mã hồ sơ bắt buộc từ 5 đến 20 ký tự"<br>DB: "Mã hồ sơ này đã tồn tại trên hệ thống. Vui lòng chọn mã khác." |
223
+ | Tên hồ sơ | `N/A` | input | Bắt buộc | Kiểu: `text_clean`<br>Độ dài [3, 100] | Required: "Vui lòng nhập tên hồ sơ."<br>"Tên hồ sơ bắt buộc từ 3 đến 100 ký tự" |
224
+ | Cấp độ dịch vụ | `N/A` | select | Bắt buộc | Kiểu: `enum` | Required: "Vui lòng chọn cấp độ dịch vụ." |
225
+ | Yêu cầu đặc biệt cho gói VIP | `N/A` | textarea | Tùy chọn | Độ dài [0, 500]<br>Phụ thuộc: `service_level == 'PREMIUM'` | Required: "Vui lòng nhập yêu cầu đặc biệt khi đăng ký gói VIP."<br>"Yêu cầu đặc biệt không được vượt quá 500 ký tự." |
226
+
227
+
228
+
229
+
230
+ <div id="custom-widgets"></div>
231
+
232
+ ## Đặc Tả Khối Giao Diện Tùy Biến (Custom UI Blocks)
233
+
234
+ ### Khối Tùy Biến (`custom`)
235
+ - **Mục đích thao tác:** Theo dõi tiến độ xử lý và xem chi tiết phản hồi từng bước duyệt
236
+
237
+
238
+
239
+
240
+
241
+ ## Đặc Tả Quy Trình Hành Động (Action Flows) {#action-flows}
242
+
243
+ ### Lưu & Xác Nhận
244
+ - **Mục đích thao tác:** Thẩm định toàn bộ form và gửi dữ liệu lên máy chủ
245
+ - **Vị trí hiển thị:** `form_footer` | **Trigger:** `click` | **Variant:** `primary`
246
+
247
+ ### Hủy Bỏ
248
+ - **Mục đích thao tác:** Hủy thao tác tạo mới và quay lại trang trước
249
+ - **Vị trí hiển thị:** `form_footer` | **Trigger:** `click` | **Variant:** `outline`
250
+
251
+
252
+
253
+
254
+
255
+ ## actors
256
+
257
+
258
+ ```yaml
259
+ []
260
+ ```
261
+
262
+
263
+
264
+ ## requirements
265
+
266
+
267
+ ```yaml
268
+ - &#34;[Ghi chú: Bắt buộc định nghĩa State Machine, và UI Permissions vào thuộc tính
269
+ states của từng item trong design.sections. KHÔNG liệt kê chung chung ở đây]&#34;
270
+ - &#34;Edge Cases: [Bắt buộc định nghĩa ngoại lệ như lỗi luồng, data hỏng,
271
+ concurrency]&#34;
272
+ ```
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+
281
+
@@ -1,7 +1,7 @@
1
1
  # Copy to qa/open/QA-<bundle.id>-NNNN.yaml — do not leave this file in qa/open/.
2
2
  id: QA-cmp-adm-002-02-01-02-0001
3
3
  kind: customer # customer | choice | tech-debt
4
- skill: spec # spec | grill-bqa | grill-dev | grill-docs | api-spec | api-update | api-integration
4
+ skill: spec # spec | grill-bqa | grill-dev | grill-docs | api-spec | api-update
5
5
  target:
6
6
  path: surfaces/<surface>/CMP-*/<NN…>/<slug>.bundle.yaml
7
7
  at: design.zones.main.items.title.purpose