@fui-org/fui-cli 2.1.4 → 2.2.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 (217) hide show
  1. package/README.md +27 -7
  2. package/dist/fui-qrb1j9jz.js +397 -0
  3. package/dist/fui.js +1 -1
  4. package/package.json +1 -1
  5. package/skills/fui/SKILL.md +143 -38
  6. package/skills/fui/agents/fui-builder.md +62 -0
  7. package/skills/fui/agents/fui-tester.md +77 -0
  8. package/skills/{fui-skill → fui}/assets/projectdefaultstyle.css +489 -489
  9. package/skills/{fui-skill → fui}/examples/component.vue +162 -162
  10. package/skills/{fui-skill → fui}/references/INDEX.md +5 -4
  11. package/skills/{fui-skill → fui}/references/advanced-techniques.md +170 -168
  12. package/skills/{fui-skill → fui}/references/component-design.md +2 -2
  13. package/skills/{fui-skill → fui}/references/component-quickref.md +78 -78
  14. package/skills/{fui-skill → fui}/references/component-table.md +287 -287
  15. package/skills/{fui-skill → fui}/references/components-dialog.md +191 -191
  16. package/skills/{fui-skill → fui}/references/components-display.md +141 -141
  17. package/skills/{fui-skill → fui}/references/components-echart.md +316 -316
  18. package/skills/{fui-skill → fui}/references/components-input.md +335 -335
  19. package/skills/{fui-skill → fui}/references/controls-patterns.md +2 -2
  20. package/skills/{fui-skill → fui}/references/controls-styling-vocabulary.md +173 -173
  21. package/skills/{fui-skill → fui}/references/db-workflow.md +9 -9
  22. package/skills/{fui-skill → fui}/references/default-function.md +456 -456
  23. package/skills/{fui-skill → fui}/references/design-modes.md +57 -57
  24. package/skills/{fui-skill → fui}/references/echart-templates.md +489 -489
  25. package/skills/{fui-skill → fui}/references/fastproject.md +99 -99
  26. package/skills/{fui-skill → fui}/references/fullstack-workflow.md +314 -313
  27. package/skills/{fui-skill → fui}/references/module-data-patterns.md +117 -117
  28. package/skills/{fui-skill → fui}/references/module-json-anatomy.md +132 -132
  29. package/skills/{fui-skill → fui}/references/module-structure.md +144 -144
  30. package/skills/{fui-skill → fui}/references/new-session.md +1 -2
  31. package/skills/{fui-skill → fui}/references/pdfmake.md +60 -60
  32. package/skills/{fui-skill → fui}/references/permission-system.md +1 -1
  33. package/skills/{fui-skill → fui}/references/platform-architecture.md +269 -269
  34. package/skills/{fui-skill → fui}/references/project-config.md +303 -303
  35. package/skills/{fui-skill → fui}/references/project-provisioning.md +4 -4
  36. package/skills/{fui-skill → fui}/references/script-map.md +262 -262
  37. package/skills/{fui-skill → fui}/references/sql-clr-functions.md +225 -225
  38. package/skills/{fui-skill → fui}/references/system-design.md +2 -2
  39. package/skills/{fui-skill → fui}/references/tapi-permission-patterns.md +156 -156
  40. package/skills/{fui-skill → fui}/references/tapi-reference.md +474 -474
  41. package/skills/fui/references/team-run.md +141 -0
  42. package/skills/fui/references/tools-registry.md +211 -0
  43. package/skills/{fui-skill → fui}/references/ui-crosswindow-patterns.md +321 -321
  44. package/skills/{fui-skill → fui}/references/ui-dialog-patterns.md +255 -255
  45. package/skills/{fui-skill → fui}/references/ui-layout-patterns.md +176 -176
  46. package/skills/{fui-skill → fui}/references/ui-patterns.md +303 -303
  47. package/skills/{fui-skill → fui}/references/ui-screenshot-review.md +95 -95
  48. package/skills/{fui-skill → fui}/references/ui-table-cell-patterns.md +318 -318
  49. package/skills/{fui-skill → fui}/references/verification.md +11 -11
  50. package/skills/{fui-skill → fui}/references/watcher-patterns.md +163 -163
  51. package/skills/{fui-skill → fui}/references/websocket-realtime.md +271 -271
  52. package/skills/{fui-skill → fui}/scripts/component-3.0.js +2715 -2715
  53. package/skills/{fui-skill → fui}/scripts/component.js +3147 -3147
  54. package/skills/{fui-skill → fui}/scripts/componentTable-3.0.js +1038 -1038
  55. package/skills/{fui-skill → fui}/scripts/componentTable.js +891 -891
  56. package/skills/{fui-skill → fui}/scripts/defaultfunction-3.0.js +866 -866
  57. package/skills/{fui-skill → fui}/scripts/defaultfunction.js +1051 -1051
  58. package/skills/{fui-skill → fui}/scripts/fastproject-3.0.js +870 -870
  59. package/skills/{fui-skill → fui}/scripts/fastproject.js +828 -828
  60. package/dist/fui-h4z7zhk2.js +0 -381
  61. package/skills/fui-skill/SKILL.md +0 -139
  62. package/skills/fui-skill/references/tools-registry.md +0 -84
  63. /package/skills/{fui-skill → fui}/assets/projectdefaultstyle-3.0.css +0 -0
  64. /package/skills/{fui-skill → fui}/design-md/airbnb/DESIGN.md +0 -0
  65. /package/skills/{fui-skill → fui}/design-md/airbnb/README.md +0 -0
  66. /package/skills/{fui-skill → fui}/design-md/airtable/DESIGN.md +0 -0
  67. /package/skills/{fui-skill → fui}/design-md/airtable/README.md +0 -0
  68. /package/skills/{fui-skill → fui}/design-md/apple/DESIGN.md +0 -0
  69. /package/skills/{fui-skill → fui}/design-md/apple/README.md +0 -0
  70. /package/skills/{fui-skill → fui}/design-md/asu/DESIGN.md +0 -0
  71. /package/skills/{fui-skill → fui}/design-md/asu/README.md +0 -0
  72. /package/skills/{fui-skill → fui}/design-md/binance/DESIGN.md +0 -0
  73. /package/skills/{fui-skill → fui}/design-md/binance/README.md +0 -0
  74. /package/skills/{fui-skill → fui}/design-md/bmw/DESIGN.md +0 -0
  75. /package/skills/{fui-skill → fui}/design-md/bmw/README.md +0 -0
  76. /package/skills/{fui-skill → fui}/design-md/bmw-m/DESIGN.md +0 -0
  77. /package/skills/{fui-skill → fui}/design-md/bmw-m/README.md +0 -0
  78. /package/skills/{fui-skill → fui}/design-md/bugatti/DESIGN.md +0 -0
  79. /package/skills/{fui-skill → fui}/design-md/bugatti/README.md +0 -0
  80. /package/skills/{fui-skill → fui}/design-md/cal/DESIGN.md +0 -0
  81. /package/skills/{fui-skill → fui}/design-md/cal/README.md +0 -0
  82. /package/skills/{fui-skill → fui}/design-md/claude/DESIGN.md +0 -0
  83. /package/skills/{fui-skill → fui}/design-md/claude/README.md +0 -0
  84. /package/skills/{fui-skill → fui}/design-md/clay/DESIGN.md +0 -0
  85. /package/skills/{fui-skill → fui}/design-md/clay/README.md +0 -0
  86. /package/skills/{fui-skill → fui}/design-md/clickhouse/DESIGN.md +0 -0
  87. /package/skills/{fui-skill → fui}/design-md/clickhouse/README.md +0 -0
  88. /package/skills/{fui-skill → fui}/design-md/cohere/DESIGN.md +0 -0
  89. /package/skills/{fui-skill → fui}/design-md/cohere/README.md +0 -0
  90. /package/skills/{fui-skill → fui}/design-md/coinbase/DESIGN.md +0 -0
  91. /package/skills/{fui-skill → fui}/design-md/coinbase/README.md +0 -0
  92. /package/skills/{fui-skill → fui}/design-md/composio/DESIGN.md +0 -0
  93. /package/skills/{fui-skill → fui}/design-md/composio/README.md +0 -0
  94. /package/skills/{fui-skill → fui}/design-md/cursor/DESIGN.md +0 -0
  95. /package/skills/{fui-skill → fui}/design-md/cursor/README.md +0 -0
  96. /package/skills/{fui-skill → fui}/design-md/elevenlabs/DESIGN.md +0 -0
  97. /package/skills/{fui-skill → fui}/design-md/elevenlabs/README.md +0 -0
  98. /package/skills/{fui-skill → fui}/design-md/expo/DESIGN.md +0 -0
  99. /package/skills/{fui-skill → fui}/design-md/expo/README.md +0 -0
  100. /package/skills/{fui-skill → fui}/design-md/ferrari/DESIGN.md +0 -0
  101. /package/skills/{fui-skill → fui}/design-md/ferrari/README.md +0 -0
  102. /package/skills/{fui-skill → fui}/design-md/figma/DESIGN.md +0 -0
  103. /package/skills/{fui-skill → fui}/design-md/figma/README.md +0 -0
  104. /package/skills/{fui-skill → fui}/design-md/framer/DESIGN.md +0 -0
  105. /package/skills/{fui-skill → fui}/design-md/framer/README.md +0 -0
  106. /package/skills/{fui-skill → fui}/design-md/fui/DESIGN.md +0 -0
  107. /package/skills/{fui-skill → fui}/design-md/hashicorp/DESIGN.md +0 -0
  108. /package/skills/{fui-skill → fui}/design-md/hashicorp/README.md +0 -0
  109. /package/skills/{fui-skill → fui}/design-md/ibm/DESIGN.md +0 -0
  110. /package/skills/{fui-skill → fui}/design-md/ibm/README.md +0 -0
  111. /package/skills/{fui-skill → fui}/design-md/intercom/DESIGN.md +0 -0
  112. /package/skills/{fui-skill → fui}/design-md/intercom/README.md +0 -0
  113. /package/skills/{fui-skill → fui}/design-md/kraken/DESIGN.md +0 -0
  114. /package/skills/{fui-skill → fui}/design-md/kraken/README.md +0 -0
  115. /package/skills/{fui-skill → fui}/design-md/lamborghini/DESIGN.md +0 -0
  116. /package/skills/{fui-skill → fui}/design-md/lamborghini/README.md +0 -0
  117. /package/skills/{fui-skill → fui}/design-md/linear.app/DESIGN.md +0 -0
  118. /package/skills/{fui-skill → fui}/design-md/linear.app/README.md +0 -0
  119. /package/skills/{fui-skill → fui}/design-md/lovable/DESIGN.md +0 -0
  120. /package/skills/{fui-skill → fui}/design-md/lovable/README.md +0 -0
  121. /package/skills/{fui-skill → fui}/design-md/mastercard/DESIGN.md +0 -0
  122. /package/skills/{fui-skill → fui}/design-md/mastercard/README.md +0 -0
  123. /package/skills/{fui-skill → fui}/design-md/meta/DESIGN.md +0 -0
  124. /package/skills/{fui-skill → fui}/design-md/meta/README.md +0 -0
  125. /package/skills/{fui-skill → fui}/design-md/minimax/DESIGN.md +0 -0
  126. /package/skills/{fui-skill → fui}/design-md/minimax/README.md +0 -0
  127. /package/skills/{fui-skill → fui}/design-md/mintlify/DESIGN.md +0 -0
  128. /package/skills/{fui-skill → fui}/design-md/mintlify/README.md +0 -0
  129. /package/skills/{fui-skill → fui}/design-md/miro/DESIGN.md +0 -0
  130. /package/skills/{fui-skill → fui}/design-md/miro/README.md +0 -0
  131. /package/skills/{fui-skill → fui}/design-md/mistral.ai/DESIGN.md +0 -0
  132. /package/skills/{fui-skill → fui}/design-md/mistral.ai/README.md +0 -0
  133. /package/skills/{fui-skill → fui}/design-md/mongodb/DESIGN.md +0 -0
  134. /package/skills/{fui-skill → fui}/design-md/mongodb/README.md +0 -0
  135. /package/skills/{fui-skill → fui}/design-md/nike/DESIGN.md +0 -0
  136. /package/skills/{fui-skill → fui}/design-md/nike/README.md +0 -0
  137. /package/skills/{fui-skill → fui}/design-md/notion/DESIGN.md +0 -0
  138. /package/skills/{fui-skill → fui}/design-md/notion/README.md +0 -0
  139. /package/skills/{fui-skill → fui}/design-md/nvidia/DESIGN.md +0 -0
  140. /package/skills/{fui-skill → fui}/design-md/nvidia/README.md +0 -0
  141. /package/skills/{fui-skill → fui}/design-md/ollama/DESIGN.md +0 -0
  142. /package/skills/{fui-skill → fui}/design-md/ollama/README.md +0 -0
  143. /package/skills/{fui-skill → fui}/design-md/opencode.ai/DESIGN.md +0 -0
  144. /package/skills/{fui-skill → fui}/design-md/opencode.ai/README.md +0 -0
  145. /package/skills/{fui-skill → fui}/design-md/pinterest/DESIGN.md +0 -0
  146. /package/skills/{fui-skill → fui}/design-md/pinterest/README.md +0 -0
  147. /package/skills/{fui-skill → fui}/design-md/playstation/DESIGN.md +0 -0
  148. /package/skills/{fui-skill → fui}/design-md/playstation/README.md +0 -0
  149. /package/skills/{fui-skill → fui}/design-md/posthog/DESIGN.md +0 -0
  150. /package/skills/{fui-skill → fui}/design-md/posthog/README.md +0 -0
  151. /package/skills/{fui-skill → fui}/design-md/raycast/DESIGN.md +0 -0
  152. /package/skills/{fui-skill → fui}/design-md/raycast/README.md +0 -0
  153. /package/skills/{fui-skill → fui}/design-md/renault/DESIGN.md +0 -0
  154. /package/skills/{fui-skill → fui}/design-md/renault/README.md +0 -0
  155. /package/skills/{fui-skill → fui}/design-md/replicate/DESIGN.md +0 -0
  156. /package/skills/{fui-skill → fui}/design-md/replicate/README.md +0 -0
  157. /package/skills/{fui-skill → fui}/design-md/resend/DESIGN.md +0 -0
  158. /package/skills/{fui-skill → fui}/design-md/resend/README.md +0 -0
  159. /package/skills/{fui-skill → fui}/design-md/revolut/DESIGN.md +0 -0
  160. /package/skills/{fui-skill → fui}/design-md/revolut/README.md +0 -0
  161. /package/skills/{fui-skill → fui}/design-md/runwayml/DESIGN.md +0 -0
  162. /package/skills/{fui-skill → fui}/design-md/runwayml/README.md +0 -0
  163. /package/skills/{fui-skill → fui}/design-md/sanity/DESIGN.md +0 -0
  164. /package/skills/{fui-skill → fui}/design-md/sanity/README.md +0 -0
  165. /package/skills/{fui-skill → fui}/design-md/sentry/DESIGN.md +0 -0
  166. /package/skills/{fui-skill → fui}/design-md/sentry/README.md +0 -0
  167. /package/skills/{fui-skill → fui}/design-md/shopify/DESIGN.md +0 -0
  168. /package/skills/{fui-skill → fui}/design-md/shopify/README.md +0 -0
  169. /package/skills/{fui-skill → fui}/design-md/slack/DESIGN.md +0 -0
  170. /package/skills/{fui-skill → fui}/design-md/spacex/DESIGN.md +0 -0
  171. /package/skills/{fui-skill → fui}/design-md/spacex/README.md +0 -0
  172. /package/skills/{fui-skill → fui}/design-md/spotify/DESIGN.md +0 -0
  173. /package/skills/{fui-skill → fui}/design-md/spotify/README.md +0 -0
  174. /package/skills/{fui-skill → fui}/design-md/starbucks/DESIGN.md +0 -0
  175. /package/skills/{fui-skill → fui}/design-md/starbucks/README.md +0 -0
  176. /package/skills/{fui-skill → fui}/design-md/stripe/DESIGN.md +0 -0
  177. /package/skills/{fui-skill → fui}/design-md/stripe/README.md +0 -0
  178. /package/skills/{fui-skill → fui}/design-md/supabase/DESIGN.md +0 -0
  179. /package/skills/{fui-skill → fui}/design-md/supabase/README.md +0 -0
  180. /package/skills/{fui-skill → fui}/design-md/superhuman/DESIGN.md +0 -0
  181. /package/skills/{fui-skill → fui}/design-md/superhuman/README.md +0 -0
  182. /package/skills/{fui-skill → fui}/design-md/tesla/DESIGN.md +0 -0
  183. /package/skills/{fui-skill → fui}/design-md/tesla/README.md +0 -0
  184. /package/skills/{fui-skill → fui}/design-md/theverge/DESIGN.md +0 -0
  185. /package/skills/{fui-skill → fui}/design-md/theverge/README.md +0 -0
  186. /package/skills/{fui-skill → fui}/design-md/together.ai/DESIGN.md +0 -0
  187. /package/skills/{fui-skill → fui}/design-md/together.ai/README.md +0 -0
  188. /package/skills/{fui-skill → fui}/design-md/uber/DESIGN.md +0 -0
  189. /package/skills/{fui-skill → fui}/design-md/uber/README.md +0 -0
  190. /package/skills/{fui-skill → fui}/design-md/vercel/DESIGN.md +0 -0
  191. /package/skills/{fui-skill → fui}/design-md/vercel/README.md +0 -0
  192. /package/skills/{fui-skill → fui}/design-md/vodafone/DESIGN.md +0 -0
  193. /package/skills/{fui-skill → fui}/design-md/vodafone/README.md +0 -0
  194. /package/skills/{fui-skill → fui}/design-md/voltagent/DESIGN.md +0 -0
  195. /package/skills/{fui-skill → fui}/design-md/voltagent/README.md +0 -0
  196. /package/skills/{fui-skill → fui}/design-md/warp/DESIGN.md +0 -0
  197. /package/skills/{fui-skill → fui}/design-md/warp/README.md +0 -0
  198. /package/skills/{fui-skill → fui}/design-md/webflow/DESIGN.md +0 -0
  199. /package/skills/{fui-skill → fui}/design-md/webflow/README.md +0 -0
  200. /package/skills/{fui-skill → fui}/design-md/wired/DESIGN.md +0 -0
  201. /package/skills/{fui-skill → fui}/design-md/wired/README.md +0 -0
  202. /package/skills/{fui-skill → fui}/design-md/wise/DESIGN.md +0 -0
  203. /package/skills/{fui-skill → fui}/design-md/wise/README.md +0 -0
  204. /package/skills/{fui-skill → fui}/design-md/x.ai/DESIGN.md +0 -0
  205. /package/skills/{fui-skill → fui}/design-md/x.ai/README.md +0 -0
  206. /package/skills/{fui-skill → fui}/design-md/zapier/DESIGN.md +0 -0
  207. /package/skills/{fui-skill → fui}/design-md/zapier/README.md +0 -0
  208. /package/skills/{fui-skill → fui}/examples/f-table-patterns.json +0 -0
  209. /package/skills/{fui-skill → fui}/examples/module-patterns.json +0 -0
  210. /package/skills/{fui-skill → fui}/examples/project-patterns.json +0 -0
  211. /package/skills/{fui-skill → fui}/references/coding-standards.md +0 -0
  212. /package/skills/{fui-skill → fui}/references/db-table-design.md +0 -0
  213. /package/skills/{fui-skill → fui}/references/fsheet.md +0 -0
  214. /package/skills/{fui-skill → fui}/references/tapi-file-api.md +0 -0
  215. /package/skills/{fui-skill → fui}/references/ui-templates.md +0 -0
  216. /package/skills/{fui-skill → fui}/scripts/fechart.js +0 -0
  217. /package/skills/{fui-skill → fui}/scripts/fsheet.js +0 -0
@@ -1,269 +1,269 @@
1
- # FUI Platform Architecture
2
-
3
- > Owns: **FUI structure and Project→Module hierarchy: how import/component/set merge, `vueData`/`v_Set`, runtime lifecycle**.
4
-
5
- Source of truth (not training data): runtime `scripts/fastproject.js` (main), `defaultfunction.js` (shared functions), `component.js`/`componentTable.js` (V3: `componentTable-3.0.js`) — core components (`f-table`, `t-*`, dialog, editor...). `f-echart` (`fechart.js`) and `f-sheet` (`fsheet.js`) are **separate files loaded via imports declared in module/project**, not auto-loaded.
6
-
7
- > Read BEFORE designing a system/module. Then: per-part config → [module-json-anatomy.md](module-json-anatomy.md); project.json & set → [project-config.md](project-config.md); UI patterns → [ui-patterns.md](ui-patterns.md) (high priority, battle-tested).
8
-
9
- ## 1. What FUI is
10
-
11
- Metadata-driven low-code: each page (module) declares UI + logic in `module.json`; `fastproject.js` builds the Vue 2 + Vuetify DOM from it. Declare only — never hand-write a Vue component per page.
12
-
13
- Page load order (pre-bundled, **never re-import**):
14
-
15
- 1. jQuery, Lodash (`_`), Moment, Numeral, Vuetify, vue-toast, jquery-confirm
16
- 2. `defaultfunction.js` — utilities (`openWindow`, `CALL`, `confirm`, `showMessage`, `ajaxCALL`, `jsonToExcel`...)
17
- 3. `component.js` + `componentTable.js` — register all `f-*` / `t-*`
18
- 4. `fastproject.js` — read `module.json`, merge config, build DOM, run actions, attach watch
19
- 5. Page data: `$projectData` (project.json), `$moduleUI` (module.json), `$projectGroupSetting`
20
-
21
- ## 2. Project → Module hierarchy (merge rules — most important)
22
-
23
- **Project** (shared) parts auto-merge into every **Module** (one page); on conflict **Module wins**.
24
-
25
- ### 2.1 `set`
26
-
27
- Effective config `v_Set` (fastproject.js):
28
-
29
- ```js
30
- $.extend(vueData.v_Set, $projectGroupSetting, $projectData, $moduleUI.set);
31
- // rồi nếu có: $.extend(v_Set, v_Set.domainSetting[domain hiện tại])
32
- ```
33
-
34
- Priority (later overrides earlier):
35
-
36
- ```
37
- $projectGroupSetting (cấu hình nhóm project — thấp nhất)
38
- ⤵ bị override bởi
39
- $projectData = project.json (khối "data")
40
- ⤵ bị override bởi
41
- $moduleUI.set = "set" trong module.json ← ƯU TIÊN CAO NHẤT
42
- ⤵ cuối cùng override bởi
43
- v_Set.domainSetting[domain] (nếu đang chạy trên domain đó)
44
- ```
45
-
46
- → Module inherits all project config (menu, apiDomain, style, login...); declare `set` only for differences. A normal page has **no `set`**. Properties: [project-config.md](project-config.md).
47
-
48
- ### 2.2 `imports` — appended, not replaced
49
-
50
- Project and module imports both load. `addImport`: `.css` → `<link>`; else `<script>`.
51
-
52
- Order is **not** framework → project → module: server (`spA_FUI_ModuleDataSelect`) UNIONs framework (per V2/V3), project (`ModuleID IS NULL`) and module scopes, then sorts **once** by `FileSort, FileName`. A module import with small `FileSort` loads **before** a project import. Express order dependencies (e.g. `echarts.min.js` before `fechart.js`) with `FileSort`, never via scope.
53
-
54
- Framework uses `FileSort` ~1-10. `fui import new`/`fui import update` guard this in code (`resolveImportSort`, `src/tools/module.ts`): empty sort → scope default (project ≥ 20, module ≥ 50); lower value → raised, with an `ℹ️` note in output. They cannot place an import before the framework — if truly needed, deploy via a route outside fui.
55
-
56
- - Project-scope: shared libs for all modules.
57
- - Module-scope: that page only (e.g. `echarts.min.js` + `fechart.js` for `f-echart`).
58
- - `imports/_imports.json` = `[]` is normal when only bundled libs are used.
59
-
60
- > Adding/removing a component that needs imports (f-echart, f-file-upload, f-editor...) → always `fui import list`, then `fui import new`/`fui import delete`. Import table: [component-quickref.md](component-quickref.md).
61
-
62
- #### Import kinds by `ContentType`
63
-
64
- | Kind | `ContentType` | Source | Edit with |
65
- | ----------------------- | ------------------------------ | --------------------------------------------------------- | ---------------------------------------------------- |
66
- | **CDN / URL reference** | empty or not JS/CSS | External URL (jsdelivr, cdnjs, custom...) — no local file | `fui import update` (metadata only: url, sort, name) |
67
- | **Uploaded content** | `text/javascript` / `text/css` | Stored on FUI server; has `fileID` and local `filePath` | `fui import upload` (overwrite content) |
68
-
69
- User attaches a JS/CSS file and asks for an import:
70
-
71
- ```
72
- ❌ WRONG: fui import new --content-type link --name "<some url>"
73
- → creates a CDN reference; file.js is never stored on the server
74
-
75
- ✅ RIGHT:
76
- 1. fui import new ... --content-type text/javascript → metadata (name, sort, scope)
77
- 2. fui import upload <fileId> -f file.js → upload content to FUI server
78
- ```
79
-
80
- (Flags: `fui import new --help`.)
81
-
82
- - `fui import upload` syncs to **every local `imports/`** declaring that `fileID` — no per-scope repeat.
83
- - CDN imports: change URL/sort/name via `fui import update`; content **cannot** be uploaded into them.
84
- - `fui import get` shows the kind (`ContentType`, `FilePath`); `fui import list` shows `ContentType` for all — check it first to pick the next command.
85
-
86
- ### 2.3 `components`
87
-
88
- - `component.js` registers all `f-*`/`t-*` **globally**.
89
- - Project-scope `uc-*.vue` (`{projectId}/components/`) → auto-loaded globally in **every** module, used by name (no `components:{}`).
90
- - Module-scope `uc-*.vue` (`{moduleId}/components/`) → that module only.
91
- - Same name → module-scope wins in that module.
92
-
93
- > Design & scope: [component-design.md](component-design.md).
94
-
95
- ### 2.4 Summary
96
-
97
- | Part | Project provides | Merge | On conflict |
98
- | ---------------- | --------------------------------------------- | ------------------------------- | ------------------- |
99
- | **set / config** | `project.json` (`data`) | Into `v_Set`, then `module.set` | **Module.set wins** |
100
- | **imports** | project `_imports.json` | **Appended** to module imports | Both load |
101
- | **components** | project-scope `uc-*.vue` + global `f-*`/`t-*` | Global in every module | Module-scope wins |
102
-
103
- ## 3. Built-in state (`vueData`)
104
-
105
- Pre-initialized; use directly in `module.json`/`script.js`:
106
-
107
- | Variable | Meaning |
108
- | -------------------------------- | -------------------------------------------------------------------------------------- |
109
- | `user` | Logged-in user (from `v_Set.userInfo`) |
110
- | `v_Set` | Effective page config (§2.1) — [project-config.md](project-config.md) |
111
- | `p_domain` | Hostname (e.g. `tsa.example.vn`) |
112
- | `p_router` / `p_routers` | Path (`/manager/schedule-assignment`) / segments (`["manager","schedule-assignment"]`) |
113
- | `p_params` | Query string (`?...`) |
114
- | `p_urlReferrer` | Referrer URL |
115
- | `v_Loading` / `v_LoadingOverlay` | API loading state (self-managed) |
116
- | `v_containerOn` | Toggle main content area |
117
-
118
- Real `vueData` (trimmed) — use for exact paths:
119
-
120
- ```json
121
- {
122
- "p_domain": "tsa.example.vn",
123
- "p_routers": ["manager", "schedule-assignment"],
124
- "p_router": "/manager/schedule-assignment",
125
- "p_params": "",
126
- "user": {
127
- "UserID": "NV0000001", "UserName": "nguyenvana",
128
- "LastName": "Nguyễn Văn", "FirstName": "A",
129
- "Phone": "09xxxxxxxx", "Email": "nguyenvana@example.vn",
130
- "GroupID": 1, "DepartmentID": "BGH", "ClassID": null,
131
- "SystemRight": 9, "LastLogin": "2026-06-05 09:16:42",
132
- "FunctionRight": ["1","2","3","4","5","6","7","8","9","10","11","12","13","14"]
133
- },
134
- "v_Set": {
135
- "title": "Hệ thống quản lý tuyển sinh",
136
- "apiDomain": "https://tapi.example.vn/",
137
- "login": "https://app.example.vn",
138
- "userInfo": "https://tapi.example.vn/acc/userinfo/ts",
139
- "logo": "https://.../Logo_ChimLac_W.png",
140
- "ProjectName": "Tuyển Sinh",
141
- "menuLeft": false,
142
- "menu": [ { "name": "...", "right": { "FunctionRight": ["10"] }, "submenu": [ ... ] } ],
143
- "userProfile": {
144
- "color": "white",
145
- "url-signout": "https://app.example.vn/Signout",
146
- "url-change-password": "https://app.example.vn/ChangePassword",
147
- "url-account": "https://app.example.vn",
148
- "url-avatar": "https://file.example.vn/me/avatarOrigin/",
149
- "url-app-list": "https://tapi.example.vn/me/auth/ApplicationList"
150
- }
151
- }
152
- }
153
- ```
154
-
155
- `user` fields depend on the `userInfo` endpoint; usually `UserID`, `UserName`, `LastName`, `FirstName`, `Phone`, `Email`, `GroupID`, `DepartmentID`, `ClassID`, `SystemRight` (int), `FunctionRight` (**string array**, e.g. `["10","14"]`), `LastLogin`; some systems add `Sex`.
156
-
157
- > `user.SystemRight` is a **number** (compare `>= 2`); `user.FunctionRight` is a **string array** (`.includes('10')` or `rightTest`). In controls: `vueData.user.UserID`, `vueData.user.SystemRight`, `vueData.v_Set.apiDomain`...
158
-
159
- ### userInfo endpoint
160
-
161
- Permission DB is reached via **apiName/Alias `acc`**:
162
-
163
- ```
164
- {apiDomain}/acc/userinfo/{project_apiName}
165
- ```
166
-
167
- - `{apiDomain}` — tAPI domain (`vueData.v_Set.apiDomain`)
168
- - `acc` — fixed permission-DB alias
169
- - `userinfo` — API name
170
- - `{project_apiName}` — project apiName/code (admin-set, e.g. `quansinh`, `ts`, `qlsv`)
171
-
172
- Declare `userInfo` in `set` of `project.json` or `module.json`; FUI fetches it on load into `vueData.user`.
173
-
174
- ```json
175
- // project.json → set
176
- {
177
- "userInfo": "https://tapi.example.vn/acc/userinfo/quansinh"
178
- }
179
- ```
180
-
181
- ```js
182
- vueData.user.UserID; // mã nhân viên/sinh viên
183
- vueData.user.UserName; // tên đăng nhập
184
- vueData.user.SystemRight; // quyền hệ thống (int 0–9)
185
- vueData.user.FunctionRight; // mảng quyền chức năng ["1","2","10",...]
186
- vueData.user.DepartmentID; // mã đơn vị
187
- ```
188
-
189
- In controls (`v-if` by right):
190
-
191
- ```json
192
- { "col": { "v-if": "vueData.user.SystemRight >= 5" } }
193
- { "col": { "v-if": "vueData.user.FunctionRight.includes('10')" } }
194
- ```
195
-
196
- In action `IN`:
197
-
198
- ```json
199
- { "API": "SP_GetDuLieu", "IN": { "UserID": "vueData.user.UserID", "DeptID": "vueData.user.DepartmentID" } }
200
- ```
201
-
202
- > tAPI auto-injects `@sys_UserID`, `@sys_UserName`, `@sys_GroupID`... into every SP — never pass them via `IN`. Use `vueData.user.*` only for client-side JS/Vue logic.
203
-
204
- ### URL params → `vueData`
205
-
206
- `buildParamURL()` sets `vueData[key] = value` for each `?key=value` **before** `data[]` runs. A child module opened via `openWindow`/`redirect` just declares same-named variables and ends `data[]` with `{ "CALL": "apiLoad" }` ([ui-crosswindow-patterns.md](ui-crosswindow-patterns.md)).
207
-
208
- ### User rights
209
-
210
- Two independent kinds, both in the central permission DB (alias `acc`, `{project_apiName}` = project APIName in `tblModules`): `SystemRight` (rank on project, int) and `FunctionRight` (per function, string array). Use in `v-if` and menu `right`; `rightTest({ SystemRight:[...], FunctionRight:[...] })` checks intersection.
211
-
212
- Concepts, `tblSysRight`/`tblFunction`, managing definitions (`fui right system|function list|new|update|delete`): [permission-system.md](permission-system.md).
213
-
214
- ## 4. Page init lifecycle (fastproject.js)
215
-
216
- ```
217
- $(document).ready → loadModuleInfo()
218
- 1. Merge v_Set: $projectGroupSetting ← $projectData ← $moduleUI.set
219
- 2. Áp domainSetting[domain hiện tại] (nếu có)
220
- 3. buildParamURL(): query ?key=value → vueData[key]
221
- 4. Nếu v_Set.userInfo: fetch thông tin user → vueData.user
222
- 5. createModuleDom():
223
- - runAction($moduleUI.data) → khởi tạo state + chạy action/CALL đầu
224
- - buildModuleUI($moduleUI.controls) → dựng DOM (container>rows>cols)
225
- - createWatch_Data / createWatch($moduleUI.watch) → gắn watcher
226
- - new Vue(...) với Vuetify(v_Set.themeStyle)
227
- - Kết nối websocket nếu có vueData.webSocket
228
- - Kiểm tra đăng nhập (v_Set.login)
229
- ```
230
-
231
- - `data[]` runs top to bottom: state init first, auto-startup `{ "CALL": ... }` last.
232
- - Put `#PARENT.*` / URL variable assignments **before** fetch CALLs.
233
-
234
- ## 5. Action keys (quick ref)
235
-
236
- Handled by `runAction`/`vueAction`. Patterns + value resolution: **[controls-patterns.md](controls-patterns.md)**.
237
-
238
- | Key | Effect |
239
- | ------------------------------ | ------------------------------------------------------------------------------------------ |
240
- | `API` | Call endpoint (POST default). Path without `http` → `v_Set.apiDomain` prepended (`fixURL`) |
241
- | `IN` | Params (mapped from `vueData`) |
242
- | `OUT` | Result target. Response with only key `data` + string `OUT` → auto-unwrap `d.data` |
243
- | `METHOD` | Override HTTP method (default POST) |
244
- | `HEADER` | Override header (default `authorization: Bearer awt`) |
245
- | `MESS` | Success toast |
246
- | `MESSBOX` | Message dialog (`showMessage`) |
247
- | `CALLBACK` | Runs after API/FUN finishes |
248
- | `ERROROUT` / `ERRORCALLBACK` | Error branch |
249
- | `CALL` | Call another named action |
250
- | `CONFIRM` / `CANCEL` | Confirm first; cancel branch |
251
- | `IF` / `THEN` / `ELSE` | Branch (JS expression on vueData) |
252
- | `FUN` (+`IN`/`OUT`/`CALLBACK`) | Global function (`openWindow`, `jsonToExcel`, `printPDF`...) |
253
- | `EXE` | Raw JS (sparingly) |
254
- | _(plain object)_ | Assigned into `vueData` |
255
-
256
- `json_data_parse` auto-parses `json_data:Field` response columns into objects ([tapi-reference.md](tapi-reference.md)).
257
-
258
- ## 6. Entry points
259
-
260
- - `f-*` / `t-*` list + required imports → [component-quickref.md](component-quickref.md).
261
- - Global utilities (`openWindow`, `CALL`, `confirm`, `showMessage`, `ajaxCALL`, `jsonToExcel`, `groupBy`, `pushRouter`, `rightTest`, `printPDF`, `webSocket_Send`...) → [default-function.md](default-function.md).
262
- - Global libs (`$`, `_`, `moment`, `numeral`, `Vue.$toast`) → [script-map.md](script-map.md) §0 — read before adding any CDN.
263
-
264
- ## 7. Design rules
265
-
266
- - Project provides the frame (menu, apiDomain, style, shared components); Module declares only differences — never repeat project config per module.
267
- - Component used by >1 module → project-scope, never copied per module.
268
- - Declare imports only where used; shared component → project-scope import.
269
- - Everything runs on `vueData`; reference state with the `vueData.` prefix in controls/attrs.
1
+ # FUI Platform Architecture
2
+
3
+ > Owns: **FUI structure and Project→Module hierarchy: how import/component/set merge, `vueData`/`v_Set`, runtime lifecycle**.
4
+
5
+ Source of truth (not training data): runtime `scripts/fastproject.js` (main), `defaultfunction.js` (shared functions), `component.js`/`componentTable.js` (V3: `componentTable-3.0.js`) — core components (`f-table`, `t-*`, dialog, editor...). `f-echart` (`fechart.js`) and `f-sheet` (`fsheet.js`) are **separate files loaded via imports declared in module/project**, not auto-loaded.
6
+
7
+ > Read BEFORE designing a system/module. Then: per-part config → [module-json-anatomy.md](module-json-anatomy.md); project.json & set → [project-config.md](project-config.md); UI patterns → [ui-patterns.md](ui-patterns.md) (high priority, battle-tested).
8
+
9
+ ## 1. What FUI is
10
+
11
+ Metadata-driven low-code: each page (module) declares UI + logic in `module.json`; `fastproject.js` builds the Vue 2 + Vuetify DOM from it. Declare only — never hand-write a Vue component per page.
12
+
13
+ Page load order (pre-bundled, **never re-import**):
14
+
15
+ 1. jQuery, Lodash (`_`), Moment, Numeral, Vuetify, vue-toast, jquery-confirm
16
+ 2. `defaultfunction.js` — utilities (`openWindow`, `CALL`, `confirm`, `showMessage`, `ajaxCALL`, `jsonToExcel`...)
17
+ 3. `component.js` + `componentTable.js` — register all `f-*` / `t-*`
18
+ 4. `fastproject.js` — read `module.json`, merge config, build DOM, run actions, attach watch
19
+ 5. Page data: `$projectData` (project.json), `$moduleUI` (module.json), `$projectGroupSetting`
20
+
21
+ ## 2. Project → Module hierarchy (merge rules — most important)
22
+
23
+ **Project** (shared) parts auto-merge into every **Module** (one page); on conflict **Module wins**.
24
+
25
+ ### 2.1 `set`
26
+
27
+ Effective config `v_Set` (fastproject.js):
28
+
29
+ ```js
30
+ $.extend(vueData.v_Set, $projectGroupSetting, $projectData, $moduleUI.set);
31
+ // rồi nếu có: $.extend(v_Set, v_Set.domainSetting[domain hiện tại])
32
+ ```
33
+
34
+ Priority (later overrides earlier):
35
+
36
+ ```
37
+ $projectGroupSetting (cấu hình nhóm project — thấp nhất)
38
+ ⤵ bị override bởi
39
+ $projectData = project.json (khối "data")
40
+ ⤵ bị override bởi
41
+ $moduleUI.set = "set" trong module.json ← ƯU TIÊN CAO NHẤT
42
+ ⤵ cuối cùng override bởi
43
+ v_Set.domainSetting[domain] (nếu đang chạy trên domain đó)
44
+ ```
45
+
46
+ → Module inherits all project config (menu, apiDomain, style, login...); declare `set` only for differences. A normal page has **no `set`**. Properties: [project-config.md](project-config.md).
47
+
48
+ ### 2.2 `imports` — appended, not replaced
49
+
50
+ Project and module imports both load. `addImport`: `.css` → `<link>`; else `<script>`.
51
+
52
+ Order is **not** framework → project → module: server (`spA_FUI_ModuleDataSelect`) UNIONs framework (per V2/V3), project (`ModuleID IS NULL`) and module scopes, then sorts **once** by `FileSort, FileName`. A module import with small `FileSort` loads **before** a project import. Express order dependencies (e.g. `echarts.min.js` before `fechart.js`) with `FileSort`, never via scope.
53
+
54
+ Framework uses `FileSort` ~1-10. `fui import new`/`fui import update` guard this in code: empty sort → scope default (project ≥ 20, module ≥ 50); lower value → raised, with a `fileSort N raised to M` note in the output. They cannot place an import before the framework — if truly needed, deploy via a route outside fui.
55
+
56
+ - Project-scope: shared libs for all modules.
57
+ - Module-scope: that page only (e.g. `echarts.min.js` + `fechart.js` for `f-echart`).
58
+ - `imports/_imports.json` = `[]` is normal when only bundled libs are used.
59
+
60
+ > Adding/removing a component that needs imports (f-echart, f-file-upload, f-editor...) → always `fui import list`, then `fui import new`/`fui import delete`. Import table: [component-quickref.md](component-quickref.md).
61
+
62
+ #### Import kinds by `ContentType`
63
+
64
+ | Kind | `ContentType` | Source | Edit with |
65
+ | ----------------------- | ------------------------------ | --------------------------------------------------------- | ---------------------------------------------------- |
66
+ | **CDN / URL reference** | empty or not JS/CSS | External URL (jsdelivr, cdnjs, custom...) — no local file | `fui import update` (metadata only: url, sort, name) |
67
+ | **Uploaded content** | `text/javascript` / `text/css` | Stored on FUI server; has `fileID` and local `filePath` | `fui import upload` (overwrite content) |
68
+
69
+ User attaches a JS/CSS file and asks for an import:
70
+
71
+ ```
72
+ ❌ WRONG: fui import new --content-type link --name "<some url>"
73
+ → creates a CDN reference; file.js is never stored on the server
74
+
75
+ ✅ RIGHT:
76
+ 1. fui import new ... --content-type text/javascript → metadata (name, sort, scope)
77
+ 2. fui import upload <fileId> -f file.js → upload content to FUI server
78
+ ```
79
+
80
+ (Flags: `fui import new --help`.)
81
+
82
+ - `fui import upload` syncs to **every local `imports/`** declaring that `fileID` — no per-scope repeat.
83
+ - CDN imports: change URL/sort/name via `fui import update`; content **cannot** be uploaded into them.
84
+ - `fui import get` shows the kind (`ContentType`, `FilePath`); `fui import list` shows `ContentType` for all — check it first to pick the next command.
85
+
86
+ ### 2.3 `components`
87
+
88
+ - `component.js` registers all `f-*`/`t-*` **globally**.
89
+ - Project-scope `uc-*.vue` (`{projectId}/components/`) → auto-loaded globally in **every** module, used by name (no `components:{}`).
90
+ - Module-scope `uc-*.vue` (`{moduleId}/components/`) → that module only.
91
+ - Same name → module-scope wins in that module.
92
+
93
+ > Design & scope: [component-design.md](component-design.md).
94
+
95
+ ### 2.4 Summary
96
+
97
+ | Part | Project provides | Merge | On conflict |
98
+ | ---------------- | --------------------------------------------- | ------------------------------- | ------------------- |
99
+ | **set / config** | `project.json` (`data`) | Into `v_Set`, then `module.set` | **Module.set wins** |
100
+ | **imports** | project `_imports.json` | **Appended** to module imports | Both load |
101
+ | **components** | project-scope `uc-*.vue` + global `f-*`/`t-*` | Global in every module | Module-scope wins |
102
+
103
+ ## 3. Built-in state (`vueData`)
104
+
105
+ Pre-initialized; use directly in `module.json`/`script.js`:
106
+
107
+ | Variable | Meaning |
108
+ | -------------------------------- | -------------------------------------------------------------------------------------- |
109
+ | `user` | Logged-in user (from `v_Set.userInfo`) |
110
+ | `v_Set` | Effective page config (§2.1) — [project-config.md](project-config.md) |
111
+ | `p_domain` | Hostname (e.g. `tsa.example.vn`) |
112
+ | `p_router` / `p_routers` | Path (`/manager/schedule-assignment`) / segments (`["manager","schedule-assignment"]`) |
113
+ | `p_params` | Query string (`?...`) |
114
+ | `p_urlReferrer` | Referrer URL |
115
+ | `v_Loading` / `v_LoadingOverlay` | API loading state (self-managed) |
116
+ | `v_containerOn` | Toggle main content area |
117
+
118
+ Real `vueData` (trimmed) — use for exact paths:
119
+
120
+ ```json
121
+ {
122
+ "p_domain": "tsa.example.vn",
123
+ "p_routers": ["manager", "schedule-assignment"],
124
+ "p_router": "/manager/schedule-assignment",
125
+ "p_params": "",
126
+ "user": {
127
+ "UserID": "NV0000001", "UserName": "nguyenvana",
128
+ "LastName": "Nguyễn Văn", "FirstName": "A",
129
+ "Phone": "09xxxxxxxx", "Email": "nguyenvana@example.vn",
130
+ "GroupID": 1, "DepartmentID": "BGH", "ClassID": null,
131
+ "SystemRight": 9, "LastLogin": "2026-06-05 09:16:42",
132
+ "FunctionRight": ["1","2","3","4","5","6","7","8","9","10","11","12","13","14"]
133
+ },
134
+ "v_Set": {
135
+ "title": "Hệ thống quản lý tuyển sinh",
136
+ "apiDomain": "https://tapi.example.vn/",
137
+ "login": "https://app.example.vn",
138
+ "userInfo": "https://tapi.example.vn/acc/userinfo/ts",
139
+ "logo": "https://.../Logo_ChimLac_W.png",
140
+ "ProjectName": "Tuyển Sinh",
141
+ "menuLeft": false,
142
+ "menu": [ { "name": "...", "right": { "FunctionRight": ["10"] }, "submenu": [ ... ] } ],
143
+ "userProfile": {
144
+ "color": "white",
145
+ "url-signout": "https://app.example.vn/Signout",
146
+ "url-change-password": "https://app.example.vn/ChangePassword",
147
+ "url-account": "https://app.example.vn",
148
+ "url-avatar": "https://file.example.vn/me/avatarOrigin/",
149
+ "url-app-list": "https://tapi.example.vn/me/auth/ApplicationList"
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ `user` fields depend on the `userInfo` endpoint; usually `UserID`, `UserName`, `LastName`, `FirstName`, `Phone`, `Email`, `GroupID`, `DepartmentID`, `ClassID`, `SystemRight` (int), `FunctionRight` (**string array**, e.g. `["10","14"]`), `LastLogin`; some systems add `Sex`.
156
+
157
+ > `user.SystemRight` is a **number** (compare `>= 2`); `user.FunctionRight` is a **string array** (`.includes('10')` or `rightTest`). In controls: `vueData.user.UserID`, `vueData.user.SystemRight`, `vueData.v_Set.apiDomain`...
158
+
159
+ ### userInfo endpoint
160
+
161
+ Permission DB is reached via **apiName/Alias `acc`**:
162
+
163
+ ```
164
+ {apiDomain}/acc/userinfo/{project_apiName}
165
+ ```
166
+
167
+ - `{apiDomain}` — tAPI domain (`vueData.v_Set.apiDomain`)
168
+ - `acc` — fixed permission-DB alias
169
+ - `userinfo` — API name
170
+ - `{project_apiName}` — project apiName/code (admin-set, e.g. `quansinh`, `ts`, `qlsv`)
171
+
172
+ Declare `userInfo` in `set` of `project.json` or `module.json`; FUI fetches it on load into `vueData.user`.
173
+
174
+ ```json
175
+ // project.json → set
176
+ {
177
+ "userInfo": "https://tapi.example.vn/acc/userinfo/quansinh"
178
+ }
179
+ ```
180
+
181
+ ```js
182
+ vueData.user.UserID; // mã nhân viên/sinh viên
183
+ vueData.user.UserName; // tên đăng nhập
184
+ vueData.user.SystemRight; // quyền hệ thống (int 0–9)
185
+ vueData.user.FunctionRight; // mảng quyền chức năng ["1","2","10",...]
186
+ vueData.user.DepartmentID; // mã đơn vị
187
+ ```
188
+
189
+ In controls (`v-if` by right):
190
+
191
+ ```json
192
+ { "col": { "v-if": "vueData.user.SystemRight >= 5" } }
193
+ { "col": { "v-if": "vueData.user.FunctionRight.includes('10')" } }
194
+ ```
195
+
196
+ In action `IN`:
197
+
198
+ ```json
199
+ { "API": "SP_GetDuLieu", "IN": { "UserID": "vueData.user.UserID", "DeptID": "vueData.user.DepartmentID" } }
200
+ ```
201
+
202
+ > tAPI auto-injects `@sys_UserID`, `@sys_UserName`, `@sys_GroupID`... into every SP — never pass them via `IN`. Use `vueData.user.*` only for client-side JS/Vue logic.
203
+
204
+ ### URL params → `vueData`
205
+
206
+ `buildParamURL()` sets `vueData[key] = value` for each `?key=value` **before** `data[]` runs. A child module opened via `openWindow`/`redirect` just declares same-named variables and ends `data[]` with `{ "CALL": "apiLoad" }` ([ui-crosswindow-patterns.md](ui-crosswindow-patterns.md)).
207
+
208
+ ### User rights
209
+
210
+ Two independent kinds, both in the central permission DB (alias `acc`, `{project_apiName}` = project APIName in `tblModules`): `SystemRight` (rank on project, int) and `FunctionRight` (per function, string array). Use in `v-if` and menu `right`; `rightTest({ SystemRight:[...], FunctionRight:[...] })` checks intersection.
211
+
212
+ Concepts, `tblSysRight`/`tblFunction`, managing definitions (`fui right system|function list|new|update|delete`): [permission-system.md](permission-system.md).
213
+
214
+ ## 4. Page init lifecycle (fastproject.js)
215
+
216
+ ```
217
+ $(document).ready → loadModuleInfo()
218
+ 1. Merge v_Set: $projectGroupSetting ← $projectData ← $moduleUI.set
219
+ 2. Áp domainSetting[domain hiện tại] (nếu có)
220
+ 3. buildParamURL(): query ?key=value → vueData[key]
221
+ 4. Nếu v_Set.userInfo: fetch thông tin user → vueData.user
222
+ 5. createModuleDom():
223
+ - runAction($moduleUI.data) → khởi tạo state + chạy action/CALL đầu
224
+ - buildModuleUI($moduleUI.controls) → dựng DOM (container>rows>cols)
225
+ - createWatch_Data / createWatch($moduleUI.watch) → gắn watcher
226
+ - new Vue(...) với Vuetify(v_Set.themeStyle)
227
+ - Kết nối websocket nếu có vueData.webSocket
228
+ - Kiểm tra đăng nhập (v_Set.login)
229
+ ```
230
+
231
+ - `data[]` runs top to bottom: state init first, auto-startup `{ "CALL": ... }` last.
232
+ - Put `#PARENT.*` / URL variable assignments **before** fetch CALLs.
233
+
234
+ ## 5. Action keys (quick ref)
235
+
236
+ Handled by `runAction`/`vueAction`. Patterns + value resolution: **[controls-patterns.md](controls-patterns.md)**.
237
+
238
+ | Key | Effect |
239
+ | ------------------------------ | ------------------------------------------------------------------------------------------ |
240
+ | `API` | Call endpoint (POST default). Path without `http` → `v_Set.apiDomain` prepended (`fixURL`) |
241
+ | `IN` | Params (mapped from `vueData`) |
242
+ | `OUT` | Result target. Response with only key `data` + string `OUT` → auto-unwrap `d.data` |
243
+ | `METHOD` | Override HTTP method (default POST) |
244
+ | `HEADER` | Override header (default `authorization: Bearer awt`) |
245
+ | `MESS` | Success toast |
246
+ | `MESSBOX` | Message dialog (`showMessage`) |
247
+ | `CALLBACK` | Runs after API/FUN finishes |
248
+ | `ERROROUT` / `ERRORCALLBACK` | Error branch |
249
+ | `CALL` | Call another named action |
250
+ | `CONFIRM` / `CANCEL` | Confirm first; cancel branch |
251
+ | `IF` / `THEN` / `ELSE` | Branch (JS expression on vueData) |
252
+ | `FUN` (+`IN`/`OUT`/`CALLBACK`) | Global function (`openWindow`, `jsonToExcel`, `printPDF`...) |
253
+ | `EXE` | Raw JS (sparingly) |
254
+ | _(plain object)_ | Assigned into `vueData` |
255
+
256
+ `json_data_parse` auto-parses `json_data:Field` response columns into objects ([tapi-reference.md](tapi-reference.md)).
257
+
258
+ ## 6. Entry points
259
+
260
+ - `f-*` / `t-*` list + required imports → [component-quickref.md](component-quickref.md).
261
+ - Global utilities (`openWindow`, `CALL`, `confirm`, `showMessage`, `ajaxCALL`, `jsonToExcel`, `groupBy`, `pushRouter`, `rightTest`, `printPDF`, `webSocket_Send`...) → [default-function.md](default-function.md).
262
+ - Global libs (`$`, `_`, `moment`, `numeral`, `Vue.$toast`) → [script-map.md](script-map.md) §0 — read before adding any CDN.
263
+
264
+ ## 7. Design rules
265
+
266
+ - Project provides the frame (menu, apiDomain, style, shared components); Module declares only differences — never repeat project config per module.
267
+ - Component used by >1 module → project-scope, never copied per module.
268
+ - Declare imports only where used; shared component → project-scope import.
269
+ - Everything runs on `vueData`; reference state with the `vueData.` prefix in controls/attrs.