request-lifecycle.md
7.9 KB
The metadata-driven request lifecycle
The diagram you'll come back to. Every metadata-driven page in xly follows this same flow; once you've internalised it, the rest of the framework is variations on a theme.
The flow
┌──────────────────────────────────────────────────────────────────────┐
│ Browser │
│ 1. Loads SPA shell at any URL allowed by gdsroute (URL whitelist) │
│ 2. User clicks a sidebar item or navigates within the SPA │
│ 3. SPA decides which module to load → calls /business/... │
└──────────────────────────────────────────────────────────────────────┘
│
│ GET /xlyEntry/business/getModelBysId/{moduleId}
│ ?sModelsId={moduleId}
▼
┌──────────────────────────────────────────────────────────────────────┐
│ xlyEntry — BusinessBaseController.getModelBysId() │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ RequestAddParamUtil.addParams(params, userInfo) │ │
│ │ → sBrandsId, sSubsidiaryId, sUserId, sLanguage, … │ │
│ │ → tenant scope is now baked into every downstream query │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ BusinessBaseService.getModelBysId(map) │
│ │ │
│ ├── load gdsmodule row (the module) │
│ ├── load gdsconfigformmaster row(s) │
│ │ (joined to module via sParentId) │
│ ├── load gdsconfigformslave rows │
│ │ (joined to form-master via sParentId) │
│ ├── merge gdsconfigformpersonalize (per tenant) │
│ ├── merge gdsconfigformcustomslave (per tenant) │
│ ├── load gdsjurisdiction (skipped for ADMIN) │
│ ├── load gdsformconst (form-level constants) │
│ ├── load sysbillnosettings (document-numbering) │
│ └── load sysreport rows linked to this form │
└──────────────────────────────────────────────────────────────────────┘
│
│ Returns one composite map:
│ { formData, gdsformconst, gdsjurisdiction,
│ billnosetting, report }
▼
┌──────────────────────────────────────────────────────────────────────┐
│ Browser SPA │
│ Renders the form using formData; populates dropdowns from │
│ gdsformconst and per-control SQL fetched separately │
│ │
│ Calls /business/getBusinessDataByFormcustomId/{formId} │
│ with sModelsId={moduleId} to load the actual rows │
└──────────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────┐
│ xlyEntry — BusinessBaseController.getBusinessDataByFormcustomId() │
│ │
│ Composes parameterised SQL from formMaster.sSqlStr / sWhere / │
│ sOrder, with sBrandsId / sSubsidiaryId injected; │
│ runs against the form's backing object (table | view | proc). │
└──────────────────────────────────────────────────────────────────────┘
│
▼
User sees the grid
The five-key composite
getModelBysId returns one Java Map with these keys, in this order:
| Key | Source | Used by the SPA for |
|---|---|---|
formData |
gdsmodule ⋈ gdsconfigformmaster ⋈ gdsconfigformslave (+ overlays) |
The form layout itself — every field, control, label, validation rule |
gdsformconst |
gdsformconst rows scoped by tenant + language |
Form-level constants — labels, defaults, dropdown text |
gdsjurisdiction |
gdsjurisdiction rows for the user's role |
Per-button and per-data permissions |
billnosetting |
sysbillnosettings row for this module |
Document-numbering rules (work-order numbers, quotation numbers) |
report |
sysreport rows linked to this form |
Print templates (Excel via jxls, PDF via iText) |
What's not in this lifecycle
A few things readers expect to find here but don't:
-
The "save" path. Save is its own endpoint
(
POST /business/addUpdateDelBusinessData), bundling add+update+delete in one request. See Slice 1. -
The "open existing row for edit" fetch. Same endpoint as the grid
load (
getBusinessDataByFormcustomId) but with the row'ssIdin the body — the handler branches on whether the body asks for one row or many. -
Workflow steps. When a module has an active approval workflow
(
bCheck = 1, populatedsVersionFlowId, deployed Activiti process), additional steps interleave. None of those tables are populated in this dev DB; see Slice 7 (deferred). -
Cache invalidation. When BACK changes a metadata row, a JMS message
invalidates cached copies on every running node —
ConsumerChangeGdsModuleThreadinxlyErpJmsConsumer. Outside the request flow but adjacent to it.
Variations covered by other slices
- Slice 1 — the canonical instance, with observed network traffic.
- Slice 2 — how the multi-tenant filter threads through every step.
- Slice 3 — view-backed instead of table-backed.
-
Slice 4 — the
gdsconfigformcustomslavemerge step. - Slice 5 — when a stored procedure body has been replaced for a specific tenant.
Read this page once and keep it open
If a future chapter uses a term you don't recognise, it almost certainly refers to one of the boxes in the diagram above. Come back here.