@fui-org/fui-cli 2.2.2 → 2.2.4
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 -0
- package/dist/fui-gt54fgs7.js +402 -0
- package/dist/fui.js +1 -1
- package/package.json +1 -1
- package/skills/fui/SKILL.md +18 -3
- package/skills/fui/references/INDEX.md +8 -6
- package/skills/fui/references/cdn-files.md +30 -0
- package/skills/fui/references/coding-standards.md +2 -2
- package/skills/fui/references/component-design.md +2 -2
- package/skills/fui/references/controls-styling-vocabulary.md +3 -3
- package/skills/fui/references/db-workflow.md +3 -3
- package/skills/fui/references/design-modes.md +1 -1
- package/skills/fui/references/module-structure.md +44 -16
- package/skills/fui/references/permission-system.md +15 -9
- package/skills/fui/references/project-config.md +1 -1
- package/skills/fui/references/project-provisioning.md +129 -218
- package/skills/fui/references/tapi-reference.md +27 -12
- package/skills/fui/references/tools-registry.md +13 -7
- package/skills/fui/references/ui-screenshot-review.md +1 -1
- package/skills/fui/references/verification.md +2 -1
- package/dist/fui-gexr4km5.js +0 -397
|
@@ -1,278 +1,189 @@
|
|
|
1
|
-
# Provisioning
|
|
1
|
+
# Provisioning: new database, new FUI project, or both
|
|
2
2
|
|
|
3
|
-
> Owns: **
|
|
3
|
+
> Owns: **creating the infrastructure of a new system** — SQL Server database, its two SQL accounts, the SEC (acc) alias and its manager, the FUI project and its IDE rights. Connection/schema/SP: [db-workflow.md](db-workflow.md); multi-module design: [system-design.md](system-design.md); table naming: [db-table-design.md](db-table-design.md); end-user rights: [permission-system.md](permission-system.md). Flags: `fui <command> --help`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This file wins over any memory or note written earlier about provisioning. Every step below is a `fui` command; **never** call a `spAPI_*` of `acc`/`fp` through `fui query`/`fui exec`/HTTP, never pass `@sys_*` parameters (tAPI injects them from your token; `fui` blocks them), never `INSERT` into `tblModules`/`tblUserModule`/`tblA_UserProject`. A step with no command ⇒ **stop and tell the user** to do it in the SEC/FUI UI.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## The three requests — separate scopes
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
|
14
|
-
| ------------------------ | --------------------------------- | -------------------------- |
|
|
15
|
-
| **A. FUI platform** | `SystemRight >= 3` on system `fp` | `fui project new` (Step 1) |
|
|
16
|
-
| **B. Target SQL Server** | create database + create login | read-only `SELECT` below |
|
|
17
|
-
|
|
18
|
-
**Check B BEFORE A.** B has no side effects; A only answers by actually creating the project. Reverse order ⇒ orphan FUI project if the DB can't be created. Late discovery leaves garbage fui can't clean up.
|
|
19
|
-
|
|
20
|
-
### Gate B — target SQL Server
|
|
21
|
-
|
|
22
|
-
`CREATE DATABASE`/`CREATE LOGIN` are server-level; a normal dev account (`db_owner` on some DBs) can't. Run with `fui query` on a connection **to the exact target server** (`fui db alias list` shows alias → server):
|
|
23
|
-
|
|
24
|
-
```sql
|
|
25
|
-
SELECT SUSER_NAME() AS LoginHienTai,
|
|
26
|
-
IS_SRVROLEMEMBER('sysadmin') AS sysadmin,
|
|
27
|
-
IS_SRVROLEMEMBER('dbcreator') AS dbcreator,
|
|
28
|
-
IS_SRVROLEMEMBER('securityadmin') AS securityadmin,
|
|
29
|
-
HAS_PERMS_BY_NAME(NULL, NULL, 'CREATE ANY DATABASE') AS taoDuocDB,
|
|
30
|
-
HAS_PERMS_BY_NAME(NULL, NULL, 'ALTER ANY LOGIN') AS taoDuocLogin;
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Pass: `sysadmin = 1`, **or** `taoDuocDB = 1` **and** `taoDuocLogin = 1`.
|
|
34
|
-
|
|
35
|
-
- `sa` not required — `dbcreator` + `securityadmin` also pass. Don't block a valid setup with "needs `sa`".
|
|
36
|
-
- Need BOTH: `dbcreator` alone creates the DB but not the Step 3 login ⇒ fails midway.
|
|
37
|
-
- `IS_SRVROLEMEMBER` returns `NULL` (not `0`) for a bad role name/invalid login ⇒ **unknown**, ask the user.
|
|
38
|
-
- A connection borrowed from a sibling project may point at another server ⇒ green for the wrong server.
|
|
39
|
-
- ⚠️ `HAS_PERMS_BY_NAME` answers only for the _connected principal_ — correct here. Never use it for another principal (e.g. `[public]` `EXECUTE`): always green for `db_owner`. Read `sys.database_permissions` instead.
|
|
40
|
-
|
|
41
|
-
Fails ⇒ **stop; user must request rights on that server**. Never run `CREATE DATABASE` to probe; never grant `db_datareader` to the app account to avoid creating a login.
|
|
42
|
-
|
|
43
|
-
### Gate A — FUI platform
|
|
44
|
-
|
|
45
|
-
Creating a project needs **`SystemRight >= 3`** on `fp`, enforced server-side in `spAPI_FUI_Dev_ProjectEdit` (direct API calls can't bypass):
|
|
46
|
-
|
|
47
|
-
```sql
|
|
48
|
-
if @jID is null -- không có id ⇒ đang TẠO MỚI
|
|
49
|
-
Begin
|
|
50
|
-
if @sys_SystemRight < 3
|
|
51
|
-
RAISERROR(N'Bạn không có quyền tạo dự án', 16, 1)
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**No right ⇒ STOP, report, do nothing else.** Project goes before the DB because `INSERT INTO tblA_Project` needs only `ProjectID`/`ProjectName`/`GroupName`/`Framework`/`pDomain`/`Router` — no database. DB-first then rejection leaves a real DB, two SQL logins and an orphan `acc` record; never run `DROP DATABASE` (fui has no guard for it), so cleanup is the user's manual job. `fui project new` _is_ the gate A check (no extra call); rejected ⇒ nothing created (if B was checked first).
|
|
55
|
-
|
|
56
|
-
| Operation | SP | Condition |
|
|
57
|
-
| ----------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------ |
|
|
58
|
-
| **Create** project (`fui project new`) | `spAPI_FUI_Dev_ProjectEdit` (empty `id`) | `SystemRight >= 3` |
|
|
59
|
-
| **Edit** project (`fui project update`) | `spAPI_FUI_Dev_ProjectEdit` (with `id`) | `SystemRight >= 2` **and** `UserRight > 2` |
|
|
60
|
-
| Publish `project.json` (`fui project publish-config`) | `spAPI_FUI_Dev_EditorUpdate` (`Mode = 'project'`) | `SystemRight >= 2` **and** `UserRight > 2` |
|
|
61
|
-
| Create/edit/publish **module** | `spAPI_FUI_Dev_ModuleEdit` · `spAPI_FUI_Dev_EditorUpdate` | `SystemRight >= 2` **and** `UserRight > 1` |
|
|
9
|
+
| The user asks for | Do | Do NOT |
|
|
10
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
|
|
11
|
+
| **a database** | database + app login (execute-only) + dev login as `db_owner` + alias on the SEC + the alias's **manager** on the SEC | FUI project, FUI rights |
|
|
12
|
+
| **a project** | FUI project + IDE rights (`fui user`) + basic `project.json` when the apiDomain/alias is known | database, SQL logins, SEC |
|
|
13
|
+
| **both** | both blocks; `project.json` `apiDomain` points at the new alias | — |
|
|
62
14
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
> ⚠️ `pDomain` is checked **before** the permission gate (`CheckDomain`): a duplicate domain gives a domain error, not a permission error. Don't go request rights over it.
|
|
15
|
+
Unclear which ⇒ ask. Never widen the scope ("a database" does not bring a project, and the reverse).
|
|
66
16
|
|
|
67
17
|
---
|
|
68
18
|
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
This file owns **phase 1 only**.
|
|
19
|
+
## Phase A — the result frame (no side effects)
|
|
72
20
|
|
|
73
|
-
|
|
74
|
-
| ----- | ------------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
75
|
-
| 0 | Clarify scope | [system-design.md](system-design.md) §Step 0 | Users, process, main entities |
|
|
76
|
-
| **1** | **Infrastructure ← HERE** | **this file** | 2 gates → `fui project new` → DB + 2 SQL accounts + `acc` alias → admin rights |
|
|
77
|
-
| 2 | Split into modules | [system-design.md](system-design.md) §Step 1 | Module list, access roles |
|
|
78
|
-
| 3 | Schema | [db-table-design.md](db-table-design.md) | Naming, PK/FK, audit columns. `CREATE TABLE` **run by the developer** |
|
|
79
|
-
| 4 | **End-user** rights | [permission-system.md](permission-system.md) + [system-design.md](system-design.md) §Step 4b | `fui right system new` / `fui right function new` — BEFORE any module gates on them |
|
|
80
|
-
| 5 | Runtime config | [project-config.md](project-config.md) | `project.json`: menu, menuLeft, navigation, domainSetting |
|
|
81
|
-
| 6 | First module | `fui module new` → [fullstack-workflow.md](fullstack-workflow.md) | 6-step UI-first flow |
|
|
21
|
+
Before creating anything, build a **result frame**: a table of the end state that will exist when the work is done, with only the blocks of the request. Unknown value ⇒ ask; a value you propose is marked **(proposed)**; never fill a value from memory or from another project.
|
|
82
22
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
---
|
|
23
|
+
**Database block**
|
|
86
24
|
|
|
87
|
-
|
|
25
|
+
| Field | Example |
|
|
26
|
+
| --------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
27
|
+
| System (zone) → SEC | LHBS → SEC `tapi.lhbs.vn` |
|
|
28
|
+
| SQL Server (IP) | `192.168.100.22` |
|
|
29
|
+
| Database, file folder | `ISO`, `D:\Database\` — folder of the **most recently created** user database (query below) |
|
|
30
|
+
| App login | `ISO` (= database name), only `GRANT EXECUTE ON SCHEMA::dbo` |
|
|
31
|
+
| Dev login → `db_owner` | `iotdev` (existing login on that server) |
|
|
32
|
+
| SEC alias | apiName `iso` (≤ 20 chars), module name "Quản lý ISO" (≤ 50 chars) |
|
|
33
|
+
| SystemRight created on the new module | `9 = Project Admin` (required: the manager holds level 9) |
|
|
34
|
+
| Alias manager on the SEC | SEC UserID + name from `fui right user search`, level **9** by default |
|
|
88
35
|
|
|
89
|
-
|
|
90
|
-
| --------- | ------------------------------------------------------------------ | --------------------------------------- |
|
|
91
|
-
| Scope | **System-wide** — one number per user per app | **Per project** |
|
|
92
|
-
| Answers | "What can this user do in app X?" | "What can this user do with project Y?" |
|
|
93
|
-
| Stored in | `acc.tblSysRight` + `acc` assignment tables | `tblA_UserProject` (FUI platform DB) |
|
|
94
|
-
| Commands | `fui right ...` (8) → [permission-system.md](permission-system.md) | `fui user ...` (5) → Step 6 |
|
|
36
|
+
**The database frame needs a working login to that server first.** Find or add a `fui` connection that reaches it and prove it is the right machine:
|
|
95
37
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
- `SystemRight` on `fp` = **may create projects** (≥ 3); necessary for every edit.
|
|
99
|
-
- `UserRight` on project Y = **may touch Y**; sufficient.
|
|
100
|
-
- ANDed: `UserRight = 3` with `SystemRight = 1` can't edit anything.
|
|
101
|
-
|
|
102
|
-
`SystemRight`/`FunctionRight` on **your business project** (not `fp`) are end-user rights — later, per [system-design.md](system-design.md) Step 4b.
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## Step 1 — Create the FUI project (gate A, before the DB)
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
fui project new --data '{
|
|
110
|
-
"ProjectID": "...", "ProjectName": "...", "GroupName": "...", "Framework": "V3",
|
|
111
|
-
"pDomain": "...",
|
|
112
|
-
"Router": ""
|
|
113
|
-
}'
|
|
38
|
+
```sql
|
|
39
|
+
SELECT @@SERVERNAME AS ServerName, CONNECTIONPROPERTY('local_net_address') AS LocalIP;
|
|
114
40
|
```
|
|
115
41
|
|
|
116
|
-
`
|
|
117
|
-
|
|
118
|
-
- **Only these SIX fields are read** from `@jsonObj`.
|
|
119
|
-
- 🔴 **`title`/`login`/`apiDomain`/`fileDomain`/`userInfo`/`menu` are silently IGNORED.** The SP writes `projectData` from a hardcoded constant:
|
|
120
|
-
```sql
|
|
121
|
-
declare @jProjectdata nvarchar(1000) = '{"title":"","apiDomain":"","login":"","menu":[]}'
|
|
122
|
-
```
|
|
123
|
-
API still returns ✅, project created, config lost — silent failure.
|
|
124
|
-
- Runtime config: edit `{projectId}/project.json` then `fui project publish-config` ([project-config.md](project-config.md)) — the **only** way `menu`/`apiDomain`/`login` get in.
|
|
125
|
-
- `projectData` must be **FLAT** — not wrapped in `"data"`.
|
|
126
|
-
- **`Framework`: `V3` for new projects** unless the user has a reason (usually matching older projects in the group). Expensive to change: decides import layer, component vocabulary, grid syntax — V2 = Vuetify 1.5 (`v-container/v-layout/v-flex`), V3 = Vuetify 3 (`v-container/v-row/v-col`), and `w` px thresholds differ. Most skill module.json examples are **V2**; for V3 cross-check [controls-patterns.md](controls-patterns.md) §6 (V2/V3 diff owner). State the choice to the user; never implicit.
|
|
127
|
-
|
|
128
|
-
**Only the caller gets `UserRight = 3` on the new project** (SP `INSERT INTO tblA_UserProject ... 3`) — hence Step 6.
|
|
129
|
-
|
|
130
|
-
Rejected with `Bạn không có quyền tạo dự án` ⇒ **stop; user must request `SystemRight >= 3` on `fp`**. Nothing created yet — keep it so.
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## Step 2 — Create the database
|
|
135
|
-
|
|
136
|
-
> Prerequisite: gate B green. Never run `CREATE DATABASE` to probe.
|
|
42
|
+
The IP must match the frame. No connection reaches it ⇒ **do not build the frame**: tell the user which server you cannot log in to and ask for a connection (`fui db add … --token-env VAR` / `--conn-env VAR`, values set by the user outside the chat). Never guess the server, never try passwords, never ask for a secret in chat.
|
|
137
43
|
|
|
138
|
-
|
|
44
|
+
Folder of the latest user database on that server (proposal for the new one):
|
|
139
45
|
|
|
140
46
|
```sql
|
|
141
|
-
SELECT
|
|
142
|
-
|
|
47
|
+
SELECT TOP 1 d.name, d.create_date,
|
|
48
|
+
LEFT(f.physical_name, LEN(f.physical_name) - CHARINDEX('\', REVERSE(f.physical_name))) AS Folder
|
|
49
|
+
FROM sys.databases d JOIN sys.master_files f ON f.database_id = d.database_id AND f.type = 0
|
|
50
|
+
WHERE d.database_id > 4
|
|
51
|
+
ORDER BY d.create_date DESC;
|
|
143
52
|
```
|
|
144
53
|
|
|
145
|
-
|
|
54
|
+
**Project block**
|
|
146
55
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
56
|
+
| Field | Example |
|
|
57
|
+
| ---------------------------------- | --------------------------------------------------------------------- |
|
|
58
|
+
| ProjectID, ProjectName, GroupName | `lhbs-iso`, "Quản lý Hệ thống ISO", `LHBS` |
|
|
59
|
+
| Framework, Router | `V3` (proposed), `""` |
|
|
60
|
+
| pDomain | `iso.lhbs.vn` (list allowed) |
|
|
61
|
+
| `project.json` apiDomain / alias | `tapi.lhbs.vn` / `iso` (when known) |
|
|
62
|
+
| IDE rights | FUI UserID + name from `fui user search`, level 1/2/3 |
|
|
152
63
|
|
|
153
|
-
|
|
64
|
+
Show the frame and let the user **adjust** it; after every change show the whole frame again. **No write runs before the user says the frame is right.** The approved frame is the to-do list; at the end, compare the real state with it line by line.
|
|
154
65
|
|
|
155
66
|
---
|
|
156
67
|
|
|
157
|
-
##
|
|
158
|
-
|
|
159
|
-
Login **named after the DB**, strong random password:
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
openssl rand -base64 12
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
```sql
|
|
166
|
-
CREATE LOGIN [TenDB] WITH PASSWORD = N'<mật khẩu vừa sinh>',
|
|
167
|
-
DEFAULT_DATABASE = [TenDB], CHECK_POLICY = ON;
|
|
168
|
-
USE [TenDB];
|
|
169
|
-
CREATE USER [TenDB] FOR LOGIN [TenDB];
|
|
170
|
-
GRANT EXECUTE ON SCHEMA::dbo TO [TenDB];
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
**Only `public` + `GRANT EXECUTE ON SCHEMA::dbo`. NO `db_datareader`, NO `db_datawriter`, NO table grants.** tAPI only runs SPs; new SPs fall under `SCHEMA::dbo` automatically. Table rights don't help the app — they only open direct table access to an abused call.
|
|
68
|
+
## Phase B — read-only checks (report before writing)
|
|
174
69
|
|
|
175
|
-
|
|
70
|
+
Database block:
|
|
176
71
|
|
|
177
|
-
|
|
72
|
+
1. Gate B — rights on the target server (through the connection proved above):
|
|
178
73
|
|
|
179
|
-
|
|
74
|
+
```sql
|
|
75
|
+
SELECT SUSER_NAME() AS LoginHienTai, IS_SRVROLEMEMBER('sysadmin') AS sysadmin,
|
|
76
|
+
HAS_PERMS_BY_NAME(NULL, NULL, 'CREATE ANY DATABASE') AS taoDuocDB,
|
|
77
|
+
HAS_PERMS_BY_NAME(NULL, NULL, 'ALTER ANY LOGIN') AS taoDuocLogin;
|
|
78
|
+
```
|
|
180
79
|
|
|
181
|
-
|
|
80
|
+
Pass: `sysadmin = 1`, or both others `= 1` (`dbcreator` alone fails midway at the login). `NULL` ⇒ unknown, ask.
|
|
81
|
+
2. The database name is free (`SELECT DB_ID(N'ISO')` is `NULL`); the dev login exists (`SELECT name FROM sys.server_principals WHERE name = N'iotdev'`).
|
|
82
|
+
3. The alias is free on **that** SEC: `fui db alias list --db <project/acc connection of that SEC> --search iso`. A project with connections on several tAPI hosts makes every SEC command ask for `--db`; that is the guard against writing to the wrong SEC.
|
|
83
|
+
4. The project that holds the SEC connection also has a connection to that SEC's own database (apiName starting with `acc`, same apiDomain): `db alias new` takes `MAX(ModuleID)+1` from it and refuses one on another host.
|
|
182
84
|
|
|
183
|
-
|
|
184
|
-
USE [TenDB];
|
|
185
|
-
CREATE USER [xTuan] FOR LOGIN [xTuan];
|
|
186
|
-
ALTER ROLE db_owner ADD MEMBER [xTuan];
|
|
187
|
-
```
|
|
85
|
+
Project block: `fui project list --filter <ProjectID>` and `--filter <domain>` find nothing.
|
|
188
86
|
|
|
189
|
-
|
|
87
|
+
Any check fails ⇒ stop, report, write nothing.
|
|
190
88
|
|
|
191
89
|
---
|
|
192
90
|
|
|
193
|
-
##
|
|
91
|
+
## Phase C — run, in order, stop at the first failure
|
|
194
92
|
|
|
195
|
-
|
|
196
|
-
fui db alias new tenalias \
|
|
197
|
-
--module-name "Tên hệ thống" \
|
|
198
|
-
--sql-server "..." \
|
|
199
|
-
--database TenDB \
|
|
200
|
-
--username TenDB \
|
|
201
|
-
--password-env TENDB_PASSWORD
|
|
202
|
-
```
|
|
93
|
+
Run only the approved blocks. Both blocks: **project first** — `fui project new` is the only way to learn whether you may create projects (Gate A, `SystemRight >= 3` on `fp`), and a refusal then leaves no orphan database.
|
|
203
94
|
|
|
204
|
-
|
|
95
|
+
### Project block
|
|
205
96
|
|
|
206
|
-
|
|
97
|
+
1. **Create**
|
|
207
98
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
99
|
+
```
|
|
100
|
+
fui project new --data '{"ProjectID":"lhbs-iso","ProjectName":"Quản lý Hệ thống ISO","GroupName":"LHBS","Framework":"V3","pDomain":["iso.lhbs.vn"],"Router":""}'
|
|
101
|
+
```
|
|
211
102
|
|
|
212
|
-
|
|
103
|
+
- Only these six fields exist; `fui` refuses any other (`title`, `login`, `apiDomain`, `menu` … belong in `project.json`, step 3).
|
|
104
|
+
- `pDomain` is stored as a JSON-array string; give an array or a string, `fui` normalizes it.
|
|
105
|
+
- Refused with `Bạn không có quyền tạo dự án` ⇒ stop; the user must request `SystemRight >= 3` on `fp`.
|
|
106
|
+
- `pDomain` is checked before the right (`CheckDomain`): a duplicate domain is a domain error, not a permission error.
|
|
107
|
+
- Only the caller gets `UserRight = 3` on the new project.
|
|
108
|
+
2. **IDE rights**: `fui user search "<name>"` → show the table, the user picks → `fui user add <UserID> --right 3`. `fui user list` to check.
|
|
109
|
+
3. **Runtime config**: `fui project sync -p <ProjectID>`, edit `<ProjectID>/project.json` (`apiDomain`, `title`, `login`, `menu`), `fui project publish-config` — [project-config.md](project-config.md). Skipped ⇒ the project can call no API.
|
|
213
110
|
|
|
214
|
-
|
|
111
|
+
### Database block
|
|
215
112
|
|
|
216
|
-
|
|
113
|
+
All SQL through `fui exec … --db <proved connection> --confirm-write` (server-level DDL and `GRANT` need the flag; each was approved through the frame).
|
|
217
114
|
|
|
218
|
-
|
|
115
|
+
4. **Database**, in the folder from the frame:
|
|
219
116
|
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
```
|
|
117
|
+
```sql
|
|
118
|
+
CREATE DATABASE [ISO]
|
|
119
|
+
ON PRIMARY (NAME = N'ISO', FILENAME = N'D:\Database\ISO.mdf')
|
|
120
|
+
LOG ON (NAME = N'ISO_log', FILENAME = N'D:\Database\ISO_log.ldf');
|
|
121
|
+
```
|
|
225
122
|
|
|
226
|
-
|
|
123
|
+
5. **App login** (execute-only), named after the database, random password nobody has to read. Shell state does not survive between commands, so keep it in a file in your scratch directory (outside the workspace), load it into a variable inside each command that needs it, never print it, and delete the file after step 7:
|
|
227
124
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
| 3 | **Admin** — needed to manage the project (`fui project publish-config` requires `> 2`) |
|
|
125
|
+
```bash
|
|
126
|
+
openssl rand -base64 18 | tr -d '\n' > "$SCRATCH/iso_app_pwd"
|
|
127
|
+
ISO_APP_PWD="$(cat "$SCRATCH/iso_app_pwd")" && fui exec "CREATE LOGIN [ISO] WITH PASSWORD = N'$ISO_APP_PWD', DEFAULT_DATABASE = [ISO], CHECK_POLICY = ON; USE [ISO]; CREATE USER [ISO] FOR LOGIN [ISO]; GRANT EXECUTE ON SCHEMA::dbo TO [ISO];" --db <proved connection> --confirm-write
|
|
128
|
+
```
|
|
233
129
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
- **Rights are ALWAYS project-level.** The SP has `@MID` and IDE module `fp/permission` passes it, but the body never reads it — all filtering is by `ProjectID`. Don't infer a module scope.
|
|
130
|
+
Only `public` + `GRANT EXECUTE ON SCHEMA::dbo`: **no** `db_datareader`/`db_datawriter`/table grants. tAPI only runs SPs.
|
|
131
|
+
6. **Dev login**: reuse the existing shared login of the frame, no new login unless asked:
|
|
237
132
|
|
|
238
|
-
|
|
133
|
+
```sql
|
|
134
|
+
USE [ISO];
|
|
135
|
+
CREATE USER [iotdev] FOR LOGIN [iotdev];
|
|
136
|
+
ALTER ROLE db_owner ADD MEMBER [iotdev];
|
|
137
|
+
```
|
|
239
138
|
|
|
240
|
-
|
|
139
|
+
7. **SEC alias** with the **app** login (never the dev login: every API call would run as `db_owner`, silently):
|
|
241
140
|
|
|
242
|
-
|
|
141
|
+
```bash
|
|
142
|
+
ISO_APP_PWD="$(cat "$SCRATCH/iso_app_pwd")" fui db alias new iso --db <project>/<acc connection of that SEC> \
|
|
143
|
+
--module-name "Quản lý ISO" --sql-server 192.168.100.22 --database ISO \
|
|
144
|
+
--username ISO --password-env ISO_APP_PWD
|
|
145
|
+
```
|
|
243
146
|
|
|
244
|
-
|
|
147
|
+
Without `--confirm-write` it sends nothing and prints the plan (SEC, ModuleID and where it came from, apiName, server, database, login). Check it against the frame, then rerun with `--confirm-write`. It calls `SM_Modules_Update` twice (record, then connection), refuses an existing alias or a taken `--module-id`, and post-checks.
|
|
148
|
+
8. **Level 9 on the new module**: `fui right system new 9 --api-name iso --db <same connection>` (the server names it "Project Admin").
|
|
149
|
+
9. **Alias manager**: `fui right user search <UserID or username prefix> --db <same connection>` → the user picks → `fui right user add <UserID> --sys-right 9 --api-name iso --db <same connection>`. A manager on SEC is exactly a user with level 9 on that module (`SM_Modules_ManagerSelect`).
|
|
150
|
+
10. **Proof**: `fui db add-by-name iso -p <project> --db …` connects; as the app login, `SELECT TOP 1 * FROM <any table>` is **denied** while `EXEC` of an SP works.
|
|
245
151
|
|
|
246
|
-
|
|
247
|
-
2. **Runtime config (mandatory)**: edit `{projectId}/project.json` (`apiDomain` → new alias, `title`, `login`, `menu`), then `fui project publish-config` — [project-config.md](project-config.md). Skipped ⇒ the project can't call any API.
|
|
248
|
-
3. `fui db add-by-name <apiName>` ([db-workflow.md](db-workflow.md) §2c) — also **proves** Steps 3 and 5 (app account + `acc` record OK).
|
|
249
|
-
4. Resume [system-design.md](system-design.md) at **Step 1**, following the index.
|
|
152
|
+
### End
|
|
250
153
|
|
|
251
|
-
|
|
154
|
+
Compare every line of the frame with the real state (`fui project list`, `fui user list`, `fui db alias list --search`, `fui right user list`) and report any line that is not met. The project is still empty: no tables, modules or right codes. Next phase: [system-design.md](system-design.md) Step 1 (one simple module ⇒ `fui module new` → [fullstack-workflow.md](fullstack-workflow.md)).
|
|
252
155
|
|
|
253
156
|
---
|
|
254
157
|
|
|
255
|
-
##
|
|
158
|
+
## Two permission planes — don't mix
|
|
256
159
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
- [ ] Dev account: **shared login reused**, only `CREATE USER` + `db_owner`
|
|
263
|
-
- [ ] `fui db alias new` loaded the **app account**
|
|
264
|
-
- [ ] `fui db add-by-name <apiName>` works
|
|
265
|
-
- [ ] `fui user list` shows exactly the right people
|
|
266
|
-
- [ ] `fui project sync` + `fui use` + **`fui project publish-config`** done
|
|
267
|
-
- [ ] Told the user **what phase 2 is**
|
|
268
|
-
- [ ] **Security check**: as the app account, `SELECT TOP 1 * FROM <any table>` is **denied** and `EXEC` of an SP works — otherwise the `GRANT` is unverified
|
|
160
|
+
| | SEC `SystemRight` / `FunctionRight` (`acc`) | FUI `UserRight` (`tblA_UserProject`) |
|
|
161
|
+
| --------- | -------------------------------------------------------------------------------- | ------------------------------------ |
|
|
162
|
+
| Scope | one level per user per **system** (alias) | per **FUI project** |
|
|
163
|
+
| Commands | `fui right system|function …` (definitions), `fui right user …` (who holds them) | `fui user …` |
|
|
164
|
+
| Grants | what a user may do in the running app; level 9 on a module = its SEC manager | who may edit the project in the IDE |
|
|
269
165
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
## Three common misreadings
|
|
166
|
+
The FUI IDE is itself the FUI app `fp`: `SystemRight` on `fp` ≥ 3 may create projects, ≥ 2 is needed for any edit, ANDed with `UserRight` on the project (> 1 modules, > 2 project metadata and `project.json`). `UserRight = 3` grants nothing in the running app, and SEC level 9 grants nothing in the IDE.
|
|
273
167
|
|
|
274
|
-
|
|
168
|
+
| Operation | Condition |
|
|
169
|
+
| ----------------------------------------------------- | ------------------------------------------ |
|
|
170
|
+
| `fui project new` | `SystemRight >= 3` on `fp` |
|
|
171
|
+
| `fui project update`, `fui project publish-config` | `SystemRight >= 2` **and** `UserRight > 2` |
|
|
172
|
+
| module create/edit/publish | `SystemRight >= 2` **and** `UserRight > 1` |
|
|
173
|
+
| `fui user add/set/remove` | `SystemRight >= 2` and (`UserRight > 2` or `SystemRight >= 4`) |
|
|
174
|
+
| `fui db alias new` | `SystemRight = 9` on the SEC itself |
|
|
175
|
+
| `fui right user add/set/remove` | SEC `SystemRight >= 3`, or level 9 on that module |
|
|
275
176
|
|
|
276
|
-
|
|
177
|
+
## Checklist
|
|
277
178
|
|
|
278
|
-
|
|
179
|
+
- [ ] Request type stated (database / project / both); nothing outside it
|
|
180
|
+
- [ ] Database frame only after a proved login to the exact server IP
|
|
181
|
+
- [ ] Frame shown, adjusted, and approved before the first write
|
|
182
|
+
- [ ] Gate B passed on the target server; names free; SEC chosen with `--db`
|
|
183
|
+
- [ ] `project new`: six fields, `Framework` agreed; `publish-config` done
|
|
184
|
+
- [ ] Database folder = folder of the latest user database on that server
|
|
185
|
+
- [ ] App login = database name, only `GRANT EXECUTE ON SCHEMA::dbo`; dev login reused as `db_owner`
|
|
186
|
+
- [ ] `db alias new` plan checked against the frame, then `--confirm-write`; app login stored
|
|
187
|
+
- [ ] Level 9 defined on the module; the manager added with `fui right user add … --sys-right 9`
|
|
188
|
+
- [ ] `fui db add-by-name` works; app login denied `SELECT`, allowed `EXEC`
|
|
189
|
+
- [ ] Frame compared line by line with the real state
|
|
@@ -65,10 +65,11 @@ https://api.domain.vn/app/FunctionName/value1/value2
|
|
|
65
65
|
| `@sys_SystemRight` | int | Tiered right (1=low, 9=high) |
|
|
66
66
|
| `@sys_FunctionRight` | varchar(2000) | Function rights as `[AD][RPT][MGR]` |
|
|
67
67
|
| `@sys_SessionID` | varchar(50) | Auth session ID |
|
|
68
|
+
| `@sys_RemoteIP` | varchar(15) | `Request.ServerVariables("REMOTE_ADDR")`; the address seen by the server |
|
|
68
69
|
| `@sys_RawData` | nvarchar(max) | Full client JSON body |
|
|
69
|
-
| `@sys_header_{HeaderName}` | varchar(n) |
|
|
70
|
+
| `@sys_header_{HeaderName}` | varchar(n) | Request header except `Authorization`; missing header becomes `NULL`. Naming rule below |
|
|
70
71
|
|
|
71
|
-
> **CRITICAL — never put `@sys_
|
|
72
|
+
> **CRITICAL — never put recognized `@sys_*` params in module.json `IN`.** tAPI assigns them from authenticated user data, the HTTP request, or the JSON body; a same-named client field is ignored.
|
|
72
73
|
>
|
|
73
74
|
> ```json
|
|
74
75
|
> // ❌ SAI — không đưa sys_ vào IN
|
|
@@ -78,9 +79,21 @@ https://api.domain.vn/app/FunctionName/value1/value2
|
|
|
78
79
|
> "IN": { "ModuleID": "sModuleID" }
|
|
79
80
|
> ```
|
|
80
81
|
|
|
82
|
+
To read the remote address in an API procedure, declare the parameter with this exact name and type. tAPI reads `REMOTE_ADDR`; do not send it in `IN`. `varchar(15)` fits IPv4 addresses, so check the deployment's IPv6 and proxy behavior before using it for a wider address range:
|
|
83
|
+
|
|
84
|
+
```sql
|
|
85
|
+
CREATE PROCEDURE spAPI_AuditVisit
|
|
86
|
+
@sys_UserID varchar(9),
|
|
87
|
+
@sys_RemoteIP varchar(15)
|
|
88
|
+
AS
|
|
89
|
+
BEGIN
|
|
90
|
+
SELECT @sys_UserID AS UserID, @sys_RemoteIP AS RemoteIP;
|
|
91
|
+
END
|
|
92
|
+
```
|
|
93
|
+
|
|
81
94
|
#### `@sys_header_*` — read HTTP headers: replace each `-` with `_`
|
|
82
95
|
|
|
83
|
-
Works for **
|
|
96
|
+
Works for request headers **except `Authorization`**. The suffix after `@sys_header_` must be nonempty. tAPI lowercases the SQL parameter name, takes the suffix, replaces every `_` with `-`, then looks it up in `Request.Headers`. `-` is invalid in SQL Server param names, so the literal name won't compile:
|
|
84
97
|
|
|
85
98
|
```sql
|
|
86
99
|
-- ❌ SAI — lỗi cú pháp ngay lúc CREATE PROCEDURE, không phải lỗi runtime
|
|
@@ -88,7 +101,7 @@ Works for **any** header. `-` is invalid in SQL Server param names, so the liter
|
|
|
88
101
|
```
|
|
89
102
|
|
|
90
103
|
- **No quoting works**: `@[sys_header_User-Agent]` and `@"sys_header_User-Agent"` are both invalid. Renaming is the **only** way.
|
|
91
|
-
- **Each `-` → one `_
|
|
104
|
+
- **Each `-` → one `_` in the SP declaration.** tAPI reverses every `_` in the suffix to `-`; a header whose actual name contains `_` cannot be represented exactly by this convention.
|
|
92
105
|
|
|
93
106
|
| HTTP header | SP param |
|
|
94
107
|
| ------------------ | ---------------------------------------- |
|
|
@@ -99,26 +112,28 @@ Works for **any** header. `-` is invalid in SQL Server param names, so the liter
|
|
|
99
112
|
| `Cookie` | `@sys_header_Cookie` — no `-`, unchanged |
|
|
100
113
|
|
|
101
114
|
- Reverse (reading an existing SP): drop `@sys_header_`, turn remaining `_` into `-` — `@sys_header_Accept_Language` → `Accept-Language`.
|
|
102
|
-
- Matching is **case-insensitive** (prefix and
|
|
115
|
+
- Matching is **case-insensitive** (prefix and header lookup): `@sys_header_User_Agent`, `@sys_Header_User_Agent`, `@sys_header_USER_AGENT` request the same header. Use `_` for each `-`; tAPI does not insert separators, so `@sys_Header_RequestID` requests `RequestID`, not `Request-ID`.
|
|
116
|
+
- `@sys_header_Authorization` is **not exposed**: the code skips assignment for that header. It does not explicitly set the SQL parameter to `NULL` in this branch; do not rely on its value.
|
|
117
|
+
- A missing header is assigned `DBNull.Value`; exceptions during header lookup are caught without a reported error, so diagnose a missing value against the actual incoming request.
|
|
103
118
|
|
|
104
119
|
```sql
|
|
105
120
|
CREATE PROCEDURE spAPI_AuditLog_Insert
|
|
106
121
|
@Action nvarchar(100),
|
|
107
122
|
@sys_UserID varchar(9),
|
|
123
|
+
@sys_RemoteIP varchar(15),
|
|
108
124
|
@sys_header_User_Agent nvarchar(500),
|
|
109
125
|
@sys_header_X_Forwarded_For varchar(200)
|
|
110
126
|
AS
|
|
111
127
|
BEGIN
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
GETDATE());
|
|
128
|
+
SELECT @Action AS ActionName,
|
|
129
|
+
@sys_UserID AS UserID,
|
|
130
|
+
@sys_RemoteIP AS RemoteIP,
|
|
131
|
+
@sys_header_User_Agent AS UserAgent,
|
|
132
|
+
@sys_header_X_Forwarded_For AS ForwardedFor;
|
|
118
133
|
END
|
|
119
134
|
```
|
|
120
135
|
|
|
121
|
-
- **Still `@sys_*`:** auto-filled, **not** in `IN`, **no default** (`= null` is a hard error; `fui sp deploy` blocks it, see below).
|
|
136
|
+
- **Still recognized `@sys_*`:** auto-filled, **not** in `IN`, **no default** (`= null` is a hard error; `fui sp deploy` blocks it, see below).
|
|
122
137
|
- **Missing header → `NULL`** (not `''`) — normal, e.g. script/server-to-server calls often lack `User-Agent`. Wrap in `ISNULL(...)` at use: comparisons give UNKNOWN (`WHERE @sys_header_User_Agent <> 'bot'` **drops** the row), and `+` concatenation gives `NULL` (blanks the whole log string).
|
|
123
138
|
- **Untrusted (client-supplied, spoofable).** Log/stats only, never authorization; take rights from `@sys_UserID`/`@sys_SystemRight` (from the verified token).
|
|
124
139
|
|
|
@@ -13,6 +13,8 @@ If the developer said **do not upload**, **local only**, **draft**, **preview fi
|
|
|
13
13
|
|
|
14
14
|
**Strict mode (`FUI_STRICT=1`)**, for runs nobody reviews step by step: `module publish json|html|script|css`, `component new|update`, `project publish-config` and `sp deploy` are **blocked** until the skill was loaded this session (`fui skill get` / `fui skill ref`), and validator **errors block** publishing module.json. Without it both are warnings.
|
|
15
15
|
|
|
16
|
+
Project CDN files are managed separately from workspace files. `fui cdn info|list|url` read CKFinder; `fui cdn upload|mkdir|rename|move|copy` change the project file store; `fui cdn download` writes a local file. `fui cdn rm|rmdir` permanently delete remote data and require authorization for the exact target plus `--confirm-delete`. Read [cdn-files.md](cdn-files.md) for paths, token handling, allowed extensions and links.
|
|
17
|
+
|
|
16
18
|
## Sync before reading
|
|
17
19
|
|
|
18
20
|
Every file fetched from the server (`module.json`, `header.html`, `body.html`, `script.js`, `_moduleInfo.json`, `uc-*.vue`, `project.json`, `_db/{connectionName}/*.sql`…) is a copy from the last checkout; someone may have changed the server since.
|
|
@@ -48,8 +50,8 @@ Users name commands loosely, often in Vietnamese.
|
|
|
48
50
|
| "which module is active" / "đang làm module gì" | `fui use` |
|
|
49
51
|
| "switch module" / "chọn module", a pasted module URL or `/project/module` route, or just a module name | `fui use <target>` |
|
|
50
52
|
| "list projects" / "danh sách project" | `fui project list` |
|
|
51
|
-
| "new project from scratch" / "tạo dự án mới", "tạo DB + project FUI mới" | [project-provisioning.md](project-provisioning.md)
|
|
52
|
-
| "new database", "register an alias" / "đăng ký alias", "thêm DB vào tAPI" | `fui db alias new`
|
|
53
|
+
| "new project from scratch" / "tạo dự án mới", "tạo DB + project FUI mới" | [project-provisioning.md](project-provisioning.md): result frame approved by the user first, then Phase B/C |
|
|
54
|
+
| "new database", "register an alias" / "đăng ký alias", "thêm DB vào tAPI" | [project-provisioning.md](project-provisioning.md) database block (`fui db alias new` is one step of it) |
|
|
53
55
|
| "let someone edit this project" / "cấp quyền admin project", "thêm người vào project" | `fui user search` → `fui user add` |
|
|
54
56
|
| "who can edit this project" / "ai được sửa project này" | `fui user list` |
|
|
55
57
|
| "update project.json", "edit the project menu" / "sửa menu project" | edit `{projectId}/project.json`, then `fui project publish-config` |
|
|
@@ -73,6 +75,7 @@ Users name commands loosely, often in Vietnamese.
|
|
|
73
75
|
| "push the component" / "up component", "sửa component" | `fui component update` |
|
|
74
76
|
| "sync components" / "sync component" | `fui component list` |
|
|
75
77
|
| "list / sync import files" / "danh sách import file" | `fui import list` |
|
|
78
|
+
| "add a CDN / library / JS / CSS link" / "nhúng CDN", "thêm thư viện", "link css/js" | `fui import new` (never `<link>`/`<script>` in header/body) |
|
|
76
79
|
| "new SP", "deploy the SP" / "tạo SP mới", "cập nhật SP" | `fui sp save` → `fui sp deploy` |
|
|
77
80
|
| "add a function right" / "thêm quyền chức năng", "tạo FunctionRight" | `fui right function new` |
|
|
78
81
|
| "save the user token" / "lưu user token", "token để gọi API" | `fui db user-token` |
|
|
@@ -92,7 +95,7 @@ Users name commands loosely, often in Vietnamese.
|
|
|
92
95
|
| `use <target>`, `use --clear` | M | ✅ | session target only; no data changes |
|
|
93
96
|
| `project list` | R | ✅ | |
|
|
94
97
|
| `project sync` | M | ✅ | refreshes every project-level file and import content; removes local `.vue`/import files that were tracked and are gone on the server (unpublished new ones are kept) |
|
|
95
|
-
| `project new` | M | ⚠️ | needs `SystemRight >= 3` on `fp`; the server reads **6 fields only** (`ProjectID`, `ProjectName`, `GroupName`, `Framework`, `pDomain`, `Router`). `title`/`login`/`apiDomain`/`menu
|
|
98
|
+
| `project new` | M | ⚠️ | needs `SystemRight >= 3` on `fp`; the server reads **6 fields only** (`ProjectID`, `ProjectName`, `GroupName`, `Framework`, `pDomain`, `Router`). other keys (`title`/`login`/`apiDomain`/`menu`…) are refused: runtime config goes through `project publish-config`. `pDomain` (array or string) is normalized to the stored JSON-array string. `project update` merges onto the current record. Full procedure: [project-provisioning.md](project-provisioning.md) |
|
|
96
99
|
| `project update` | M | ⚠️ | edits an existing project; `projectData.id` is required (without it the server would create) |
|
|
97
100
|
| `project publish-config` | M | ⚠️ | pushes the local **file** `{projectId}/project.json`; edit the file first. A JSON syntax error is a hard stop (pushing `{}` would wipe menu and settings). Skips when unchanged |
|
|
98
101
|
| `user search`, `user list` | R | ✅ | `user search` is the only source of the exact `UserID`: show its rows and let the user pick. `user list` = who may edit the project in the FUI IDE (`UserRight` 1/2/3), **not** the `acc` `SystemRight` ([permission-system.md](permission-system.md)) |
|
|
@@ -109,10 +112,10 @@ Users name commands loosely, often in Vietnamese.
|
|
|
109
112
|
| `module new` | M | ⚠️ | creates an **empty** module on the server; confirm id and name first, then `fui module get`. An id already in `_modules.json` is a hard error |
|
|
110
113
|
| `module update` | M | ⚠️ | metadata of an existing module. Changing `ModuleID` changes its URL (old links break) and renames the local folder: warn the user |
|
|
111
114
|
| `module delete` | M | 🔴 | **permanent on the server, no history there**; archives the local folder and clears a matching session target |
|
|
112
|
-
| `module validate`, `module outline`, `module preview` | R | ✅ | `validate` does **not** read `script.js`: an `EXE`/`FUN` calling an unwritten function only shows in `--render` as `... is not defined` ([advanced-techniques.md](advanced-techniques.md) §2). `[design]` warnings must be fixed unless the user asked for that style |
|
|
115
|
+
| `module validate`, `module outline`, `module preview` | R | ✅ | `validate` does **not** read `script.js`: an `EXE`/`FUN` calling an unwritten function only shows in `--render` as `... is not defined` ([advanced-techniques.md](advanced-techniques.md) §2). `[design]` warnings must be fixed unless the user asked for that style. It also reads `header.html`/`body.html` and lists CSS, library tags and old placeholders there as header/body warnings |
|
|
113
116
|
| `module simulate`, `module check`, `component preview` | R | ✅ | write only `_preview/`, `_componentPreview/` and `_testdata/`; an unmocked read-only API may be called for real ([verification.md](verification.md)) |
|
|
114
117
|
| `module publish json` | M | ⚠️ | **only** module.json; no preview needed |
|
|
115
|
-
| `module publish script`, `module publish css` | M | ⚠️ | an **empty** file clears it on the server; a missing file is refused |
|
|
118
|
+
| `module publish script`, `module publish css` | M | ⚠️ | an **empty** file clears it on the server; a missing file is refused. These two files hold all page code and CSS, never header/body |
|
|
116
119
|
| `module publish html` | M | ⚠️ | header/body/title **and** module.json; needs the token from `module preview`, which covers the whole payload (any file edited after the preview voids it). Also pushes non-empty `script.js`/`style.css`, and **reconciles `components/*.vue` with the server: a server component with no local file is DELETED** (the preview lists it as `deleted component <name>`) |
|
|
117
120
|
|
|
118
121
|
### Components
|
|
@@ -155,7 +158,7 @@ Scope, for every component command:
|
|
|
155
158
|
| `db remove <project>/<connectionName>` | M | ⚠️ | removes only the named local connection and updates the default; server alias and cached `_db/<connectionName>/` files remain |
|
|
156
159
|
| `db user-token`, `db default`, `db migrate` | M | ✅ | local only |
|
|
157
160
|
| `db token-rebuild` | M | ⚠️ | overwrites the stored token; `--db` is required when the project has several connections |
|
|
158
|
-
| `db alias new` | M | ⚠️ | registers an existing database as a tAPI alias on `
|
|
161
|
+
| `db alias new` | M | ⚠️ | registers an existing database as a tAPI alias on one SEC (`--db` picks it when the project spans several hosts); prints the plan and sends nothing until `--confirm-write`; ModuleID = MAX+1 from the acc database on the same apiDomain (`--acc-db`). The login must be the **application** account (execute-only), never a `db_owner` dev login |
|
|
159
162
|
| `schema`, `sp list`, `sp path`, `sp help`, `sp verify` | R | ✅ | `schema` reads one connection: a "missing" table usually means the wrong connection. `sp list` covers every connection unless `--db`. `sp help` also clears the tAPI cache for that function |
|
|
160
163
|
| `schema pull` | M | ✅ | rewrites `_db/{connectionName}/` of **one** connection, bodies included. Files of procedures dropped on the server are archived. Files in neither schema are only **listed** (maybe an undeployed draft): read that note and ask before `--prune-local-only` |
|
|
161
164
|
| `sp get` | M | ✅ | overwrites `_db/{connectionName}/{name}.sql` (old copy to `_history/`). Not read-only |
|
|
@@ -168,6 +171,9 @@ Scope, for every component command:
|
|
|
168
171
|
| `right system list`, `right function list` | R | ✅ | read `acc` and refresh `{projectId}/_db/rights.json`; **until they ran once, validate/simulate/render cannot check right codes** |
|
|
169
172
|
| `right system new/update`, `right function new/update` | M | ⚠️ | create and edit are separate; `update` needs the id from `list` |
|
|
170
173
|
| `right system delete`, `right function delete` | M | 🔴 | `function delete` also removes every user assignment of that code |
|
|
174
|
+
| `right user list`, `right user search` | R | ✅ | who holds which SystemRight on a system; exact SEC UserID (not the FUI `DEV…` id) |
|
|
175
|
+
| `right user add/set` | M | ⚠️ | add/set are separate; the level must be defined first; level 9 = the module's SEC manager |
|
|
176
|
+
| `right user remove` | M | 🔴 | also removes the user's FunctionRights there; needs `--confirm-write` |
|
|
171
177
|
|
|
172
178
|
Guarding with a right code that is not defined fails silently: `rightTest()` is always false, the control vanishes with no JS error, and **the preview still shows it** ([permission-system.md](permission-system.md)).
|
|
173
179
|
|
|
@@ -191,7 +197,7 @@ Guarding with a right code that is not defined fails silently: `rightTest()` is
|
|
|
191
197
|
- Only `module.json` → `fui module publish json` (no preview needed).
|
|
192
198
|
- `header.html` / `body.html` / title (with or without module.json) → `fui module preview`, review the diff yourself, then `fui module publish html --approval <token>`. It pushes module.json too. A separate approval turn is unnecessary when this publish completes the requested module work; stop if the developer previously asked not to upload or to review first.
|
|
193
199
|
- `script.js` (also to clear it) → `fui module publish script`. `module publish json` does not push it.
|
|
194
|
-
- `style.css` (also to clear it) → `fui module publish css`.
|
|
200
|
+
- `style.css` (also to clear it) → `fui module publish css`. It is the only home for module CSS: never `<style>`/`style="…"` in `header.html`/`body.html`. JS/CSS libraries go in through `fui import new`, not `<link>`/`<script src>` ([module-structure.md](module-structure.md) §CSS and JS placement).
|
|
195
201
|
- `uc-*.vue` → `fui component new <name>` the first time, `fui component update <name>` after. A **project-scope** component must be previewed and pushed **before** rendering a module that uses it: `--render` hard-blocks when the local file differs from the server.
|
|
196
202
|
- Several files changed → one command per file, in turn. `fui file push <path...>` routes each path to its publisher.
|
|
197
203
|
|