@fui-org/fui-cli 1.3.1 → 2.0.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.
- package/README.md +19 -3
- package/dist/fui-bmg5pnmq.js +379 -0
- package/dist/fui.js +1 -1
- package/package.json +7 -6
- package/skills/fui/SKILL.md +9 -41
- package/skills/fui-skill/SKILL.md +95 -225
- package/skills/fui-skill/assets/projectdefaultstyle-3.0.css +555 -0
- package/skills/fui-skill/assets/projectdefaultstyle.css +207 -235
- package/skills/fui-skill/references/INDEX.md +105 -137
- package/skills/fui-skill/references/advanced-techniques.md +76 -68
- package/skills/fui-skill/references/coding-standards.md +56 -56
- package/skills/fui-skill/references/component-design.md +166 -173
- package/skills/fui-skill/references/component-quickref.md +61 -60
- package/skills/fui-skill/references/component-table.md +128 -117
- package/skills/fui-skill/references/components-dialog.md +55 -56
- package/skills/fui-skill/references/components-display.md +24 -30
- package/skills/fui-skill/references/components-echart.md +186 -261
- package/skills/fui-skill/references/components-input.md +72 -96
- package/skills/fui-skill/references/controls-patterns.md +196 -342
- package/skills/fui-skill/references/controls-styling-vocabulary.md +130 -97
- package/skills/fui-skill/references/db-table-design.md +24 -28
- package/skills/fui-skill/references/db-workflow.md +191 -390
- package/skills/fui-skill/references/default-function.md +169 -128
- package/skills/fui-skill/references/design-modes.md +35 -63
- package/skills/fui-skill/references/echart-templates.md +204 -196
- package/skills/fui-skill/references/fastproject.md +62 -60
- package/skills/fui-skill/references/fsheet.md +109 -124
- package/skills/fui-skill/references/fullstack-workflow.md +90 -128
- package/skills/fui-skill/references/module-data-patterns.md +31 -40
- package/skills/fui-skill/references/module-json-anatomy.md +47 -52
- package/skills/fui-skill/references/module-structure.md +80 -196
- package/skills/fui-skill/references/new-session.md +49 -51
- package/skills/fui-skill/references/pdfmake.md +17 -17
- package/skills/fui-skill/references/permission-system.md +89 -108
- package/skills/fui-skill/references/platform-architecture.md +128 -153
- package/skills/fui-skill/references/project-config.md +102 -134
- package/skills/fui-skill/references/project-provisioning.md +139 -244
- package/skills/fui-skill/references/script-map.md +208 -242
- package/skills/fui-skill/references/sql-clr-functions.md +98 -97
- package/skills/fui-skill/references/system-design.md +63 -88
- package/skills/fui-skill/references/tapi-file-api.md +46 -52
- package/skills/fui-skill/references/tapi-permission-patterns.md +51 -53
- package/skills/fui-skill/references/tapi-reference.md +132 -207
- package/skills/fui-skill/references/tools-registry.md +84 -460
- package/skills/fui-skill/references/ui-crosswindow-patterns.md +79 -75
- package/skills/fui-skill/references/ui-dialog-patterns.md +98 -72
- package/skills/fui-skill/references/ui-layout-patterns.md +26 -26
- package/skills/fui-skill/references/ui-patterns.md +71 -83
- package/skills/fui-skill/references/ui-screenshot-review.md +63 -62
- package/skills/fui-skill/references/ui-table-cell-patterns.md +61 -59
- package/skills/fui-skill/references/ui-templates.md +16 -23
- package/skills/fui-skill/references/verification.md +236 -246
- package/skills/fui-skill/references/watcher-patterns.md +30 -63
- package/skills/fui-skill/references/websocket-realtime.md +83 -66
- package/skills/fui-skill/scripts/component-3.0.js +298 -131
- package/skills/fui-skill/scripts/component.js +277 -271
- package/skills/fui-skill/scripts/componentTable-3.0.js +182 -53
- package/skills/fui-skill/scripts/componentTable.js +171 -49
- package/skills/fui-skill/scripts/defaultfunction-3.0.js +88 -3
- package/skills/fui-skill/scripts/defaultfunction.js +88 -3
- package/skills/fui-skill/scripts/fsheet.js +38 -0
- package/dist/fui-x7kph78r.js +0 -420
- package/skills/fui-skill/README.md +0 -112
- package/skills/fui-skill/metadata.json +0 -75
- package/skills/fui-skill-cli/SKILL.md +0 -139
- package/skills/fui-skill-cli/references/INDEX.md +0 -110
- package/skills/fui-skill-cli/references/advanced-techniques.md +0 -168
- package/skills/fui-skill-cli/references/coding-standards.md +0 -112
- package/skills/fui-skill-cli/references/component-design.md +0 -448
- package/skills/fui-skill-cli/references/component-quickref.md +0 -78
- package/skills/fui-skill-cli/references/component-table.md +0 -248
- package/skills/fui-skill-cli/references/components-dialog.md +0 -191
- package/skills/fui-skill-cli/references/components-display.md +0 -141
- package/skills/fui-skill-cli/references/components-echart.md +0 -316
- package/skills/fui-skill-cli/references/components-input.md +0 -335
- package/skills/fui-skill-cli/references/controls-patterns.md +0 -701
- package/skills/fui-skill-cli/references/controls-styling-vocabulary.md +0 -137
- package/skills/fui-skill-cli/references/db-table-design.md +0 -73
- package/skills/fui-skill-cli/references/db-workflow.md +0 -288
- package/skills/fui-skill-cli/references/default-function.md +0 -425
- package/skills/fui-skill-cli/references/design-modes.md +0 -57
- package/skills/fui-skill-cli/references/echart-templates.md +0 -489
- package/skills/fui-skill-cli/references/fastproject.md +0 -99
- package/skills/fui-skill-cli/references/fsheet.md +0 -203
- package/skills/fui-skill-cli/references/fullstack-workflow.md +0 -313
- package/skills/fui-skill-cli/references/module-data-patterns.md +0 -117
- package/skills/fui-skill-cli/references/module-json-anatomy.md +0 -132
- package/skills/fui-skill-cli/references/module-structure.md +0 -141
- package/skills/fui-skill-cli/references/new-session.md +0 -85
- package/skills/fui-skill-cli/references/pdfmake.md +0 -60
- package/skills/fui-skill-cli/references/permission-system.md +0 -150
- package/skills/fui-skill-cli/references/platform-architecture.md +0 -269
- package/skills/fui-skill-cli/references/project-config.md +0 -303
- package/skills/fui-skill-cli/references/project-provisioning.md +0 -278
- package/skills/fui-skill-cli/references/script-map.md +0 -262
- package/skills/fui-skill-cli/references/sql-clr-functions.md +0 -225
- package/skills/fui-skill-cli/references/system-design.md +0 -89
- package/skills/fui-skill-cli/references/tapi-file-api.md +0 -185
- package/skills/fui-skill-cli/references/tapi-permission-patterns.md +0 -156
- package/skills/fui-skill-cli/references/tapi-reference.md +0 -474
- package/skills/fui-skill-cli/references/tools-registry.md +0 -84
- package/skills/fui-skill-cli/references/ui-crosswindow-patterns.md +0 -321
- package/skills/fui-skill-cli/references/ui-dialog-patterns.md +0 -255
- package/skills/fui-skill-cli/references/ui-layout-patterns.md +0 -176
- package/skills/fui-skill-cli/references/ui-patterns.md +0 -303
- package/skills/fui-skill-cli/references/ui-screenshot-review.md +0 -95
- package/skills/fui-skill-cli/references/ui-table-cell-patterns.md +0 -318
- package/skills/fui-skill-cli/references/ui-templates.md +0 -22
- package/skills/fui-skill-cli/references/verification.md +0 -236
- package/skills/fui-skill-cli/references/watcher-patterns.md +0 -163
- package/skills/fui-skill-cli/references/websocket-realtime.md +0 -271
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
# SQL CLR Functions —
|
|
1
|
+
# SQL CLR Functions — DLL-backed SQL Server functions
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Owns: **SQL CLR functions: httpCall, sendMail, ImageResize, FileReader, RegexMatch...**
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
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` —
|
|
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
|
-
|
|
20
|
+
Resizes to at most `@maxWidth` x `@maxHeight`.
|
|
21
21
|
|
|
22
|
-
|
|
|
23
|
-
|
|
24
|
-
| `@extension`
|
|
25
|
-
| `@OriginalImage`
|
|
26
|
-
| `@maxWidth`, `@maxHeight` |
|
|
27
|
-
| `@preserverAspectRatio`
|
|
28
|
-
| `@quality`
|
|
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
|
-
|
|
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
|
-
|
|
39
|
+
Crops a `@Width` x `@Height` rectangle starting at `(@StartAtX, @StartAtY)`.
|
|
40
40
|
|
|
41
41
|
---
|
|
42
42
|
|
|
43
|
-
## 2. `SQLHttpHelper` — HTTP
|
|
43
|
+
## 2. `SQLHttpHelper` — HTTP, public value store, mail
|
|
44
44
|
|
|
45
45
|
### `dbo.publicValueUUID` / `publicValueGet` / `publicValueSet`
|
|
46
46
|
|
|
47
|
-
|
|
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` —
|
|
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`
|
|
62
|
+
`httpAPI` has the **identical** signature (different internals): use `httpAPI` for internal tAPI calls, `httpCall` for general outbound HTTP.
|
|
63
63
|
|
|
64
|
-
|
|
|
65
|
-
|
|
66
|
-
| `@Method` | `'GET'`, `'POST'`, `'PUT'`, `'DELETE'`... (
|
|
67
|
-
| `@URL`
|
|
68
|
-
| `@Header` |
|
|
69
|
-
| `@Data`
|
|
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
|
-
**
|
|
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
|
-
####
|
|
77
|
+
#### `@Header` syntax — pipe-delimited `Key: Value`
|
|
78
78
|
|
|
79
|
-
|
|
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
|
-
|
|
85
|
+
Header names are **case-insensitive**; special handling:
|
|
86
86
|
|
|
87
|
-
| Header name
|
|
88
|
-
|
|
89
|
-
| `Authorization`, `X-*`,
|
|
90
|
-
| `referer` / `referrer`
|
|
91
|
-
| `user-agent`
|
|
92
|
-
| `accept`
|
|
93
|
-
| `accept-language`
|
|
94
|
-
| `accept-encoding`
|
|
95
|
-
| `content-type`
|
|
96
|
-
|
|
|
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
|
-
**
|
|
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
|
-
**
|
|
109
|
+
**Joining headers:** exactly one `|` between pairs, no extra/missing `|`. A pair without `:` is **silently skipped** (no error).
|
|
110
110
|
|
|
111
|
-
####
|
|
111
|
+
#### `httpCall`/`httpAPI` response
|
|
112
112
|
|
|
113
|
-
-
|
|
114
|
-
-
|
|
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
|
-
→
|
|
119
|
-
-
|
|
120
|
-
- Timeout/exception
|
|
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
|
-
|
|
129
|
+
Sends email over SMTP from T-SQL.
|
|
130
130
|
|
|
131
|
-
|
|
|
132
|
-
|
|
133
|
-
| `@email_to`
|
|
134
|
-
| `@subject`
|
|
135
|
-
| `@content`
|
|
136
|
-
| `@from`
|
|
137
|
-
| `@fromDisplayName`
|
|
138
|
-
| `@smtp_server`, `@smtp_port` |
|
|
139
|
-
| `@userName`, `@Password`
|
|
140
|
-
| `@EnableSSL`
|
|
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
|
-
> **
|
|
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` —
|
|
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
|
-
|
|
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
|
-
|
|
|
164
|
-
|
|
165
|
-
| `FileCreateFolder` |
|
|
166
|
-
| `FileReader`
|
|
167
|
-
| `FileWriter`
|
|
168
|
-
| `FileExists`
|
|
169
|
-
| `FileDelete`
|
|
170
|
-
| `FileMove`
|
|
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
|
-
>
|
|
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` —
|
|
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
|
-
|
|
|
187
|
-
|
|
188
|
-
| `RegexReplace`
|
|
189
|
-
| `RegexIsMatch`
|
|
190
|
-
| `RegexMatch`
|
|
191
|
-
| `RegexMatchArray` |
|
|
192
|
-
| `CompareWord`
|
|
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`
|
|
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
|
-
####
|
|
196
|
+
#### `RegexMatchArray` shape — JSON object, not array
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
Flat object (`{...}`, not `[...]`), keys `"M{m}G{g}"`:
|
|
199
199
|
|
|
200
|
-
- `m` =
|
|
201
|
-
- `g` =
|
|
202
|
-
-
|
|
203
|
-
-
|
|
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
|
-
|
|
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
|
-
(
|
|
211
|
+
(G1 = G2 here because the whole match equals the only group; with no groups each match yields only `G1`.)
|
|
212
212
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
-
|
|
216
|
-
-
|
|
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.
|
|
221
|
+
## 5. When to use them in SPs
|
|
221
222
|
|
|
222
|
-
-
|
|
223
|
-
-
|
|
224
|
-
-
|
|
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 —
|
|
1
|
+
# System Design — Multi-Module App
|
|
2
2
|
|
|
3
|
-
>
|
|
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
|
-
|
|
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
|
-
|
|
7
|
+
## Step 0 — Clarify scope
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Don't code yet. Confirm:
|
|
10
10
|
|
|
11
|
-
|
|
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
|
-
|
|
18
|
+
Missing info → **ask**; never assume and build the wrong system.
|
|
14
19
|
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
+
## Step 2 — Schema first
|
|
29
34
|
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
+
**Output:** tables + relations, user-confirmed.
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
## Step 3 — SPs per entity
|
|
42
45
|
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|