@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,335 @@
1
+ # Project Config — project.json & module set
2
+
3
+ > File này sở hữu: **`project.json`: menu, menuLeft, điều hướng, domainSetting, `right`, quan hệ với `set` của module**.
4
+
5
+ > Cơ chế trộn nền tảng: [platform-architecture.md](platform-architecture.md) §2.1. File này là **danh mục thuộc tính** đầy đủ của project.json và `set`.
6
+
7
+ > **Sửa rồi đẩy lên thế nào:** `project.json` là **file-driven** như `module.json` — sửa file
8
+ > `{projectId}/project.json` trong workspace, rồi gọi `project_publish_config({ projectId })`. Tool
9
+ > không nhận config qua tham số, nên bản local không bao giờ lệch server sau khi publish. Lấy bản
10
+ > mới nhất về trước khi sửa: `project_sync`. (`project_update` là chuyện khác — nó sửa **metadata**
11
+ > project, không phải runtime config.)
12
+
13
+ ## Quan hệ project.json ↔ module.json `set`
14
+
15
+ `project.json` là config mặc định cho toàn bộ project. Mỗi module có object `set` riêng — khi runtime render một module, `fastproject.js` merge **3 tầng** (tầng sau ghi đè tầng trước) rồi áp override theo domain:
16
+
17
+ ```
18
+ $projectGroupSetting (cấu hình nhóm project — thấp nhất)
19
+ ⤵ override bởi
20
+ project.json (khối "data")
21
+ ⤵ override bởi
22
+ module.json "set" ← ưu tiên cao nhất
23
+ ⤵ cuối cùng override bởi
24
+ domainSetting[domain hiện tại] (nếu đang chạy trên domain đó)
25
+ ```
26
+
27
+ Kết quả lưu ở `vueData.v_Set` — mọi nơi trong trang đọc qua `vueData.v_Set.*`.
28
+
29
+ **Kết quả:** Module kế thừa toàn bộ config project (menu, style, apiDomain...) nhưng có thể override bất kỳ field nào cho riêng trang đó. Trang bình thường **không cần `set`**.
30
+
31
+ ### Danh mục thuộc tính `v_Set` (project.json.data hoặc module.set)
32
+
33
+ Runtime khởi tạo và sử dụng các field sau (nguồn: `fastproject.js`):
34
+
35
+ | Field | Kiểu | Tác động |
36
+ |---|---|---|
37
+ | `title` | string | Tiêu đề trang (thanh header) |
38
+ | `apiDomain` | string | Base URL tAPI — API path không `http` được prepend giá trị này |
39
+ | `login` | string | URL trang đăng nhập; runtime tự mở khi thiếu token / 401 |
40
+ | `userInfo` | string | Endpoint lấy thông tin user → `vueData.user`; rỗng = không fetch |
41
+ | `menu` | `false` \| array | Menu header ngang; `false` = ẩn (cao 48px khi hiện) |
42
+ | `menuLeft` | array | Menu sidebar trái |
43
+ | `menuComponent` | array | Custom component nhúng vào vùng menu |
44
+ | `menuStyle` | object | Màu top/left menu |
45
+ | `logo` | string | URL logo trên header |
46
+ | `userProfile` | object/string | Cấu hình khối profile user trên header |
47
+ | `themeStyle` | object | Truyền vào `new Vuetify(...)` — theme màu Vuetify của trang |
48
+ | `disableValidate` | boolean | `true` = bỏ qua validate form khi submit |
49
+ | `authDomain` | string | Domain để xóa cookie khi `logout()` |
50
+ | `fileDomain` | string | Base URL file server |
51
+ | `domainSetting` | object | Override config theo domain (đa domain) |
52
+ | `webSocket` | object | Cấu hình SignalR group real-time (xem [websocket-realtime.md](websocket-realtime.md)) |
53
+
54
+ **Ví dụ:** Project có `menuLeft` dài, nhưng một trang landing page muốn ẩn menu:
55
+
56
+ ```json
57
+ // module.json — set của trang đó
58
+ "set": {
59
+ "menu": false
60
+ }
61
+ ```
62
+
63
+ → Trang này không hiển thị header menu, các trang khác vẫn bình thường.
64
+
65
+ ---
66
+
67
+ ## Cấu trúc project.json
68
+
69
+ `project.json` chứa một object `data` duy nhất (không phải array như module.json):
70
+
71
+ ```json
72
+ {
73
+ "data": {
74
+ "ProjectName": "...",
75
+ "title": "...",
76
+ "apiDomain": "...",
77
+ "login": "...",
78
+ "userInfo": "...",
79
+ "apiFile": "...",
80
+ "menuStyle": { ... },
81
+ "menu": false | [ ... ],
82
+ "menuLeft": [ ... ],
83
+ "menuComponent": [ ... ],
84
+ "domainSetting": { ... }
85
+ }
86
+ }
87
+ ```
88
+
89
+ ### Các field trong `data`
90
+
91
+ | Field | Kiểu | Mô tả |
92
+ |---|---|---|
93
+ | `ProjectName` | string | Tên project hiển thị |
94
+ | `title` | string | Tiêu đề mặc định cho các trang |
95
+ | `logo` | string | URL ảnh logo trên thanh menu, ví dụ `"/images/fastUI_White.png"` |
96
+ | `apiDomain` | string | Base URL tAPI kèm apiName, ví dụ `https://tapi.example2.vn/` hoặc `https://tapi.example.vn/acc/` |
97
+ | `login` | string | URL trang đăng nhập |
98
+ | `userInfo` | string | Endpoint lấy thông tin user đã đăng nhập. FUI public: `"https://api.fui.vn/fp/userinfo"` |
99
+ | `apiFile` | string | Endpoint upload file (tùy chọn) |
100
+ | `fileDomain` | string | Base URL file server (tùy chọn) |
101
+ | `menuStyle` | object | Style cho menu top/left |
102
+ | `menu` | `false` hoặc array | Menu header ngang — `false` = ẩn hoàn toàn |
103
+ | `menuLeft` | array | Menu sidebar trái |
104
+ | `menuComponent` | array | Component tùy chỉnh nhúng vào vùng menu |
105
+ | `domainSetting` | object | Override config theo từng domain (đa domain) |
106
+
107
+ ---
108
+
109
+ ## menuStyle
110
+
111
+ Tùy chỉnh màu sắc cho top menu và left menu:
112
+
113
+ ```json
114
+ "menuStyle": {
115
+ "topmenu": {
116
+ "bgcolor": "#217D46",
117
+ "textcolor": "white"
118
+ },
119
+ "leftmenu": {
120
+ "bgcolor": "#217D46",
121
+ "textcolor": "white"
122
+ }
123
+ }
124
+ ```
125
+
126
+ ---
127
+
128
+ ## menu (top header)
129
+
130
+ - `false` → ẩn hoàn toàn thanh header chứa menu
131
+ - Array → danh sách menu item hiển thị ở thanh top
132
+
133
+ **Chiều cao cố định: 48px.** Khi `menu` đang hiển thị (không phải `false`), thanh menu chiếm 48px trên đầu trang. Bất kỳ tính toán chiều cao "full màn hình" nào cho vùng nội dung (`calc(100vh - Npx)`, `$(window).height() - N`, CSS `height: 100vh` trên container...) đều phải cộng thêm 48px vào phần trừ đi để tránh tràn/scroll ngoài ý muốn:
134
+
135
+ ```css
136
+ /* Có menu hiển thị */
137
+ height: calc(100vh - 48px);
138
+
139
+ /* menu: false → không trừ phần này */
140
+ height: 100vh;
141
+ ```
142
+
143
+ Áp dụng cho cả `module.json` (`:height` của `f-table`, `f-echart`...) lẫn CSS trong `header.html`/component cho trang `HTMLOnly=true`.
144
+
145
+ ---
146
+
147
+ ## menuLeft (sidebar)
148
+
149
+ Array các menu item hiển thị ở sidebar trái. Cấu trúc một item:
150
+
151
+ ```json
152
+ {
153
+ "name": "Tên mục",
154
+ "icon": "mdi-folder-multiple",
155
+ "url": "/duong-dan-module",
156
+ "submenu": [ ... ],
157
+ "right": {
158
+ "SystemRight": [1, 2, 3, 5, 9],
159
+ "FunctionRight": ["10", "20"]
160
+ }
161
+ }
162
+ ```
163
+
164
+ ### Cấu trúc menu item
165
+
166
+ | Field | Bắt buộc | Mô tả |
167
+ |---|---|---|
168
+ | `name` | ✅ | Tên hiển thị |
169
+ | `url` | ❌ | Đường dẫn module (bỏ qua nếu chỉ là nhóm có submenu) |
170
+ | `icon` | ❌ | Icon Material Design (`mdi-*`) |
171
+ | `submenu` | ❌ | Mảng menu con (cùng cấu trúc) |
172
+ | `right` | ❌ | Điều kiện hiển thị theo quyền — thiếu = hiển thị cho tất cả |
173
+
174
+ ### Kiểm tra quyền hiển thị menu (`right`)
175
+
176
+ > Phân biệt `SystemRight` (cấp bậc) vs `FunctionRight` (quyền theo chức năng) và cách quản lý định nghĩa quyền: xem [permission-system.md](permission-system.md).
177
+
178
+ ```json
179
+ "right": {
180
+ "SystemRight": [1, 2, 5, 9],
181
+ "FunctionRight": ["10", "20"]
182
+ }
183
+ ```
184
+
185
+ - **`SystemRight`**: `user.SystemRight` (số) phải nằm trong mảng này mới thấy menu item
186
+ - **`FunctionRight`**: `user.FunctionRight` (mảng chuỗi) phải giao với mảng này (có ít nhất một mã) mới thấy
187
+ - **`UserID`**: chỉ các `UserID` liệt kê mới thấy — dùng cho menu nội bộ/DEV
188
+ - Khi khai báo nhiều key: user phải thỏa **tất cả** (hàm `rightTest` kiểm tra giao từng key với `vueData.user[key]`)
189
+ - Không khai báo `right` → item hiển thị cho tất cả user đã đăng nhập
190
+
191
+ **Ví dụ thực tế — menu DEV chỉ cho vài UserID:**
192
+ ```json
193
+ {
194
+ "name": "DEV",
195
+ "right": { "UserID": ["NV0000177", "NV0001078", "NV0000605"] },
196
+ "submenu": [
197
+ { "name": "Tra cứu lịch sử OTP", "url": "/hoso-sms-history" }
198
+ ]
199
+ }
200
+ ```
201
+ > Menu top thường chỉ có `name` + `right` + `submenu` (không `url` ở cấp cha); `url` nằm ở từng mục `submenu`.
202
+
203
+ **Ví dụ thực tế — menu chỉ cho Tổ trưởng/BGH cấp 1:**
204
+ ```json
205
+ {
206
+ "name": "Cấp 1 - Tổ trưởng",
207
+ "icon": "mdi-account-tie",
208
+ "right": {
209
+ "FunctionRight": ["10"],
210
+ "SystemRight": [5, 9]
211
+ },
212
+ "submenu": [ ... ]
213
+ }
214
+ ```
215
+ → Chỉ user có `FunctionRight` chứa `"10"` (cấp 1) VÀ `SystemRight` là 5 hoặc 9 mới thấy mục này.
216
+
217
+ ---
218
+
219
+ ## menuComponent
220
+
221
+ Mảng các custom Vue component được nhúng vào vùng menu (ví dụ: dropdown chọn niên khóa, chọn vai trò):
222
+
223
+ ```json
224
+ "menuComponent": [
225
+ { "el": "uc-nien-khoa" },
226
+ { "el": "uc-vaitro" }
227
+ ]
228
+ ```
229
+
230
+ Component phải được đăng ký trong `components/_components.json` của project.
231
+
232
+ ---
233
+
234
+ ## userProfile (khối tài khoản trên header)
235
+
236
+ Cấu hình khối avatar/tài khoản góc phải header (đăng xuất, đổi mật khẩu, danh sách app):
237
+
238
+ ```json
239
+ "userProfile": {
240
+ "color": "white",
241
+ "url-signout": "https://app.example.vn/Signout",
242
+ "url-change-password": "https://app.example.vn/ChangePassword",
243
+ "url-account": "https://app.example.vn",
244
+ "url-avatar": "https://file.example.vn/me/avatarOrigin/",
245
+ "url-app-list": "https://tapi.example.vn/me/auth/ApplicationList"
246
+ }
247
+ ```
248
+
249
+ | Field | Ý nghĩa |
250
+ |---|---|
251
+ | `color` | Màu chữ/icon khối profile |
252
+ | `url-signout` | URL đăng xuất |
253
+ | `url-change-password` | URL đổi mật khẩu |
254
+ | `url-account` | URL trang tài khoản |
255
+ | `url-avatar` | Base URL ảnh đại diện (ghép `UserID`) |
256
+ | `url-app-list` | Endpoint danh sách ứng dụng (menu chuyển app) |
257
+
258
+ > `menuLeft: false` = không dùng sidebar trái (chỉ menu top). `menuLeft: [ ... ]` = bật sidebar.
259
+
260
+ ---
261
+
262
+ ## domainSetting (đa domain)
263
+
264
+ Khi một project chạy trên nhiều domain khác nhau (mỗi domain có tAPI server và DB riêng), dùng `domainSetting` để override config theo domain:
265
+
266
+ ```json
267
+ "domainSetting": {
268
+ "sec.example.vn": {
269
+ "apiDomain": "https://tapi.example.vn/acc/",
270
+ "fileDomain": "https://file.example.vn/acc/",
271
+ "login": "https://app.example.vn",
272
+ "userInfo": "https://tapi.example.vn/acc/UserInfo/acc"
273
+ },
274
+ "sec.example3.vn": {
275
+ "apiDomain": "https://api.example3.vn/acc/",
276
+ "fileDomain": "https://file.example3.vn/acc/",
277
+ "login": "https://login.example3.vn",
278
+ "userInfo": "https://api.example3.vn/acc/UserInfo/acc"
279
+ }
280
+ }
281
+ ```
282
+
283
+ Key là hostname của domain. Runtime tự phát hiện domain hiện tại và áp dụng override tương ứng.
284
+
285
+ ---
286
+
287
+ ## module.json `set` — Override cho từng trang
288
+
289
+ `set` trong module.json có thể override bất kỳ field nào từ project.json. Các field thường dùng:
290
+
291
+ ```json
292
+ "set": {
293
+ "title": "Trang quản lý sinh viên",
294
+ "menu": false,
295
+ "menuLeft": [ ... ]
296
+ }
297
+ ```
298
+
299
+ | Dùng `set` khi | Ví dụ |
300
+ |---|---|
301
+ | Trang có tiêu đề riêng | `"title": "Nhập điểm Tiểu học"` |
302
+ | Trang ẩn menu header | `"menu": false` |
303
+ | Trang cần menu sidebar khác | Override `"menuLeft"` với danh sách rút gọn |
304
+ | Trang landing / public | `"menu": false, "menuLeft": []` |
305
+
306
+ **Không cần ghi lại các field không thay đổi** — module chỉ cần khai báo những gì khác với project default.
307
+
308
+ ---
309
+
310
+ ## Tóm tắt quan hệ file
311
+
312
+ ```
313
+ project.json.data ← config mặc định cho toàn project
314
+ ↓ bị override bởi
315
+ module.json.set ← config riêng cho từng trang
316
+
317
+ Effective config = merge(project.json.data, module.json.set)
318
+ (module.set được ưu tiên)
319
+ ```
320
+
321
+ ---
322
+
323
+ ## openWindow — Quy tắc truyền tham số URL
324
+
325
+ Khi mở sub-window bằng `openWindow`, URL chỉ truyền **ID của record cha** mà module con thực sự dùng để query DB. Không truyền name, label hay field nào có thể tra lại từ DB trong module con.
326
+
327
+ ```json
328
+ // ✅ Đúng — chỉ truyền ID cần thiết
329
+ "url": "`/ContestDetail?ContestID={{sContestID}}"
330
+
331
+ // ❌ Sai — truyền thừa field có thể tra từ DB
332
+ "url": "`/ContestDetail?ContestID={{sContestID}}&ContestName={{sContestName}}"
333
+ ```
334
+
335
+ **Lý do:** Module con load dữ liệu đầy đủ từ DB theo ID — truyền thêm field thừa làm URL dài, dữ liệu có thể lỗi thời, và tạo dependency không cần thiết giữa 2 module.