Modules, forms, virtual tables
The three core nouns of xly's metadata model. A reader who internalises these can navigate the rest of the framework. The vocabulary is not always consistent in the codebase — same concept, different names in different files — so part of this page is reconciling the synonyms.
Module
The unit of "a configurable thing in the system".
-
One row per module in
gdsmodule. - Carries the URL fragment (
sName), display names (sChinese,sEnglish,sBig5), tree position (sParentId,sAllId), product edition (sVersionFlowId, see Slice 2), optional CRUD procedure names (sSaveProName,sDeleteProName,sProcName,sCalcProName,sSaveProNameBefore).
The Java codebase calls this concept "module", "model", "models", and
"modle" (typo, common). The variable sModelsId and method
getModelConfigByModleId both take a module sId, despite the naming.
See the naming caution in Slice 1.
Form
The screen layout for a module — header + N field definitions.
-
Master: one row per form in
gdsconfigformmaster. Carries the backing object (sTbName), backing-object type (sType∈{table, view, proc}), default SQL fragments (sSqlStr,sWhere,sOrder), grid behaviour (bGrd,iPageSize), jurisdiction column. -
Slave: one row per field in
gdsconfigformslave. Carries the field name (sName— matches a column in the backing object), control type (sControlName), display labels, validation rules, default value, dropdown SQL, button instructions. - A module is linked to its form via
gdsconfigformmaster.sParentId = gdsmodule.sId— semantic FK, no enforcement. (Note:gdsmodule.sFormIdexists but is empty for most modules and is not the canonical link.)
The form is the user-visible artefact: when a PM "creates a screen" in
BACK, what they're really doing is INSERTing a gdsconfigformmaster row
plus 5-50 gdsconfigformslave rows.
Virtual table
xly's term (and table prefix) for a "table" that is itself defined as
metadata, not as a CREATE TABLE statement.
- One row per virtual table in
gdsconfigtbmaster. - One row per virtual column in
gdsconfigtbslave.
Virtual tables are how PMs declare "I want this kind of thing" without asking an engineer. Most virtual tables back to a real physical table (the framework supports the migration step, or it pre-creates a generic "wide" table the PM populates), but the abstraction the runtime sees is the metadata declaration, not the underlying storage.
This is distinct from a database view: a virtual table is metadata; a
view is a CREATE VIEW SQL object. Both can back a form (via
gdsconfigformmaster.sType = 'table' or 'view'). See Slice 3
for the view-backed case.
How they fit together
gdsmodule (module, 1 row)
└── (joined via sParentId)
gdsconfigformmaster (form-master, 1 row per form)
├── gdsconfigformslave (fields, N rows)
├── gdsconfigformcustomslave (per-tenant fields, N or 0)
└── gdsconfigformuserslave (per-user tweaks, N or 0)
gdsmodule.sName → registered route in gdsroute (URL whitelist)
gdsmodule.sFormId → (mostly empty — historical)
Every form has exactly one module. Every module should have at most one
form, but a few have several gdsconfigformmaster rows pointing at the
same sParentId — those represent screens with multiple panels or
sub-tabs.
Three nouns, one engine
The runtime — BusinessBaseController and BusinessBaseServiceImpl,
documented in Slice 1 — knows how to
render any module / form / virtual-table combination. There is no
per-module Java code. PMs creating new modules are creating new rows;
they are not creating new code paths.