@fui-org/fui-cli 2.2.3 → 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/dist/fui.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{enableCompileCache as a}from"node:module";a?.();var{run:e}=await import("./fui-8tyckpke.js");await e();
2
+ import{enableCompileCache as a}from"node:module";a?.();var{run:e}=await import("./fui-gt54fgs7.js");await e();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fui-org/fui-cli",
3
- "version": "2.2.3",
3
+ "version": "2.2.4",
4
4
  "description": "Token-lean CLI for the FUI low-code platform (Node.js)",
5
5
  "keywords": [
6
6
  "ai",
@@ -63,10 +63,16 @@ A request to create, design, fix or update a module authorizes the agent to publ
63
63
 
64
64
  - **No `style`/`class` beautifying unless asked**; grid + Vuetify + project theme suffice. → [controls-styling-vocabulary.md](references/controls-styling-vocabulary.md)
65
65
 
66
+ **CSS and JS placement (both `HTMLOnly` values)**
67
+
68
+ - **NEVER** CSS in `header.html`/`body.html`: no `<style>` block, no static `style="…"`. Module CSS → `style.css` (`fui module publish css`); component CSS → its `.vue` `<style scoped>`.
69
+ - **NEVER** `<link rel="stylesheet">`/`<script src>` in header/body: every JS/CSS library or CDN URL → `fui import new` (own file: then `fui import upload`). Inline page code → `script.js`.
70
+ - Editing header/body/CSS of a module that already breaks this → move it out in the same change. Raw tag only when an import cannot do it (`type="module"`, `integrity`, `defer`, a config global needed before the library loads...); say which and why. `module validate`/`check`/`preview` list leftovers as **header/body warnings**. → [module-structure.md](references/module-structure.md) §CSS and JS placement
71
+
66
72
  **`uc-*.vue` components**
67
73
 
68
74
  - One `uc-<name>.vue` file (Vue 2 options API). FUI names it by filename and registers every `uc-*.vue` globally: **NEVER** `name:` or `components: {}`.
69
- - Component CSS → `<style scoped>` (saved as `ComCSS`), but it does NOT scope (text concat, no SFC compile): prefix EVERY selector with the component's class. Module-wide CSS → `style.css` (`fui module publish css`); `header.html` still valid. → [coding-standards.md](references/coding-standards.md)
75
+ - Component CSS → `<style scoped>` (saved as `ComCSS`), but it does NOT scope (text concat, no SFC compile): prefix EVERY selector with the component's class. Module-wide CSS → `style.css` (`fui module publish css`), never `header.html`. → [coding-standards.md](references/coding-standards.md)
70
76
  - **NEVER** backtick template strings in `<template>`. → [component-design.md](references/component-design.md) · [coding-standards.md](references/coding-standards.md)
71
77
  - Use Vuetify components where they fit and validate props. Check one alone with `fui component preview <uc-name> --cases [...]` before wiring it into a module, then `fui component new|update <name>`.
72
78
 
@@ -74,7 +80,7 @@ A request to create, design, fix or update a module authorizes the agent to publ
74
80
 
75
81
  - Before using an existing control, check `defaultControlAttr[control].import` in `scripts/component.js` (V2) or `scripts/component-3.0.js` (V3). Treat that array and its order as the source of truth for required JS/CSS; then check imports on every add or remove. → [component-quickref.md](references/component-quickref.md)
76
82
  - **NEVER** add CDN for bundled libs (jQuery, lodash, moment, numeral, Vuetify, toast, jquery-confirm...); list: [script-map.md](references/script-map.md) §0.
77
- - That ban is `HTMLOnly=false` only. `HTMLOnly: true` bundles **nothing** (no Vue, Vuetify, jQuery, lodash, MDI, `projectdefaultstyle.css`, `#fastProjectAPP`): CDNs are **required**, **per HTMLOnly module** (project level has no effect). → [module-structure.md](references/module-structure.md) §HTMLOnly=true
83
+ - That ban is `HTMLOnly=false` only. `HTMLOnly: true` bundles **nothing** (no Vue, Vuetify, jQuery, lodash, MDI, `projectdefaultstyle.css`, `#fastProjectAPP`): CDNs are **required**, as module imports (`fui import new`), **per HTMLOnly module** (project level has no effect). → [module-structure.md](references/module-structure.md) §HTMLOnly=true
78
84
 
79
85
  **Database** (enforced in code; details under "Writes need the user")
80
86
 
@@ -220,6 +226,10 @@ fui sp list --search Student # columns: db name kind count local
220
226
 
221
227
  Before writing `apiMocks` for an SP that exists, run `fui sp verify <name>`. It reads the real body (never calls the endpoint) and prints the params, the response shape, the error contract, read/write and a mock snippet. `sp delete` and `sp rename` change the server: ask the user first.
222
228
 
229
+ ## New database or project
230
+
231
+ "Create a database" (database + SQL accounts + SEC alias + its manager), "create a project" (FUI project + IDE rights) and "create both" are three separate scopes. Before any write, show the user a **result frame** of the end state, let them adjust it and wait for their approval; a database frame needs a proved login to the exact server first. Steps and commands: [project-provisioning.md](references/project-provisioning.md).
232
+
223
233
  ## Writes need the user
224
234
 
225
235
  - Writes to real data exit `3` until you add `--confirm-write`. That covers `INSERT`, `UPDATE`, `DELETE`, `MERGE` and `TRUNCATE` in `query` or `exec` (also inside `EXEC('...')` or `sp_executesql`), `SELECT ... INTO` a real table, `DROP PROCEDURE`/`FUNCTION`/`VIEW`, and `ALTER TABLE ... ALTER COLUMN`.
@@ -240,6 +250,10 @@ fui file restore <path> [--at YYYYMMDD_HHMMSS] # the current file is archived
240
250
  fui file ledger <path...> [--mark|--forget]
241
251
  ```
242
252
 
253
+ ## Project CDN files
254
+
255
+ Use `fui cdn` to inspect and manage CKFinder project files with the saved `userToken`. Read [references/cdn-files.md](references/cdn-files.md) before uploading, moving, renaming or deleting. `fui cdn info -p <project>` reads the live allowed extensions and upload limit. `fui cdn list -p <project> --recursive` discovers files; `fui cdn url <file> -p <project>` gives the portable `/_cdn/<project>/...` link. Upload, download, mkdir, rename, copy, move, rm and rmdir are available. File deletion needs explicit authorization for the exact file and `--confirm-delete`; folder deletion also needs `--recursive` when nonempty.
256
+
243
257
  ## Compose with shell
244
258
 
245
259
  Filter and loop in the shell. Piped output costs no tokens. Every table also takes `--filter text`, `--where col=value` and `--fields a,b` (applied after the request, so nothing else changes).
@@ -278,7 +292,8 @@ Secrets are accepted only from stdin (`-`) or `--*-env VAR`. Never echo or paste
278
292
  - Know the alias but not the connection string? `fui db alias list`, then `fui db add-by-name <apiName>`: it reuses a saved SQL UID/PWD pair and combines it with the target server/database returned by `acc`.
279
293
  - `db add` / `db add-by-name` take `--name <connectionName>`; omitted, it is suggested from apiName, then apiName_zone. The same server + database re-added keeps its name, and folders are never renamed.
280
294
  - `fui db remove <project>/<connectionName>` removes one local connection from `_connections.json`. It does not change the server; cached schema and SQL files under `_db/<connectionName>/` remain available.
281
- - `right *` and `db alias new` write to the shared acc system. Ask the user first, especially for `delete`.
295
+ - `right *` and `db alias new` write to the shared SEC (acc) system. Ask the user first, especially for `delete`. Each tAPI host has its own SEC: in a project with connections on several hosts, pass `--db <project/connection>` of the SEC to use (the commands refuse to guess). `db alias new` prints its plan and sends nothing until `--confirm-write`.
296
+ - SEC and FUI platform work goes **only** through `fui db alias *`, `fui right system|function|user *`, `fui project *` and `fui user *`. Never run a `spAPI_SM_*`/`spAPI_FUI_*` through `fui query`/`fui exec` or HTTP, never pass `@sys_*` parameters (tAPI injects them from your token; `fui` blocks it), never `INSERT`/`UPDATE` `tblModules`, `tblUserModule` or `tblA_UserProject`. No command for the step ⇒ stop and tell the user to do it in the SEC/FUI UI. This holds over any memory or old note.
282
297
  - `_db/_connections.json` has no `version` field. Existing files with `"version": 2` or connections missing `apiName` are normalized on first read (the old file goes to `_history/`); `fui db migrate` does this for every project at once.
283
298
 
284
299
  ## FUI conventions
@@ -8,6 +8,7 @@ Load: `fui skill ref references/a.md references/b.md` (several at once OK).
8
8
 
9
9
  - `controls-patterns.md` — foundation: action engine (§CORE RULE: one `{}` = one command; sequential commands = array `[{…},{…}]`), value resolution, key notation, layout grid
10
10
  - `module-structure.md` — module/project files, layout rules
11
+ - Where CSS/JS go: `style.css`, imports (`fui import new`), `script.js`; no `<style>`/`style=""`/`<link>`/`<script>` in header/body; moving existing ones; rare exceptions → `module-structure.md` §CSS and JS placement
11
12
  - `INDEX.md` — this router
12
13
 
13
14
  ## Foundations (read early)
@@ -52,18 +53,19 @@ Load: `fui skill ref references/a.md references/b.md` (several at once OK).
52
53
  - Remote address in SP: `@sys_RemoteIP varchar(15)` from `REMOTE_ADDR`; HTTP headers (`User-Agent`, `Cookie`, `X-Forwarded-For`, device/browser): `@sys_header_*`, each `-` → `_`, except `Authorization` → `tapi-reference.md` §2
53
54
  - SP permission checks (5 patterns, `@sys_SystemRight`, `getSystemRight`) → `tapi-permission-patterns.md`
54
55
  - File upload/download/view (`spAPIFILE_`, `fileContent`, `tblFileData`) → `tapi-file-api.md`
56
+ - Project CDN assets (CKFinder list, upload, folder, rename, move, copy, delete, portable URL) → `cdn-files.md`
55
57
  - SQL CLR: httpCall, sendMail, ImageResize, FileReader, RegexMatch… → `sql-clr-functions.md`
56
58
 
57
59
  ## User permissions
58
60
 
59
- - `SystemRight` (level) vs `FunctionRight` (per function), `v-if`/menu `right`, `fui right system|function list/new/update/delete` (8 commands) → `permission-system.md`
61
+ - `SystemRight` (level) vs `FunctionRight` (per function), `v-if`/menu `right`, `fui right system|function list/new/update/delete` (8 commands), who holds a level / SEC module manager (`fui right user list/search/add/set/remove`) → `permission-system.md`
60
62
  - Guarding control/menu/SP with a right code — it must exist; how to create → `permission-system.md` (§"A right code must EXIST before guarding with it")
61
63
  - SQL permission checks in SP body → `tapi-permission-patterns.md`
62
64
 
63
65
  ## Database
64
66
 
65
67
  - DB doesn't exist: new SQL Server DB, two SQL account types, tAPI alias in `acc` → `project-provisioning.md`
66
- - Before `CREATE DATABASE` / `CREATE LOGIN`: check server rights (`sysadmin`, or `CREATE ANY DATABASE` + `ALTER ANY LOGIN`); if missing, refuse, no trial run → `project-provisioning.md` §Step 0
68
+ - Before `CREATE DATABASE` / `CREATE LOGIN`: check server rights (`sysadmin`, or `CREATE ANY DATABASE` + `ALTER ANY LOGIN`); if missing, refuse, no trial run → `project-provisioning.md` §Phase B
67
69
  - Connection, dbToken, schema, SP workflow → `db-workflow.md`
68
70
  - Multiple DBs / an alias repeated across zones: `connectionName` names a readable folder, `apiName` is stored separately, `--db` picks the connection → `db-workflow.md` (§1, §4)
69
71
  - Cross-domain SSO: userToken of same parent domain works as-is; don't re-ask/verify → `db-workflow.md` §6a
@@ -72,8 +74,8 @@ Load: `fui skill ref references/a.md references/b.md` (several at once OK).
72
74
 
73
75
  ## Process / system design
74
76
 
75
- - New project / new DB + FUI project from zero: CREATE DATABASE, app vs dev accounts, `acc` alias, `fui project new`, admin grant; do BEFORE `system-design.md` → `project-provisioning.md`
76
- - Grant/revoke IDE project-edit rights for a developer (`UserRight`, `fui user search/list/add/set/remove`); not end-user rights (`permission-system.md`) → `project-provisioning.md` (§Step 6)
77
+ - "Create a database", "create a project" or both (three separate scopes): result frame approved by the user first, CREATE DATABASE, app vs dev accounts, SEC alias + its manager, `fui project new`, IDE rights; do BEFORE `system-design.md` → `project-provisioning.md`
78
+ - Grant/revoke IDE project-edit rights for a developer (`UserRight`, `fui user search/list/add/set/remove`); not end-user rights (`permission-system.md`) → `project-provisioning.md` (§Phase C, project block)
77
79
  - Multi-module app from a description (decomposition, schema-first, menu, rights) → `system-design.md`
78
80
  - One fullstack module, 6-step UI-first → `fullstack-workflow.md`
79
81
  - project.json: menu, navigation, permissions, domain → `project-config.md`
@@ -104,7 +106,7 @@ Load: `fui skill ref references/a.md references/b.md` (several at once OK).
104
106
  Pick the mode BEFORE writing controls. Owner: `design-modes.md`.
105
107
 
106
108
  - App-mode (default): CRUD, forms, lists, internal dashboards. Source: ONLY `fui design read fui` + `controls-styling-vocabulary.md`; NO brand DESIGN.md, NO custom styles.
107
- - Web-mode: landing/intro/public pages (usually `HTMLOnly: true`). Source: `fui design list` → `fui design read <brand>` by tone/industry; free CSS in header.html.
109
+ - Web-mode: landing/intro/public pages (usually `HTMLOnly: true`). Source: `fui design list` → `fui design read <brand>` by tone/industry; free CSS in `style.css`, libraries as imports.
108
110
  - Mode choice, `border-radius` limits, `{projectId}/DESIGN.md` loop → `design-modes.md`
109
111
  - App-mode dialog/form/palette anatomy → `fui design read fui` (not `fui skill ref`)
110
112
  - `{projectId}/DESIGN.md`, if present, overrides same-topic rules of the active mode; check before designing.
@@ -0,0 +1,30 @@
1
+ # Project CDN files
2
+
3
+ `fui cdn` works with the project's CKFinder 2.6 connector at `cdn.fui.vn`. It uses a saved `userToken` as a Bearer credential, sends `Referer: https://cdn.fui.vn/?folder=<projectId>`, obtains the project's resource type and hash with `Init`, and handles the connector's CSRF cookie on writes. Never print or paste the token, session cookie or resource hash. A resource type is named after the project ID; do not assume it is `Images` or `Files`.
4
+
5
+ The tool reads allowed extensions and the 20 MB default upload limit from each project's live `Init` response. The supplied server configuration permits `js,json,css,csv,doc,docx,gif,jpeg,jpg,png,mid,mov,mp3,mp4,mpc,mpeg,mpg,ods,odt,pdf,ppt,pptx,pxd,qt,ram,rar,rm,rmi,rmvb,rtf,sdc,sitd,tar,tgz,tif,tiff,txt,vsd,wav,wma,wmv,xls,xlsx,zip,woff,woff2,ttf,otf`; the live response is authoritative. CKFinder may resize large images to 2000 × 2000, rename an upload on collision, and reject unsafe names or invalid images.
6
+
7
+ ## Commands
8
+
9
+ ```bash
10
+ fui cdn info -p fp
11
+ fui cdn list / -p fp --recursive
12
+ fui cdn list /images/ -p fp
13
+ fui cdn mkdir /images/ -p fp
14
+ fui cdn upload ./logo.png -p fp --to /images/
15
+ fui cdn url /images/logo.png -p fp --origin https://fui.vn
16
+ fui cdn download /images/logo.png -o ./logo.png -p fp
17
+ fui cdn rename /images/logo.png logo-new.png -p fp
18
+ fui cdn rename /images/ assets -p fp
19
+ fui cdn copy /assets/logo-new.png --to /archive/ -p fp
20
+ fui cdn move /assets/logo-new.png --to /images/ -p fp
21
+ fui cdn rm /images/logo-new.png -p fp --confirm-delete
22
+ fui cdn rmdir /images/ -p fp --confirm-delete
23
+ fui cdn rmdir /archive/ -p fp --confirm-delete --recursive
24
+ ```
25
+
26
+ `cdn list` shows both folders and files. Add `--recursive` to walk the tree, and `--depth N` to limit recursion. Copy and move operate on files, into an existing folder, without overwriting a same-named item. `cdn rename` handles files and folders. `cdn download` refuses to replace a local file unless `--overwrite` is supplied. Use `--user-token-from <project/connection>` or `--user-token-env VAR` if the FUI domain has multiple saved tokens.
27
+
28
+ Upload and URL commands return both a portable relative link and a full link for `https://fui.vn`; `--origin` changes the full link to another project-serving domain. Prefer the relative `/_cdn/<projectId>/folder/file.ext` link in web pages. `cdn url` verifies the file exists before returning it.
29
+
30
+ Deletion is permanent. A request to build or edit a page does not by itself authorize removing existing project files. Obtain explicit authorization for the exact file or folder, then pass `--confirm-delete`; a nonempty folder also needs `--recursive`. Temporary assets created during an authorized test may be removed after the test if the user identified them as disposable.
@@ -17,7 +17,7 @@
17
17
  ### CSS Classes
18
18
 
19
19
  - **`<style scoped>` in `.vue` is allowed** (saved server-side as `ComCSS`) but `scoped` has **no real effect** — FUI just concatenates every component's `ComCSS` in the module into one global stylesheet (`ComponentCSSBuild()`): no AST transform, no `data-v-xxxx`. **Scope every selector manually**: give the root template element a unique class matching the component name (kebab-case, e.g. `uc-invoice-list`) and write every rule under it (`.uc-invoice-list__title`, never bare `.title`). Full example: [component-design.md](component-design.md).
20
- - **Placement**: component CSS → `<style scoped>` in the `.vue` (manually scoped). Module-wide CSS → `style.css` (publish with `fui module publish css`). `header.html` still works for CSS but is no longer the only option.
20
+ - **Placement**: component CSS → `<style scoped>` in the `.vue` (manually scoped). Module-wide CSS → `style.css` (publish with `fui module publish css`). Never CSS in `header.html`/`body.html` (no `<style>`, no static `style="…"`): [module-structure.md](module-structure.md) §CSS and JS placement.
21
21
  - **Vuetify utilities first** (`ma-2`, `pa-0`, `d-flex`, `primary--text`).
22
22
  - **Custom classes**: meaningful prefixed names (`ep-hero`, `ep-field-grid`); avoid generic `.box`, `.red`.
23
23
  - **State classes**: descriptive (`.is-active`, `.has-error`).
@@ -65,7 +65,7 @@ Define the app menu in `module.json`'s `set` object.
65
65
  - **Required**: `_info.json` and `module.json` at module root.
66
66
  - **`components/`**: only `.vue` files; no subfolders unless strictly necessary (FUI scans this root).
67
67
  - **`components/_components.json`**: keep the registry when using `uc-*` components.
68
- - **`header.html`**: still valid for CSS, but prefer manually scoped `<style scoped>` in `.vue` for component CSS and `style.css` for module-wide CSS.
68
+ - **`header.html` / `body.html`**: markup only. CSS → `style.css` (component CSS → its `.vue`), JS/CSS libraries → `fui import new`, inline code → `script.js`. Existing CSS or library tags there → move them when you edit those files. Rules and the rare exceptions: [module-structure.md](module-structure.md) §CSS and JS placement.
69
69
  - **`module.json`**: keep clean; move large static lists to the DB or separate JSON files if supported.
70
70
 
71
71
  ## 4. Best Practices
@@ -227,7 +227,7 @@ methods: {
227
227
  </style>
228
228
  ```
229
229
 
230
- Module-wide CSS → `style.css` (`fui module publish css`); `header.html` still works but isn't the only option.
230
+ Module-wide CSS → `style.css` (`fui module publish css`), never `header.html`/`body.html` ([module-structure.md](module-structure.md) §CSS and JS placement).
231
231
 
232
232
  ### Before adding a class → check the approved vocabulary
233
233
 
@@ -244,7 +244,7 @@ Allowed Vuetify classes/props (spacing, flex, text, color, radius, elevation, br
244
244
 
245
245
  §8 is **V3** (`v-row`/`v-col`); V2 projects use `v-layout`/`v-flex`. Silent breakage both ways: `v-flex` in V3 **shows content with wrong layout**, nothing reports it. Fixing an old component → `fui component preview` on **the project's framework** before pushing.
246
246
 
247
- Component-specific CSS → its own `<style scoped>`, manually scoped — not `header.html` unless shared by several components/the module.
247
+ Component-specific CSS → its own `<style scoped>`, manually scoped. CSS shared by several module components or the whole module → `style.css`, never `header.html`.
248
248
 
249
249
  ---
250
250
 
@@ -110,7 +110,7 @@ The override does **not** touch `transition`. In particular, never add `scrollba
110
110
  Do not use `fpScrollbar` for:
111
111
 
112
112
  - **`f-table`/`f-sheet`**: the table scrolls internally by `:height` (see [ui-table-cell-patterns.md](ui-table-cell-patterns.md)); putting it on an outer wrapper only adds a nested scrollbar.
113
- - **`HTMLOnly: true` modules**: they do not load `projectdefaultstyle.css`, so the class does not exist (see [module-structure.md](module-structure.md) §HTMLOnly=true). There, writing scrollbar CSS in the module is fine.
113
+ - **`HTMLOnly: true` modules**: they do not load `projectdefaultstyle.css`, so the class does not exist (see [module-structure.md](module-structure.md) §HTMLOnly=true). There, writing scrollbar CSS in the module's `style.css` is fine.
114
114
 
115
115
  ### Icon size
116
116
 
@@ -118,7 +118,7 @@ Do not use `fpScrollbar` for:
118
118
  - **Don't set `small` or `:small`** on `v-icon`, icon buttons, or buttons with icons just to look "compact".
119
119
  - Shrink only when the user explicitly asks or a specialised component/pattern prescribes it; then set the prop on exactly that component — don't shrink the whole button unintentionally.
120
120
 
121
- **Before adding a class → check the table above.** Define a custom class only for what Vuetify lacks: complex grid-template, animation, pseudo-element (`::before`), specific child selectors. Put it in `header.html`, clearly prefixed, **minimal count** — don't recreate card/badge/spacing Vuetify already has.
121
+ **Before adding a class → check the table above.** Define a custom class only for what Vuetify lacks: complex grid-template, animation, pseudo-element (`::before`), specific child selectors. Put it in the module's `style.css` (a component's own class: its `<style scoped>`), clearly prefixed, **minimal count**; never in `header.html`/`body.html` — don't recreate card/badge/spacing Vuetify already has.
122
122
 
123
123
  > `flex-md-grow-0` + `col: { class: "shrink" }` + `style: "width:200px"` = **fixed-width filter field** — standard toolbar pattern ([ui-patterns.md](ui-patterns.md) §4). The only valid place for `style` (width only).
124
124
 
@@ -168,6 +168,6 @@ Only when the user **explicitly requests** specific presentation (e.g. "grey bac
168
168
 
169
169
  - Prop → Vuetify utility class → `mw-*` for width → `style` last.
170
170
  - `border-radius` on request: obey limits in [design-modes.md](design-modes.md) (large frame ≤12px, medium ≤8px, small ≤6px).
171
- - No `<style>` in `.vue`; CSS goes in `header.html`.
171
+ - CSS goes in `style.css` (component-only CSS: the component's manually prefixed `<style scoped>`), never in `header.html`/`body.html`. [module-structure.md](module-structure.md) §CSS and JS placement.
172
172
 
173
173
  > **About to type `style` or name a new class → stop and ask "did the user request this?". If not → drop it.**
@@ -277,9 +277,9 @@ EXEC XDATA23.Calendar2015.dbo.spIO_IN_DeleteMonHocInfo @MonHocID, @ErrorDKMH OUT
277
277
 
278
278
  | Situation | Command |
279
279
  | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
280
- | DB doesn't exist (from scratch) | [project-provisioning.md](project-provisioning.md): 2 permission gates → CREATE DATABASE → 2 accounts → `fui db alias new` |
281
- | Check `CREATE DATABASE`/`CREATE LOGIN` rights | [project-provisioning.md](project-provisioning.md) §Step 0 — `IS_SRVROLEMEMBER` + `HAS_PERMS_BY_NAME`, read-only |
282
- | DB exists, no alias in `acc` | `fui db alias new` ([project-provisioning.md](project-provisioning.md) §Step 5) |
280
+ | DB doesn't exist (from scratch) | [project-provisioning.md](project-provisioning.md): result frame → read-only checks → CREATE DATABASE → 2 accounts → `fui db alias new` → SEC manager |
281
+ | Check `CREATE DATABASE`/`CREATE LOGIN` rights | [project-provisioning.md](project-provisioning.md) §Phase B — `IS_SRVROLEMEMBER` + `HAS_PERMS_BY_NAME`, read-only |
282
+ | DB exists, no alias in `acc` | `fui db alias new` ([project-provisioning.md](project-provisioning.md) §Phase C, database block) |
283
283
  | First connect, have dbToken | `fui db add` |
284
284
  | Alias only, no dbToken | `fui db alias list` → `fui db add-by-name` |
285
285
  | Which DBs am I granted | `fui db alias list` |
@@ -13,7 +13,7 @@ Before writing any `controls`, decide the module's mode. This is the first, **ha
13
13
  | Applies to | Management software: CRUD, lists, forms, internal dashboards, permissions | Landing pages, product intros, public pages (usually `HTMLOnly: true`) |
14
14
  | Aesthetic source | **ONLY** `fui design read fui` + `controls-styling-vocabulary.md` | Brand DESIGN.md (`fui design list` → `fui design read <brand>`) |
15
15
  | Brand DESIGN.md (nike, linear, bmw...) | **FORBIDDEN** — even "just the colors" | Allowed, pick by tone/industry |
16
- | Custom style/class | **FORBIDDEN** (per `controls-styling-vocabulary.md`) | Allowed in `header.html` |
16
+ | Custom style/class | **FORBIDDEN** (per `controls-styling-vocabulary.md`) | Allowed, in `style.css` only (never `header.html`/`body.html`) |
17
17
  | Component preference | `f-*` / `v-*` per FUI standard | Free HTML/CSS |
18
18
 
19
19
  **Web-mode signals**: `HTMLOnly: true` in `_moduleInfo.json`, or user says "landing page / intro page / public home page". Everything else → App-mode. Unsure → **ask the user**.
@@ -1,6 +1,6 @@
1
1
  # Module Structure
2
2
 
3
- > Owns: project/module tree, per-file duties, `_moduleInfo.json`/`mTitle`, `HTMLOnly`, default meta tags. `uc-*.vue` rules: [component-design.md](component-design.md); `module.json` content: [controls-patterns.md](controls-patterns.md). _(Tier A — load with `fui skill ref references/controls-patterns.md references/module-structure.md` before any module/UI work; `fui skill get` does not print it.)_
3
+ > Owns: project/module tree, per-file duties, where CSS/JS go (`style.css`, imports, `script.js`; never in header/body), `_moduleInfo.json`/`mTitle`, `HTMLOnly`, default meta tags. `uc-*.vue` rules: [component-design.md](component-design.md); `module.json` content: [controls-patterns.md](controls-patterns.md). _(Tier A — load with `fui skill ref references/controls-patterns.md references/module-structure.md` before any module/UI work; `fui skill get` does not print it.)_
4
4
 
5
5
  Use when creating, refactoring or reviewing a module. With workspace access it is the real folder layout; in chat, use it to organize the response without assuming files exist.
6
6
 
@@ -33,10 +33,10 @@ Use when creating, refactoring or reviewing a module. With workspace access it i
33
33
  |-- _moduleInfo.json # Required: module metadata + mTitle (page title) + HTMLOnly
34
34
  |-- module.json # Required: data/watch/controls/set (unused when HTMLOnly=true)
35
35
  |-- script.js # Recommended: helper logic for FUN/EXE/chart/transform
36
- |-- style.css # Optional: module-wide CSS (published via fui module publish css)
37
- |-- header.html # Full <head> content: <link>, <style>, <script> tags
38
- |-- body.html # HTMLOnly=false: supplementary body HTML
39
- | # HTMLOnly=true: entire page content (custom HTML/Vue app)
36
+ |-- style.css # Module-wide CSS: the ONLY place for page CSS (fui module publish css)
37
+ |-- header.html # Inner <head>: <meta>/icon tags; normally empty (no CSS, no library tags)
38
+ |-- body.html # HTMLOnly=false: supplementary body markup, usually empty
39
+ | # HTMLOnly=true: entire page markup (no <style>, style="", <link>, <script>)
40
40
  |-- imports/ # Module-scope import files
41
41
  | `-- _imports.json # Declared module-level JS/CSS imports
42
42
  `-- components/ # Optional: custom Vue components
@@ -57,11 +57,11 @@ Required: `_moduleInfo.json`, `module.json`. Recommended: `script.js`, `imports/
57
57
 
58
58
  **script.js** — complex transforms, chart builders, debounce, parsing; expose functions for `FUN`/`EXE` and template helpers. Prefer a reusable function over large inline `EXE`.
59
59
 
60
- **style.css** — module-wide CSS not tied to one component. Publish with `fui module publish css`; an empty file is not auto-cleared by `fui module publish html`. Component-local CSS goes in the component's `<style scoped>`.
60
+ **style.css** — all module CSS not tied to one component (both `HTMLOnly` values). Publish with `fui module publish css`; an empty file is not auto-cleared by `fui module publish html`. Component-local CSS goes in the component's `<style scoped>`. Placement rules: [§CSS and JS placement](#css-and-js-placement).
61
61
 
62
62
  **\_moduleInfo.json** — keep `ProjectID`, `ModuleID`, `ModuleName`, `Framework` accurate. `mTitle` is the page title (edit it here; sent as `title` by `fui module publish html`). Read `HTMLOnly` before structuring anything.
63
63
 
64
- **header.html** — inner `<head>` content only (`<link>`, `<style>`, `<script>`, `<meta>`); no wrapper, no `<title>` (use `mTitle`). `HTMLOnly=false`: usually CSS only; server injects framework and project scripts. `HTMLOnly=true`: bring your own runtime — read [HTMLOnly=true: no library is embedded](#htmlonlytrue-no-library-is-embedded) first. These meta tags are on every page — never repeat them:
64
+ **header.html** — inner `<head>` content only; no wrapper, no `<title>` (use `mTitle`). Normally **empty**: CSS goes to `style.css`, JS/CSS libraries to imports, page JS to `script.js` ([§CSS and JS placement](#css-and-js-placement)). What may stay: extra `<meta>` and non-CSS/JS `<link>` (`icon`, `manifest`, `preconnect`), plus the rare exception tag listed in that section. `HTMLOnly=true`: bring your own runtime through imports — read [HTMLOnly=true: no library is embedded](#htmlonlytrue-no-library-is-embedded) first. These meta tags are on every page — never repeat them:
65
65
 
66
66
  ```html
67
67
  <meta charset="UTF-8" />
@@ -75,7 +75,38 @@ Required: `_moduleInfo.json`, `module.json`. Recommended: `script.js`, `imports/
75
75
  - Vuetify breakpoints follow real device CSS pixels.
76
76
  - `viewport-fit=cover` → fullscreen/`HTMLOnly` layouts touching top/bottom need `env(safe-area-inset-*)` padding (iOS notch/home indicator).
77
77
 
78
- **body.html** — inner `<body>` content only. `HTMLOnly=false`: supplementary HTML beside the Vue runtime, usually empty. `HTMLOnly=true`: the whole page (plain HTML or own Vue app with own `<div id="app">`/`<v-app>`); FUI's default mount point is hidden. Server and publish command strip `<head>`/`<body>` wrappers.
78
+ **body.html** — inner `<body>` markup only. `HTMLOnly=false`: supplementary HTML beside the Vue runtime, usually empty. `HTMLOnly=true`: the whole page markup (plain HTML or own Vue app with own `<div id="app">`/`<v-app>`), with its app code in `script.js`; FUI's default mount point is hidden. No `<style>`, static `style="…"`, `<link>` or `<script>` here ([§CSS and JS placement](#css-and-js-placement)). Server and publish command strip `<head>`/`<body>` wrappers.
79
+
80
+ ## CSS and JS placement
81
+
82
+ `header.html` and `body.html` hold markup, never design or libraries. `style.css` and imports load as separate cacheable files (`style.css` as the module StyleCSS `<link>`), are visible to `fui import list`, `fui file status` and the render report, and keep CSS in one place instead of scattered through the page.
83
+
84
+ | Content | Goes to | Push |
85
+ | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------- |
86
+ | Module CSS: classes, layout, `@font-face`, `@media`, keyframes | `style.css` | `fui module publish css` |
87
+ | Component CSS | the component's `<style scoped>`, every selector prefixed ([component-design.md](component-design.md)) | `fui component update <name>` |
88
+ | JS/CSS library or CDN URL | `fui import new --type js\|css --content-type link --name <url> --sort N` | immediate |
89
+ | Own JS/CSS file to host | `fui import new --content-type text/javascript\|text/css`, then `fui import upload <fileId> -f <file>` | immediate |
90
+ | Page logic (also an `HTMLOnly` Vue app) | `script.js`: it runs after the body markup and after every import | `fui module publish script` |
91
+ | Images, fonts, documents | `fui cdn upload`, referenced as `/_cdn/<project>/…` from `style.css` or markup ([cdn-files.md](cdn-files.md)) | immediate |
92
+
93
+ Never in `header.html`/`body.html`:
94
+
95
+ - a `<style>` block or a static `style="…"` attribute → a named, prefixed class in `style.css`. A Vue `:style` binding whose value comes from data is fine; a constant value is not.
96
+ - `<link rel="stylesheet">` or `<script src>` → an import, in load order through `--sort`.
97
+ - inline `<script>` code → `script.js`.
98
+
99
+ **A module that already has them:** when the task edits `header.html`, `body.html` or the module's CSS/JS, move them in the same change: `<style>` content → `style.css` (keep rule order), each static `style="…"` → a class in `style.css`, each `<link>`/`<script src>` → `fui import new` keeping the old order, inline code → `script.js`; then delete them from header/body. Order shifts (`style.css` loads after project CSS; import scripts load after the body), so compare with `fui module simulate --render` and push everything: imports, `fui module publish css|script`, then `fui module preview` → `fui module publish html`. For any other edit to such a module, name the leftovers in the report and offer the move.
100
+
101
+ **Exceptions** (only when no import or file above can do it): imports emit a plain `<link rel="stylesheet">` or `<script src>`, so a tag that needs more stays in `header.html`:
102
+
103
+ - attributes an import cannot carry: `type="module"`, `nomodule`, `integrity`/`crossorigin`, `async`/`defer`, `data-*` config the library reads from its own tag;
104
+ - a config global that must exist **before** a library loads (e.g. `window.MathJax = {…}`), since `script.js` runs after the imports;
105
+ - a third-party embed snippet the vendor requires at a fixed spot in the markup.
106
+
107
+ Keep such a tag minimal, never put design CSS beside it, and tell the user which tag stayed and why.
108
+
109
+ `fui module validate`, `module check`, `module preview` and `module publish html` print a **header/body warning** block for each `<style>`, static `style="…"`, stylesheet `<link>`, `<script src>` and inline JS `<script>` they find, plus the placeholders an old FUI MCP wrote (`<style>/* Module styles */</style>`, `<!-- Module body -->`: delete them). Tags with an exception attribute above, `<script type="module">`, templates (`type="text/x-template"`) and JSON data scripts are not reported. The warnings never block a publish; clear the ones in files this task edits.
79
110
 
80
111
  **imports/\_imports.json** — module-scope JS/CSS imports; entry `{ name, type, contentType, fileID, scope, sort }`. `sort` = load order: new imports use **>= 40** (40, 50, 60…); 1–39 is reserved for system/framework. Project-scope imports live in `{projectId}/imports/_imports.json`.
81
112
 
@@ -119,10 +150,7 @@ Not embedded, even if the project declares them:
119
150
  | Project-level StyleCSS, `projectdefaultstyle.css` | shared project classes gone (incl. `.shrink`) |
120
151
  | `<div id="fastProjectAPP">` | no mount point — build your own root in `body.html` |
121
152
 
122
- **Declare every needed library in each HTMLOnly module**; project-level declarations do not help. Either:
123
-
124
- - `fui import new` into the module's `imports/_imports.json` with `--sort` >= 40 (see `fui import new --help`) — preferred: visible in `fui import list` and the `fui module simulate --render` report; or
125
- - raw `<link>`/`<script>` in `header.html` — flexible, but no command lists them.
153
+ **Declare every needed library in each HTMLOnly module**; project-level declarations do not help. Use `fui import new` into the module's `imports/_imports.json`, one import per file in load order via `--sort` (see `fui import new --help`): imports are visible in `fui import list` and the `fui module simulate --render` report. A raw `<link>`/`<script>` in `header.html` only for the exceptions in [§CSS and JS placement](#css-and-js-placement). Page CSS still goes to `style.css` and the app code to `script.js` (both are emitted for HTMLOnly too).
126
154
 
127
155
  **[script-map.md](script-map.md) does not apply here**: its "already bundled, no duplicate CDN" list is for `HTMLOnly=false` only. In HTMLOnly the CDN is required, not a duplicate.
128
156
 
@@ -131,8 +159,8 @@ Not embedded, even if the project declares them:
131
159
  ## Patterns
132
160
 
133
161
  - **A — simple**: `_moduleInfo.json`, `module.json`, `script.js`, `imports/_imports.json`; no `components/` unless needed.
134
- - **B — dashboard/report (recommended)**: `module.json` filters + action orchestration; `script.js` conversion/chart utils; `components/uc-*.vue` chart/table presentation; `header.html` module/component CSS. Keeps large `module.json` maintainable.
135
- - **C — HTMLOnly page**: `_moduleInfo.json` (`HTMLOnly: true`), empty `module.json` skeleton, `header.html` all CSS + JS libraries, `body.html` whole page (plain HTML or self-contained Vue app); `components/`/`script.js` only if needed.
162
+ - **B — dashboard/report (recommended)**: `module.json` filters + action orchestration; `script.js` conversion/chart utils; `components/uc-*.vue` chart/table presentation; `style.css` module CSS, component CSS in each `.vue`. Keeps large `module.json` maintainable.
163
+ - **C — HTMLOnly page**: `_moduleInfo.json` (`HTMLOnly: true`), empty `module.json` skeleton, every JS/CSS library as a module import, `style.css` all page CSS, `body.html` page markup only, `script.js` the page/Vue app code; `components/` only if needed.
136
164
 
137
165
  ## Review Checklist
138
166
 
@@ -140,5 +168,5 @@ Not embedded, even if the project declares them:
140
168
  2. false: valid `data/watch/controls/set`? true: `module.json` empty, all content in `body.html`?
141
169
  3. Heavy logic in `script.js`, not oversized `EXE`?
142
170
  4. Custom UI in `components/uc-*.vue`, registered in `_components.json`?
143
- 5. Imports in `imports/_imports.json`?
144
- 6. `header.html`/`body.html` inner content only (no `<head>`/`<body>`)?
171
+ 5. Every JS/CSS library in `imports/_imports.json`, none as `<link>`/`<script src>` in header/body (exceptions: [§CSS and JS placement](#css-and-js-placement))?
172
+ 6. `header.html`/`body.html` inner content only (no `<head>`/`<body>`), with no `<style>`, static `style="…"` or inline `<script>`; CSS in `style.css`, code in `script.js`?
@@ -56,7 +56,8 @@ Shared by all FUI projects:
56
56
  - **`tblSysRight`** — `SystemRight` levels (0–9) of **one project** + `Note`; `9` always **Project Admin**
57
57
  - **`tblFunction`** — `FunctionRight` definitions (`FunctionCode` + `FunctionName`) of **one project** — catalog of assignable functions, not per-user assignment
58
58
 
59
- > **Assigning** levels/codes to users is a separate admin operation, outside the 8 commands below (they manage **definitions** only).
59
+ > **Definitions** (which levels/codes exist) are the 8 `fui right system|function` commands; **assignments** (which user holds which level on the system) are the 5 `fui right user` commands. Both go through the SEC with your userToken; never call their `spAPI_SM_*` yourself.
60
+ - **`tblUserModule`** — who holds which `SystemRight` on which system; level `9` on a module makes that user its **SEC manager**
60
61
 
61
62
  ### ⚠️ Not `UserRight` — right to EDIT a project in the FUI IDE
62
63
 
@@ -67,7 +68,7 @@ Shared by all FUI projects:
67
68
  | Scope | **Whole app** — one level per user | **Per project** |
68
69
  | Stored in | `acc.tblSysRight` / `acc.tblFunction` | `tblA_UserProject` (FUI platform DB, not `acc`) |
69
70
  | Runtime read | `vueData.user.SystemRight` / `.FunctionRight` | none — FUI IDE only |
70
- | Commands | 8 `fui right …` below | 5 `fui user …` → [project-provisioning.md](project-provisioning.md) §Step 6 |
71
+ | Commands | 8 + 5 `fui right …` below | 5 `fui user …` → [project-provisioning.md](project-provisioning.md) §Phase C |
71
72
 
72
73
  The FUI IDE _is itself a FUI app_ (project `fp`), so `SystemRight` **on `fp`** is the developer's IDE right. Both axes **AND** (from real SP bodies):
73
74
 
@@ -140,11 +141,16 @@ Create / edit / delete are **three separate commands**: delete is 🔴 irreversi
140
141
  3. `apiName`/`projectId` default to the session's active project — pass `apiName` for **another** project, or when the project has **several connections** and the right belongs to a non-default alias.
141
142
  4. Server checks the caller: Select needs `SystemRight >= 2` on `acc`; Update needs higher, or admin (`9`) of the target project.
142
143
 
143
- **Platform API** (reference; use the commands):
144
+ 5. **Which SEC**: each tAPI host (LHU, LHBS, FUI, FAP …) runs its own SEC. A project with connections on several hosts makes every `right`/`db alias` command refuse until `--db <project/connection>` names the connection whose apiDomain + userToken to use; the output always says `SEC <apiDomain>`.
144
145
 
145
- ```
146
- POST {apiDomain}/acc/SM_SystemRight_Select { ModuleID | APIName }
147
- POST {apiDomain}/acc/SM_SystemRight_Update { ModuleID | APIName, SysRight, Note, Delete }
148
- POST {apiDomain}/acc/SM_FunctionRight_Select { ModuleID | APIName }
149
- POST {apiDomain}/acc/SM_FunctionRight_Update { FunctionID, ModuleID | APIName, FunctionCode, FunctionName, Delete }
150
- ```
146
+ ## 5 commands — who holds a level (`tblUserModule`)
147
+
148
+ | Command | Role | Safety |
149
+ | --------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
150
+ | `fui right user list [--api-name a] [--db c]` | Users of the system with their level and FunctionRights | Read-only |
151
+ | `fui right user search <UserID or username prefix> [--db c]` | Find a SEC account (top 50) | Read-only — the only source of the exact SEC `UserID` (≤ 9 chars, not the FUI `DEV…` id) |
152
+ | `fui right user add <UserID> --sys-right N [--api-name a] [--db c]` | Give a user with no right on the system level `N` | Level must be defined (`fui right system new N` first); existing user = hard error → `set` |
153
+ | `fui right user set <UserID> --sys-right N …` | Change the level of a user who has one | No row = hard error → `add` |
154
+ | `fui right user remove <UserID> --confirm-write …` | Remove the user from the system | 🔴 Also deletes every FunctionRight they hold there; ask first, then `--confirm-write` |
155
+
156
+ Show the `search` table and let the user pick before `add`: names repeat. A new system's manager = `fui right system new 9` then `fui right user add <UserID> --sys-right 9` ([project-provisioning.md](project-provisioning.md) Phase C).
@@ -120,7 +120,7 @@ height: calc(100vh - 48px);
120
120
  height: 100vh;
121
121
  ```
122
122
 
123
- Applies to `module.json` (`:height` of `f-table`, `f-echart`...) and to CSS in `header.html`/components for `HTMLOnly=true` pages.
123
+ Applies to `module.json` (`:height` of `f-table`, `f-echart`...) and to CSS in `style.css`/components for `HTMLOnly=true` pages.
124
124
 
125
125
  ## menuLeft (sidebar)
126
126