@fui-org/fui-cli 0.2.0 → 0.3.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 +13 -1
  2. package/dist/fui.js +160 -43
  3. package/package.json +4 -2
  4. package/skills/fui/SKILL.md +131 -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,504 @@
1
+ # DB Connection Workflow
2
+
3
+ > File này sở hữu: **kết nối DB, dbToken, schema cache, workflow làm việc với SP, rollback**. Mức rủi ro + guard từng tool xem [tools-registry.md](tools-registry.md); checklist SP xem [verification.md](verification.md).
4
+
5
+ Hướng dẫn toàn diện về kết nối database cho một FUI project — từ tìm thông tin kết nối, build token, đến quản lý schema và SP.
6
+
7
+ ---
8
+
9
+ ## 1. Thông tin kết nối lưu ở đâu
10
+
11
+ Mỗi project có thư mục `_db/` riêng, **bên trong là một thư mục con cho MỖI kết nối** — một project
12
+ FUI gọi được nhiều database cùng lúc, mỗi cái qua một alias (`apiName`) riêng:
13
+
14
+ ```
15
+ {FUI_MCP_WORKDIR}/{projectId}/
16
+ └── _db/
17
+ ├── _connections.json ← MỌI kết nối của project + kết nối mặc định
18
+ ├── rights.json ← cache quyền từ "acc", khoá theo alias
19
+ ├── {alias}/ ← alias = apiName = đoạn đầu trong "API": "/{alias}/Ten"
20
+ │ ├── schema.json ← cache schema của DB đó
21
+ │ └── {name}.sql ← SP của DB đó (KHÔNG có tầng "sp/")
22
+ └── {alias-khác}/…
23
+ ```
24
+
25
+ **Alias là khoá nối mọi thứ lại**: đoạn đầu trong `"API": "/fee/HocPhi_Select"` của module.json chính
26
+ là `apiName` trong tAPI, cũng chính là tên thư mục `_db/fee/`. Đọc module.json là biết ngay lời gọi
27
+ đó chạy trên database nào và phải mở thư mục nào.
28
+
29
+ > Mọi tool DB nhận tham số **`db`** (alias) để chọn kết nối. Bỏ trống thì MCP tự suy từ object đang
30
+ > thao tác; **suy không ra thì nó trả về một MENU các alias** — chọn một cái rồi gọi lại, đừng đoán.
31
+
32
+ Bản cũ **không** nằm cạnh bản hiện tại: mọi thứ sắp bị ghi đè/xoá đi về một kho chung
33
+ `{FUI_MCP_WORKDIR}/_history/`, giữ nguyên hình dạng đường dẫn gốc:
34
+
35
+ ```
36
+ {FUI_MCP_WORKDIR}/_history/{projectId}/_db/{alias}/{name}_{thời điểm}.sql
37
+ {FUI_MCP_WORKDIR}/_history/{projectId}/_db/{alias}/{name}_{thời điểm}_deleted.sql ← SP bị DROP
38
+ ```
39
+
40
+ Một kho duy nhất cho cả project lẫn DB: lúc cần bản cũ chỉ phải nhớ **một** chỗ, và mọi bản của cùng
41
+ một file nằm cạnh nhau (tìm theo tên file, không phải theo thời điểm). Kho này **không bao giờ tự
42
+ dọn** — user tự xoá tay khi thấy đủ.
43
+
44
+ **Cấu trúc `_db/_connections.json`:**
45
+
46
+ ```json
47
+ {
48
+ "default": "acc",
49
+ "connections": {
50
+ "acc": {
51
+ "apiDomain": "api.example3.vn",
52
+ "sqlServer": "192.0.2.101",
53
+ "database": "AccountUser",
54
+ "dbToken": "<base64-encoded connection string>",
55
+ "userToken": "<bearer token — tùy chọn>"
56
+ },
57
+ "Dashboard": { "apiDomain": "api.example3.vn", "…": "…" }
58
+ }
59
+ }
60
+ ```
61
+
62
+ `default` chỉ áp cho thao tác **đọc** không nêu `db`. Thao tác **ghi** (`db_sql_execute` có lệnh ghi,
63
+ `db_sql_execute_nonquery`, `db_token_rebuild`) không bao giờ tự dùng mặc định — phải nêu rõ `db`.
64
+
65
+ | Field | Bắt buộc | Mô tả |
66
+ |---|---|---|
67
+ | khoá của mục | ✅ | Chính là `apiName`/alias — vừa là tên thư mục `_db/{alias}/`, vừa là đoạn đầu trong `"API": "/{alias}/Ten"` |
68
+ | `apiDomain` | ✅ | **Chỉ host, KHÔNG có alias, KHÔNG có dấu `/` ở cuối** — ví dụ `api.example3.vn` |
69
+ | `sqlServer` | ❌* | Host SQL Server — cần có để dùng `db_token_rebuild` |
70
+ | `database` | ❌* | Tên database — cần có để dùng `db_token_rebuild` |
71
+ | `dbToken` | ✅ | Chuỗi kết nối SQL Server đã base64-encode |
72
+ | `userToken` | ❌ | Bearer token để test `spAPI_*` sau khi deploy |
73
+
74
+ *Nên truyền khi `db_connect` để sau này có thể `db_token_rebuild` mà không cần hỏi lại.
75
+
76
+ > **CRITICAL — `apiDomain` mang HAI nghĩa khác nhau trong hệ thống, đừng lẫn lộn:**
77
+ > - `_db/_connections.json` (MCP, bảng trên) → **host trần**, không alias, không `/` cuối: `api.example3.vn`.
78
+ > - `project.json`'s `data.apiDomain` (runtime FUI, mục 2a bên dưới) → **base URL đầy đủ** đã kèm sẵn `apiName` + `/` cuối: `https://tapi.example.vn/acc/`.
79
+ >
80
+ > Ghép URL thủ công bằng cách lấy `_db/_connections.json`'s `apiDomain` (host trần) rồi nối thẳng `apiName` vào — **không chèn `/`** — là lỗi hay gặp nhất khi tự gõ tay: `tapi.lhu.edu.vn` + `ts` → `tapi.lhu.edu.vnts` (sai, "ts" bị nuốt vào domain) thay vì `tapi.lhu.edu.vn/ts` (đúng). Xem thêm ví dụ đối chiếu ❌/✅ ở [tapi-reference.md](tapi-reference.md) §3. Cách an toàn nhất: đừng tự ghép — copy nguyên văn dòng `Wiring URL` từ `db_sp_verify`/`db_sp_help`.
81
+
82
+ ---
83
+
84
+ ## 2. Tìm thông tin kết nối của một project
85
+
86
+ ### 2a. Đọc `apiDomain` từ project.json
87
+
88
+ `project.json` của mỗi project thường có trường `data.apiDomain` — đây là base URL của tAPI server kèm apiName:
89
+
90
+ ```json
91
+ "data": {
92
+ "apiDomain": "https://tapi.example.vn/acc/",
93
+ ...
94
+ }
95
+ ```
96
+
97
+ Từ URL này:
98
+ - **`apiDomain`** → `tapi.example.vn`
99
+ - **`apiName`** → `acc` (phần path đầu tiên sau domain)
100
+
101
+ Một số project có nhiều domain, mỗi domain dùng một tAPI server riêng:
102
+
103
+ ```json
104
+ "domainSetting": {
105
+ "sec.example.vn": {
106
+ "apiDomain": "https://tapi.example.vn/acc/"
107
+ },
108
+ "sec.example3.vn": {
109
+ "apiDomain": "https://api.example3.vn/acc/"
110
+ }
111
+ }
112
+ ```
113
+
114
+ → Hỏi user đang làm việc với domain nào để chọn `apiDomain` đúng.
115
+
116
+ ### 2b. Chỉ biết alias, chưa có dbToken → `db_alias_list` + `db_connect_by_name`
117
+
118
+ `db_connect` đòi sẵn `dbToken`, mà `dbToken` là base64 của một chuỗi kết nối **kèm UID/PWD**. Khi bạn
119
+ chỉ biết `apiName` thì **đừng đi tra tay bằng PowerShell** (moi UID/PWD ra command line là phơi
120
+ credential, và cả quy trình đó nay đã có tool):
121
+
122
+ **Bước 1 — xem mình được cấp những database nào:**
123
+ ```
124
+ db_alias_list()
125
+ ```
126
+ **Không cần tham số nào.** `SM_Modules_ManagerSelect` không nhận tham số: tAPI bơm `@sys_UserID` từ
127
+ Bearer token ở phía server, nên danh sách trả về **đã lọc sẵn theo quyền quản lý của chính bạn**.
128
+ Trả về bảng `APIName | SQLServer | DatabaseName | ModuleName | Enable`. Danh sách dài thì thêm
129
+ `search` để lọc phía client (khớp `APIName`/`DatabaseName`/`ModuleName`, không phân biệt hoa-thường).
130
+
131
+ **Bước 2 — kết nối:**
132
+ ```
133
+ db_connect_by_name({ apiName: "basic" })
134
+ ```
135
+ Tool làm trọn gói: tra `SQLServer`/`DatabaseName` từ acc → **mượn cặp UID/PWD** của một kết nối bạn đã
136
+ có → dựng `dbToken` → **test `SELECT 1` trước khi lưu bất cứ thứ gì** → `saveConnection` +
137
+ fetch schema về `_db/{alias}/`. Báo cáo giống hệt `db_connect`. **Không bao giờ in dbToken/UID/PWD.**
138
+
139
+ Thứ đang mượn là **cặp tài khoản**, còn Server/Database thì lấy từ acc — đúng ranh giới của quy trình
140
+ làm tay cũ. Workspace có nhiều login **khác nhau** → tool trả **menu** để bạn chọn, không đoán; nêu rõ
141
+ bằng `borrowCredentialsFrom: "{projectId}/{alias}"`. (Một login xuất hiện ở nhiều kết nối cùng group
142
+ là chuyện thường và **không** bị coi là nhập nhằng.)
143
+
144
+ **Không tìm thấy `apiName` mang HAI nghĩa** — alias không tồn tại, **hoặc** bạn không được cấp quyền
145
+ quản lý nó. Đừng vội kết luận là gõ sai tên: chạy `db_alias_list()` xem mình thực sự có gì.
146
+
147
+ Project **chưa có kết nối nào** vẫn chạy được (đây đúng là lúc cần tool nhất): `apiDomain` bóc từ
148
+ `project.json` local, `userToken` mượn từ kết nối của project khác cùng domain — chỉ tự chọn khi có
149
+ đúng một ứng viên, nhiều thì trả menu. Bí quá thì truyền thẳng `apiDomain` + `userToken`.
150
+
151
+ > ⚠️ Field `Password` trong response của `SM_Modules_ManagerSelect` là **hash nội bộ của tAPI**, không
152
+ > phải SQL Server password thực — không dùng được để build dbToken. Tool **không in field này ra**.
153
+
154
+ ### 2c. Workflow đầy đủ — kết nối DB lần đầu cho project mới
155
+
156
+ > Mục này giả định database **đã tồn tại và đã được đăng ký alias** trong `acc`. Chưa có (dựng dự án
157
+ > từ số 0) → làm [project-provisioning.md](project-provisioning.md) trước: tạo DB, hai tài khoản SQL,
158
+ > rồi `db_alias_new` để có alias — xong mới quay lại đây.
159
+
160
+ ```
161
+ 1. project_sync(projectId) → có project.json local (nguồn của apiDomain)
162
+ 2. session_set({ projectId }) → khỏi phải truyền projectId ở mọi bước sau
163
+ 3. db_alias_list() → xem mình được cấp quyền quản lý những alias nào
164
+ 4. db_connect_by_name({ apiName }) → tra + dựng token + test + lưu + fetch schema, một lượt
165
+ (KHÔNG gọi db_schema_get thêm — đã fetch rồi)
166
+ 5. [Module gọi thêm alias khác?] lặp bước 4 cho từng alias còn thiếu.
167
+ Kết nối thêm KHÔNG tự giành `default` — muốn đổi thì `makeDefault: true`.
168
+ ```
169
+
170
+ Đã cầm sẵn `dbToken` (ai đó đưa, hoặc chép từ nơi khác) thì bỏ qua bước 3–4, gọi thẳng `db_connect`.
171
+
172
+ ---
173
+
174
+ ## 3. Build dbToken
175
+
176
+ > Chỉ cần khi bạn **có sẵn UID/PWD trong tay** và muốn gọi `db_connect` trực tiếp. Mượn credential từ
177
+ > một kết nối đã có thì dùng `db_connect_by_name` (§2b) — nó dựng token giúp, và không in ra plain text.
178
+
179
+ `dbToken` là chuỗi kết nối SQL Server được **base64-encode**. Chuỗi gốc:
180
+
181
+ ```
182
+ Server={sqlServer};Database={database};UID={uid};PWD={pwd};Encrypt=True;TrustServerCertificate=True;
183
+ ```
184
+
185
+ **Build bằng JavaScript:**
186
+ ```js
187
+ Buffer.from("Server=192.0.2.101;Database=AccountUser;UID=sa;PWD=MyPass;Encrypt=True;TrustServerCertificate=True;").toString("base64")
188
+ ```
189
+
190
+ **Build bằng PowerShell:**
191
+ ```powershell
192
+ [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("Server=192.0.2.101;Database=AccountUser;UID=sa;PWD=MyPass;Encrypt=True;TrustServerCertificate=True;"))
193
+ ```
194
+
195
+ ---
196
+
197
+ ## 4. Workflow kết nối lần đầu
198
+
199
+ ### Xác định projectId trước khi kết nối
200
+
201
+ Thông tin kết nối DB được lưu vào `{FUI_MCP_WORKDIR}/{projectId}/_db/_connections.json`, dưới khoá
202
+ `apiName`. **Một project có thể có nhiều apiName** — `projectId` và `apiName` là hai thứ khác nhau,
203
+ đừng suy cái này ra cái kia.
204
+
205
+ **Quy tắc bắt buộc:** Nếu user không chỉ rõ projectId, hoặc alias/database chưa rõ thuộc project nào → **phải hỏi xác nhận** trước khi gọi `db_connect`:
206
+
207
+ > _"Thông tin kết nối DB này sẽ được lưu vào project nào? (projectId)"_
208
+
209
+ Không tự đoán projectId rồi gọi luôn — lưu sai project sẽ khiến schema/SP bị đặt nhầm chỗ và khó tìm lại.
210
+
211
+ ```
212
+ db_connect(apiDomain, dbToken, apiName, [sqlServer, database, userToken])
213
+ → schema tự động được fetch và lưu vào _db/{alias}/schema.json
214
+ → KHÔNG gọi db_schema_get thêm sau bước này
215
+ ```
216
+
217
+ ### Project gọi nhiều database → gọi `db_connect` NHIỀU LẦN
218
+
219
+ Mở `module.json` và quét mọi `"API": "/{alias}/…"`: **mỗi alias khác nhau là một kết nối cần có**.
220
+ Gọi `db_connect` lần lượt cho từng alias — lần sau **không đụng** gì tới kết nối đã có, mỗi cái nằm
221
+ trong thư mục `_db/{alias}/` của riêng nó.
222
+
223
+ Thiếu một alias thì mọi lời gọi thuộc alias đó **không được kiểm gì cả**: `module_validate` không có
224
+ schema để đối chiếu tên SP, `db_sp_verify`/`db_sp_get` không tìm thấy SP, và `db_sp_deploy` không có
225
+ đường nào tới đúng database đó.
226
+
227
+ Kết nối **thêm vào không tự giành mặc định** — kết nối đầu tiên vẫn là `default`. Muốn đổi thì
228
+ `db_connect({ …, makeDefault: true })`.
229
+
230
+ **Tham số đầy đủ nên truyền:**
231
+
232
+ ```json
233
+ {
234
+ "projectId": "my-project",
235
+ "apiDomain": "tapi.example.vn",
236
+ "apiName": "acc",
237
+ "sqlServer": "192.0.2.101",
238
+ "database": "MyDatabase",
239
+ "dbToken": "<base64>",
240
+ "userToken": "<bearer token nếu có>"
241
+ }
242
+ ```
243
+
244
+ Truyền `sqlServer` + `database` ngay từ đầu để sau này dùng được `db_token_rebuild` mà không cần hỏi lại.
245
+
246
+ ---
247
+
248
+ ## 5. Khi đổi mật khẩu — db_token_rebuild
249
+
250
+ Khi UID hoặc PWD thay đổi nhưng Server và Database vẫn giữ nguyên:
251
+
252
+ **Bước 1:** Xác nhận kết nối cần sửa đã có `sqlServer` và `database`
253
+ ```
254
+ db_config_read(projectId)
255
+ ```
256
+
257
+ **Bước 2:** Rebuild token — server tự lấy `sqlServer`/`database` từ kết nối đó, chỉ cần truyền thông tin thay đổi
258
+ ```
259
+ db_token_rebuild({ projectId, db, uid, password })
260
+ ```
261
+
262
+ Tool sẽ tự build lại `dbToken`, test kết nối, và lưu. Nếu `sqlServer`/`database` chưa có → phải dùng `db_connect` đầy đủ thay thế.
263
+
264
+ **`db` là BẮT BUỘC khi project có nhiều hơn một kết nối** — đây là thao tác ghi đè credential, đoán
265
+ sai thì ghi token của DB này đè lên DB kia. Một kết nối duy nhất thì bỏ trống được.
266
+
267
+ ---
268
+
269
+ ## 6. userToken — Mục đích và chia sẻ
270
+
271
+ ### Mục đích
272
+
273
+ `userToken` là **Bearer token của người dùng** — dùng để gọi các `spAPI_*` endpoint sau khi deploy, nhằm test API như một user thực. Khác với `dbToken` là kết nối trực tiếp vào SQL Server.
274
+
275
+ ```
276
+ dbToken → kết nối SQL Server để chạy schema/SP
277
+ userToken → gọi REST API của tAPI như một end-user (test spAPI_*)
278
+ ```
279
+
280
+ ### Chia sẻ userToken giữa các project
281
+
282
+ **userToken có thể dùng chung** cho các project trong cùng một **GroupName** (xem trong `_projectInfo.json`):
283
+
284
+ ```json
285
+ { "GroupName": "GroupA" }
286
+ ```
287
+
288
+ Nếu đã có `userToken` từ project GroupA khác → có thể set thẳng cho project mới mà không cần đăng nhập lại:
289
+
290
+ ```
291
+ db_user_token_set({ projectId, db, userToken })
292
+ ```
293
+
294
+ Hoặc bỏ qua `userToken` khi gọi tool — MCP sẽ tự scan workspace tìm token từ project cùng group.
295
+
296
+ ### userToken lưu THEO TỪNG KẾT NỐI
297
+
298
+ `userToken` nằm trong mục của một alias trong `_db/_connections.json`, không phải một giá trị chung
299
+ của project. Project nhiều database thì mỗi kết nối cần token riêng — truyền `db: "<alias>"` để nói
300
+ rõ set vào kết nối nào; bỏ trống thì vào kết nối mặc định.
301
+
302
+ Điều này quan trọng với `right_*`: nhóm tool quyền gọi alias `acc` bằng `userToken` lấy từ **kết nối
303
+ khớp `apiName` đang thao tác** (không khớp thì kết nối mặc định) — thiếu token ở đúng kết nối đó thì
304
+ tool quyền không chạy được dù kết nối khác đã có token.
305
+
306
+ ### Set userToken sau khi kết nối
307
+
308
+ Nếu chưa có lúc `db_connect`, set riêng sau:
309
+ ```
310
+ db_user_token_set({ projectId, db, userToken })
311
+ ```
312
+
313
+ ---
314
+
315
+ ## 6a. SSO theo tên miền — cùng domain cha thì token DÙNG ĐƯỢC, đừng hỏi lại
316
+
317
+ **Sự thật nền tảng:** SSO giữa các API của các project FUI được chứng thực **theo tên miền cha**. Mọi
318
+ API nằm dưới cùng một domain cha (ví dụ mọi host `*.lhu.edu.vn`: `tapi.lhu.edu.vn`, `api.lhu.edu.vn`,
319
+ `capnhatluong.lhu.edu.vn`…) **chấp nhận cùng một `userToken`**.
320
+
321
+ Hệ quả trực tiếp — đây là điểm hay bị làm sai:
322
+
323
+ - **Đã có `userToken` của một project/alias thuộc domain cha đó thì dùng thẳng cho project/alias khác
324
+ cùng domain cha. KHÔNG hỏi lại người dùng "token này có gọi được không", KHÔNG đi thử một lời gọi
325
+ để "xác minh", KHÔNG bắt đăng nhập lại.** Câu trả lời đã biết trước từ tên miền.
326
+ - Việc scan workspace tìm token sẵn có (`db_user_token_set` gọi không kèm `userToken`) là hợp lệ và
327
+ nên làm — nó chính là hiện thực hoá luật này.
328
+
329
+ Ranh giới của luật (chỗ vẫn phải hỏi):
330
+
331
+ | Tình huống | Xử lý |
332
+ |---|---|
333
+ | Cùng domain cha (`*.lhu.edu.vn` → `*.lhu.edu.vn`) | **Dùng ngay**, không hỏi, không thử |
334
+ | Khác domain cha (`*.lhu.edu.vn` → `*.dhlh.vn`, `*.fap.vn`) | Token **không** áp dụng — cần token riêng của domain kia |
335
+ | Project nhiều domain (`domainSetting` có nhiều host khác domain cha nhau) | Mỗi domain cha là một vùng SSO riêng — xem `domainSetting` trong `project.json` (mục 2a) để biết đang đứng ở vùng nào |
336
+
337
+ > `GroupName` trong `_projectInfo.json` (mục 6 bên trên) là cách **gộp nhóm ở tầng quản trị**, còn
338
+ > tên miền cha là thứ **thực sự quyết định** token có được chấp nhận hay không. Hai cái thường trùng
339
+ > nhau; khi lệch thì tin vào tên miền.
340
+
341
+ ---
342
+
343
+ ## 7. Refresh schema
344
+
345
+ | Khi nào | Tool |
346
+ |---|---|
347
+ | Sau `db_connect` | **Không cần** — schema đã tự fetch |
348
+ | User yêu cầu refresh | `db_schema_get({ projectId, db })` |
349
+ | Vừa tạo/đổi tên/xóa table hoặc SP | `db_schema_get({ projectId, db })` |
350
+ | Schema local trông cũ/thiếu | `db_schema_get({ projectId, db })` |
351
+
352
+ Đọc schema đã cache (nhanh, không gọi DB):
353
+ ```
354
+ db_schema_read({ projectId, db, objectType?, search? })
355
+ ```
356
+ `objectType`: `Table`, `View`, `API`, `API File`, `Procedure`, `Function`
357
+
358
+ **Mỗi kết nối có schema riêng** (`_db/{alias}/schema.json`) và cả hai tool này thao tác trên **đúng
359
+ một** kết nối. Project nhiều database thì `db_schema_get` một alias **không** làm mới alias còn lại —
360
+ tra `db_config_read` xem có bao nhiêu kết nối rồi refresh từng cái. Không thấy một bảng/SP trong
361
+ `db_schema_read` thường không phải "chưa có" mà là **đang đọc nhầm kết nối**.
362
+
363
+ **Cũng tải lại thân SP:** `db_schema_get` làm mới **mọi thứ kết nối đó đang giữ** — `schema.json` lẫn
364
+ từng file `_db/{alias}/{name}.sql`. Bản `.sql` local khác server được chép vào `_history/` trước rồi
365
+ mới ghi đè, nên không mất; nhưng đừng coi file local là bản mới nhất nếu chưa refresh.
366
+
367
+ **Tự dọn SP/function mồ côi khi refresh:** `db_connect`/`db_schema_get` quét **các file `.sql` thật
368
+ trong `_db/{alias}/`** rồi xếp làm ba nhóm — chỉ trong phạm vi kết nối đó, không nhìn sang alias khác:
369
+
370
+ | Nhóm | Điều kiện | Hành vi |
371
+ |---|---|---|
372
+ | Còn sống | tên có trong schema MỚI | giữ + tải lại thân từ server |
373
+ | Đã xóa trên server | có ở schema CŨ, mất ở schema MỚI | **archive** vào `_history/{projectId}/_db/{alias}/{name}_{thời điểm}_deleted.sql` rồi xóa khỏi `_db/{alias}/` |
374
+ | Chỉ có ở local | không có ở cả hai | **chỉ liệt kê, không xóa** — nhiều khả năng là SP đang soạn qua `db_sp_save` chưa deploy. Muốn dọn: `db_schema_get({ pruneLocalOnly: true })` |
375
+
376
+ Không để lại file cũ tưởng là định nghĩa còn hiệu lực; tool in dòng `📋 Archived orphaned local SP
377
+ file(s)...` nếu có. So tên **không phân biệt hoa-thường** (SQL Server không phân biệt, file có thể lệch case).
378
+
379
+ ---
380
+
381
+ ## 8. Workflow làm việc với SP
382
+
383
+ ```
384
+ 1. db_sp_list(projectId) → xem danh sách SP — MỌI kết nối, ghi rõ SP nào thuộc alias nào
385
+ 2. db_sp_get(name, projectId) → fetch định nghĩa SP từ DB → lưu _db/{alias}/{name}.sql
386
+ 3. [sửa file _db/{alias}/{name}.sql]
387
+ 4. db_sp_save(name, sql, projectId) → lưu SQL vào local, chưa deploy
388
+ 5. db_sp_deploy(name, projectId) → deploy lên DB
389
+ (bản ĐANG CHẠY trên server tự lưu vào _history/
390
+ trước khi ghi — đây là bản để rollback)
391
+ nếu tên là spAPI_*/spAPIFILE_* → tự gọi /help xoá
392
+ cache tAPI (một lần, hỏng thì bỏ qua — không chặn
393
+ deploy, không cần gọi lại)
394
+ 6. db_sp_help(name, projectId) → BẮT BUỘC gọi thủ công khi SP được ALTER/deploy bằng
395
+ con đường khác ngoài db_sp_deploy (ví dụ:
396
+ db_sql_execute_nonquery chạy ALTER PROCEDURE
397
+ trực tiếp) — đường đó không có auto-clear.
398
+ Cũng dùng khi muốn xem tham số đầu vào của API
399
+ trước khi wire IN/OUT vào module.json.
400
+ Tool gọi MỘT lần theo URL chuẩn, hỏng thì chỉ báo
401
+ một dòng thông tin — ĐỪNG thử URL biến thể khác
402
+ 7. db_sp_verify(name, params) → kiểm chứng TĨNH contract API vừa deploy (đọc hay ghi đều
403
+ qua tool này) — KHÔNG gọi endpoint nào, chỉ đọc thân SP
404
+ thật và suy luận response shape, contract lỗi, phân loại
405
+ đọc/ghi, sinh sẵn snippet apiMocks cho module_simulate.
406
+ BẮT BUỘC chạy trước khi viết apiMocks cho một SP đã tồn
407
+ tại — tự bịa cấu trúc là sai, module_simulate sẽ cảnh báo
408
+ nếu phát hiện mock khớp SP thật mà chưa được verify.
409
+ ```
410
+
411
+ **Chọn kết nối trong cả 7 bước:** bỏ trống `db` thì MCP **suy từ chính tên SP** — dò tên đó trong
412
+ schema và trong file `.sql` local của từng kết nối. Ra đúng một kết nối thì đi tiếp im lặng; ra
413
+ **không** kết nối nào hoặc **nhiều hơn một** (SP trùng tên ở hai DB) thì tool trả về **menu các alias**,
414
+ chọn một cái rồi gọi lại — đừng đoán. Riêng `db_sp_save` với SP **mới hoàn toàn** thì chưa có gì để
415
+ suy: project nhiều kết nối phải nêu `db` ngay từ lần lưu đầu.
416
+
417
+ > Cách suy luận của `db_sp_verify` (đọc thân SP thật, không đoán theo tên, lỗi cứng khi không đọc
418
+ > được thân SP) và cách kiểm tra API ghi bằng module_simulate: xem
419
+ > [tools-registry.md](tools-registry.md#quy-tắc-bắt-buộc-cho-db-tools). Các guard `DROP`/`ALTER
420
+ > TABLE`, `DELETE`/`UPDATE` không `WHERE` đều enforce ở code level, không bypass được; lệnh ghi qua
421
+ > `db_sql_execute`/`db_sql_execute_nonquery` cần `confirmWrite: true`.
422
+
423
+ **Rollback SP:**
424
+ 1. Đọc file trong `{FUI_MCP_WORKDIR}/_history/{projectId}/_db/{alias}/{name}_{thời điểm}.sql`
425
+ 2. `db_sp_save(name, oldSql)` — ghi lại bản cũ vào local
426
+ 3. `db_sp_deploy(name)` — deploy lại
427
+
428
+ ---
429
+
430
+ ## 8a. Linked Server — quy ước `spIO_IN_` / `spIO_OUT_`
431
+
432
+ SQL Server Linked Server đã có sẵn trong hệ thống FUI. Tuy nhiên, **vì lý do bảo mật, không thể truy vấn trực tiếp table của DB khác qua linked server** — chỉ được phép gọi một stored procedure đã định nghĩa sẵn phía kia.
433
+
434
+ **Cú pháp gọi qua Linked Server trong thân SP:**
435
+ ```sql
436
+ EXEC XDATA23.Calendar2015.dbo.spIO_IN_DeleteMonHocInfo @MonHocID, @ErrorDKMH OUTPUT
437
+ -- ^^^^^^^^^^^^^^^^^^^^^^^^^ ← 4 phần: linked-server.database.schema.tên-SP
438
+ ```
439
+
440
+ ### Quy ước đặt tên SP vượt ranh giới Linked Server
441
+
442
+ | Tiền tố | Hướng dữ liệu | Khi nào dùng |
443
+ |---|---|---|
444
+ | `spIO_IN_` | Dữ liệu đi **vào** DB hiện tại (nhận/import từ DB kia) | SP nhận lệnh từ DB ngoài, tác động lên DB hiện tại |
445
+ | `spIO_OUT_` | Dữ liệu đi **ra** khỏi DB hiện tại (xuất/cung cấp cho DB kia) | SP cung cấp dữ liệu cho DB ngoài gọi vào |
446
+
447
+ **Hệ quả quan trọng:**
448
+
449
+ - Khi thấy một SP trong `db_sp_list` / schema có tiền tố `spIO_IN_` hoặc `spIO_OUT_` → đó là SP biên giới Linked Server, **không phải tAPI endpoint** (dù tên có `spIO_`). Không wire vào `"API":` trong module.json.
450
+ - Tiền tố giúp nhận ra ranh giới ngay trong `db_sp_list` mà không cần đọc thân SP — tên nói lên bản chất.
451
+ - Khi tạo SP mới có tác dụng qua Linked Server: **bắt buộc đặt tiền tố** `spIO_IN_` hoặc `spIO_OUT_` theo đúng hướng dữ liệu, không đặt tên tự do.
452
+ - SP loại này **không deploy được bằng `db_sp_deploy` sang DB kia** — nó chạy **trên DB hiện tại** nhưng bên trong `EXEC` gọi sang DB kia. Deploy bình thường vào alias của DB sở hữu SP đó.
453
+
454
+ ---
455
+
456
+ ## 9. Kiểm tra nhanh các kết nối hiện có
457
+
458
+ ```
459
+ db_config_read(projectId)
460
+ ```
461
+
462
+ Liệt kê **mọi kết nối** của project: alias (`db`), `apiDomain`, `sqlServer`, `database`, thư mục
463
+ `_db/{alias}/`, trạng thái `dbToken`/`userToken` (có/không — **không trả giá trị token**), và alias
464
+ nào đang là `default`.
465
+
466
+ Gọi tool này **trước tiên** khi chưa chắc phải truyền `db` nào cho tool khác. Nó cũng nêu ra các thư
467
+ mục trong `_db/` không thuộc kết nối nào (rác của bản cũ, hoặc kết nối đã bỏ) — không tool nào đọc
468
+ chúng nữa, tự xóa tay khi chắc chắn không cần.
469
+
470
+ ---
471
+
472
+ ## 10. Cheat sheet — Tool theo tình huống
473
+
474
+ | Tình huống | Tool cần dùng |
475
+ |---|---|
476
+ | **Database chưa tồn tại** — dựng dự án từ số 0 | [project-provisioning.md](project-provisioning.md) (kiểm 2 cổng quyền → CREATE DATABASE → 2 tài khoản → `db_alias_new`) |
477
+ | Kiểm mình có quyền `CREATE DATABASE`/`CREATE LOGIN` trên máy chủ không | [project-provisioning.md](project-provisioning.md) §Bước 0 — `IS_SRVROLEMEMBER` + `HAS_PERMS_BY_NAME`, chỉ đọc |
478
+ | Database đã có nhưng **chưa được đăng ký alias** trong `acc` | `db_alias_new` (xem [project-provisioning.md](project-provisioning.md) §Bước 5) |
479
+ | Kết nối DB lần đầu, **đã có sẵn dbToken** | `db_connect` |
480
+ | Kết nối DB nhưng **chỉ biết alias, không có dbToken** | `db_alias_list` → `db_connect_by_name` |
481
+ | Xem mình được cấp quyền quản lý những database nào | `db_alias_list()` (không tham số) |
482
+ | Project gọi thêm một database nữa (alias khác) | `db_connect_by_name` lần nữa với `apiName` mới |
483
+ | Xem project đang có những kết nối nào, alias nào default | `db_config_read` |
484
+ | Đổi UID/PWD, server/database giữ nguyên | `db_token_rebuild` (nêu `db` nếu nhiều kết nối) |
485
+ | Set userToken sau khi connect | `db_user_token_set` (nêu `db` nếu nhiều kết nối) |
486
+ | Xem danh sách tables/SPs | `db_sp_list` |
487
+ | Lấy nội dung SP từ DB | `db_sp_get` |
488
+ | Refresh schema từ DB thực | `db_schema_get` |
489
+ | Đọc schema đã cache | `db_schema_read` |
490
+ | Lưu SQL chỉnh sửa vào local | `db_sp_save` |
491
+ | Deploy SP lên DB (tự xoá cache tAPI nếu là spAPI_*/spAPIFILE_*) | `db_sp_deploy` |
492
+ | Xem tham số đầu vào của API đã deploy (trước khi wire vào module.json) | `db_sp_help` |
493
+ | Xoá cache tAPI thủ công sau khi ALTER qua `db_sql_execute_nonquery` (đường đó không có auto-clear) | `db_sp_help` **(bắt buộc)** |
494
+ | Kiểm chứng tĩnh API vừa deploy (trước khi wire vào UI, không gọi sống) | `db_sp_verify` |
495
+ | Xóa SP khỏi DB | `db_sp_delete` |
496
+ | Đổi tên SP | `db_sp_rename` |
497
+ | Tìm SQLServer + DatabaseName của alias | `db_alias_list({ search })` (xem mục 2b) |
498
+ | Build dbToken bằng cách mượn UID/PWD của kết nối sẵn có | `db_connect_by_name` làm luôn (xem mục 2b) — **đừng decode tay bằng PowerShell** |
499
+
500
+ ---
501
+
502
+ ## 11. Quy tắc thiết kế bảng
503
+
504
+ Quy ước đặt tên bảng, khóa chính, trường timestamp và cột audit đã tách sang **[db-table-design.md](db-table-design.md)** — load file đó khi thiết kế schema mới.