@fui-org/fui-cli 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -3
- package/dist/fui.js +160 -43
- package/package.json +4 -2
- package/skills/fui/SKILL.md +131 -66
- package/skills/fui-skill/README.md +112 -0
- package/skills/fui-skill/SKILL.md +269 -0
- package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
- package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
- package/skills/fui-skill/design-md/airbnb/README.md +5 -0
- package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
- package/skills/fui-skill/design-md/airtable/README.md +5 -0
- package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
- package/skills/fui-skill/design-md/apple/README.md +5 -0
- package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
- package/skills/fui-skill/design-md/asu/README.md +107 -0
- package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
- package/skills/fui-skill/design-md/binance/README.md +5 -0
- package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/bmw/README.md +5 -0
- package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
- package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
- package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
- package/skills/fui-skill/design-md/bugatti/README.md +5 -0
- package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
- package/skills/fui-skill/design-md/cal/README.md +5 -0
- package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
- package/skills/fui-skill/design-md/claude/README.md +5 -0
- package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
- package/skills/fui-skill/design-md/clay/README.md +5 -0
- package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
- package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
- package/skills/fui-skill/design-md/cohere/README.md +5 -0
- package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
- package/skills/fui-skill/design-md/coinbase/README.md +5 -0
- package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
- package/skills/fui-skill/design-md/composio/README.md +5 -0
- package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
- package/skills/fui-skill/design-md/cursor/README.md +5 -0
- package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
- package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
- package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
- package/skills/fui-skill/design-md/expo/README.md +5 -0
- package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
- package/skills/fui-skill/design-md/ferrari/README.md +5 -0
- package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
- package/skills/fui-skill/design-md/figma/README.md +5 -0
- package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/framer/README.md +5 -0
- package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
- package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
- package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
- package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
- package/skills/fui-skill/design-md/ibm/README.md +5 -0
- package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
- package/skills/fui-skill/design-md/intercom/README.md +5 -0
- package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
- package/skills/fui-skill/design-md/kraken/README.md +5 -0
- package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
- package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
- package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
- package/skills/fui-skill/design-md/linear.app/README.md +5 -0
- package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
- package/skills/fui-skill/design-md/lovable/README.md +5 -0
- package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
- package/skills/fui-skill/design-md/mastercard/README.md +5 -0
- package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
- package/skills/fui-skill/design-md/meta/README.md +5 -0
- package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
- package/skills/fui-skill/design-md/minimax/README.md +5 -0
- package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
- package/skills/fui-skill/design-md/mintlify/README.md +5 -0
- package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
- package/skills/fui-skill/design-md/miro/README.md +5 -0
- package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
- package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
- package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
- package/skills/fui-skill/design-md/mongodb/README.md +5 -0
- package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
- package/skills/fui-skill/design-md/nike/README.md +5 -0
- package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
- package/skills/fui-skill/design-md/notion/README.md +5 -0
- package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
- package/skills/fui-skill/design-md/nvidia/README.md +5 -0
- package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
- package/skills/fui-skill/design-md/ollama/README.md +5 -0
- package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
- package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
- package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
- package/skills/fui-skill/design-md/pinterest/README.md +5 -0
- package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
- package/skills/fui-skill/design-md/playstation/README.md +5 -0
- package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
- package/skills/fui-skill/design-md/posthog/README.md +5 -0
- package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
- package/skills/fui-skill/design-md/raycast/README.md +5 -0
- package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
- package/skills/fui-skill/design-md/renault/README.md +5 -0
- package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
- package/skills/fui-skill/design-md/replicate/README.md +5 -0
- package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
- package/skills/fui-skill/design-md/resend/README.md +5 -0
- package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
- package/skills/fui-skill/design-md/revolut/README.md +5 -0
- package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
- package/skills/fui-skill/design-md/runwayml/README.md +5 -0
- package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
- package/skills/fui-skill/design-md/sanity/README.md +5 -0
- package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
- package/skills/fui-skill/design-md/sentry/README.md +5 -0
- package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
- package/skills/fui-skill/design-md/shopify/README.md +5 -0
- package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
- package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
- package/skills/fui-skill/design-md/spacex/README.md +5 -0
- package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
- package/skills/fui-skill/design-md/spotify/README.md +5 -0
- package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
- package/skills/fui-skill/design-md/starbucks/README.md +5 -0
- package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
- package/skills/fui-skill/design-md/stripe/README.md +5 -0
- package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
- package/skills/fui-skill/design-md/supabase/README.md +5 -0
- package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
- package/skills/fui-skill/design-md/superhuman/README.md +5 -0
- package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
- package/skills/fui-skill/design-md/tesla/README.md +5 -0
- package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
- package/skills/fui-skill/design-md/theverge/README.md +5 -0
- package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
- package/skills/fui-skill/design-md/together.ai/README.md +5 -0
- package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
- package/skills/fui-skill/design-md/uber/README.md +5 -0
- package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
- package/skills/fui-skill/design-md/vercel/README.md +5 -0
- package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
- package/skills/fui-skill/design-md/vodafone/README.md +5 -0
- package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
- package/skills/fui-skill/design-md/voltagent/README.md +5 -0
- package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
- package/skills/fui-skill/design-md/warp/README.md +5 -0
- package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
- package/skills/fui-skill/design-md/webflow/README.md +5 -0
- package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
- package/skills/fui-skill/design-md/wired/README.md +5 -0
- package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/wise/README.md +5 -0
- package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
- package/skills/fui-skill/design-md/x.ai/README.md +5 -0
- package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
- package/skills/fui-skill/design-md/zapier/README.md +5 -0
- package/skills/fui-skill/examples/component.vue +162 -0
- package/skills/fui-skill/examples/f-table-patterns.json +331 -0
- package/skills/fui-skill/examples/module-patterns.json +973 -0
- package/skills/fui-skill/examples/project-patterns.json +222 -0
- package/skills/fui-skill/metadata.json +75 -0
- package/skills/fui-skill/references/INDEX.md +144 -0
- package/skills/fui-skill/references/advanced-techniques.md +160 -0
- package/skills/fui-skill/references/coding-standards.md +112 -0
- package/skills/fui-skill/references/component-design.md +455 -0
- package/skills/fui-skill/references/component-quickref.md +77 -0
- package/skills/fui-skill/references/component-table.md +276 -0
- package/skills/fui-skill/references/components-dialog.md +192 -0
- package/skills/fui-skill/references/components-display.md +147 -0
- package/skills/fui-skill/references/components-echart.md +391 -0
- package/skills/fui-skill/references/components-input.md +359 -0
- package/skills/fui-skill/references/controls-patterns.md +847 -0
- package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
- package/skills/fui-skill/references/db-table-design.md +77 -0
- package/skills/fui-skill/references/db-workflow.md +504 -0
- package/skills/fui-skill/references/default-function.md +415 -0
- package/skills/fui-skill/references/design-modes.md +85 -0
- package/skills/fui-skill/references/echart-templates.md +481 -0
- package/skills/fui-skill/references/fastproject.md +97 -0
- package/skills/fui-skill/references/fsheet.md +218 -0
- package/skills/fui-skill/references/fullstack-workflow.md +351 -0
- package/skills/fui-skill/references/module-data-patterns.md +126 -0
- package/skills/fui-skill/references/module-json-anatomy.md +137 -0
- package/skills/fui-skill/references/module-structure.md +260 -0
- package/skills/fui-skill/references/new-session.md +108 -0
- package/skills/fui-skill/references/pdfmake.md +60 -0
- package/skills/fui-skill/references/permission-system.md +169 -0
- package/skills/fui-skill/references/platform-architecture.md +294 -0
- package/skills/fui-skill/references/project-config.md +335 -0
- package/skills/fui-skill/references/project-provisioning.md +383 -0
- package/skills/fui-skill/references/script-map.md +296 -0
- package/skills/fui-skill/references/sql-clr-functions.md +224 -0
- package/skills/fui-skill/references/system-design.md +116 -0
- package/skills/fui-skill/references/tapi-file-api.md +191 -0
- package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
- package/skills/fui-skill/references/tapi-reference.md +549 -0
- package/skills/fui-skill/references/tools-registry.md +460 -0
- package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
- package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
- package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
- package/skills/fui-skill/references/ui-patterns.md +315 -0
- package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
- package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
- package/skills/fui-skill/references/ui-templates.md +29 -0
- package/skills/fui-skill/references/verification.md +246 -0
- package/skills/fui-skill/references/watcher-patterns.md +196 -0
- package/skills/fui-skill/references/websocket-realtime.md +254 -0
- package/skills/fui-skill/scripts/component-3.0.js +2549 -0
- package/skills/fui-skill/scripts/component.js +3142 -0
- package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
- package/skills/fui-skill/scripts/componentTable.js +769 -0
- package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
- package/skills/fui-skill/scripts/defaultfunction.js +966 -0
- package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
- package/skills/fui-skill/scripts/fastproject.js +828 -0
- package/skills/fui-skill/scripts/fechart.js +890 -0
- package/skills/fui-skill/scripts/fsheet.js +1330 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# tAPI — File API (GET / UPLOAD)
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **API file qua SP: `spAPIFILE_*`, `tblFileData`, alias `fileContent`, `@sys_FileContent`/`@sys_FileName`**.
|
|
4
|
+
|
|
5
|
+
SP GET và UPLOAD file qua tAPI: prefix `spAPIFILE_`, cột binary alias `fileContent`, params `@sys_FileContent`/`@sys_FileName`, bảng chuẩn `tblFileData`. Load file này khi module cần upload/download/xem file. **Không tự suy từ training data** — tAPI có quy ước riêng.
|
|
6
|
+
|
|
7
|
+
> Nền tảng SP (naming, params, response): xem [tapi-reference.md](tapi-reference.md).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## GET file
|
|
12
|
+
|
|
13
|
+
SP phải SELECT **tối thiểu 3 cột bắt buộc** (có thể thêm cột metadata tùy ý):
|
|
14
|
+
|
|
15
|
+
| Cột | Bắt buộc | Ý nghĩa |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `FileName` | ✅ | Tên file trả về — có thể là biểu thức, ví dụ `FileName + FileType` |
|
|
18
|
+
| `ContentType` | ✅ | MIME type (vd: `application/pdf`, `image/png`) |
|
|
19
|
+
| `fileContent` | ✅ | Binary content — alias từ cột kiểu **`image` hoặc `varbinary`**. tAPI nhận diện đây là nội dung file cần stream qua kiểu dữ liệu này |
|
|
20
|
+
| cột khác | ❌ | Metadata tùy chọn, ví dụ `Modified`, `FileSize` — phải là kiểu thông thường (không phải binary) |
|
|
21
|
+
|
|
22
|
+
```sql
|
|
23
|
+
-- Ví dụ thực tế: FileName ghép đuôi, thêm cột Modified, binary aliased từ FileContentBIN
|
|
24
|
+
CREATE PROCEDURE spAPIFILE_moduleImportFile
|
|
25
|
+
@fileID varchar(50)
|
|
26
|
+
AS BEGIN
|
|
27
|
+
SELECT
|
|
28
|
+
FileName = FileName + FileType,
|
|
29
|
+
ContentType,
|
|
30
|
+
Modified = ISNULL(UpdateTime, CreateTime),
|
|
31
|
+
fileContent = FileContentBIN
|
|
32
|
+
FROM tblA_ImportFile
|
|
33
|
+
WHERE fileID = LEFT(@fileID, 32)
|
|
34
|
+
END
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> `fileContent` phải alias từ cột kiểu `image` hoặc `varbinary(max)` — tAPI dùng kiểu dữ liệu này để nhận biết và stream nội dung file. Tên cột trong bảng tùy ý (`FileContentBIN`, `BinaryContent`, ...).
|
|
38
|
+
> `FileName` nên bao gồm cả phần đuôi file (`.pdf`, `.xlsx`...) để browser nhận đúng kiểu.
|
|
39
|
+
|
|
40
|
+
**Tham số URL — `@fileID` và `@filename`:**
|
|
41
|
+
|
|
42
|
+
| Param | Bắt buộc | Nguồn | Ý nghĩa |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `@fileID varchar(...)` | ✅ | Segment đầu tiên sau FunctionName | ID của file cần lấy |
|
|
45
|
+
| `@filename varchar(...)` | ❌ | Segment CUỐI cùng trong URL | Phần tên file hiển thị trong URL (browser/download manager dùng để đặt tên khi tải) |
|
|
46
|
+
|
|
47
|
+
Ngoài hai tham số trên, có thể khai báo thêm `@sys_*` auth params nếu cần kiểm tra quyền.
|
|
48
|
+
|
|
49
|
+
```sql
|
|
50
|
+
CREATE PROCEDURE spAPIFILE_Document
|
|
51
|
+
@fileID varchar(50), -- bắt buộc, inject từ URL
|
|
52
|
+
@filename varchar(200), -- tùy chọn — inject từ segment cuối URL; SP có thể dùng để
|
|
53
|
+
-- ghi log, kiểm tra, hoặc override FileName trả về
|
|
54
|
+
@sys_UserID varchar(9) -- tùy chọn, inject từ token
|
|
55
|
+
AS BEGIN
|
|
56
|
+
...
|
|
57
|
+
END
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**4 route pattern hỗ trợ:**
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
{domain}/{apiName}/{FunctionName}/{fileID}
|
|
64
|
+
{domain}/{apiName}/{FunctionName}/{fileID}/{filename}
|
|
65
|
+
{domain}/{apiName}/download/{FunctionName}/{fileID}/{filename}
|
|
66
|
+
{domain}/{apiName}/viewer/{FunctionName}/{fileID}/{filename}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`{FunctionName}` là phần tên sau prefix `spAPIFILE_`. Ví dụ SP `spAPIFILE_Document` → URL dùng `Document`.
|
|
70
|
+
|
|
71
|
+
Route `/viewer/` dùng để xem trực tiếp trong browser (inline), `/download/` để tải về.
|
|
72
|
+
|
|
73
|
+
> **Lưu ý `@filename`:** Segment này trong URL thường là tên file gốc (ví dụ `BaoCao_2024.pdf`) — browser và download manager dùng nó để đặt tên file khi tải về, không nhất thiết phải khớp với `FileName` trong bảng DB. SP không khai báo `@filename` thì tAPI vẫn nhận route có segment đó — param đơn thuần bị bỏ qua.
|
|
74
|
+
|
|
75
|
+
## Upload file
|
|
76
|
+
|
|
77
|
+
**Params đặc biệt do tAPI tự inject khi upload:**
|
|
78
|
+
|
|
79
|
+
| Param | Kiểu | Mô tả |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `@sys_FileContent` | varbinary(max) | Binary content của file |
|
|
82
|
+
| `@sys_FileName` | nvarchar(200) | Tên file gốc |
|
|
83
|
+
| `@sys_FileContentType` | varchar(100) | MIME type |
|
|
84
|
+
| `@sys_FileSize` | int | Kích thước file (bytes) |
|
|
85
|
+
| `@sys_UploadData` | nvarchar(max) | JSON data bổ sung truyền qua header |
|
|
86
|
+
|
|
87
|
+
Ngoài ra toàn bộ `@sys_` auth params cũng available: `@sys_UserID`, `@sys_UserName`, `@sys_SessionID`, `@sys_GroupID`, `@sys_DepartmentID`, `@sys_SystemRight`, `@sys_FunctionRight`.
|
|
88
|
+
|
|
89
|
+
```sql
|
|
90
|
+
CREATE PROCEDURE spAPIFILE_UPLOAD_Attachment
|
|
91
|
+
@url1_SessionID varchar(36),
|
|
92
|
+
@url2_Mode varchar(20),
|
|
93
|
+
@sys_UserID varchar(9),
|
|
94
|
+
@sys_FileContent varbinary(max),
|
|
95
|
+
@sys_FileName nvarchar(200),
|
|
96
|
+
@sys_FileContentType varchar(100),
|
|
97
|
+
@sys_FileSize int
|
|
98
|
+
AS BEGIN
|
|
99
|
+
INSERT INTO tblAttachFiles(FileName, Capacity, SessionID, CreateUser)
|
|
100
|
+
VALUES(@sys_FileName, @sys_FileSize, @url1_SessionID, @sys_UserID)
|
|
101
|
+
END
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Route: `POST {domain}/{apiName}/upload/{spName}/{url1}/{url2}...`
|
|
105
|
+
|
|
106
|
+
## Bảng lưu trữ file chuẩn — `tblFileData`
|
|
107
|
+
|
|
108
|
+
Đây là cấu trúc bảng chuẩn để dùng chung với cả `spAPIFILE_` (GET) và `spAPIFILE_UPLOAD_` (POST). Khi thiết kế module có file, tạo bảng này (hoặc bảng tương tự) trước khi viết SP.
|
|
109
|
+
|
|
110
|
+
```sql
|
|
111
|
+
CREATE TABLE [dbo].[tblFileData](
|
|
112
|
+
[FileID] [char](36) NOT NULL, -- UUID, DEFAULT newid()
|
|
113
|
+
[FileName] [nvarchar](200) NOT NULL,
|
|
114
|
+
[PhysicalName] [char](36) NOT NULL, -- UUID, DEFAULT newid()
|
|
115
|
+
[PhysicalSegment] [char](10) NOT NULL, -- subfolder theo ngày, DEFAULT getPhysicalSegment(getdate())
|
|
116
|
+
[CreateTime] [datetime] NOT NULL, -- DEFAULT getdate()
|
|
117
|
+
[WriteToDisk] [datetime] NULL, -- null = chưa ghi ra disk
|
|
118
|
+
[BinaryContent] [image] NULL, -- binary file content — alias là fileContent trong SP GET
|
|
119
|
+
[ContentType] [varchar](100) NULL, -- MIME type, DEFAULT ''
|
|
120
|
+
[Size] [int] NULL,
|
|
121
|
+
CONSTRAINT [PK_tblFileData] PRIMARY KEY CLUSTERED ([FileID] ASC)
|
|
122
|
+
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
|
123
|
+
GO
|
|
124
|
+
|
|
125
|
+
ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_FileID] DEFAULT (newid()) FOR [FileID]
|
|
126
|
+
ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_PhysicalName] DEFAULT (newid()) FOR [PhysicalName]
|
|
127
|
+
ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_PhysicalSegment] DEFAULT ([dbo].[getPhysicalSegment](getdate())) FOR [PhysicalSegment]
|
|
128
|
+
ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_CreateTime] DEFAULT (getdate()) FOR [CreateTime]
|
|
129
|
+
ALTER TABLE [dbo].[tblFileData] ADD CONSTRAINT [DF_tblFileData_ContentType] DEFAULT ('') FOR [ContentType]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
> **Lưu ý về DDL:** các câu `ALTER TABLE ... ADD CONSTRAINT` ở trên **chạy được qua tool** (ADD là thao tác cộng thêm). Riêng `CREATE TABLE` thì không — MCP chặn, phải do lập trình viên tự chạy. Đây là tài liệu tham chiếu cấu trúc.
|
|
133
|
+
|
|
134
|
+
**Giải thích từng field:**
|
|
135
|
+
|
|
136
|
+
| Field | Kiểu | Mô tả |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `FileID` | char(36) PK | UUID tự sinh bằng `newid()` — dùng làm key trong URL |
|
|
139
|
+
| `FileName` | nvarchar(200) | Tên file gốc khi upload |
|
|
140
|
+
| `PhysicalName` | char(36) | UUID tự sinh — tên file thực tế lưu trên disk (tránh trùng tên) |
|
|
141
|
+
| `PhysicalSegment` | char(10) | Subfolder phân tán theo ngày từ hàm `getPhysicalSegment(date)` |
|
|
142
|
+
| `CreateTime` | datetime | Thời điểm tạo record, DEFAULT getdate() |
|
|
143
|
+
| `WriteToDisk` | datetime NULL | Khi nào binary được ghi ra disk; `NULL` = chỉ lưu DB, chưa ra file system |
|
|
144
|
+
| `BinaryContent` | image NULL | Nội dung binary của file — SP GET phải alias là `fileContent` |
|
|
145
|
+
| `ContentType` | varchar(100) | MIME type, ví dụ `application/pdf`, `image/png` |
|
|
146
|
+
| `Size` | int NULL | Kích thước bytes |
|
|
147
|
+
|
|
148
|
+
**SP GET file — map tới bảng:**
|
|
149
|
+
|
|
150
|
+
```sql
|
|
151
|
+
CREATE PROCEDURE spAPIFILE_Document
|
|
152
|
+
@FileID char(36),
|
|
153
|
+
@sys_UserID varchar(9),
|
|
154
|
+
@sys_SystemRight int
|
|
155
|
+
AS BEGIN
|
|
156
|
+
IF @sys_SystemRight < 1
|
|
157
|
+
BEGIN RAISERROR(N'[Unauthorized]Bạn không có quyền.', 16, 1) RETURN END
|
|
158
|
+
|
|
159
|
+
-- BinaryContent phải alias là fileContent — tAPI đọc đúng tên này
|
|
160
|
+
SELECT FileName, ContentType, fileContent = BinaryContent
|
|
161
|
+
FROM tblFileData WHERE FileID = @FileID
|
|
162
|
+
END
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**SP UPLOAD — lưu vào bảng:**
|
|
166
|
+
|
|
167
|
+
```sql
|
|
168
|
+
CREATE PROCEDURE spAPIFILE_UPLOAD_Document
|
|
169
|
+
@url1_RefID varchar(50),
|
|
170
|
+
@sys_UserID varchar(9),
|
|
171
|
+
@sys_SystemRight int,
|
|
172
|
+
@sys_FileContent varbinary(max),
|
|
173
|
+
@sys_FileName nvarchar(200),
|
|
174
|
+
@sys_FileContentType varchar(100),
|
|
175
|
+
@sys_FileSize int
|
|
176
|
+
AS BEGIN
|
|
177
|
+
IF @sys_SystemRight < 2
|
|
178
|
+
BEGIN RAISERROR(N'[Unauthorized]Bạn không có quyền.', 16, 1) RETURN END
|
|
179
|
+
|
|
180
|
+
DECLARE @NewFileID char(36) = newid() -- sinh UUID trước, dùng để SELECT lại sau
|
|
181
|
+
|
|
182
|
+
INSERT INTO tblFileData(FileID, FileName, BinaryContent, ContentType, Size)
|
|
183
|
+
VALUES(@NewFileID, @sys_FileName, @sys_FileContent, @sys_FileContentType, @sys_FileSize)
|
|
184
|
+
|
|
185
|
+
-- Trả về record vừa insert để client cập nhật danh sách
|
|
186
|
+
SELECT FileID, FileName, Size, ContentType, CreateTime
|
|
187
|
+
FROM tblFileData WHERE FileID = @NewFileID
|
|
188
|
+
END
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
> **Lưu ý `BinaryContent [image]`**: Kiểu `image` là legacy của SQL Server nhưng vẫn hoạt động tốt với tAPI. Nếu muốn dùng kiểu mới hơn có thể dùng `varbinary(max)` — cả hai đều map được vào `fileContent` alias.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# tAPI — Kiểm tra quyền người dùng (Permission Check Patterns)
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **5 pattern kiểm tra quyền trong thân SP (`@sys_SystemRight`, `getSystemRight`, RAISERROR)**. Khái niệm quyền xem [permission-system.md](permission-system.md).
|
|
4
|
+
|
|
5
|
+
Các pattern kiểm tra quyền trong thân Stored Procedure tAPI. Load file này khi SP cần phân quyền.
|
|
6
|
+
|
|
7
|
+
> Nền tảng SP (naming, params, response, RAISERROR): xem [tapi-reference.md](tapi-reference.md).
|
|
8
|
+
> Khái niệm `SystemRight`/`FunctionRight`, cấu trúc `tblSysRight`/`tblFunction`, và 4 tool quản lý định nghĩa quyền: xem [permission-system.md](permission-system.md).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Tham số hệ thống liên quan đến quyền
|
|
13
|
+
|
|
14
|
+
tAPI tự inject các tham số sau — không cần client truyền lên:
|
|
15
|
+
|
|
16
|
+
| Tham số | Kiểu | Mô tả |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| `@sys_UserID` | varchar(9) | Mã người dùng đang đăng nhập |
|
|
19
|
+
| `@sys_SystemRight` | int | Mức quyền của user trên module hiện tại |
|
|
20
|
+
| `@sys_FunctionRight` | varchar(2000) | Quyền chức năng dạng `[AD][RPT][MGR]` |
|
|
21
|
+
|
|
22
|
+
**Khai báo trong SP** — luôn đặt cuối danh sách tham số, **không được gán default cho bất kỳ tham số nào, kể cả `@sys_*`** (xem [tapi-reference.md](tapi-reference.md) §2 — tAPI luôn truyền đủ mọi tham số, thiếu thì truyền `NULL`, nên `DEFAULT` không bao giờ được dùng tới; `db_sp_deploy` chặn cứng nếu có):
|
|
23
|
+
|
|
24
|
+
```sql
|
|
25
|
+
CREATE PROCEDURE spAPI_EntityAction
|
|
26
|
+
@BusinessParam1 int,
|
|
27
|
+
@BusinessParam2 nvarchar(100),
|
|
28
|
+
@sys_UserID varchar(9),
|
|
29
|
+
@sys_SystemRight int
|
|
30
|
+
AS
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Các mức `@sys_SystemRight`
|
|
34
|
+
|
|
35
|
+
Ý nghĩa từng mức **do mỗi project tự định nghĩa** (`tblSysRight.Note`, quản lý qua `right_system_list`/`right_system_update` — xem [permission-system.md](permission-system.md)). Bảng dưới là quy ước phổ biến dùng khi viết pattern kiểm tra trong SP — không phải giá trị cố định của platform, ngoại trừ `9` luôn là Project Admin:
|
|
36
|
+
|
|
37
|
+
| Giá trị | Ý nghĩa thực tế (quy ước phổ biến) |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `0` | Không có quyền / chưa được cấp quyền trên module |
|
|
40
|
+
| `1` | Quyền xem cơ bản |
|
|
41
|
+
| `2` | Quyền thao tác chuẩn (đọc, thêm, sửa thông thường) |
|
|
42
|
+
| `3` | Quyền nâng cao (quản lý nội bộ, thao tác nhạy cảm) |
|
|
43
|
+
| `9` | Module Admin / Project Admin (cố định trên toàn platform) |
|
|
44
|
+
|
|
45
|
+
## Helper function kiểm tra quyền theo module cụ thể
|
|
46
|
+
|
|
47
|
+
```sql
|
|
48
|
+
dbo.getSystemRight(@ModuleID, @sys_UserID)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Trả về mức `SysRight` mà user được assign cho một module xác định — dùng khi cần kiểm tra quyền trên module **khác** với module hiện tại.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Pattern 1 — Chặn truy cập cơ bản (READ operations)
|
|
56
|
+
|
|
57
|
+
Dùng cho mọi SP đọc dữ liệu cần đăng nhập. Yêu cầu ít nhất `SysRight = 2`.
|
|
58
|
+
|
|
59
|
+
```sql
|
|
60
|
+
If @sys_SystemRight < 2
|
|
61
|
+
Begin
|
|
62
|
+
Raiserror(N'[Unauthorized]Bạn không có quyền trên chức năng này.', 16, 1)
|
|
63
|
+
Return
|
|
64
|
+
End
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Pattern 2 — Chặn user hoàn toàn không có quyền (minimal check)
|
|
68
|
+
|
|
69
|
+
Dùng khi muốn cho phép cả `SysRight = 1` thao tác, chỉ chặn `SysRight = 0`.
|
|
70
|
+
|
|
71
|
+
```sql
|
|
72
|
+
If @sys_SystemRight = 0
|
|
73
|
+
Begin
|
|
74
|
+
Raiserror(N'[Unauthorized]Bạn không có quyền trên chức năng này.', 16, 1)
|
|
75
|
+
Return
|
|
76
|
+
End
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Pattern 3 — Kiểm tra 2 tầng: global + module admin (WRITE operations)
|
|
80
|
+
|
|
81
|
+
Dùng cho các thao tác ghi có tác động đến cấu hình module hoặc dữ liệu người dùng khác. User phải đạt **một trong hai điều kiện**:
|
|
82
|
+
- `@sys_SystemRight >= 3` (quyền cao toàn hệ thống), **hoặc**
|
|
83
|
+
- Là Module Admin (`getSystemRight >= 9`) của module đó.
|
|
84
|
+
|
|
85
|
+
```sql
|
|
86
|
+
-- Tầng 1: phải có quyền cơ bản
|
|
87
|
+
If @sys_SystemRight < 2
|
|
88
|
+
Begin
|
|
89
|
+
Raiserror(N'[Unauthorized]Bạn không có quyền trên chức năng này.', 16, 1)
|
|
90
|
+
Return
|
|
91
|
+
End
|
|
92
|
+
|
|
93
|
+
-- Tầng 2: phải là admin hệ thống hoặc admin của module đó
|
|
94
|
+
If @sys_SystemRight < 3 and dbo.getSystemRight(@ModuleID, @sys_UserID) < 9
|
|
95
|
+
Begin
|
|
96
|
+
Raiserror(N'[Unauthorized]Bạn không có quyền trên Module này.', 16, 1)
|
|
97
|
+
Return
|
|
98
|
+
End
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Pattern 4 — Kiểm tra logic nghiệp vụ trước khi thực thi
|
|
102
|
+
|
|
103
|
+
Dùng khi thao tác hợp lệ về quyền nhưng vi phạm ràng buộc dữ liệu (ví dụ: xóa cha khi còn con).
|
|
104
|
+
|
|
105
|
+
```sql
|
|
106
|
+
-- Kiểm tra ràng buộc trước khi xóa
|
|
107
|
+
If exists(Select * from tblChild WHERE ParentID = @ParentID)
|
|
108
|
+
Begin
|
|
109
|
+
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)
|
|
110
|
+
Return
|
|
111
|
+
End
|
|
112
|
+
|
|
113
|
+
DELETE tblParent WHERE ParentID = @ParentID
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Pattern 5 — Kiểm tra `@sys_FunctionRight`
|
|
117
|
+
|
|
118
|
+
Dùng khi phân quyền theo chức năng cụ thể (không chỉ theo mức số).
|
|
119
|
+
|
|
120
|
+
```sql
|
|
121
|
+
If CHARINDEX('[ADMIN]', @sys_FunctionRight) = 0
|
|
122
|
+
Begin
|
|
123
|
+
Raiserror(N'[Unauthorized]Bạn không có quyền thực hiện chức năng này.', 16, 1)
|
|
124
|
+
Return
|
|
125
|
+
End
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Quy tắc đặt thứ tự kiểm tra
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
1. Kiểm tra quyền hệ thống (@sys_SystemRight) ← luôn đầu tiên
|
|
134
|
+
2. Kiểm tra quyền module (getSystemRight) ← nếu cần 2 tầng
|
|
135
|
+
3. Kiểm tra quyền chức năng (@sys_FunctionRight) ← nếu dùng FunctionRight
|
|
136
|
+
4. Kiểm tra ràng buộc nghiệp vụ ← sau cùng, trước khi ghi
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Quy ước thông báo lỗi
|
|
140
|
+
|
|
141
|
+
| Tình huống | Message chuẩn |
|
|
142
|
+
|---|---|
|
|
143
|
+
| Thiếu quyền global | `N'[Unauthorized]Bạn không có quyền trên chức năng này.'` |
|
|
144
|
+
| Thiếu quyền module | `N'[Unauthorized]Bạn không có quyền trên Module này.'` |
|
|
145
|
+
| Thiếu quyền chức năng (`FunctionRight`) | `N'[Unauthorized]Bạn không có quyền thực hiện chức năng này.'` |
|
|
146
|
+
| Vi phạm ràng buộc | Mô tả cụ thể, **không** có prefix: `N'Phải xóa X trước khi xóa Y.'` |
|
|
147
|
+
| Dữ liệu không hợp lệ | `N'Dữ liệu không hợp lệ.'` hoặc mô tả cụ thể, **không** có prefix |
|
|
148
|
+
|
|
149
|
+
**Format `RAISERROR` bắt buộc:**
|
|
150
|
+
```sql
|
|
151
|
+
RAISERROR(N'Thông báo lỗi tiếng Việt.', 16, 1)
|
|
152
|
+
RETURN
|
|
153
|
+
```
|
|
154
|
+
- **Severity luôn là `16`** — áp dụng cho mọi loại lỗi (validation, unauthorized, business logic)
|
|
155
|
+
- Prefix `N` bắt buộc cho Unicode tiếng Việt
|
|
156
|
+
- `RETURN` bắt buộc ngay sau `RAISERROR` — thiếu `RETURN` SP tiếp tục chạy dù đã báo lỗi
|
|
157
|
+
- Client nhận `{ "Message": "..." }` với nội dung thông báo
|
|
158
|
+
- **Mọi lỗi thiếu quyền ở 5 pattern trên phải mở message bằng `[Unauthorized]`** (vd `N'[Unauthorized]Bạn không có quyền...'`) — tAPI dựa vào tiền tố này để trả HTTP status `401` thay vì mặc định, và tự cắt `[Unauthorized]` khỏi `Message` trước khi trả về client. Lỗi ràng buộc/nghiệp vụ (Pattern 4) **không** dùng prefix này — chi tiết cơ chế + cách client xử lý status 401 xem [tapi-reference.md](tapi-reference.md) §5.
|