@fui-org/fui-cli 0.2.0 → 0.4.0

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 (212) hide show
  1. package/README.md +20 -2
  2. package/dist/fui.js +347 -44
  3. package/package.json +15 -3
  4. package/skills/fui/SKILL.md +149 -66
  5. package/skills/fui-skill/README.md +112 -0
  6. package/skills/fui-skill/SKILL.md +269 -0
  7. package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
  8. package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
  9. package/skills/fui-skill/design-md/airbnb/README.md +5 -0
  10. package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
  11. package/skills/fui-skill/design-md/airtable/README.md +5 -0
  12. package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
  13. package/skills/fui-skill/design-md/apple/README.md +5 -0
  14. package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
  15. package/skills/fui-skill/design-md/asu/README.md +107 -0
  16. package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
  17. package/skills/fui-skill/design-md/binance/README.md +5 -0
  18. package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
  19. package/skills/fui-skill/design-md/bmw/README.md +5 -0
  20. package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
  21. package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
  22. package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
  23. package/skills/fui-skill/design-md/bugatti/README.md +5 -0
  24. package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
  25. package/skills/fui-skill/design-md/cal/README.md +5 -0
  26. package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
  27. package/skills/fui-skill/design-md/claude/README.md +5 -0
  28. package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
  29. package/skills/fui-skill/design-md/clay/README.md +5 -0
  30. package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
  31. package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
  32. package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
  33. package/skills/fui-skill/design-md/cohere/README.md +5 -0
  34. package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
  35. package/skills/fui-skill/design-md/coinbase/README.md +5 -0
  36. package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
  37. package/skills/fui-skill/design-md/composio/README.md +5 -0
  38. package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
  39. package/skills/fui-skill/design-md/cursor/README.md +5 -0
  40. package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
  41. package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
  42. package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
  43. package/skills/fui-skill/design-md/expo/README.md +5 -0
  44. package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
  45. package/skills/fui-skill/design-md/ferrari/README.md +5 -0
  46. package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
  47. package/skills/fui-skill/design-md/figma/README.md +5 -0
  48. package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
  49. package/skills/fui-skill/design-md/framer/README.md +5 -0
  50. package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
  51. package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
  52. package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
  53. package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
  54. package/skills/fui-skill/design-md/ibm/README.md +5 -0
  55. package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
  56. package/skills/fui-skill/design-md/intercom/README.md +5 -0
  57. package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
  58. package/skills/fui-skill/design-md/kraken/README.md +5 -0
  59. package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
  60. package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
  61. package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
  62. package/skills/fui-skill/design-md/linear.app/README.md +5 -0
  63. package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
  64. package/skills/fui-skill/design-md/lovable/README.md +5 -0
  65. package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
  66. package/skills/fui-skill/design-md/mastercard/README.md +5 -0
  67. package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
  68. package/skills/fui-skill/design-md/meta/README.md +5 -0
  69. package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
  70. package/skills/fui-skill/design-md/minimax/README.md +5 -0
  71. package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
  72. package/skills/fui-skill/design-md/mintlify/README.md +5 -0
  73. package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
  74. package/skills/fui-skill/design-md/miro/README.md +5 -0
  75. package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
  76. package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
  77. package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
  78. package/skills/fui-skill/design-md/mongodb/README.md +5 -0
  79. package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
  80. package/skills/fui-skill/design-md/nike/README.md +5 -0
  81. package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
  82. package/skills/fui-skill/design-md/notion/README.md +5 -0
  83. package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
  84. package/skills/fui-skill/design-md/nvidia/README.md +5 -0
  85. package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
  86. package/skills/fui-skill/design-md/ollama/README.md +5 -0
  87. package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
  88. package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
  89. package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
  90. package/skills/fui-skill/design-md/pinterest/README.md +5 -0
  91. package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
  92. package/skills/fui-skill/design-md/playstation/README.md +5 -0
  93. package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
  94. package/skills/fui-skill/design-md/posthog/README.md +5 -0
  95. package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
  96. package/skills/fui-skill/design-md/raycast/README.md +5 -0
  97. package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
  98. package/skills/fui-skill/design-md/renault/README.md +5 -0
  99. package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
  100. package/skills/fui-skill/design-md/replicate/README.md +5 -0
  101. package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
  102. package/skills/fui-skill/design-md/resend/README.md +5 -0
  103. package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
  104. package/skills/fui-skill/design-md/revolut/README.md +5 -0
  105. package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
  106. package/skills/fui-skill/design-md/runwayml/README.md +5 -0
  107. package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
  108. package/skills/fui-skill/design-md/sanity/README.md +5 -0
  109. package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
  110. package/skills/fui-skill/design-md/sentry/README.md +5 -0
  111. package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
  112. package/skills/fui-skill/design-md/shopify/README.md +5 -0
  113. package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
  114. package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
  115. package/skills/fui-skill/design-md/spacex/README.md +5 -0
  116. package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
  117. package/skills/fui-skill/design-md/spotify/README.md +5 -0
  118. package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
  119. package/skills/fui-skill/design-md/starbucks/README.md +5 -0
  120. package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
  121. package/skills/fui-skill/design-md/stripe/README.md +5 -0
  122. package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
  123. package/skills/fui-skill/design-md/supabase/README.md +5 -0
  124. package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
  125. package/skills/fui-skill/design-md/superhuman/README.md +5 -0
  126. package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
  127. package/skills/fui-skill/design-md/tesla/README.md +5 -0
  128. package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
  129. package/skills/fui-skill/design-md/theverge/README.md +5 -0
  130. package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
  131. package/skills/fui-skill/design-md/together.ai/README.md +5 -0
  132. package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
  133. package/skills/fui-skill/design-md/uber/README.md +5 -0
  134. package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
  135. package/skills/fui-skill/design-md/vercel/README.md +5 -0
  136. package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
  137. package/skills/fui-skill/design-md/vodafone/README.md +5 -0
  138. package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
  139. package/skills/fui-skill/design-md/voltagent/README.md +5 -0
  140. package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
  141. package/skills/fui-skill/design-md/warp/README.md +5 -0
  142. package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
  143. package/skills/fui-skill/design-md/webflow/README.md +5 -0
  144. package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
  145. package/skills/fui-skill/design-md/wired/README.md +5 -0
  146. package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
  147. package/skills/fui-skill/design-md/wise/README.md +5 -0
  148. package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
  149. package/skills/fui-skill/design-md/x.ai/README.md +5 -0
  150. package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
  151. package/skills/fui-skill/design-md/zapier/README.md +5 -0
  152. package/skills/fui-skill/examples/component.vue +162 -0
  153. package/skills/fui-skill/examples/f-table-patterns.json +331 -0
  154. package/skills/fui-skill/examples/module-patterns.json +973 -0
  155. package/skills/fui-skill/examples/project-patterns.json +222 -0
  156. package/skills/fui-skill/metadata.json +75 -0
  157. package/skills/fui-skill/references/INDEX.md +144 -0
  158. package/skills/fui-skill/references/advanced-techniques.md +160 -0
  159. package/skills/fui-skill/references/coding-standards.md +112 -0
  160. package/skills/fui-skill/references/component-design.md +455 -0
  161. package/skills/fui-skill/references/component-quickref.md +77 -0
  162. package/skills/fui-skill/references/component-table.md +276 -0
  163. package/skills/fui-skill/references/components-dialog.md +192 -0
  164. package/skills/fui-skill/references/components-display.md +147 -0
  165. package/skills/fui-skill/references/components-echart.md +391 -0
  166. package/skills/fui-skill/references/components-input.md +359 -0
  167. package/skills/fui-skill/references/controls-patterns.md +847 -0
  168. package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
  169. package/skills/fui-skill/references/db-table-design.md +77 -0
  170. package/skills/fui-skill/references/db-workflow.md +504 -0
  171. package/skills/fui-skill/references/default-function.md +415 -0
  172. package/skills/fui-skill/references/design-modes.md +85 -0
  173. package/skills/fui-skill/references/echart-templates.md +481 -0
  174. package/skills/fui-skill/references/fastproject.md +97 -0
  175. package/skills/fui-skill/references/fsheet.md +218 -0
  176. package/skills/fui-skill/references/fullstack-workflow.md +351 -0
  177. package/skills/fui-skill/references/module-data-patterns.md +126 -0
  178. package/skills/fui-skill/references/module-json-anatomy.md +137 -0
  179. package/skills/fui-skill/references/module-structure.md +260 -0
  180. package/skills/fui-skill/references/new-session.md +108 -0
  181. package/skills/fui-skill/references/pdfmake.md +60 -0
  182. package/skills/fui-skill/references/permission-system.md +169 -0
  183. package/skills/fui-skill/references/platform-architecture.md +294 -0
  184. package/skills/fui-skill/references/project-config.md +335 -0
  185. package/skills/fui-skill/references/project-provisioning.md +383 -0
  186. package/skills/fui-skill/references/script-map.md +296 -0
  187. package/skills/fui-skill/references/sql-clr-functions.md +224 -0
  188. package/skills/fui-skill/references/system-design.md +116 -0
  189. package/skills/fui-skill/references/tapi-file-api.md +191 -0
  190. package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
  191. package/skills/fui-skill/references/tapi-reference.md +549 -0
  192. package/skills/fui-skill/references/tools-registry.md +460 -0
  193. package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
  194. package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
  195. package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
  196. package/skills/fui-skill/references/ui-patterns.md +315 -0
  197. package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
  198. package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
  199. package/skills/fui-skill/references/ui-templates.md +29 -0
  200. package/skills/fui-skill/references/verification.md +246 -0
  201. package/skills/fui-skill/references/watcher-patterns.md +196 -0
  202. package/skills/fui-skill/references/websocket-realtime.md +254 -0
  203. package/skills/fui-skill/scripts/component-3.0.js +2549 -0
  204. package/skills/fui-skill/scripts/component.js +3142 -0
  205. package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
  206. package/skills/fui-skill/scripts/componentTable.js +769 -0
  207. package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
  208. package/skills/fui-skill/scripts/defaultfunction.js +966 -0
  209. package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
  210. package/skills/fui-skill/scripts/fastproject.js +828 -0
  211. package/skills/fui-skill/scripts/fechart.js +890 -0
  212. package/skills/fui-skill/scripts/fsheet.js +1330 -0
@@ -0,0 +1,60 @@
1
+ # PDF Generation với pdfmake
2
+
3
+ > File này sở hữu: **`f-pdfmake`: docDefinition, font tiếng Việt, in/tải PDF**.
4
+
5
+ Kỹ thuật tạo PDF phức tạp bằng thư viện `pdfmake` trong FUI (dùng qua component `f-pdfmake`).
6
+
7
+ ## Dynamic Tables
8
+
9
+ Map mảng dữ liệu thành rows trong bảng:
10
+
11
+ ```javascript
12
+ body: [
13
+ [{ text: 'STT', bold: true }, { text: 'Name', bold: true }],
14
+ ...data.items.map(item => ([
15
+ item.index,
16
+ item.name
17
+ ]))
18
+ ]
19
+ ```
20
+
21
+ ## SVG Checkboxes
22
+
23
+ Ký tự Unicode (☑/☐) có thể không render được trong một số font PDF. Dùng SVG path thay thế:
24
+
25
+ ```javascript
26
+ const checkedSvg = '<svg ...>...</svg>';
27
+ const uncheckedSvg = '<svg ...>...</svg>';
28
+
29
+ {
30
+ svg: item.isChecked ? checkedSvg : uncheckedSvg,
31
+ width: 14
32
+ }
33
+ ```
34
+
35
+ ## Complex Layouts
36
+
37
+ Dùng `columns` cho layout mà table thông thường không xử lý được (ví dụ checkbox cạnh text):
38
+
39
+ ```javascript
40
+ {
41
+ columns: [
42
+ { svg: checkedSvg, width: 14 },
43
+ { text: ' Label text', width: '*' }
44
+ ]
45
+ }
46
+ ```
47
+
48
+ ## Signature Section Table
49
+
50
+ Dùng nested table để tạo khối chữ ký căn chỉnh đúng:
51
+
52
+ ```javascript
53
+ table: {
54
+ widths: ['16%', '16%', '16%', '16%', '16%', '16%'],
55
+ body: [
56
+ [{ text: 'Title', colSpan: 3 }, {}, {}, { text: 'Title', colSpan: 3 }, {}, {}],
57
+ ['Sign 1', 'Sign 2', 'Sign 3', 'Sign 4', 'Sign 5', 'Sign 6']
58
+ ]
59
+ }
60
+ ```
@@ -0,0 +1,169 @@
1
+ # Hệ thống phân quyền FUI — SystemRight & FunctionRight
2
+
3
+ > File này sở hữu: **khái niệm `SystemRight` vs `FunctionRight`, `rightTest`, gác `v-if`/menu, 8 tool quản lý định nghĩa quyền**. Kiểm quyền trong thân SP xem [tapi-permission-patterns.md](tapi-permission-patterns.md).
4
+
5
+ FUI có **2 loại quyền độc lập, không thay thế nhau**. Nhầm lẫn hai loại này là lỗi thường gặp khi thiết kế `v-if`, menu `right`, hoặc kiểm tra quyền trong SP.
6
+
7
+ > Kiểm tra quyền **trong thân SP** (pattern SQL cụ thể): xem [tapi-permission-patterns.md](tapi-permission-patterns.md). File này tập trung vào khái niệm + 8 tool quản lý định nghĩa quyền.
8
+
9
+ ---
10
+
11
+ ## Khi user hỏi về "phân quyền"/"quyền" trong hệ thống — quy trình bắt buộc
12
+
13
+ Không trả lời chỉ dựa vào suy đoán hoặc code/schema đã đọc từ trước — luôn lấy dữ liệu **thật** tại thời điểm hỏi:
14
+
15
+ 1. Gọi `right_system_list` + `right_function_list` để lấy đúng định nghĩa `SystemRight`/`FunctionRight` **hiện tại** của project (không đoán theo tên biến hay comment cũ).
16
+ 2. Gọi `db_schema_read` (search theo từ khóa liên quan như `right`/`quyen`/`role`/`permission`/`phanquyen`) để kiểm tra project có **bảng phân quyền riêng** trong DB của chính nó hay không — khác với `acc.tblSysRight`/`acc.tblFunction` (đó là DANH MỤC định nghĩa quyền dùng chung mọi project, không phải bảng gán quyền chi tiết). Nhiều project tự dựng thêm bảng gán quyền theo module/màn hình/thao tác (CRUD) riêng ngoài 2 loại quyền chuẩn — phải kiểm tra trước khi kết luận hệ thống "chỉ có SystemRight/FunctionRight".
17
+ 3. Tổng hợp cả 2 nguồn (định nghĩa quyền chuẩn từ `acc` + bảng phân quyền riêng của project nếu có) trước khi trả lời hoặc thiết kế logic kiểm tra quyền.
18
+
19
+ ---
20
+
21
+ ## 🔴 Bắt buộc: mã quyền phải TỒN TẠI trước khi đem gác
22
+
23
+ Viết `"v-if": "vueData.user.FunctionRight.includes('42')"` hay `"right": {"FunctionRight": ["42"]}` **không tạo ra** mã 42. Nếu 42 chưa có trong `tblFunction` của project thì không user nào được cấp nó → `rightTest()` (dùng `_.intersection`) luôn trả `false` → **nút/menu biến mất, không lỗi JS, không `[Vue warn]`**. Không có gì đỏ lên; chỉ có người dùng báo "không thấy nút".
24
+
25
+ Ba cạm bẫy làm lỗi này sống sót qua mọi tầng kiểm chứng:
26
+
27
+ 1. **Preview nói dối.** `module_simulate` và `renderUI` **cấp cho user preview đúng những mã quét được từ chính module** (để menu không biến mất oan) — nghĩa là mã bịa ra vẫn hiện đúng trong ảnh render. Nay hai tool đó đối chiếu với cache và in dòng `🚨 FunctionRight CHƯA ĐƯỢC ĐỊNH NGHĨA…`; **đọc dòng đó, đừng chỉ nhìn ảnh**.
28
+ 2. **SP không cứu được.** `@sys_FunctionRight` chỉ chứa mã user **thật sự được cấp**; mã không tồn tại đơn giản là không bao giờ khớp.
29
+ 3. **Không suy ra mã từ tên/comment cũ.** Nguồn sự thật duy nhất là `right_function_list` / `right_system_list`.
30
+
31
+ **Quy trình:**
32
+
33
+ | Khi | Làm gì |
34
+ |---|---|
35
+ | Bắt đầu làm việc với quyền trên một project | `right_function_list` + `right_system_list` — ngoài việc in danh sách, hai tool này ghi cache `{projectId}/_db/rights.json` **dưới khoá `apiName`**, thứ duy nhất cho phép các tool no-live-call đối chiếu. Project nhiều alias thì **chạy cho từng alias**: mục của alias này không bao giờ được đem ra kiểm cho alias kia |
36
+ | Thiết kế module/menu cần một quyền chưa có | `right_function_new({ functionCode, functionName })` (hoặc `right_system_new`) **trước**, rồi mới gác — không viết mã "để đó rồi tạo sau" |
37
+ | Sau khi sửa module.json có gác quyền | `module_validate` — mã không có trong cache ra **warning** kèm sẵn lệnh `right_function_new` để copy |
38
+
39
+ `module_validate` chỉ đọc file local (no-live-call): **chưa chạy `right_*_list` lần nào thì chưa có cache, và nó nói thẳng là không kiểm được** thay vì im lặng báo hợp lệ. `SystemRight 9` (Project Admin) là hằng của nền tảng — luôn hợp lệ, không bao giờ bị cảnh báo.
40
+
41
+ ---
42
+
43
+ ## 2 loại quyền — phân biệt rõ
44
+
45
+ | | `SystemRight` | `FunctionRight` |
46
+ |---|---|---|
47
+ | **Bản chất** | **Cấp bậc** của user khi vào một project | **Quyền theo từng chức năng** cụ thể |
48
+ | **Kiểu dữ liệu** | 1 số nguyên `0–9` | Mảng mã chức năng (string[]) |
49
+ | **Trả lời câu hỏi** | "Bạn là ai trong hệ thống này?" (Users, Managers, Administrators, Project Admin...) | "Bạn được phép làm việc gì?" (xem báo cáo, đặt hàng, thanh toán...) |
50
+ | **Định nghĩa ở đâu** | `tblSysRight` — mỗi mức có `Note` (tên cấp bậc) do project tự đặt | `tblFunction` — mỗi chức năng có `FunctionCode` (số) + `FunctionName` |
51
+ | **Gán cho user** | 1 mức duy nhất trên project đó | 0..N mã, độc lập với cấp bậc |
52
+ | **Runtime (client)** | `vueData.user.SystemRight` (số) | `vueData.user.FunctionRight` (mảng chuỗi) |
53
+ | **SP-side** | `@sys_SystemRight` | `@sys_FunctionRight` (chuỗi dạng `[10][20]`) |
54
+
55
+ **Ví dụ dễ hình dung:** `SystemRight` giống chức vụ ("Nhân viên" = 1, "Quản lý" = 5, "Project Admin" = 9 — cố định). `FunctionRight` giống checklist quyền hạn cụ thể được cấp riêng cho từng người, bất kể chức vụ — một Nhân viên vẫn có thể được cấp quyền "Thanh toán" nếu công việc yêu cầu, một Quản lý có thể KHÔNG có quyền "Xóa dữ liệu" nếu không cần.
56
+
57
+ **Khi nào dùng loại nào:**
58
+ - Ẩn/hiện cả một khu vực UI theo "đẳng cấp" tổng quát (khu vực quản trị, mục chỉ admin thấy) → `SystemRight`
59
+ - Bật/tắt một nút hoặc luồng nghiệp vụ cụ thể (nút "Duyệt", nút "Xuất báo cáo") mà không phụ thuộc cấp bậc → `FunctionRight`
60
+ - Nhiều màn hình dùng **cả hai cùng lúc** (AND) — xem ví dụ `right` trong `project-config.md`.
61
+
62
+ ---
63
+
64
+ ## Lưu trữ — database phân quyền trung tâm (alias `acc`)
65
+
66
+ Mọi project FUI dùng chung 1 database phân quyền trung tâm, alias tAPI là `acc`:
67
+
68
+ - **`tblModules`** — mỗi project là 1 dòng, nhận diện qua `APIName` (= apiName/alias của project)
69
+ - **`tblSysRight`** — định nghĩa các mức `SystemRight` (0–9) của **một project cụ thể**, kèm `Note` (tên cấp bậc); `9` luôn cố định là **Project Admin**
70
+ - **`tblFunction`** — định nghĩa các `FunctionRight` (`FunctionCode` số + `FunctionName`) của **một project cụ thể** — đây là danh mục "chức năng có thể gán quyền", không phải bảng gán quyền cho từng user
71
+
72
+ > Việc **gán** một mức `SystemRight`/`FunctionRight` cụ thể cho từng user là thao tác quản trị riêng (ngoài phạm vi 8 tool bên dưới — các tool này chỉ quản lý **định nghĩa** danh mục quyền của project, không gán quyền cho user).
73
+
74
+ ### ⚠️ Đừng nhầm với `UserRight` — quyền SỬA PROJECT trong IDE FUI
75
+
76
+ Có một hệ thống quyền **thứ hai** tên nghe rất giống: `UserRight` trong `tblA_UserProject` — quyền **sửa project trong IDE FUI**.
77
+
78
+ | | `SystemRight` / `FunctionRight` (file này) | `UserRight` |
79
+ |---|---|---|
80
+ | Phạm vi | **Toàn bộ một app** — một mức cho một user trên app đó | **Từng project một** |
81
+ | Lưu ở | `acc.tblSysRight` / `acc.tblFunction` | `tblA_UserProject` (DB nền tảng FUI, không phải `acc`) |
82
+ | Runtime đọc bằng | `vueData.user.SystemRight` / `.FunctionRight` | (không có — chỉ IDE FUI dùng) |
83
+ | Tool | 8 tool `right_*` dưới đây | 5 tool `project_user_*` → [project-provisioning.md](project-provisioning.md) §Bước 6 |
84
+
85
+ **Điểm dễ hiểu sai:** IDE FUI *bản thân nó cũng là một app FUI* (project `fp`). Nên `SystemRight` **trên `fp`** chính là quyền của lập trình viên trong IDE — không phải chỉ là "quyền người dùng cuối". Hai trục **AND với nhau**, đọc từ thân SP thật:
86
+
87
+ | Thao tác trong IDE | Điều kiện |
88
+ |---|---|
89
+ | Tạo project (`project_new`) | `SystemRight >= 3` trên `fp` |
90
+ | Sửa metadata project (`project_update`) | `SystemRight >= 2` **và** `UserRight > 2` |
91
+ | Publish `project.json` (`project_publish_config`) | `SystemRight >= 2` **và** `UserRight > 2` |
92
+ | Tạo/sửa module, publish module (`module_*`) | `SystemRight >= 2` **và** `UserRight > 1` |
93
+
94
+ Có `UserRight = 3` mà `SystemRight = 1` thì vẫn không sửa được gì, và ngược lại. Cấp nhầm trục là cấp quyền ở sai nơi rồi kết luận "cấp rồi mà không có tác dụng".
95
+
96
+ ---
97
+
98
+ ## Runtime (client-side)
99
+
100
+ Sau khi khai báo `userInfo` (xem [platform-architecture.md](platform-architecture.md)), FUI tự fetch và gán:
101
+
102
+ ```js
103
+ vueData.user.SystemRight // số, vd: 5
104
+ vueData.user.FunctionRight // mảng chuỗi, vd: ["10", "20"]
105
+ ```
106
+
107
+ **Dùng trong `v-if` (ẩn/hiện theo quyền):**
108
+
109
+ ```json
110
+ { "col": { "v-if": "vueData.user.SystemRight >= 5" } }
111
+ { "col": { "v-if": "vueData.user.FunctionRight.includes('10')" } }
112
+ ```
113
+
114
+ **Dùng trong menu `right`** (xem chi tiết [project-config.md](project-config.md)):
115
+
116
+ ```json
117
+ "right": { "SystemRight": [1, 2, 5, 9], "FunctionRight": ["10", "20"] }
118
+ ```
119
+ - `SystemRight`: `user.SystemRight` phải **nằm trong** mảng mới thấy
120
+ - `FunctionRight`: `user.FunctionRight` phải **giao ít nhất 1 mã** với mảng mới thấy
121
+ - Có cả hai key → **AND** (phải thỏa cả hai)
122
+
123
+ **Hàm `rightTest`** kiểm tra giao quyền (dùng trong menu/logic JS):
124
+
125
+ ```js
126
+ rightTest({ SystemRight: [5, 9], FunctionRight: ['10'] })
127
+ ```
128
+
129
+ ---
130
+
131
+ ## SP-side (Stored Procedure)
132
+
133
+ tAPI tự inject `@sys_SystemRight` và `@sys_FunctionRight` vào mọi SP — không cần client truyền lên. **5 pattern kiểm tra quyền trong thân SP** (chặn truy cập, kiểm tra 2 tầng module admin, kiểm tra `FunctionRight`...): xem [tapi-permission-patterns.md](tapi-permission-patterns.md).
134
+
135
+ ---
136
+
137
+ ## 8 MCP tools — quản lý định nghĩa quyền của project
138
+
139
+ Các tool này thao tác trực tiếp lên database `acc` (4 API `SM_SystemRight_Select/Update`, `SM_FunctionRight_Select/Update`), dùng **userToken** của dev (đã được cấp quyền vào `acc`) lấy từ `_db/_connections.json` của project hiện tại — không cần cấu hình kết nối riêng.
140
+
141
+ Project nối nhiều database thì token được lấy từ **kết nối khớp `apiName` đang thao tác** (không khớp thì kết nối mặc định) — thiếu `userToken` ở đúng kết nối đó là tool quyền không chạy được, dù kết nối khác đã có token. Xem `db_config_read` để biết kết nối nào đã có token.
142
+
143
+ Tạo / sửa / xóa là **ba tool riêng**: xóa là thao tác 🔴 không hoàn tác, không được nằm chung schema với thao tác thường dưới dạng một boolean dễ truyền nhầm.
144
+
145
+ | Tool | Vai trò | Params chính | Ghi chú an toàn |
146
+ |---|---|---|---|
147
+ | `right_system_list` | Liệt kê định nghĩa `SystemRight` (0–9 + Note) của project | `apiName?`, `projectId?` | Read-only, an toàn |
148
+ | `right_system_new` | Định nghĩa một mức `SystemRight` **chưa có** | `sysRight` (0–9), `note?` (≤50 ký tự, bỏ qua nếu `sysRight=9`), `apiName?`, `projectId?` | Khoá do người dùng chọn (không có ID tự sinh) → tool hỏi `SM_SystemRight_Select` trước; mức đã có = **lỗi cứng**, trỏ sang `right_system_update` |
149
+ | `right_system_update` | **Chỉ sửa** mức `SystemRight` đã có | `sysRight` (**bắt buộc**, lấy từ `right_system_list`), `note?`, `apiName?`, `projectId?` | ⚠️ Ghi đè note hiện tại |
150
+ | `right_system_delete` | Xóa định nghĩa một mức `SystemRight` | `sysRight` (**bắt buộc**), `apiName?`, `projectId?` | 🔴 **Server tự chặn** nếu còn user đang giữ mức quyền đó |
151
+ | `right_function_list` | Liệt kê định nghĩa `FunctionRight` (FunctionID/Code/Name) của project | `apiName?`, `projectId?` | Read-only, an toàn — nguồn duy nhất lấy `functionId` thật |
152
+ | `right_function_new` | Tạo `FunctionRight` mới | `functionCode` (số, unique/project), `functionName?` (≤100 ký tự), `apiName?`, `projectId?` | Gửi `FunctionID: 0` (lệnh INSERT của SP); server từ chối nếu `functionCode` trùng |
153
+ | `right_function_update` | **Chỉ sửa** `FunctionRight` đã có | `functionId` (**bắt buộc**, lấy từ `right_function_list`), `functionCode`, `functionName?`, `apiName?`, `projectId?` | ⚠️ Không còn `?? 0` — quên `functionId` là lỗi, không âm thầm biến thành tạo mới |
154
+ | `right_function_delete` | Xóa 1 `FunctionRight` | `functionId` (**bắt buộc**), `apiName?`, `projectId?` | 🔴 Xóa function **KÈM toàn bộ phân quyền user** đã gán mã đó — không khôi phục được |
155
+
156
+ **Quy tắc dùng:**
157
+ 1. Trước khi gọi `right_system_delete`/`right_function_delete` — luôn tóm tắt rõ hậu quả và chờ user xác nhận (destructive, không hoàn tác).
158
+ 2. Tạo mới thì dùng `right_*_new`; sửa thì **bắt buộc** có định danh (`functionId` / `sysRight`) lấy từ `right_*_list` — không tool nào upsert ngầm.
159
+ 3. Cả 8 tool đều lấy `apiName`/`projectId` mặc định từ project đang active trong session nếu không truyền — truyền `apiName` khi cần thao tác lên project **khác**, hoặc khi project hiện tại có **nhiều kết nối** và quyền cần sửa thuộc alias không phải mặc định.
160
+ 4. Server tự kiểm tra quyền người gọi: Select cần `SystemRight >= 2` trên hệ thống `acc`; Update cần cao hơn hoặc là admin (`9`) của project đích.
161
+
162
+ **API nền tảng** (tham khảo, thường không cần gọi trực tiếp — dùng 8 tool ở trên):
163
+
164
+ ```
165
+ POST {apiDomain}/acc/SM_SystemRight_Select { ModuleID | APIName }
166
+ POST {apiDomain}/acc/SM_SystemRight_Update { ModuleID | APIName, SysRight, Note, Delete }
167
+ POST {apiDomain}/acc/SM_FunctionRight_Select { ModuleID | APIName }
168
+ POST {apiDomain}/acc/SM_FunctionRight_Update { FunctionID, ModuleID | APIName, FunctionCode, FunctionName, Delete }
169
+ ```
@@ -0,0 +1,294 @@
1
+ # FUI Platform Architecture — Cấu tạo & cơ chế phân cấp
2
+
3
+ > File này sở hữu: **cấu tạo FUI và phân cấp Project→Module: import/component/set trộn thế nào, `vueData`/`v_Set`, vòng đời runtime**.
4
+
5
+ Hiểu FUI vận hành thế nào **dưới nắp** để thiết kế đúng ngay từ đầu. Nội dung ở đây rút trực tiếp từ runtime `scripts/fastproject.js` (file chính của nền tảng), `defaultfunction.js` (hàm dùng chung), `component.js`/`componentTable.js` (V3: `componentTable-3.0.js`) — đăng ký component lõi có sẵn (`f-table`, `t-*`, dialog, editor...). `f-echart` (`fechart.js`) và `f-sheet` (`fsheet.js`) là hai component **tách file riêng, nạp qua import khai trong module/project**, không tự động load như phần lõi. Đây là **nguồn sự thật** — không suy từ training data.
6
+
7
+ > Đọc file này TRƯỚC khi thiết kế hệ thống/module. Sau đó: cấu hình từng phần → [module-json-anatomy.md](module-json-anatomy.md); project.json & set → [project-config.md](project-config.md); pattern UI thực tế → [ui-patterns.md](ui-patterns.md) (ưu tiên cao — đã tinh chỉnh qua thực chiến).
8
+
9
+ ---
10
+
11
+ ## 1. FUI là gì
12
+
13
+ FUI (Framework UI) là nền tảng low-code **metadata-driven**: mỗi trang (module) mô tả UI + logic bằng JSON (`module.json`), runtime `fastproject.js` đọc JSON đó và tự dựng DOM Vue 2 + Vuetify. Không viết Vue component thủ công cho từng trang — chỉ khai báo.
14
+
15
+ Một trang FUI khi chạy nạp theo thứ tự (đã bundle sẵn, **không import lại**):
16
+ 1. Thư viện nền: jQuery, Lodash (`_`), Moment, Numeral, Vuetify, vue-toast, jquery-confirm
17
+ 2. `defaultfunction.js` — hàm tiện ích (`openWindow`, `CALL`, `confirm`, `showMessage`, `ajaxCALL`, `jsonToExcel`...)
18
+ 3. `component.js` + `componentTable.js` — đăng ký toàn bộ component `f-*` / `t-*`
19
+ 4. `fastproject.js` — engine: đọc `module.json`, merge config, dựng DOM, chạy action, gắn watch
20
+ 5. Data của trang: `$projectData` (project.json), `$moduleUI` (module.json), `$projectGroupSetting`
21
+
22
+ ---
23
+
24
+ ## 2. Phân cấp Project → Module (CƠ CHẾ TRỘN — quan trọng nhất)
25
+
26
+ FUI có hai cấp: **Project** (dùng chung) và **Module** (một trang). Ba thành phần của Project **tự động nhúng/trộn xuống** mọi Module; khi trùng, **Module chi phối (override)**.
27
+
28
+ ### 2.1 `set` — project.json trộn vào `set` của module
29
+
30
+ Runtime tính config hiệu lực `v_Set` bằng (fastproject.js):
31
+
32
+ ```js
33
+ $.extend(vueData.v_Set, $projectGroupSetting, $projectData, $moduleUI.set);
34
+ // rồi nếu có: $.extend(v_Set, v_Set.domainSetting[domain hiện tại])
35
+ ```
36
+
37
+ Thứ tự ưu tiên (sau ghi đè trước):
38
+
39
+ ```
40
+ $projectGroupSetting (cấu hình nhóm project — thấp nhất)
41
+ ⤵ bị override bởi
42
+ $projectData = project.json (khối "data")
43
+ ⤵ bị override bởi
44
+ $moduleUI.set = "set" trong module.json ← ƯU TIÊN CAO NHẤT
45
+ ⤵ cuối cùng override bởi
46
+ v_Set.domainSetting[domain] (nếu đang chạy trên domain đó)
47
+ ```
48
+
49
+ → Module **kế thừa toàn bộ** config project (menu, apiDomain, style, login...) và chỉ cần khai báo `set` cho những gì khác biệt. Đây là lý do `module.json` của một trang bình thường **không có `set`** (kế thừa hết từ project).
50
+
51
+ Chi tiết các thuộc tính của `set`/`v_Set` và project.json: [project-config.md](project-config.md).
52
+
53
+ ### 2.2 `imports` — project imports **nối** với module imports
54
+
55
+ Import (JS/CSS) khai báo ở cấp project **và** cấp module đều được nạp — không thay thế nhau. Runtime (`addImport`): file `.css` → thêm `<link>`; file khác → nạp như `<script>`.
56
+
57
+ Thứ tự nạp **không phải** "framework rồi project rồi module": server (`spA_FUI_ModuleDataSelect`) UNION cả **ba** phạm vi — framework (theo V2/V3), project (`ModuleID IS NULL`), module — rồi sort **chung một lần** theo `FileSort, FileName`. Nên một import module-scope có `FileSort` nhỏ vẫn nạp **trước** import project-scope. Phụ thuộc thứ tự (vd `echarts.min.js` phải trước `fechart.js`) → phải thể hiện bằng `FileSort`, đừng trông vào phạm vi.
58
+
59
+ Framework tự xưng `FileSort` thấp (~1-10). `file_import_new`/`file_import_update` tự bảo vệ ngưỡng này ở code level (`resolveImportSort`, `src/tools/module.ts`): `fileSort` bỏ trống → mặc định an toàn theo scope (project ≥ 20, module ≥ 50); truyền một giá trị thấp hơn ngưỡng đó → tự nâng lên, kèm ghi chú `ℹ️` trong kết quả tool. Không có cách nào truyền một `FileSort` đủ thấp để chen trước framework qua hai tool này — nếu thật sự cần thứ tự sát framework, phải deploy trực tiếp qua route khác ngoài MCP.
60
+
61
+ - Import project-scope: dùng chung cho mọi module (thư viện chung).
62
+ - Import module-scope: chỉ trang đó (vd `echarts.min.js` + `fechart.js` cho trang có `f-echart`).
63
+ - Module thật thường có `imports/_imports.json` = `[]` khi chỉ dùng thư viện bundle sẵn.
64
+
65
+ > Thêm/bỏ component cần import (f-echart, f-file-upload, f-editor...) → luôn `file_import_list` rồi `file_import_new`/`file_import_delete`. Bảng import: [component-quickref.md](component-quickref.md).
66
+
67
+ #### Hai loại import: CDN/URL vs Nội dung upload (`ContentType`)
68
+
69
+ Một import record trong FUI tồn tại dưới **một trong hai dạng** — phân biệt ngay ở `ContentType`:
70
+
71
+ | Dạng | `ContentType` | Nguồn | Tool chỉnh sửa nội dung |
72
+ |---|---|---|---|
73
+ | **Tham chiếu CDN / URL** | rỗng hoặc không phải JS/CSS | URL ngoài (jsdelivr, cdnjs, custom server...) — không có file local | `file_import_update` (chỉ sửa metadata: url, sort, tên) |
74
+ | **Nội dung đã upload** | `text/javascript` / `text/css` | File lưu trên server FUI, có `fileID` và `filePath` local | `file_import_upload_content` (ghi đè nội dung) |
75
+
76
+ **Hệ quả thực tế — khi người dùng đính kèm file JS/CSS trong chat:**
77
+
78
+ ```
79
+ User đính kèm file.js → nhờ AI tạo import
80
+
81
+ ❌ SAI: file_import_new({ url: "<url nào đó>" })
82
+ → tạo CDN reference, file.js không được lưu lên server
83
+
84
+ ✅ ĐÚNG:
85
+ 1. file_import_new({ ... }) → tạo metadata (tên, sort, scope)
86
+ 2. file_import_upload_content(fileId, nộidung) → upload nội dung file lên server FUI
87
+ ```
88
+
89
+ - `file_import_upload_content` đồng bộ nội dung tới **mọi thư mục `imports/` local** đang khai `fileID` đó — không cần gọi lại tool cho từng scope.
90
+ - Import dạng CDN (URL ngoài): dùng `file_import_update` nếu muốn đổi URL, sort, hay tên — **không thể** upload content vào record này.
91
+ - Dùng `file_import_get` để biết một import đang ở dạng nào (xem trường `ContentType` và `FilePath` trong kết quả).
92
+
93
+ > Kiểm tra trước khi thao tác: `file_import_list` liệt kê mọi import kèm `ContentType` — nhìn vào đó là biết ngay nên gọi tool nào tiếp theo.
94
+
95
+ ### 2.3 `components` — component **dùng chung toàn project**
96
+
97
+ - `component.js` đăng ký sẵn mọi component `f-*`/`t-*` **global**.
98
+ - Custom `uc-*.vue` **project-scope** (`{projectId}/components/`) → FUI tự load **global ở MỌI module**, gọi thẳng bằng tên (không khai báo `components:{}`).
99
+ - `uc-*.vue` **module-scope** (`{moduleId}/components/`) → chỉ dùng trong module đó.
100
+ - Trùng tên → bản module-scope chi phối trong phạm vi module đó.
101
+
102
+ > Component design & scope: [component-design.md](component-design.md).
103
+
104
+ ### 2.4 Bảng tóm tắt phân cấp
105
+
106
+ | Thành phần | Project cung cấp | Trộn vào module thế nào | Khi trùng |
107
+ |---|---|---|---|
108
+ | **set / config** | `project.json` (khối `data`) | Trộn vào `v_Set`, rồi `module.set` | **Module.set thắng** |
109
+ | **imports** | project `_imports.json` | **Nối thêm** vào import module | Cả hai đều nạp |
110
+ | **components** | `uc-*.vue` project-scope + `f-*`/`t-*` global | Auto-load global mọi module | Module-scope thắng |
111
+
112
+ ---
113
+
114
+ ## 3. Runtime state có sẵn (`vueData`)
115
+
116
+ `fastproject.js` khởi tạo sẵn các biến này trong `vueData` — dùng được ngay trong `module.json`/`script.js`, không cần khai báo:
117
+
118
+ | Biến | Ý nghĩa |
119
+ |---|---|
120
+ | `user` | Thông tin user đăng nhập (fetch từ `v_Set.userInfo`) — xem cấu trúc bên dưới |
121
+ | `v_Set` | Config hiệu lực của trang (mục 2.1) — xem [project-config.md](project-config.md) |
122
+ | `p_domain` | Hostname hiện tại (vd `tsa.example.vn`) |
123
+ | `p_router` / `p_routers` | Path hiện tại (`/manager/schedule-assignment`) / mảng segment (`["manager","schedule-assignment"]`) |
124
+ | `p_params` | Query string (`?...`) |
125
+ | `p_urlReferrer` | URL trang giới thiệu |
126
+ | `v_Loading` / `v_LoadingOverlay` | Trạng thái loading khi gọi API (tự quản lý) |
127
+ | `v_containerOn` | Bật/tắt vùng nội dung chính |
128
+
129
+ ### Cấu trúc `vueData` thực tế (mẫu)
130
+
131
+ Runtime khởi tạo sẵn `p_*`, `user`, `v_Set`. Đây là một `vueData` thật (đã rút gọn) — dùng để biết chính xác đường dẫn khi tham chiếu:
132
+
133
+ ```json
134
+ {
135
+ "p_domain": "tsa.example.vn",
136
+ "p_routers": ["manager", "schedule-assignment"],
137
+ "p_router": "/manager/schedule-assignment",
138
+ "p_params": "",
139
+ "user": {
140
+ "UserID": "NV0000001", "UserName": "nguyenvana",
141
+ "LastName": "Nguyễn Văn", "FirstName": "A",
142
+ "Phone": "09xxxxxxxx", "Email": "nguyenvana@example.vn",
143
+ "GroupID": 1, "DepartmentID": "BGH", "ClassID": null,
144
+ "SystemRight": 9, "LastLogin": "2026-06-05 09:16:42",
145
+ "FunctionRight": ["1","2","3","4","5","6","7","8","9","10","11","12","13","14"]
146
+ },
147
+ "v_Set": {
148
+ "title": "Hệ thống quản lý tuyển sinh",
149
+ "apiDomain": "https://tapi.example.vn/",
150
+ "login": "https://app.example.vn",
151
+ "userInfo": "https://tapi.example.vn/acc/userinfo/ts",
152
+ "logo": "https://.../Logo_ChimLac_W.png",
153
+ "ProjectName": "Tuyển Sinh",
154
+ "menuLeft": false,
155
+ "menu": [ { "name": "...", "right": { "FunctionRight": ["10"] }, "submenu": [ ... ] } ],
156
+ "userProfile": {
157
+ "color": "white",
158
+ "url-signout": "https://app.example.vn/Signout",
159
+ "url-change-password": "https://app.example.vn/ChangePassword",
160
+ "url-account": "https://app.example.vn",
161
+ "url-avatar": "https://file.example.vn/me/avatarOrigin/",
162
+ "url-app-list": "https://tapi.example.vn/me/auth/ApplicationList"
163
+ }
164
+ }
165
+ }
166
+ ```
167
+
168
+ **Trường của `user`** (thay đổi tùy `userInfo` endpoint, nhưng thường gồm): `UserID`, `UserName`, `LastName`, `FirstName`, `Phone`, `Email`, `GroupID`, `DepartmentID`, `ClassID`, `SystemRight` (int), `FunctionRight` (**mảng string**, vd `["10","14"]`), `LastLogin`. Một số hệ thống có thêm `Sex`.
169
+
170
+ > **Lưu ý dùng:** `user.SystemRight` là **số** (so sánh `>= 2`); `user.FunctionRight` là **mảng chuỗi** (kiểm tra bằng `.includes('10')` hoặc `rightTest`). Tham chiếu trong controls: `vueData.user.UserID`, `vueData.user.SystemRight`, `vueData.v_Set.apiDomain`...
171
+
172
+ ### API lấy thông tin user (userInfo endpoint)
173
+
174
+ FUI dùng database phân quyền riêng, truy cập qua **apiName/Alias `acc`**. Endpoint lấy thông tin user và quyền hạn trên một project có cấu trúc:
175
+
176
+ ```
177
+ {apiDomain}/acc/userinfo/{project_apiName}
178
+ ```
179
+
180
+ - `{apiDomain}` — domain tAPI của hệ thống (lấy từ `vueData.v_Set.apiDomain`)
181
+ - `acc` — alias cố định cho database phân quyền (không đổi)
182
+ - `userinfo` — tên API lấy thông tin user
183
+ - `{project_apiName}` — apiName/code của project (do admin cấu hình, ví dụ: `quansinh`, `ts`, `qlsv`)
184
+
185
+ **Cách dùng:** khai báo `userInfo` trong `project.json` (field `set`) hoặc `module.json` (field `set`). FUI tự fetch khi trang load và gán kết quả vào `vueData.user`.
186
+
187
+ ```json
188
+ // project.json → set
189
+ {
190
+ "userInfo": "https://tapi.example.vn/acc/userinfo/quansinh"
191
+ }
192
+ ```
193
+
194
+ Sau khi khai báo, toàn bộ thông tin user có sẵn trong `vueData.user`:
195
+
196
+ ```js
197
+ vueData.user.UserID // mã nhân viên/sinh viên
198
+ vueData.user.UserName // tên đăng nhập
199
+ vueData.user.SystemRight // quyền hệ thống (int 0–9)
200
+ vueData.user.FunctionRight // mảng quyền chức năng ["1","2","10",...]
201
+ vueData.user.DepartmentID // mã đơn vị
202
+ ```
203
+
204
+ **Dùng trong controls (v-if ẩn/hiện theo quyền):**
205
+
206
+ ```json
207
+ { "col": { "v-if": "vueData.user.SystemRight >= 5" } }
208
+ { "col": { "v-if": "vueData.user.FunctionRight.includes('10')" } }
209
+ ```
210
+
211
+ **Dùng trong action IN (truyền vào API):**
212
+
213
+ ```json
214
+ { "API": "SP_GetDuLieu", "IN": { "UserID": "vueData.user.UserID", "DeptID": "vueData.user.DepartmentID" } }
215
+ ```
216
+
217
+ > **Lưu ý:** `@sys_UserID`, `@sys_UserName`, `@sys_GroupID`... được tAPI tự inject vào mọi SP — không cần truyền thủ công qua `IN`. Chỉ tham chiếu `vueData.user.*` khi cần dùng trong logic JS/Vue phía client.
218
+
219
+ ### Tham số URL tự inject vào `vueData`
220
+
221
+ `buildParamURL()` đọc mọi query param `?key=value` và gán `vueData[key] = value` **trước khi** `data[]` chạy. → Module con mở qua `openWindow`/`redirect` chỉ cần khai báo biến trùng tên param rồi `{ "CALL": "apiLoad" }` ở cuối `data[]`. (Xem [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md).)
222
+
223
+ ### Quyền của user
224
+
225
+ FUI có 2 loại quyền độc lập — `SystemRight` (cấp bậc trên project) và `FunctionRight` (quyền theo từng chức năng cụ thể), cả hai định nghĩa trong database phân quyền trung tâm (alias `acc`, `{project_apiName}` = APIName của project trong `tblModules`). Runtime: `vueData.user.SystemRight` (int)/`vueData.user.FunctionRight` (mảng string) dùng cho `v-if` và `right` trong menu; hàm `rightTest({ SystemRight:[...], FunctionRight:[...] })` kiểm tra giao quyền.
226
+
227
+ **Khái niệm đầy đủ (SystemRight vs FunctionRight), cấu trúc `tblSysRight`/`tblFunction`, và 4 MCP tool quản lý định nghĩa quyền (`right_system_list/set`, `right_function_list/set`):** xem [permission-system.md](permission-system.md).
228
+
229
+ ---
230
+
231
+ ## 4. Vòng đời khởi tạo một trang (fastproject.js)
232
+
233
+ ```
234
+ $(document).ready → loadModuleInfo()
235
+ 1. Merge v_Set: $projectGroupSetting ← $projectData ← $moduleUI.set
236
+ 2. Áp domainSetting[domain hiện tại] (nếu có)
237
+ 3. buildParamURL(): query ?key=value → vueData[key]
238
+ 4. Nếu v_Set.userInfo: fetch thông tin user → vueData.user
239
+ 5. createModuleDom():
240
+ - runAction($moduleUI.data) → khởi tạo state + chạy action/CALL đầu
241
+ - buildModuleUI($moduleUI.controls) → dựng DOM (container>rows>cols)
242
+ - createWatch_Data / createWatch($moduleUI.watch) → gắn watcher
243
+ - new Vue(...) với Vuetify(v_Set.themeStyle)
244
+ - Kết nối websocket nếu có vueData.webSocket
245
+ - Kiểm tra đăng nhập (v_Set.login)
246
+ ```
247
+
248
+ Hệ quả thiết kế:
249
+ - `data[]` chạy tuần tự trên xuống; đặt khởi tạo state trước, `{ "CALL": ... }` auto-startup ở cuối.
250
+ - Đặt các gán `#PARENT.*` / biến từ URL **trước** các CALL fetch để dữ liệu sẵn sàng.
251
+
252
+ ---
253
+
254
+ ## 5. Action engine — các key trong một action (tham chiếu nhanh)
255
+
256
+ `runAction`/`vueAction` xử lý một object action theo các key sau (nguồn: fastproject.js). Pattern chi tiết + value resolution: **[controls-patterns.md](controls-patterns.md)**.
257
+
258
+ | Key | Tác dụng |
259
+ |---|---|
260
+ | `API` | Gọi endpoint (POST mặc định). Đường dẫn không `http` → tự prepend `v_Set.apiDomain` (`fixURL`) |
261
+ | `IN` | Tham số gửi lên (map từ `vueData`) |
262
+ | `OUT` | Nơi lưu kết quả. Nếu response chỉ có key `data` và `OUT` là string → tự unwrap `d.data` |
263
+ | `METHOD` | Override HTTP method (mặc định POST) |
264
+ | `HEADER` | Override header (mặc định `authorization: Bearer awt`) |
265
+ | `MESS` | Toast thành công |
266
+ | `MESSBOX` | Hộp thoại thông báo (`showMessage`) |
267
+ | `CALLBACK` | Action chạy sau khi API/FUN xong |
268
+ | `ERROROUT` / `ERRORCALLBACK` | Xử lý nhánh lỗi |
269
+ | `CALL` | Gọi action đã đặt tên khác |
270
+ | `CONFIRM` / `CANCEL` | Hỏi xác nhận trước, nhánh hủy |
271
+ | `IF` / `THEN` / `ELSE` | Rẽ nhánh (điều kiện là JS expression trên vueData) |
272
+ | `FUN` (+`IN`/`OUT`/`CALLBACK`) | Gọi hàm global (`openWindow`, `jsonToExcel`, `printPDF`...) |
273
+ | `EXE` | Chạy JS thô (dùng dè xẻn) |
274
+ | *(object thường)* | Gán trực tiếp vào `vueData` (state set) |
275
+
276
+ `json_data_parse` tự parse cột `json_data:Field` trong response thành object (xem [tapi-reference.md](tapi-reference.md)).
277
+
278
+ ---
279
+
280
+ ## 6. Component & hàm dựng sẵn (điểm vào)
281
+
282
+ - **Component `f-*` / `t-*`**: danh mục đầy đủ + import cần thiết → [component-quickref.md](component-quickref.md).
283
+ - **Hàm tiện ích global** (`openWindow`, `CALL`, `confirm`, `showMessage`, `ajaxCALL`, `jsonToExcel`, `groupBy`, `pushRouter`, `rightTest`, `printPDF`, `webSocket_Send`...) → [default-function.md](default-function.md).
284
+ - **Thư viện toàn cục** (`$`, `_`, `moment`, `numeral`, `Vue.$toast`) → [script-map.md](script-map.md) §0 "Thư viện đã bundled sẵn" — đọc trước khi định thêm CDN.
285
+
286
+ ---
287
+
288
+ ## 7. Ghi nhớ thiết kế
289
+
290
+ - Project cung cấp khung (menu, apiDomain, style, component chung); Module chỉ khai báo phần khác biệt.
291
+ - Đừng lặp lại config đã có ở project trong từng module.
292
+ - Component dùng >1 module → đặt project-scope (global), không copy vào từng module.
293
+ - Import chỉ khai báo ở nơi thực sự dùng; component dùng chung → import project-scope.
294
+ - Mọi thứ chạy trên `vueData`; tham chiếu state bằng tiền tố `vueData.` trong controls/attr.