@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,225 +0,0 @@
1
- # SQL CLR Functions — DLL-backed SQL Server functions
2
-
3
- > Owns: **SQL CLR functions: httpCall, sendMail, ImageResize, FileReader, RegexMatch...**
4
-
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
-
7
- A needed function is not in the DB → **do not invent it**; tell the user the DB lacks it.
8
-
9
- ---
10
-
11
- ## 1. `SQLImageHelper` — images
12
-
13
- ### `dbo.ImageResize`
14
-
15
- ```sql
16
- dbo.ImageResize(@extension nvarchar(10), @OriginalImage varbinary(max), @maxWidth int, @maxHeight int, @preserverAspectRatio bit, @quality int)
17
- RETURNS varbinary(max)
18
- ```
19
-
20
- Resizes to at most `@maxWidth` x `@maxHeight`.
21
-
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
-
30
- Returns resized `varbinary` — write to a `varbinary` column/file or return via tAPI File.
31
-
32
- ### `dbo.ImageCrop`
33
-
34
- ```sql
35
- dbo.ImageCrop(@OriginalImage varbinary(max), @StartAtX int, @StartAtY int, @Width int, @Height int)
36
- RETURNS varbinary(max)
37
- ```
38
-
39
- Crops a `@Width` x `@Height` rectangle starting at `(@StartAtX, @StartAtY)`.
40
-
41
- ---
42
-
43
- ## 2. `SQLHttpHelper` — HTTP, public value store, mail
44
-
45
- ### `dbo.publicValueUUID` / `publicValueGet` / `publicValueSet`
46
-
47
- Server-level shared key-value store (not a SQL table) — keeps temp state across SP calls without a table.
48
-
49
- ```sql
50
- dbo.publicValueUUID() RETURNS nvarchar(max) -- sinh 1 UUID mới, dùng làm key
51
- dbo.publicValueGet(@name nvarchar(max)) RETURNS nvarchar(max) -- đọc value theo key
52
- dbo.publicValueSet(@name nvarchar(max), @Data nvarchar(max)) RETURNS int -- ghi value theo key
53
- ```
54
-
55
- ### `dbo.httpCall` / `dbo.httpAPI` — HTTP from T-SQL
56
-
57
- ```sql
58
- dbo.httpCall(@Method nvarchar(max), @URL nvarchar(max), @Header nvarchar(max), @Data nvarchar(max))
59
- RETURNS nvarchar(max)
60
- ```
61
-
62
- `httpAPI` has the **identical** signature (different internals): use `httpAPI` for internal tAPI calls, `httpCall` for general outbound HTTP.
63
-
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
-
71
- **Example:**
72
-
73
- ```sql
74
- SELECT dbo.httpCall('POST', 'https://tapi.example.vn/me/auth/ApplicationList', '', '')
75
- ```
76
-
77
- #### `@Header` syntax — pipe-delimited `Key: Value`
78
-
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
-
81
- ```
82
- "Authorization: Bearer eyJhbGciOi...|X-Custom-Header: abc123"
83
- ```
84
-
85
- Header names are **case-insensitive**; special handling:
86
-
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
-
98
- **Bearer token + custom header:**
99
-
100
- ```sql
101
- SELECT dbo.httpCall(
102
- 'POST',
103
- 'https://api.example.com/data',
104
- 'Authorization: Bearer abc123xyz|Content-Type: application/json; charset=utf-8',
105
- '{"key":"value"}'
106
- )
107
- ```
108
-
109
- **Joining headers:** exactly one `|` between pairs, no extra/missing `|`. A pair without `:` is **silently skipped** (no error).
110
-
111
- #### `httpCall`/`httpAPI` response
112
-
113
- - Status **200**: raw response body verbatim (JSON, text, anything).
114
- - Status **not 200** (400, 401, 404, 500...): wrapped JSON:
115
- ```json
116
- { "httpErrorCode": 404, "responseData": "<nội dung body, hoặc escaped string nếu không phải JSON>" }
117
- ```
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
-
122
- ### `dbo.sendMail`
123
-
124
- ```sql
125
- dbo.sendMail(@email_to nvarchar(max), @subject nvarchar(max), @content nvarchar(max), @from nvarchar(max), @fromDisplayName nvarchar(max), @smtp_server nvarchar(max), @smtp_port int, @userName nvarchar(max), @Password nvarchar(max), @EnableSSL bit)
126
- RETURNS nvarchar(max)
127
- ```
128
-
129
- Sends email over SMTP from T-SQL.
130
-
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
-
142
- ```sql
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
- ```
145
-
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
-
148
- ---
149
-
150
- ## 3. `SQLFileSystem` — server files
151
-
152
- ```sql
153
- dbo.FileCreateFolder(@Path nvarchar(max)) RETURNS nvarchar(max)
154
- dbo.FileReader(@Path nvarchar(max)) RETURNS varbinary(max)
155
- dbo.FileWriter(@Content varbinary(max), @Path nvarchar(max)) RETURNS nvarchar(max)
156
- dbo.FileExists(@Path nvarchar(max)) RETURNS bit
157
- dbo.FileDelete(@Path nvarchar(max)) RETURNS nvarchar(max)
158
- dbo.FileMove(@SourceFileName nvarchar(max), @DestFileName nvarchar(max)) RETURNS nvarchar(max)
159
- ```
160
-
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
-
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
-
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
-
174
- ---
175
-
176
- ## 4. `SQLExpansionFunction` — regex & string compare
177
-
178
- ```sql
179
- dbo.RegexReplace(@Input nvarchar(max), @Pattern nvarchar(1000), @Replacement nvarchar(4000)) RETURNS nvarchar(max)
180
- dbo.RegexIsMatch(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS bit
181
- dbo.RegexMatch(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS nvarchar(max)
182
- dbo.RegexMatchArray(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS nvarchar(max)
183
- dbo.CompareWord(@String1 nvarchar(max), @String2 nvarchar(max)) RETURNS int
184
- ```
185
-
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
-
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
-
196
- #### `RegexMatchArray` shape — JSON object, not array
197
-
198
- Flat object (`{...}`, not `[...]`), keys `"M{m}G{g}"`:
199
-
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
-
205
- `RegexMatchArray('SDT: 0901 - 0902', '(\d{4})')` (one group) returns:
206
-
207
- ```json
208
- { "M1G1": "0901", "M1G2": "0901", "M2G1": "0902", "M2G2": "0902" }
209
- ```
210
-
211
- (G1 = G2 here because the whole match equals the only group; with no groups each match yields only `G1`.)
212
-
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.
218
-
219
- ---
220
-
221
- ## 5. When to use them in SPs
222
-
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,89 +0,0 @@
1
- # System Design — Multi-Module App
2
-
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
-
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
-
7
- ## Step 0 — Clarify scope
8
-
9
- Don't code yet. Confirm:
10
-
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.
17
-
18
- Missing info → **ask**; never assume and build the wrong system.
19
-
20
- ## Step 1 — Decompose into modules
21
-
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 |
28
-
29
- **Output:** module table — name, purpose, entities, access roles.
30
-
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.
32
-
33
- ## Step 2 — Schema first
34
-
35
- Before any module.json:
36
-
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).
41
-
42
- **Output:** tables + relations, user-confirmed.
43
-
44
- ## Step 3 — SPs per entity
45
-
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).
47
-
48
- - **Shared SPs** (catalogs, lookups) → neutral names.
49
- - Consistent authorization via `@sys_SystemRight`/`@sys_FunctionRight` ([tapi-permission-patterns.md](tapi-permission-patterns.md)).
50
-
51
- ## Step 4 — Project structure (system level only)
52
-
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).
57
-
58
- ## Step 4b — Create right DEFINITIONS before any guarded module.json
59
-
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.
61
-
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.
66
-
67
- ## Step 5 — Build order (lowest risk first)
68
-
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.
76
-
77
- Each module: full [fullstack-workflow.md](fullstack-workflow.md) — analyze → **Design Review Gate (§Step 1b)** → hard-coded UI → contract → SP → API wiring → static verification.
78
-
79
- ## Checklist
80
-
81
- - [ ] All modules + access roles listed; scope user-confirmed
82
- - [ ] Overall schema (PK/FK, junction, lookup) locked before coding
83
- - [ ] Same convention across modules
84
- - [ ] Shared components at project scope, not copied
85
- - [ ] Menu/navigation in project.json
86
- - [ ] **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
87
- - [ ] `fui module validate` shows no right-code warnings (`fui right * list` run for cache)
88
- - [ ] Permissions consistent by role across SPs
89
- - [ ] Order: schema → **right definitions** → SP → core module → dependent modules → menu
@@ -1,185 +0,0 @@
1
- # tAPI — File API (GET / UPLOAD)
2
-
3
- > Owns: **file APIs via SP: `spAPIFILE_*`, `tblFileData`, alias `fileContent`, `@sys_FileContent`/`@sys_FileName`**. Load when a module needs upload/download/view of files. **Never infer from training data** — tAPI has its own conventions. SP basics (naming, params, response): [tapi-reference.md](tapi-reference.md).
4
-
5
- ---
6
-
7
- ## GET file
8
-
9
- SP must SELECT **at least 3 required columns** (extra metadata columns allowed):
10
-
11
- | Column | Required | Meaning |
12
- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
13
- | `FileName` | ✅ | Returned file name — may be an expression, e.g. `FileName + FileType` |
14
- | `ContentType` | ✅ | MIME type (e.g. `application/pdf`, `image/png`) |
15
- | `fileContent` | ✅ | Binary content — alias of an **`image` or `varbinary`** column. tAPI detects the file content to stream by this data type |
16
- | other columns | ❌ | Optional metadata, e.g. `Modified`, `FileSize` — must be normal (non-binary) types |
17
-
18
- ```sql
19
- -- Ví dụ thực tế: FileName ghép đuôi, thêm cột Modified, binary aliased từ FileContentBIN
20
- CREATE PROCEDURE spAPIFILE_moduleImportFile
21
- @fileID varchar(50)
22
- AS BEGIN
23
- SELECT
24
- FileName = FileName + FileType,
25
- ContentType,
26
- Modified = ISNULL(UpdateTime, CreateTime),
27
- fileContent = FileContentBIN
28
- FROM tblA_ImportFile
29
- WHERE fileID = LEFT(@fileID, 32)
30
- END
31
- ```
32
-
33
- > `fileContent` must alias an `image` or `varbinary(max)` column — tAPI uses the type to detect and stream the file. Table column name is free (`FileContentBIN`, `BinaryContent`, ...).
34
- > `FileName` should include the extension (`.pdf`, `.xlsx`...) so the browser detects the type.
35
-
36
- **URL params — `@fileID` and `@filename`:**
37
-
38
- | Param | Required | Source | Meaning |
39
- | ------------------------ | -------- | -------------------------------- | ------------------------------------------------------------------------------------ |
40
- | `@fileID varchar(...)` | ✅ | First segment after FunctionName | ID of the file |
41
- | `@filename varchar(...)` | ❌ | LAST URL segment | Display file name in the URL (browser/download manager uses it to name the download) |
42
-
43
- Extra `@sys_*` auth params may be declared for permission checks.
44
-
45
- ```sql
46
- CREATE PROCEDURE spAPIFILE_Document
47
- @fileID varchar(50), -- bắt buộc, inject từ URL
48
- @filename varchar(200), -- tùy chọn — inject từ segment cuối URL; SP có thể dùng để
49
- -- ghi log, kiểm tra, hoặc override FileName trả về
50
- @sys_UserID varchar(9) -- tùy chọn, inject từ token
51
- AS BEGIN
52
- ...
53
- END
54
- ```
55
-
56
- **4 supported routes:**
57
-
58
- ```
59
- {domain}/{apiName}/{FunctionName}/{fileID}
60
- {domain}/{apiName}/{FunctionName}/{fileID}/{filename}
61
- {domain}/{apiName}/download/{FunctionName}/{fileID}/{filename}
62
- {domain}/{apiName}/viewer/{FunctionName}/{fileID}/{filename}
63
- ```
64
-
65
- `{FunctionName}` is the name after the `spAPIFILE_` prefix: SP `spAPIFILE_Document` → URL uses `Document`. `/viewer/` = view inline in browser; `/download/` = download.
66
-
67
- > **`@filename`:** usually the original name (e.g. `BaoCao_2024.pdf`) used by browser/download manager to name the file; need not match `FileName` in the DB. If the SP doesn't declare `@filename`, tAPI still accepts the route with that segment — the param is simply ignored.
68
-
69
- ## Upload file
70
-
71
- **Special params injected by tAPI on upload:**
72
-
73
- | Param | Type | Meaning |
74
- | ---------------------- | -------------- | --------------------------------- |
75
- | `@sys_FileContent` | varbinary(max) | File binary content |
76
- | `@sys_FileName` | nvarchar(200) | Original file name |
77
- | `@sys_FileContentType` | varchar(100) | MIME type |
78
- | `@sys_FileSize` | int | File size (bytes) |
79
- | `@sys_UploadData` | nvarchar(max) | Extra JSON data passed via header |
80
-
81
- All `@sys_` auth params are also available: `@sys_UserID`, `@sys_UserName`, `@sys_SessionID`, `@sys_GroupID`, `@sys_DepartmentID`, `@sys_SystemRight`, `@sys_FunctionRight`.
82
-
83
- ```sql
84
- CREATE PROCEDURE spAPIFILE_UPLOAD_Attachment
85
- @url1_SessionID varchar(36),
86
- @url2_Mode varchar(20),
87
- @sys_UserID varchar(9),
88
- @sys_FileContent varbinary(max),
89
- @sys_FileName nvarchar(200),
90
- @sys_FileContentType varchar(100),
91
- @sys_FileSize int
92
- AS BEGIN
93
- INSERT INTO tblAttachFiles(FileName, Capacity, SessionID, CreateUser)
94
- VALUES(@sys_FileName, @sys_FileSize, @url1_SessionID, @sys_UserID)
95
- END
96
- ```
97
-
98
- Route: `POST {domain}/{apiName}/upload/{spName}/{url1}/{url2}...`
99
-
100
- ## Standard file table — `tblFileData`
101
-
102
- Standard structure shared by `spAPIFILE_` (GET) and `spAPIFILE_UPLOAD_` (POST). For modules with files, create this table (or similar) before writing SPs.
103
-
104
- ```sql
105
- CREATE TABLE [dbo].[tblFileData](
106
- [FileID] [char](36) NOT NULL, -- UUID, DEFAULT newid()
107
- [FileName] [nvarchar](200) NOT NULL,
108
- [PhysicalName] [char](36) NOT NULL, -- UUID, DEFAULT newid()
109
- [PhysicalSegment] [char](10) NOT NULL, -- subfolder theo ngày, DEFAULT getPhysicalSegment(getdate())
110
- [CreateTime] [datetime] NOT NULL, -- DEFAULT getdate()
111
- [WriteToDisk] [datetime] NULL, -- null = chưa ghi ra disk
112
- [BinaryContent] [image] NULL, -- binary file content — alias là fileContent trong SP GET
113
- [ContentType] [varchar](100) NULL, -- MIME type, DEFAULT ''
114
- [Size] [int] NULL,
115
- CONSTRAINT [PK_tblFileData] PRIMARY KEY CLUSTERED ([FileID] ASC)
116
- ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
117
- GO
118
-
119
- ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_FileID] DEFAULT (newid()) FOR [FileID]
120
- ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_PhysicalName] DEFAULT (newid()) FOR [PhysicalName]
121
- ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_PhysicalSegment] DEFAULT ([dbo].[getPhysicalSegment](getdate())) FOR [PhysicalSegment]
122
- ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_CreateTime] DEFAULT (getdate()) FOR [CreateTime]
123
- ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_ContentType] DEFAULT ('') FOR [ContentType]
124
- ```
125
-
126
- > **DDL:** the `ALTER TABLE ... ADD CONSTRAINT` statements **can run via fui** (ADD is additive). `CREATE TABLE` cannot — fui blocks it; the developer must run it. This is a structure reference.
127
-
128
- **Fields:**
129
-
130
- | Field | Type | Meaning |
131
- | ----------------- | ------------- | ----------------------------------------------------------------------------- |
132
- | `FileID` | char(36) PK | Auto UUID via `newid()` — used as the URL key |
133
- | `FileName` | nvarchar(200) | Original upload name |
134
- | `PhysicalName` | char(36) | Auto UUID — actual file name on disk (avoids collisions) |
135
- | `PhysicalSegment` | char(10) | Date-based subfolder from `getPhysicalSegment(date)` |
136
- | `CreateTime` | datetime | Record creation time, DEFAULT getdate() |
137
- | `WriteToDisk` | datetime NULL | When the binary was written to disk; `NULL` = DB only, not on file system yet |
138
- | `BinaryContent` | image NULL | File binary — GET SP must alias it `fileContent` |
139
- | `ContentType` | varchar(100) | MIME type, e.g. `application/pdf`, `image/png` |
140
- | `Size` | int NULL | Size in bytes |
141
-
142
- **GET SP on the table:**
143
-
144
- ```sql
145
- CREATE PROCEDURE spAPIFILE_Document
146
- @FileID char(36),
147
- @sys_UserID varchar(9),
148
- @sys_SystemRight int
149
- AS BEGIN
150
- IF @sys_SystemRight < 1
151
- BEGIN RAISERROR(N'[Unauthorized]Bạn không có quyền.', 16, 1) RETURN END
152
-
153
- -- BinaryContent phải alias là fileContent — tAPI đọc đúng tên này
154
- SELECT FileName, ContentType, fileContent = BinaryContent
155
- FROM tblFileData WHERE FileID = @FileID
156
- END
157
- ```
158
-
159
- **UPLOAD SP into the table:**
160
-
161
- ```sql
162
- CREATE PROCEDURE spAPIFILE_UPLOAD_Document
163
- @url1_RefID varchar(50),
164
- @sys_UserID varchar(9),
165
- @sys_SystemRight int,
166
- @sys_FileContent varbinary(max),
167
- @sys_FileName nvarchar(200),
168
- @sys_FileContentType varchar(100),
169
- @sys_FileSize int
170
- AS BEGIN
171
- IF @sys_SystemRight < 2
172
- BEGIN RAISERROR(N'[Unauthorized]Bạn không có quyền.', 16, 1) RETURN END
173
-
174
- DECLARE @NewFileID char(36) = newid() -- sinh UUID trước, dùng để SELECT lại sau
175
-
176
- INSERT INTO tblFileData(FileID, FileName, BinaryContent, ContentType, Size)
177
- VALUES(@NewFileID, @sys_FileName, @sys_FileContent, @sys_FileContentType, @sys_FileSize)
178
-
179
- -- Trả về record vừa insert để client cập nhật danh sách
180
- SELECT FileID, FileName, Size, ContentType, CreateTime
181
- FROM tblFileData WHERE FileID = @NewFileID
182
- END
183
- ```
184
-
185
- > **`BinaryContent [image]`**: `image` is legacy SQL Server but works fine with tAPI. `varbinary(max)` also works — both map to the `fileContent` alias.
@@ -1,156 +0,0 @@
1
- # tAPI — Permission Check Patterns
2
-
3
- > Owns: **5 permission-check patterns in SP bodies (`@sys_SystemRight`, `getSystemRight`, RAISERROR)**. Load when an SP needs authorization. SP basics (naming, params, response, RAISERROR): [tapi-reference.md](tapi-reference.md). `SystemRight`/`FunctionRight` concepts, `tblSysRight`/`tblFunction`, right-definition commands: [permission-system.md](permission-system.md).
4
-
5
- ---
6
-
7
- ## Permission-related system params
8
-
9
- Injected by tAPI — the client never sends them:
10
-
11
- | Param | Type | Meaning |
12
- | -------------------- | ------------- | ------------------------------------- |
13
- | `@sys_UserID` | varchar(9) | Logged-in user ID |
14
- | `@sys_SystemRight` | int | User's level on the current module |
15
- | `@sys_FunctionRight` | varchar(2000) | Function rights like `[AD][RPT][MGR]` |
16
-
17
- **Declare** at the end of the param list. **No default on any param, including `@sys_*`** ([tapi-reference.md](tapi-reference.md) §2 — tAPI always passes every param, `NULL` when missing, so `DEFAULT` is never used; `fui sp deploy` hard-blocks it):
18
-
19
- ```sql
20
- CREATE PROCEDURE spAPI_EntityAction
21
- @BusinessParam1 int,
22
- @BusinessParam2 nvarchar(100),
23
- @sys_UserID varchar(9),
24
- @sys_SystemRight int
25
- AS
26
- ```
27
-
28
- ## `@sys_SystemRight` levels
29
-
30
- Meaning is **defined per project** (`tblSysRight.Note`, managed via `fui right system list`/`update` — [permission-system.md](permission-system.md)). Common convention for SP checks — not platform-fixed, except `9` is always Project Admin:
31
-
32
- | Value | Common meaning |
33
- | ----- | -------------------------------------------------- |
34
- | `0` | No right / not granted on the module |
35
- | `1` | Basic view |
36
- | `2` | Standard operations (read, add, normal edit) |
37
- | `3` | Advanced (internal management, sensitive ops) |
38
- | `9` | Module Admin / Project Admin (fixed platform-wide) |
39
-
40
- ## Helper: rights on a specific module
41
-
42
- ```sql
43
- dbo.getSystemRight(@ModuleID, @sys_UserID)
44
- ```
45
-
46
- Returns the user's `SysRight` on a given module — use to check rights on a module **other than** the current one.
47
-
48
- ---
49
-
50
- ## Pattern 1 — Basic access block (READ)
51
-
52
- Every read SP that needs login. Requires `SysRight >= 2`.
53
-
54
- ```sql
55
- If @sys_SystemRight < 2
56
- Begin
57
- Raiserror(N'[Unauthorized]Bạn không có quyền trên chức năng này.', 16, 1)
58
- Return
59
- End
60
- ```
61
-
62
- ## Pattern 2 — Block only users with no right (minimal)
63
-
64
- Allows `SysRight = 1`; blocks only `SysRight = 0`.
65
-
66
- ```sql
67
- If @sys_SystemRight = 0
68
- Begin
69
- Raiserror(N'[Unauthorized]Bạn không có quyền trên chức năng này.', 16, 1)
70
- Return
71
- End
72
- ```
73
-
74
- ## Pattern 3 — 2-tier: global + module admin (WRITE)
75
-
76
- Writes affecting module config or other users' data. User must meet **either**:
77
-
78
- - `@sys_SystemRight >= 3` (high global right), **or**
79
- - Module Admin (`getSystemRight >= 9`) of that module.
80
-
81
- ```sql
82
- -- Tầng 1: phải có quyền cơ bản
83
- If @sys_SystemRight < 2
84
- Begin
85
- Raiserror(N'[Unauthorized]Bạn không có quyền trên chức năng này.', 16, 1)
86
- Return
87
- End
88
-
89
- -- Tầng 2: phải là admin hệ thống hoặc admin của module đó
90
- If @sys_SystemRight < 3 and dbo.getSystemRight(@ModuleID, @sys_UserID) < 9
91
- Begin
92
- Raiserror(N'[Unauthorized]Bạn không có quyền trên Module này.', 16, 1)
93
- Return
94
- End
95
- ```
96
-
97
- ## Pattern 4 — Business-rule check before executing
98
-
99
- Authorized but violates a data constraint (e.g. deleting a parent that still has children).
100
-
101
- ```sql
102
- -- Kiểm tra ràng buộc trước khi xóa
103
- If exists(Select * from tblChild WHERE ParentID = @ParentID)
104
- Begin
105
- Raiserror(N'Phải xóa dữ liệu liên quan trước khi thực hiện thao tác này.', 16, 1)
106
- Return
107
- End
108
-
109
- DELETE tblParent WHERE ParentID = @ParentID
110
- ```
111
-
112
- ## Pattern 5 — `@sys_FunctionRight` check
113
-
114
- Authorization by specific function (not just numeric level).
115
-
116
- ```sql
117
- If CHARINDEX('[ADMIN]', @sys_FunctionRight) = 0
118
- Begin
119
- Raiserror(N'[Unauthorized]Bạn không có quyền thực hiện chức năng này.', 16, 1)
120
- Return
121
- End
122
- ```
123
-
124
- ---
125
-
126
- ## Check order
127
-
128
- ```
129
- 1. Kiểm tra quyền hệ thống (@sys_SystemRight) ← luôn đầu tiên
130
- 2. Kiểm tra quyền module (getSystemRight) ← nếu cần 2 tầng
131
- 3. Kiểm tra quyền chức năng (@sys_FunctionRight) ← nếu dùng FunctionRight
132
- 4. Kiểm tra ràng buộc nghiệp vụ ← sau cùng, trước khi ghi
133
- ```
134
-
135
- ## Error message conventions
136
-
137
- | Case | Standard message |
138
- | ---------------------------------------- | --------------------------------------------------------------------- |
139
- | Missing global right | `N'[Unauthorized]Bạn không có quyền trên chức năng này.'` |
140
- | Missing module right | `N'[Unauthorized]Bạn không có quyền trên Module này.'` |
141
- | Missing function right (`FunctionRight`) | `N'[Unauthorized]Bạn không có quyền thực hiện chức năng này.'` |
142
- | Constraint violation | Specific description, **no** prefix: `N'Phải xóa X trước khi xóa Y.'` |
143
- | Invalid data | `N'Dữ liệu không hợp lệ.'` or specific description, **no** prefix |
144
-
145
- **Mandatory `RAISERROR` format:**
146
-
147
- ```sql
148
- RAISERROR(N'Thông báo lỗi tiếng Việt.', 16, 1)
149
- RETURN
150
- ```
151
-
152
- - **Severity always `16`** — every error kind (validation, unauthorized, business logic)
153
- - `N` prefix required for Vietnamese Unicode
154
- - `RETURN` required right after `RAISERROR` — without it the SP keeps running after the error
155
- - Client receives `{ "Message": "..." }`
156
- - **Every missing-right error in the 5 patterns must start with `[Unauthorized]`** (e.g. `N'[Unauthorized]Bạn không có quyền...'`) — tAPI uses this prefix to return HTTP `401` instead of the default, and strips `[Unauthorized]` from `Message` before returning. Constraint/business errors (Pattern 4) do **not** use it — mechanism + client 401 handling: [tapi-reference.md](tapi-reference.md) §5.