@fui-org/fui-cli 1.3.2 → 2.1.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 (115) hide show
  1. package/README.md +21 -3
  2. package/dist/fui-cx180e19.js +379 -0
  3. package/dist/fui.js +1 -1
  4. package/package.json +3 -6
  5. package/skills/fui/SKILL.md +9 -41
  6. package/skills/fui-skill/SKILL.md +95 -225
  7. package/skills/fui-skill/assets/projectdefaultstyle-3.0.css +555 -0
  8. package/skills/fui-skill/assets/projectdefaultstyle.css +207 -235
  9. package/skills/fui-skill/references/INDEX.md +105 -137
  10. package/skills/fui-skill/references/advanced-techniques.md +76 -68
  11. package/skills/fui-skill/references/coding-standards.md +56 -56
  12. package/skills/fui-skill/references/component-design.md +166 -173
  13. package/skills/fui-skill/references/component-quickref.md +61 -60
  14. package/skills/fui-skill/references/component-table.md +128 -117
  15. package/skills/fui-skill/references/components-dialog.md +55 -56
  16. package/skills/fui-skill/references/components-display.md +24 -30
  17. package/skills/fui-skill/references/components-echart.md +186 -261
  18. package/skills/fui-skill/references/components-input.md +72 -96
  19. package/skills/fui-skill/references/controls-patterns.md +196 -342
  20. package/skills/fui-skill/references/controls-styling-vocabulary.md +130 -97
  21. package/skills/fui-skill/references/db-table-design.md +24 -28
  22. package/skills/fui-skill/references/db-workflow.md +191 -390
  23. package/skills/fui-skill/references/default-function.md +169 -128
  24. package/skills/fui-skill/references/design-modes.md +35 -63
  25. package/skills/fui-skill/references/echart-templates.md +204 -196
  26. package/skills/fui-skill/references/fastproject.md +62 -60
  27. package/skills/fui-skill/references/fsheet.md +109 -124
  28. package/skills/fui-skill/references/fullstack-workflow.md +90 -128
  29. package/skills/fui-skill/references/module-data-patterns.md +31 -40
  30. package/skills/fui-skill/references/module-json-anatomy.md +47 -52
  31. package/skills/fui-skill/references/module-structure.md +80 -196
  32. package/skills/fui-skill/references/new-session.md +49 -51
  33. package/skills/fui-skill/references/pdfmake.md +17 -17
  34. package/skills/fui-skill/references/permission-system.md +89 -108
  35. package/skills/fui-skill/references/platform-architecture.md +128 -153
  36. package/skills/fui-skill/references/project-config.md +102 -134
  37. package/skills/fui-skill/references/project-provisioning.md +139 -244
  38. package/skills/fui-skill/references/script-map.md +208 -242
  39. package/skills/fui-skill/references/sql-clr-functions.md +98 -97
  40. package/skills/fui-skill/references/system-design.md +63 -88
  41. package/skills/fui-skill/references/tapi-file-api.md +46 -52
  42. package/skills/fui-skill/references/tapi-permission-patterns.md +51 -53
  43. package/skills/fui-skill/references/tapi-reference.md +132 -207
  44. package/skills/fui-skill/references/tools-registry.md +84 -460
  45. package/skills/fui-skill/references/ui-crosswindow-patterns.md +79 -75
  46. package/skills/fui-skill/references/ui-dialog-patterns.md +98 -72
  47. package/skills/fui-skill/references/ui-layout-patterns.md +26 -26
  48. package/skills/fui-skill/references/ui-patterns.md +71 -83
  49. package/skills/fui-skill/references/ui-screenshot-review.md +63 -62
  50. package/skills/fui-skill/references/ui-table-cell-patterns.md +61 -59
  51. package/skills/fui-skill/references/ui-templates.md +16 -23
  52. package/skills/fui-skill/references/verification.md +236 -246
  53. package/skills/fui-skill/references/watcher-patterns.md +30 -63
  54. package/skills/fui-skill/references/websocket-realtime.md +83 -66
  55. package/skills/fui-skill/scripts/component-3.0.js +298 -131
  56. package/skills/fui-skill/scripts/component.js +277 -271
  57. package/skills/fui-skill/scripts/componentTable-3.0.js +182 -53
  58. package/skills/fui-skill/scripts/componentTable.js +171 -49
  59. package/skills/fui-skill/scripts/defaultfunction-3.0.js +88 -3
  60. package/skills/fui-skill/scripts/defaultfunction.js +88 -3
  61. package/skills/fui-skill/scripts/fsheet.js +38 -0
  62. package/skills/fui-target/.claude-plugin/plugin.json +6 -0
  63. package/skills/fui-target/hooks/hooks.json +1 -0
  64. package/skills/fui-target/hooks/register.tsx +71 -0
  65. package/skills/fui-target/types/index.d.ts +7 -0
  66. package/dist/fui-y8an39cn.js +0 -420
  67. package/skills/fui-skill/README.md +0 -112
  68. package/skills/fui-skill/metadata.json +0 -75
  69. package/skills/fui-skill-cli/SKILL.md +0 -139
  70. package/skills/fui-skill-cli/references/INDEX.md +0 -110
  71. package/skills/fui-skill-cli/references/advanced-techniques.md +0 -168
  72. package/skills/fui-skill-cli/references/coding-standards.md +0 -112
  73. package/skills/fui-skill-cli/references/component-design.md +0 -448
  74. package/skills/fui-skill-cli/references/component-quickref.md +0 -78
  75. package/skills/fui-skill-cli/references/component-table.md +0 -248
  76. package/skills/fui-skill-cli/references/components-dialog.md +0 -191
  77. package/skills/fui-skill-cli/references/components-display.md +0 -141
  78. package/skills/fui-skill-cli/references/components-echart.md +0 -316
  79. package/skills/fui-skill-cli/references/components-input.md +0 -335
  80. package/skills/fui-skill-cli/references/controls-patterns.md +0 -701
  81. package/skills/fui-skill-cli/references/controls-styling-vocabulary.md +0 -137
  82. package/skills/fui-skill-cli/references/db-table-design.md +0 -73
  83. package/skills/fui-skill-cli/references/db-workflow.md +0 -288
  84. package/skills/fui-skill-cli/references/default-function.md +0 -425
  85. package/skills/fui-skill-cli/references/design-modes.md +0 -57
  86. package/skills/fui-skill-cli/references/echart-templates.md +0 -489
  87. package/skills/fui-skill-cli/references/fastproject.md +0 -99
  88. package/skills/fui-skill-cli/references/fsheet.md +0 -203
  89. package/skills/fui-skill-cli/references/fullstack-workflow.md +0 -313
  90. package/skills/fui-skill-cli/references/module-data-patterns.md +0 -117
  91. package/skills/fui-skill-cli/references/module-json-anatomy.md +0 -132
  92. package/skills/fui-skill-cli/references/module-structure.md +0 -141
  93. package/skills/fui-skill-cli/references/new-session.md +0 -85
  94. package/skills/fui-skill-cli/references/pdfmake.md +0 -60
  95. package/skills/fui-skill-cli/references/permission-system.md +0 -150
  96. package/skills/fui-skill-cli/references/platform-architecture.md +0 -269
  97. package/skills/fui-skill-cli/references/project-config.md +0 -303
  98. package/skills/fui-skill-cli/references/project-provisioning.md +0 -278
  99. package/skills/fui-skill-cli/references/script-map.md +0 -262
  100. package/skills/fui-skill-cli/references/sql-clr-functions.md +0 -225
  101. package/skills/fui-skill-cli/references/system-design.md +0 -89
  102. package/skills/fui-skill-cli/references/tapi-file-api.md +0 -185
  103. package/skills/fui-skill-cli/references/tapi-permission-patterns.md +0 -156
  104. package/skills/fui-skill-cli/references/tapi-reference.md +0 -474
  105. package/skills/fui-skill-cli/references/tools-registry.md +0 -84
  106. package/skills/fui-skill-cli/references/ui-crosswindow-patterns.md +0 -321
  107. package/skills/fui-skill-cli/references/ui-dialog-patterns.md +0 -255
  108. package/skills/fui-skill-cli/references/ui-layout-patterns.md +0 -176
  109. package/skills/fui-skill-cli/references/ui-patterns.md +0 -303
  110. package/skills/fui-skill-cli/references/ui-screenshot-review.md +0 -95
  111. package/skills/fui-skill-cli/references/ui-table-cell-patterns.md +0 -318
  112. package/skills/fui-skill-cli/references/ui-templates.md +0 -22
  113. package/skills/fui-skill-cli/references/verification.md +0 -236
  114. package/skills/fui-skill-cli/references/watcher-patterns.md +0 -163
  115. package/skills/fui-skill-cli/references/websocket-realtime.md +0 -271
@@ -1,14 +1,14 @@
1
- # SQL CLR Functions — Hàm mở rộng nhúng DLL trong SQL Server
1
+ # SQL CLR Functions — DLL-backed SQL Server functions
2
2
 
3
- > File này sở hữu: **hàm SQL CLR: httpCall, sendMail, ImageResize, FileReader, RegexMatch...**
3
+ > Owns: **SQL CLR functions: httpCall, sendMail, ImageResize, FileReader, RegexMatch...**
4
4
 
5
- Database của project có thể đã cài sẵn các **SQL CLR scalar function** (hàm SQL được backing bởi DLL .NET biên dịch sẵn, đăng ký qua `CREATE ASSEMBLY` + `CREATE FUNCTION ... EXTERNAL NAME`). Khi thấy các hàm này trong `db_schema_read` hoặc trong định nghĩa SP hiện có, có thể **gọi trực tiếp trong T-SQL** như hàm built-in bình thường — không cần cài đặt lại, không cần biết code C# bên trong.
5
+ A project DB may have **SQL CLR scalar functions** (precompiled .NET DLL, registered via `CREATE ASSEMBLY` + `CREATE FUNCTION ... EXTERNAL NAME`). If they appear in `fui schema` or in an existing SP definition, **call them directly in T-SQL** like built-ins — no install, no need to know the C#.
6
6
 
7
- Nếu hàm cần dùng không có trong danh sách dưới đây (không tồn tại trong DB), **không tự bịa ra** — báo cho user biết là DB chưa có hàm này.
7
+ A needed function is not in the DB → **do not invent it**; tell the user the DB lacks it.
8
8
 
9
9
  ---
10
10
 
11
- ## 1. `SQLImageHelper` — Xử lý ảnh
11
+ ## 1. `SQLImageHelper` — images
12
12
 
13
13
  ### `dbo.ImageResize`
14
14
 
@@ -17,17 +17,17 @@ dbo.ImageResize(@extension nvarchar(10), @OriginalImage varbinary(max), @maxWidt
17
17
  RETURNS varbinary(max)
18
18
  ```
19
19
 
20
- Resize ảnh nhị phân về kích thước tối đa `@maxWidth` x `@maxHeight`.
20
+ Resizes to at most `@maxWidth` x `@maxHeight`.
21
21
 
22
- | Tham số | Ý nghĩa |
23
- |---|---|
24
- | `@extension` | Định dạng ảnh output, ví dụ `'jpg'`, `'png'` |
25
- | `@OriginalImage` | Dữ liệu ảnh gốc dạng `varbinary` |
26
- | `@maxWidth`, `@maxHeight` | Kích thước tối đa (px) |
27
- | `@preserverAspectRatio` | `1` = giữ tỉ lệ khung hình, resize theo cạnh dài nhất; `0` = resize ép đúng `maxWidth`x`maxHeight` |
28
- | `@quality` | Chất lượng nén (thường 1-100) |
22
+ | Param | Meaning |
23
+ | ------------------------- | ------------------------------------------------------------------------------ |
24
+ | `@extension` | Output format, e.g. `'jpg'`, `'png'` |
25
+ | `@OriginalImage` | Source image `varbinary` |
26
+ | `@maxWidth`, `@maxHeight` | Max size (px) |
27
+ | `@preserverAspectRatio` | `1` = keep ratio, fit longest side; `0` = force exactly `maxWidth`x`maxHeight` |
28
+ | `@quality` | Compression quality (usually 1-100) |
29
29
 
30
- Trả về `varbinary` — ảnh đã resize, ghi thẳng vào cột `varbinary`/file hoặc trả qua tAPI File.
30
+ Returns resized `varbinary` — write to a `varbinary` column/file or return via tAPI File.
31
31
 
32
32
  ### `dbo.ImageCrop`
33
33
 
@@ -36,15 +36,15 @@ dbo.ImageCrop(@OriginalImage varbinary(max), @StartAtX int, @StartAtY int, @Widt
36
36
  RETURNS varbinary(max)
37
37
  ```
38
38
 
39
- Cắt (crop) một vùng chữ nhật từ ảnh gốc, bắt đầu tại `(@StartAtX, @StartAtY)`, kích thước `@Width` x `@Height`.
39
+ Crops a `@Width` x `@Height` rectangle starting at `(@StartAtX, @StartAtY)`.
40
40
 
41
41
  ---
42
42
 
43
- ## 2. `SQLHttpHelper` — HTTP call, public value store, gửi mail
43
+ ## 2. `SQLHttpHelper` — HTTP, public value store, mail
44
44
 
45
45
  ### `dbo.publicValueUUID` / `publicValueGet` / `publicValueSet`
46
46
 
47
- Một key-value store dùng chung ở tầng server (không phải bảng SQL) — hữu ích để lưu tạm state xuyên suốt nhiều lần gọi SP mà không cần tạo bảng.
47
+ Server-level shared key-value store (not a SQL table) — keeps temp state across SP calls without a table.
48
48
 
49
49
  ```sql
50
50
  dbo.publicValueUUID() RETURNS nvarchar(max) -- sinh 1 UUID mới, dùng làm key
@@ -52,50 +52,50 @@ dbo.publicValueGet(@name nvarchar(max)) RETURNS nvarchar(max) -- đọc value
52
52
  dbo.publicValueSet(@name nvarchar(max), @Data nvarchar(max)) RETURNS int -- ghi value theo key
53
53
  ```
54
54
 
55
- ### `dbo.httpCall` / `dbo.httpAPI` — Gọi HTTP request từ T-SQL
55
+ ### `dbo.httpCall` / `dbo.httpAPI` — HTTP from T-SQL
56
56
 
57
57
  ```sql
58
58
  dbo.httpCall(@Method nvarchar(max), @URL nvarchar(max), @Header nvarchar(max), @Data nvarchar(max))
59
59
  RETURNS nvarchar(max)
60
60
  ```
61
61
 
62
- `httpAPI` có chữ ký tham số **giống hệt** `httpCall` (khác implementation nội bộ — dùng khi cần gọi API nội bộ tAPI, còn `httpCall` dùng cho HTTP tổng quát ra ngoài).
62
+ `httpAPI` has the **identical** signature (different internals): use `httpAPI` for internal tAPI calls, `httpCall` for general outbound HTTP.
63
63
 
64
- | Tham số | Ý nghĩa |
65
- |---|---|
66
- | `@Method` | `'GET'`, `'POST'`, `'PUT'`, `'DELETE'`... (không phân biệt hoa thường, mặc định `GET` nếu rỗng) |
67
- | `@URL` | URL đầy đủ, phải là absolute URL hợp lệ |
68
- | `@Header` | Danh sách header, xem cú pháp bên dưới — truyền `''` nếu không cần custom header |
69
- | `@Data` | Body request dạng JSON string — **chỉ được gửi khi Method khác GET/HEAD**; luôn gửi dưới dạng `Content-Type: application/json` trừ khi `@Header` override lại |
64
+ | Param | Meaning |
65
+ | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
66
+ | `@Method` | `'GET'`, `'POST'`, `'PUT'`, `'DELETE'`... (case-insensitive; empty → `GET`) |
67
+ | `@URL` | Full, valid absolute URL |
68
+ | `@Header` | Header list, syntax below — `''` for none |
69
+ | `@Data` | JSON string body — **sent only when Method is not GET/HEAD**; always `Content-Type: application/json` unless `@Header` overrides |
70
70
 
71
- **Ví dụ:**
71
+ **Example:**
72
72
 
73
73
  ```sql
74
74
  SELECT dbo.httpCall('POST', 'https://tapi.example.vn/me/auth/ApplicationList', '', '')
75
75
  ```
76
76
 
77
- #### Cú pháp `@Header` — pipe-delimited `Key: Value`
77
+ #### `@Header` syntax — pipe-delimited `Key: Value`
78
78
 
79
- Đây là phần quan trọng nhất khi dùng `httpCall`/`httpAPI`. `@Header` là một chuỗi duy nhất, mỗi cặp header cách nhau bởi `|`, mỗi cặp có dạng `Key: Value` (tách bằng dấu `:` đầu tiên, phần còn lại — kể cả nếu chứa `:` — thuộc về value):
79
+ Most important part. One string; pairs separated by `|`; each pair `Key: Value`, split on the **first** `:` (the rest, including further `:`, is the value):
80
80
 
81
81
  ```
82
82
  "Authorization: Bearer eyJhbGciOi...|X-Custom-Header: abc123"
83
83
  ```
84
84
 
85
- Implementation (C#) xử lý như sau — **không phân biệt hoa/thường tên header**, và một số tên có xử lý đặc biệt:
85
+ Header names are **case-insensitive**; special handling:
86
86
 
87
- | Header name | Hành vi |
88
- |---|---|
89
- | `Authorization`, `X-*`, mọi tên khác | Add thẳng vào request headers (`TryAddWithoutValidation`) — dùng cho token, API key |
90
- | `referer` / `referrer` | Parse thành URI, set `request.Headers.Referrer` |
91
- | `user-agent` | Ghi đè `User-Agent` mặc định |
92
- | `accept` | Ghi đè `Accept` |
93
- | `accept-language` | Ghi đè `Accept-Language` |
94
- | `accept-encoding` | Ghi đè `Accept-Encoding` |
95
- | `content-type` | Nếu request có body (`Method` khác GET/HEAD) → set vào `Content.Headers.Content-Type` (ghi đè `application/json` mặc định); nếu không có body → set vào request headers thường |
96
- | Bất kỳ header nào bắt đầu bằng `content-` (khác `content-type`) | Nếu có body → route vào `Content.Headers` thay vì request headers (theo chuẩn HTTP — các header `Content-*` mô tả nội dung body) |
87
+ | Header name | Behavior |
88
+ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
89
+ | `Authorization`, `X-*`, any other | Added to request headers as-is (`TryAddWithoutValidation`) — tokens, API keys |
90
+ | `referer` / `referrer` | Parsed to URI → `request.Headers.Referrer` |
91
+ | `user-agent` | Overrides default `User-Agent` |
92
+ | `accept` | Overrides `Accept` |
93
+ | `accept-language` | Overrides `Accept-Language` |
94
+ | `accept-encoding` | Overrides `Accept-Encoding` |
95
+ | `content-type` | With body (Method not GET/HEAD) → `Content.Headers.Content-Type` (overrides default `application/json`); no body → normal request headers |
96
+ | Any other `content-*` | With body → routed to `Content.Headers` instead of request headers |
97
97
 
98
- **Ví dụ set Bearer token + custom header:**
98
+ **Bearer token + custom header:**
99
99
 
100
100
  ```sql
101
101
  SELECT dbo.httpCall(
@@ -106,18 +106,18 @@ SELECT dbo.httpCall(
106
106
  )
107
107
  ```
108
108
 
109
- **Lưu ý khi ghép nhiều header:** không được có thêm dấu `|` thừa hoặc thiếu — mỗi cặp phải tách rõ bằng đúng 1 dấu `|`, thiếu `:` trong 1 cặp thì cặp đó bị bỏ qua (không lỗi, chỉ silent skip).
109
+ **Joining headers:** exactly one `|` between pairs, no extra/missing `|`. A pair without `:` is **silently skipped** (no error).
110
110
 
111
- #### Response format của `httpCall`/`httpAPI`
111
+ #### `httpCall`/`httpAPI` response
112
112
 
113
- - Nếu HTTP status = **200**: trả về **nguyên văn body** của response (không bọc thêm gì) — có thể là JSON, text thuần, hoặc bất kỳ định dạng nào server trả về.
114
- - Nếu HTTP status **khác 200** (400, 401, 404, 500...): trả về JSON dạng bọc lỗi:
113
+ - Status **200**: raw response body verbatim (JSON, text, anything).
114
+ - Status **not 200** (400, 401, 404, 500...): wrapped JSON:
115
115
  ```json
116
- {"httpErrorCode": 404, "responseData": "<nội dung body, hoặc escaped string nếu không phải JSON>"}
116
+ { "httpErrorCode": 404, "responseData": "<nội dung body, hoặc escaped string nếu không phải JSON>" }
117
117
  ```
118
- → khi parse kết quả trong SP, luôn kiểm tra xem response có field `httpErrorCode` không để biết là lỗi hay thành công.
119
- - Nếu URL không hợp lệ: trả về `{"httpErrorCode":0,"responseData":"Invalid URL"}`.
120
- - Timeout/exception khác: trả message lỗi dạng text (không phải JSON), nên khi dùng trong SP cần tự kiểm tra format trước khi `OPENJSON`.
118
+ → in SPs, always check for an `httpErrorCode` field to tell error from success.
119
+ - Invalid URL: `{"httpErrorCode":0,"responseData":"Invalid URL"}`.
120
+ - Timeout/other exception: plain-text error message (not JSON) — check the format before `OPENJSON`.
121
121
 
122
122
  ### `dbo.sendMail`
123
123
 
@@ -126,28 +126,28 @@ dbo.sendMail(@email_to nvarchar(max), @subject nvarchar(max), @content nvarchar(
126
126
  RETURNS nvarchar(max)
127
127
  ```
128
128
 
129
- Gửi email qua SMTP trực tiếp từ T-SQL.
129
+ Sends email over SMTP from T-SQL.
130
130
 
131
- | Tham số | Ý nghĩa |
132
- |---|---|
133
- | `@email_to` | Địa chỉ người nhận |
134
- | `@subject` | Tiêu đề mail |
135
- | `@content` | Nội dung mail (HTML hoặc text) |
136
- | `@from` | Địa chỉ email gửi (phải khớp/được phép bởi SMTP account) |
137
- | `@fromDisplayName` | Tên hiển thị người gửi |
138
- | `@smtp_server`, `@smtp_port` | Ví dụ `'smtp.gmail.com'`, `587` |
139
- | `@userName`, `@Password` | Tài khoản SMTP dùng để auth |
140
- | `@EnableSSL` | `1` = bật SSL/TLS (bắt buộc với Gmail SMTP) |
131
+ | Param | Meaning |
132
+ | ---------------------------- | ---------------------------------------------------------- |
133
+ | `@email_to` | Recipient |
134
+ | `@subject` | Subject |
135
+ | `@content` | Body (HTML or text) |
136
+ | `@from` | Sender address (must match/be allowed by the SMTP account) |
137
+ | `@fromDisplayName` | Sender display name |
138
+ | `@smtp_server`, `@smtp_port` | e.g. `'smtp.gmail.com'`, `587` |
139
+ | `@userName`, `@Password` | SMTP auth account |
140
+ | `@EnableSSL` | `1` = SSL/TLS (required for Gmail SMTP) |
141
141
 
142
142
  ```sql
143
143
  SELECT dbo.sendMail('user@example.vn','Tiêu đề','Nội dung','noreply@example.vn','My System','smtp.gmail.com',587,'noreply@example.vn','app-password',1)
144
144
  ```
145
145
 
146
- > **Bảo mật:** không hardcode `@Password` SMTP trực tiếp trong SP nếu tránh được — cân nhắc lưu qua `publicValueSet`/`publicValueGet` hoặc config bảng riêng có phân quyền, để không lộ credential khi ai đó xem definition của SP.
146
+ > **Security:** avoid hardcoding the SMTP `@Password` in the SP — store it via `publicValueSet`/`publicValueGet` or a permission-restricted config table so it is not exposed in the SP definition.
147
147
 
148
148
  ---
149
149
 
150
- ## 3. `SQLFileSystem` — Đọc/ghi file trên server
150
+ ## 3. `SQLFileSystem` — server files
151
151
 
152
152
  ```sql
153
153
  dbo.FileCreateFolder(@Path nvarchar(max)) RETURNS nvarchar(max)
@@ -158,22 +158,22 @@ dbo.FileDelete(@Path nvarchar(max)) RETURNS nvarchar(max)
158
158
  dbo.FileMove(@SourceFileName nvarchar(max), @DestFileName nvarchar(max)) RETURNS nvarchar(max)
159
159
  ```
160
160
 
161
- Thao tác trực tiếp trên filesystem của **máy SQL Server** (không phải máy client) — `@Path` là đường dẫn tuyệt đối trên server đó. Dùng khi SP cần lưu file kết quả (ví dụ ảnh đã resize bằng `ImageResize`, PDF xuất ra) vào một thư mục cố định để tAPI File API hoặc IIS phục vụ lại.
161
+ Operates on the **SQL Server machine's** filesystem (not the client); `@Path` is an absolute server path. Use when an SP saves output (e.g. `ImageResize` result, exported PDF) to a fixed folder served by tAPI File API or IIS.
162
162
 
163
- | Hàm | Ý nghĩa |
164
- |---|---|
165
- | `FileCreateFolder` | Tạo thư mục (kể cả nested), trả message kết quả |
166
- | `FileReader` | Đọc toàn bộ nội dung file, trả `varbinary` |
167
- | `FileWriter` | Ghi `@Content` (varbinary) vào `@Path`, tạo mới hoặc ghi đè |
168
- | `FileExists` | Kiểm tra tồn tại, trả `bit` |
169
- | `FileDelete` | Xóa file |
170
- | `FileMove` | Di chuyển/đổi tên file từ `@SourceFileName` sang `@DestFileName` |
163
+ | Function | Meaning |
164
+ | ------------------ | ------------------------------------------------------------- |
165
+ | `FileCreateFolder` | Creates folder (nested too), returns result message |
166
+ | `FileReader` | Reads whole file as `varbinary` |
167
+ | `FileWriter` | Writes `@Content` (varbinary) to `@Path`, create or overwrite |
168
+ | `FileExists` | Returns `bit` |
169
+ | `FileDelete` | Deletes file |
170
+ | `FileMove` | Moves/renames `@SourceFileName` → `@DestFileName` |
171
171
 
172
- > Vì đây là thao tác trên đĩa server thật, cân nhắc quyền hạn (permission check trong SP) trước khi cho phép `FileDelete`/`FileWriter` chạy theo input từ client — tương tự nguyên tắc guard DDL/DML đã áp dụng cho `db_sql_execute_nonquery`.
172
+ > Real server disk: add a permission check in the SP before letting client input drive `FileDelete`/`FileWriter` — same DDL/DML guard principle as `fui exec`.
173
173
 
174
174
  ---
175
175
 
176
- ## 4. `SQLExpansionFunction` — Regex & so sánh chuỗi
176
+ ## 4. `SQLExpansionFunction` — regex & string compare
177
177
 
178
178
  ```sql
179
179
  dbo.RegexReplace(@Input nvarchar(max), @Pattern nvarchar(1000), @Replacement nvarchar(4000)) RETURNS nvarchar(max)
@@ -183,42 +183,43 @@ dbo.RegexMatchArray(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS nvarc
183
183
  dbo.CompareWord(@String1 nvarchar(max), @String2 nvarchar(max)) RETURNS int
184
184
  ```
185
185
 
186
- | Hàm | Ý nghĩa |
187
- |---|---|
188
- | `RegexReplace` | Thay thế theo regex `.NET` — dùng khi T-SQL `REPLACE` không đủ (cần pattern, không phải literal string) |
189
- | `RegexIsMatch` | Kiểm tra `@Input` có khớp `@Pattern` không, trả `bit` — dùng validate format (email, phone, mã số...) ngay trong SP |
190
- | `RegexMatch` | Trả về **match đầu tiên** tìm được (`Match.Value` — toàn bộ chuỗi khớp, không tách group), rỗng nếu không khớp |
191
- | `RegexMatchArray` | Trả về **tất cả match, kèm từng capture group**, dạng **JSON object phẳng** (không phải array) — xem cấu trúc chi tiết bên dưới |
192
- | `CompareWord` | So sánh độ giống nhau giữa 2 chuỗi, trả `int` (thường là số ký tự khác biệt hoặc similarity score — kiểm tra thực tế qua `SELECT dbo.CompareWord('a','b')` nếu cần biết thang đo chính xác) |
186
+ | Function | Meaning |
187
+ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
188
+ | `RegexReplace` | .NET regex replace — when T-SQL `REPLACE` (literal only) is not enough |
189
+ | `RegexIsMatch` | `bit` match test — validate format (email, phone, codes...) in the SP |
190
+ | `RegexMatch` | **First match** only (`Match.Value`, whole match, no groups); empty if none |
191
+ | `RegexMatchArray` | **All matches with each capture group**, as a **flat JSON object** (not array) — see below |
192
+ | `CompareWord` | Similarity of 2 strings as `int` (likely differing-char count or a score — check the scale with `SELECT dbo.CompareWord('a','b')` if needed) |
193
193
 
194
- `@Pattern` dùng cú pháp regex chuẩn .NET (`\d`, `\w`, `^$`, group `()`...), không phải T-SQL `LIKE` pattern. Cả 4 hàm regex đều **luôn bật cố định** `IgnoreCase | Multiline | Singleline` — nghĩa là mặc định **không phân biệt hoa/thường**, `^`/`$` khớp theo từng dòng, và `.` khớp cả ký tự xuống dòng — không có cách nào tắt các flag này qua tham số.
194
+ `@Pattern` is standard .NET regex (`\d`, `\w`, `^$`, groups `()`...), not T-SQL `LIKE`. All 4 regex functions **always** use `IgnoreCase | Multiline | Singleline`: case-insensitive, `^`/`$` per line, `.` matches newlines — cannot be turned off.
195
195
 
196
- #### Cấu trúc thật của `RegexMatchArray` — JSON object, không phải array
196
+ #### `RegexMatchArray` shape — JSON object, not array
197
197
 
198
- Dựa theo code C#, kết quả là một **object phẳng** (`{...}`), không phải `[...]`. Key có dạng `"M{m}G{g}"`:
198
+ Flat object (`{...}`, not `[...]`), keys `"M{m}G{g}"`:
199
199
 
200
- - `m` = số thứ tự match (match thứ 1, 2, 3... trong `@Input`, đánh số từ 1)
201
- - `g` = số thứ tự group **trong chính match đó** (đánh số từ 1): `G1` luôn là **toàn bộ chuỗi khớp** (tương đương `Match.Groups[0]`, cũng là giá trị mà `RegexMatch` trả về), `G2`, `G3`... là các **capture group** `(...)` trong `@Pattern`, nếu có.
202
- - Nếu không có match nào, trả về object rỗng `"{}"`.
203
- - Giá trị mỗi key đã được loại bỏ tab/newline/carriage-return (`\t`, `\n`, `\r`) và escape dấu `"`.
200
+ - `m` = match index in `@Input`, from 1.
201
+ - `g` = group index **within that match**, from 1: `G1` is always the **whole match** (`Match.Groups[0]`, same as `RegexMatch`); `G2`, `G3`... are the capture groups `(...)` in `@Pattern`, if any.
202
+ - No match → `"{}"`.
203
+ - Values have tab/newline/CR (`\t`, `\n`, `\r`) removed and `"` escaped.
204
204
 
205
- Ví dụ: `RegexMatchArray('SDT: 0901 - 0902', '(\d{4})')` (pattern có 1 group) trả về:
205
+ `RegexMatchArray('SDT: 0901 - 0902', '(\d{4})')` (one group) returns:
206
206
 
207
207
  ```json
208
- {"M1G1": "0901", "M1G2": "0901", "M2G1": "0902", "M2G2": "0902"}
208
+ { "M1G1": "0901", "M1G2": "0901", "M2G1": "0902", "M2G2": "0902" }
209
209
  ```
210
210
 
211
- (ở đây G1 = G2 vì toàn bộ match trùng với group con duy nhất — nếu pattern không có group con nào, mỗi match cũng chỉ sinh ra đúng 1 cặp `G1`.)
211
+ (G1 = G2 here because the whole match equals the only group; with no groups each match yields only `G1`.)
212
212
 
213
- Vì đây là **object**, không phải array, nên khi parse trong T-SQL:
214
- - `OPENJSON(@result)` **không có `path` mặc định cho array** — vẫn chạy được nhưng trả về theo schema `key/value/type` (mỗi key `"M1G1"` là 1 row, cột `key` = tên, cột `value` = giá trị) chứ không phải mỗi match 1 row có cấu trúc lồng nhau.
215
- - Muốn lấy giá trị 1 match/group cụ thể theo tên biết trước, dùng `JSON_VALUE(@result, '$."M1G1"')`.
216
- - Muốn duyệt tất cả kết quả, dùng `OPENJSON(@result)` không truyền path, rồi tự parse tiền tố `M{m}G{g}` từ cột `key` nếu cần nhóm theo match.
213
+ Parsing in T-SQL (it is an object):
214
+
215
+ - `OPENJSON(@result)` still works but returns `key/value/type` rows (one row per key like `"M1G1"`), not one structured row per match.
216
+ - One known match/group: `JSON_VALUE(@result, '$."M1G1"')`.
217
+ - Iterate all: `OPENJSON(@result)` without path, parse the `M{m}G{g}` prefix from `key` to group by match.
217
218
 
218
219
  ---
219
220
 
220
- ## 5. Khi nào dùng các hàm này trong SP
221
+ ## 5. When to use them in SPs
221
222
 
222
- - Luôn kiểm tra hàm đã tồn tại trong DB trước (`db_schema_read` filter theo `objectType` function, hoặc `SELECT * FROM sys.objects WHERE type='FS'`) — SQL CLR function chỉ dùng được nếu assembly đã được `CREATE ASSEMBLY` trên DB đó. Không phải DB nào cũng có.
223
- - Dùng trong `spAPI_*` khi nghiệp vụ cần: gọi API ngoài (`httpCall`), xử lý ảnh upload (`ImageResize`/`ImageCrop`), gửi email thông báo (`sendMail`), validate chuỗi bằng regex (`RegexIsMatch`), hoặc lưu file lên đĩa server (`FileWriter`).
224
- - Kết quả trả về `nvarchar(max)` dạng JSON (như `httpCall`, `RegexMatchArray`) nên dùng `OPENJSON`/`JSON_VALUE` để parse tiếp trong T-SQL trước khi trả ra ngoài qua tAPI.
223
+ - Always confirm the function exists first (`fui schema` filtered to functions, or `SELECT * FROM sys.objects WHERE type='FS'`) — usable only if the assembly was `CREATE ASSEMBLY`'d on that DB. Not every DB has them.
224
+ - Use in `spAPI_*` when needed: external API (`httpCall`), uploaded image processing (`ImageResize`/`ImageCrop`), notification email (`sendMail`), regex validation (`RegexIsMatch`), saving files to server disk (`FileWriter`).
225
+ - JSON `nvarchar(max)` results (`httpCall`, `RegexMatchArray`) → parse with `OPENJSON`/`JSON_VALUE` in T-SQL before returning via tAPI.
@@ -1,116 +1,91 @@
1
- # System Design — Thiết kế app FUI nhiều module từ đầu
1
+ # System Design — Multi-Module App
2
2
 
3
- > File này sở hữu: **thiết kế app nhiều module từ mô tả: phân rã module, schema-first, menu, phân quyền**. Làm một module cụ thể xem [fullstack-workflow.md](fullstack-workflow.md).
3
+ > Owns: **multi-module app design from a description: decomposition, schema-first, menu, permissions**. Use when the user describes a whole application, not one module. Each module still follows [fullstack-workflow.md](fullstack-workflow.md).
4
4
 
5
- Playbook cấp **hệ thống**: khi user mô tả cả một phần mềm (nhiều màn hình/chức năng) chứ không phải một module đơn lẻ. File này điều phối; mỗi module cụ thể vẫn theo [fullstack-workflow.md](fullstack-workflow.md).
5
+ > Read order: this file → [db-table-design.md](db-table-design.md) (schema) → [tapi-reference.md](tapi-reference.md) (API) → [fullstack-workflow.md](fullstack-workflow.md) (per module) → [project-config.md](project-config.md) (menu/rights).
6
6
 
7
- > Đọc trước khi bắt tay: file này (phân rã hệ thống) → [db-table-design.md](db-table-design.md) (schema) → [tapi-reference.md](tapi-reference.md) (API) → [fullstack-workflow.md](fullstack-workflow.md) (từng module) → [project-config.md](project-config.md) (menu/quyền).
7
+ ## Step 0 — Clarify scope
8
8
 
9
- ---
9
+ Don't code yet. Confirm:
10
10
 
11
- ## Bước 0 — Làm rõ phạm vi trước khi thiết kế
11
+ - **Users/roles** (admin, staff, customer...) → drives permissions & menu.
12
+ - **Main end-to-end flows** (e.g. "create order → approve → ship").
13
+ - **Core entities** + relations (1-n, n-n).
14
+ - **Existing DB/project or fully new?**
15
+ - Existing → `fui project list`, `fui module list`, `fui schema` first.
16
+ - Fully new → do [project-provisioning.md](project-provisioning.md) **first** (no DB/project = nothing to design on); return once `fui db add-by-name` and `fui project new` succeed.
12
17
 
13
- Đừng code ngay. Xác nhận với user:
18
+ Missing info → **ask**; never assume and build the wrong system.
14
19
 
15
- - **Ai dùng?** Vai trò người dùng (admin, nhân viên, khách...) → quyết định phân quyền & menu.
16
- - **Quy trình nghiệp vụ chính là gì?** Liệt kê các luồng end-to-end (ví dụ: "tạo đơn → duyệt → xuất kho").
17
- - **Dữ liệu cốt lõi (entity chính)?** Danh sách thực thể + quan hệ (1-n, n-n).
18
- - **Có sẵn DB/project chưa,** hay dựng mới hoàn toàn?
19
- - **Có sẵn** → `project_list`, `module_list`, `db_schema_read` để nắm hiện trạng trước.
20
- - **Dựng mới hoàn toàn** → làm [project-provisioning.md](project-provisioning.md) **trước file này**: chưa có database và chưa có project FUI thì không có gì để thiết kế lên. Quay lại Bước 1 sau khi `db_connect_by_name` và `project_new` đã chạy được.
20
+ ## Step 1 — Decompose into modules
21
21
 
22
- Nếu thiếu thông tin → **hỏi**, không tự giả định rồi dựng cả hệ thống sai hướng.
22
+ | Principle | Example |
23
+ | ------------------------------------------- | -------------------------------------------------------- |
24
+ | One module = one coherent screen/function | "Student management", "Revenue report", "Order approval" |
25
+ | Group by main entity | One entity's CRUD in one module (list + add/edit dialog) |
26
+ | Split by role when flows differ | Admin vs end-user screens → separate modules |
27
+ | Separate dashboards/reports from data entry | Chart summary page on its own, not inside CRUD |
23
28
 
24
- ---
29
+ **Output:** module table — name, purpose, entities, access roles.
25
30
 
26
- ## Bước 1 — Phân rã hệ thống thành module
31
+ All modules in a project follow the **same convention** (control naming, toolbar/filter/action placement); check existing ones with `fui module get` before inventing a style.
27
32
 
28
- Một "phần mềm" = nhiều module FUI. Quy tắc phân rã:
33
+ ## Step 2 — Schema first
29
34
 
30
- | Nguyên tắc | Áp dụng |
31
- |---|---|
32
- | Một module = một màn hình/chức năng mạch lạc | "Quản lý sinh viên", "Báo cáo doanh thu", "Duyệt đơn" — mỗi cái một module |
33
- | Nhóm theo entity chính | CRUD một entity thường gói trong một module (list + dialog thêm/sửa) |
34
- | Tách theo vai trò khi luồng khác nhau | Màn hình admin vs màn hình người dùng cuối → module riêng |
35
- | Dashboard/report tách khỏi màn nhập liệu | Trang tổng hợp (chart) riêng, không nhồi vào CRUD |
35
+ Before any module.json:
36
36
 
37
- **Output:** bảng danh sách module — tên, mục đích, entity liên quan, vai trò truy cập.
37
+ 1. Tables + PK + FK for **all** entities. Per [db-table-design.md](db-table-design.md): `tbl` + PascalCase, PK `[Entity]ID`, audit `CreateUser/CreateTime/UpdateUser/UpdateTime`.
38
+ 2. n-n → junction table (e.g. `tblUserRole`).
39
+ 3. **`CREATE TABLE` is run by the developer** — fui blocks it; present DDL for review. Existing tables, gated by data loss: `ALTER TABLE ... ADD` and `DROP CONSTRAINT` run directly; `ALTER COLUMN` needs `--confirm-write`; `DROP COLUMN`/`DROP TABLE`/`SWITCH` hard-blocked.
40
+ 4. Design lookup/catalog tables early (shared dropdowns).
38
41
 
39
- Kiểm tra tính nhất quán: các module cùng project nên theo **cùng convention** (đặt tên control, vị trí toolbar/filter/action). Tham khảo module đã có bằng `module_get` trước khi tự sáng tạo kiểu khác.
42
+ **Output:** tables + relations, user-confirmed.
40
43
 
41
- ---
44
+ ## Step 3 — SPs per entity
42
45
 
43
- ## Bước 2 — Thiết kế database schema-first
46
+ Each entity → standard set `List/Get/Insert/Update/Delete` + `AUTH_*Options` for dropdowns ([tapi-reference.md](tapi-reference.md) §1, [fullstack-workflow.md](fullstack-workflow.md) Steps 2-3).
44
47
 
45
- Trước khi viết bất kỳ module.json nào, chốt schema tổng thể:
48
+ - **Shared SPs** (catalogs, lookups) → neutral names.
49
+ - Consistent authorization via `@sys_SystemRight`/`@sys_FunctionRight` ([tapi-permission-patterns.md](tapi-permission-patterns.md)).
46
50
 
47
- 1. Vẽ danh sách bảng + PK + FK cho **toàn bộ** entity (không chỉ một bảng). Theo quy ước [db-table-design.md](db-table-design.md): `tbl` + PascalCase, PK `[Entity]ID`, cột audit `CreateUser/CreateTime/UpdateUser/UpdateTime`.
48
- 2. Xác định quan hệ n-n → bảng nối (ví dụ `tblUserRole`).
49
- 3. **`CREATE TABLE` do lập trình viên tự chạy** — MCP chặn, AI trình bày DDL để user duyệt & chạy. Sửa bảng ĐÃ CÓ thì mở theo tiêu chí *mất dữ liệu hay không*: `ALTER TABLE ... ADD` và `DROP CONSTRAINT` chạy thẳng, `ALTER COLUMN` cần `confirmWrite`, còn `DROP COLUMN`/`DROP TABLE`/`SWITCH` vẫn chặn cứng.
50
- 4. Danh mục/bảng tra cứu (lookup) thiết kế sớm — nhiều module sẽ dùng chung cho dropdown.
51
+ ## Step 4 — Project structure (system level only)
51
52
 
52
- **Output:** sơ đồ bảng + quan hệ, đã được user xác nhận.
53
+ - **Menu & navigation:** `project.json` (menuLeft/menu/menuStyle) — [project-config.md](project-config.md), `examples/project-patterns.json`.
54
+ - **Components shared across modules** → project scope `{projectId}/components/` (`fui component new`/`update` with a project, no module; see `fui component --help`) so they auto-load everywhere — [component-design.md](component-design.md).
55
+ - **Cross-module navigation:** `pushRouter`/`openWindow` ([ui-crosswindow-patterns.md](ui-crosswindow-patterns.md)); pass IDs via URL, child module queries itself.
56
+ - **Cross-module permissions:** unify `SystemRight`/`FunctionRight` by Step-0 roles; **define real codes before guarding** (Step 4b).
53
57
 
54
- ---
58
+ ## Step 4b — Create right DEFINITIONS before any guarded module.json
55
59
 
56
- ## Bước 3 — Thiết kế API (SP) theo entity
60
+ A code exists only as a row in the project's `acc.tblSysRight`/`acc.tblFunction`. `FunctionRight.includes('42')` **does not create** 42; a missing code silently hides the control ([permission-system.md](permission-system.md) §"Mandatory: a right code must EXIST before you guard with it"). Often forgotten: it is not in the project DB, schema, or any workspace file.
57
61
 
58
- Map mỗi entity → bộ SP tAPI chuẩn (`List/Get/Insert/Update/Delete` + `AUTH_*Options` cho dropdown). Xem [tapi-reference.md](tapi-reference.md) §1, [fullstack-workflow.md](fullstack-workflow.md) Bước 2-3.
62
+ 1. `fui right system list` + `fui right function list` — see what exists (new projects usually empty); writes cache `_db/rights.json` **keyed by `apiName`** for `fui module validate`. Multi-alias → run **per alias**; never reuse one alias's cache for another.
63
+ 2. Each Step-0 role → a `SystemRight` level (`fui right system new`, level + note). `9` = Project Admin exists already.
64
+ 3. Each separately toggled operation (approve, export, delete…) → a `FunctionRight` (`fui right function new`, code + name). Keep one `code → meaning` table in the design shared by all modules; no module invents numbers.
65
+ 4. Lock the table with the user **before** coding — changing codes after assigning real users is manual work outside fui.
59
66
 
60
- Ở cấp hệ thống, chú ý:
61
- - **SP dùng chung** (danh mục, lookup) → đặt tên trung tính, nhiều module gọi lại.
62
- - Phân quyền nhất quán qua `@sys_SystemRight`/`@sys_FunctionRight` — xem [tapi-permission-patterns.md](tapi-permission-patterns.md).
67
+ ## Step 5 — Build order (lowest risk first)
63
68
 
64
- ---
69
+ 0. **Infrastructure** (fully new only): database + two SQL accounts + alias `acc` + FUI project + admin rights — [project-provisioning.md](project-provisioning.md).
70
+ 1. **Schema + lookup data** — inspect with `fui query` (TOP 20).
71
+ 2. **Right definitions** (4b) — SP `@sys_FunctionRight` checks and `v-if` guards reference them; creating later means everything was written with non-existent codes.
72
+ 3. **Core-entity SPs**, statically verified with `fui sp verify` (reads body, no live call).
73
+ 4. **Main-entity CRUD module** — convention template for the rest.
74
+ 5. **Dependent modules** (reports, dashboards) once data exists.
75
+ 6. **Menu + shared components** last.
65
76
 
66
- ## Bước 4 — Cấu trúc project: menu, điều hướng, component dùng chung
77
+ Once the shared infrastructure (schema, rights, shared components) is settled in Steps 0-4b, modules that are INDEPENDENT of each other (steps 4-5 above) can be built **in parallel by several Claude Code sessions** instead of one after another in one session: one session per module, coordinated with `ListAgents`/`SendMessage`. How to open sessions and hand out work: → [new-session.md](new-session.md) §6.
67
78
 
68
- Đây là phần **chỉ có ở cấp hệ thống** (một module đơn lẻ không cần):
79
+ Each module: full [fullstack-workflow.md](fullstack-workflow.md) — analyze → **Design Review Gate (§Step 1b)** → hard-coded UI → contract → SP → API wiring → static verification.
69
80
 
70
- - **Menu & điều hướng:** cấu hình trong `project.json` (menuLeft/menu/menuStyle). Xem [project-config.md](project-config.md) và `examples/project-patterns.json`.
71
- - **Component dùng chung nhiều module** → đặt project-scope (`{projectId}/components/`, gọi `component_new`/`component_update` với `projectId` không kèm `moduleId`) để auto-load ở mọi module. Xem [component-design.md](component-design.md).
72
- - **Điều hướng giữa module:** `pushRouter`/`openWindow` (xem [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md)); truyền ID qua URL, module con tự query.
73
- - **Phân quyền xuyên module:** thống nhất `SystemRight`/`FunctionRight` theo vai trò đã xác định ở Bước 0 — và **định nghĩa mã thật trước khi gác**, xem Bước 4b.
81
+ ## Checklist
74
82
 
75
- ---
76
-
77
- ## Bước 4b — Tạo ĐỊNH NGHĨA quyền (làm TRƯỚC khi viết module.json nào có gác quyền)
78
-
79
- Vai trò xác định ở Bước 0 mới chỉ là ý định. Mã quyền chỉ tồn tại khi có dòng trong `acc.tblSysRight`/`acc.tblFunction` của project — viết `FunctionRight.includes('42')` **không tạo ra** mã 42, và mã không tồn tại làm control biến mất im lặng (chi tiết + lý do các tầng kiểm chứng không bắt được: [permission-system.md](permission-system.md) §"Bắt buộc: mã quyền phải TỒN TẠI trước khi đem gác").
80
-
81
- Hệ thống mới thường quên bước này vì nó không thuộc DB của project, không nằm trong schema, không có file nào trong workspace nhắc tới.
82
-
83
- 1. `right_system_list` + `right_function_list` — xem project đã có gì (project mới thường trống; cũng ghi cache `_db/rights.json` **theo khoá `apiName`** để `module_validate` đối chiếu được. Hệ thống gọi nhiều alias thì chạy cho **từng alias**, cache của alias này không dùng cho alias kia).
84
- 2. Map **mỗi vai trò** ở Bước 0 → một mức `SystemRight` (`right_system_new({ sysRight, note })`); `9` = Project Admin có sẵn, không cần tạo.
85
- 3. Map **mỗi thao tác cần bật/tắt riêng** (duyệt, xuất báo cáo, xóa…) → một `FunctionRight` (`right_function_new({ functionCode, functionName })`). Đặt bảng `mã → ý nghĩa` vào phần thiết kế để mọi module dùng chung một bộ mã, không mỗi module bịa một dãy số.
86
- 4. Chốt bảng đó với user **trước khi** code — đổi mã sau khi đã gán quyền cho user thật là việc phải làm tay ngoài MCP.
87
-
88
- ---
89
-
90
- ## Bước 5 — Thứ tự triển khai
91
-
92
- Dựng theo thứ tự giảm rủi ro:
93
-
94
- 0. **Hạ tầng** (chỉ khi dựng mới hoàn toàn): database + hai tài khoản SQL + alias `acc` + project FUI + quyền quản trị — [project-provisioning.md](project-provisioning.md).
95
- 1. **Schema + lookup data** trước (mọi thứ phụ thuộc vào đây) — khảo sát bằng `db_sql_execute` (TOP 20).
96
- 2. **Định nghĩa quyền** (Bước 4b) — SP kiểm `@sys_FunctionRight` và module gác `v-if` đều tham chiếu tới đây; tạo sau thì mọi thứ ở trên đã viết bằng mã chưa tồn tại.
97
- 3. **SP cho entity cốt lõi**, kiểm chứng tĩnh bằng `db_sp_verify` (đọc thân SP + suy luận, không gọi endpoint sống).
98
- 4. **Module CRUD entity chính** — dùng làm khuôn mẫu convention cho các module sau.
99
- 5. **Module phụ thuộc** (báo cáo, dashboard) sau khi dữ liệu đã có.
100
- 6. **Menu + component dùng chung** ráp cuối để nối các module.
101
-
102
- Mỗi module: theo trọn [fullstack-workflow.md](fullstack-workflow.md) — phân tích → **Design Review Gate (§Bước 1b)** → UI data cứng → chốt contract → SP → wiring API → kiểm chứng tĩnh.
103
-
104
- ---
105
-
106
- ## Checklist cấp hệ thống
107
-
108
- - [ ] Đã liệt kê đầy đủ module + vai trò truy cập, user xác nhận phạm vi
109
- - [ ] Schema tổng thể (bảng + PK/FK + bảng nối + lookup) đã chốt trước khi code
110
- - [ ] Convention thống nhất giữa các module (tham khảo module đã có)
111
- - [ ] Component dùng chung đặt project-scope, không copy lặp
112
- - [ ] Menu/điều hướng cấu hình trong project.json
113
- - [ ] **Đã tạo định nghĩa quyền thật** (`right_system_new`/`right_function_new`) cho mọi vai trò/thao tác, có bảng `mã → ý nghĩa` user đã chốt — không module nào gác bằng mã chưa tồn tại
114
- - [ ] `module_validate` không còn warning về mã quyền (đã chạy `right_*_list` để có cache đối chiếu)
115
- - [ ] Phân quyền nhất quán theo vai trò xuyên suốt các SP
116
- - [ ] Thứ tự triển khai: schema → **định nghĩa quyền** → SP → module lõi → module phụ → menu
83
+ - [ ] All modules + access roles listed; scope user-confirmed
84
+ - [ ] Overall schema (PK/FK, junction, lookup) locked before coding
85
+ - [ ] Same convention across modules
86
+ - [ ] Shared components at project scope, not copied
87
+ - [ ] Menu/navigation in project.json
88
+ - [ ] **Real right definitions** (`fui right system new`/`fui right function new`) for every role/operation, user-locked `code → meaning` table — no guard uses a non-existent code
89
+ - [ ] `fui module validate` shows no right-code warnings (`fui right * list` run for cache)
90
+ - [ ] Permissions consistent by role across SPs
91
+ - [ ] Order: schema → **right definitions** → SP → core module → dependent modules → menu