Commit 4ce526064767aacf74c93b9b07228e10fa29db28

Authored by zichun
1 parent 84b99a3d

docs: en wiki — add BI / KPI / Charts engine chapter

User asked "Is there a BI engine?" Investigation found a substantial
metadata-driven BI layer that the wiki had no dedicated coverage for.

New page reference/maintainer/bi-engine.md:
- Charts: gdsconfigcharmaster (3,006 rows) + slave (1,951) +
  CharServiceImpl (2,219 lines, one of the heaviest in
  xlyBusinessService). 11 chart types catalogued by sCharType
  distribution: Div(1558)/sLabel(1143)/Progress(137)/sPie(52)/
  commonList(45)/sColumnarGroup(30)/sColumnar(28)/sBrokenLine(5)/
  sBar(3)/ColorBlock(3)/sGauge(2).
- 20 Sp_chart_* aggregation procs catalogued by domain (homepage
  cards, today/month sales, financial, equipment/shop-floor).
- 6 /indexPage/commonChar dashboard modules listed by sId+name.
- KPI subsystem: 6 kpi* tables (kpimaster=124,524 rows live),
  KpiServiceImpl (833 lines), BusinessModelKpiServiceImpl (901),
  FlushModleKpiThread, 2 Sp_KPI_* procs + spKPImodule.
- Render flow end-to-end (SPA → getModelBysId → CharServiceImpl
  → generic proc dispatch → ECharts).
- Customer-override KPI examples under script/客户/ noted.
- Explicit "what this is not": not self-service BI, not real-time
  analytics, not OLAP-cube-backed.
- Added to mkdocs nav under Reference (Maintainer).

Tech-stack.md correction:
- The OLAP4J row previously claimed "1 file in xlyPersist imports
  org.olap4j.*". Empirical re-grep returns ZERO Java imports of
  org.olap4j anywhere in source. The jars are classpath dead weight
  (the xmlaserver line is even commented out in build.gradle).
  Updated row to reflect the actual state and link to bi-engine.md.
en/docs/reference/maintainer/bi-engine.md 0 → 100644
  1 +# BI / KPI / Charts engine
  2 +
  3 +xly does **not** ship a generic OLAP / cube engine (no Mondrian, no
  4 +Saiku, no MDX; the bundled `olap4j-1.2.0.jar` has zero Java imports
  5 +and is dead weight — see [tech-stack.md](tech-stack.md#3-cache-in-memory)
  6 +note on OLAP4J).
  7 +
  8 +What xly *does* ship is a **homebrewed metadata-driven dashboard +
  9 +KPI layer** built on the same primitives as everything else in the
  10 +framework: rows in `gds*` metadata tables pointing at `Sp_*` stored
  11 +procedures, rendered through generic Java services. This page maps it
  12 +end-to-end.
  13 +
  14 +## Three pieces
  15 +
  16 +| Piece | Surface | Backing tables | Service |
  17 +|---|---|---|---|
  18 +| **Charts** (cards, bar/line/pie/gauge widgets, dashboards) | `/indexPage/commonChar` modules in FROUNT; 图表配置 admin in BACK | `gdsconfigcharmaster` (3,006 rows), `gdsconfigcharslave` (1,951 rows) | `CharServiceImpl` (2,219 lines, one of the heaviest in xlyBusinessService) |
  19 +| **KPI** (per-employee / per-module performance scoring) | KPI screens in BACK / FROUNT (e.g., `行为KPI项目设置`, `5.经营KPI分析`, `异常清除KPI任务表`) | `kpimaster` (124,524 rows), `kpidetail` (1,308), `kpimodule` (44), `kpimoduleuser`, `kpimoduleuserday`, `kpislavel` | `KpiServiceImpl` (833 lines, in `xlyBusinessService/.../KPIService/`) + `BusinessModelKpiServiceImpl` (901 lines) + `FlushModleKpiThread` (background refresh) |
  20 +| **Pre-baked aggregation procs** | Invoked by chart rows | n/a | 20 `Sp_chart_*` procedures + 2 `Sp_KPI_*` procedures + `spKPImodule` |
  21 +
  22 +## Charts: how a dashboard renders
  23 +
  24 +A chart in xly is a row in `gdsconfigcharmaster` with this shape (key columns):
  25 +
  26 +| Column | Role |
  27 +|---|---|
  28 +| `sId` | Chart id |
  29 +| `sParentId` | The owning module (`gdsmodule.sId`) |
  30 +| `sChinese` / `sEnglish` / `sBig5` | Chart title |
  31 +| `sCharType` | Widget type — see distribution below |
  32 +| `sProcedureName` | The stored procedure that produces the chart's data |
  33 +| `sProcedureParam` | JSON parameter spec for the proc |
  34 +| `iWidth` | Layout span (24-column grid) |
  35 +
  36 +`sCharType` distribution in the live dev DB:
  37 +
  38 +| `sCharType` | Count | What it renders |
  39 +|---|---:|---|
  40 +| `Div` | 1558 | Container / layout-only block |
  41 +| `sLabel` | 1143 | Single-value text card (e.g., "今日销售额: ¥X") |
  42 +| `Progress` | 137 | Progress bar |
  43 +| `sPie` | 52 | Pie chart |
  44 +| `commonList` | 45 | Embedded data grid (re-uses the universal grid) |
  45 +| `sColumnarGroup` | 30 | Grouped bar chart |
  46 +| `sColumnar` | 28 | Single-series bar chart |
  47 +| `sBrokenLine` | 5 | Line chart |
  48 +| `sBar` | 3 | Horizontal bar chart |
  49 +| `ColorBlock` | 3 | Color-coded heatmap-style block |
  50 +| `sGauge` | 2 | Gauge / dial widget |
  51 +
  52 +Slave rows (`gdsconfigcharslave`) carry the per-series / per-column
  53 +breakout for charts that need multiple data series.
  54 +
  55 +The runtime path:
  56 +
  57 +```
  58 +SPA opens a /indexPage/commonChar?sModelsId=<dashboard module id>
  59 + │
  60 + ▼
  61 +GET /xlyEntry/business/getModelBysId/<id>
  62 + → returns the dashboard's metadata composite (formData includes
  63 + the chart layout from gdsconfigcharmaster + slave rows)
  64 + │
  65 + ▼
  66 +For each chart:
  67 + POST /xlyEntry/business/getXxx (CharServiceImpl method) with the
  68 + chart's sProcedureName + sProcedureParam
  69 + → CharServiceImpl invokes the named Sp_chart_* proc through
  70 + generic procedure dispatch
  71 + │
  72 + ▼
  73 +SPA renders each card using ECharts (frontend), one card per chart row
  74 +```
  75 +
  76 +## The 20 `Sp_chart_*` procs
  77 +
  78 +| Proc | What it computes |
  79 +|---|---|
  80 +| `Sp_chart_home_11`, `Sp_chart_home_13` | Homepage dashboard cards |
  81 +| `Sp_chart_TodayOrder`, `Sp_chart_TodayOrder_hm`, `Sp_chart_ThisMonthQty`, `Sp_chart_MonthOrder`, `Sp_chart_MonthTeamQty` | Today / current-month order counts and team output |
  82 +| `Sp_chart_TodayProfit`, `Sp_chart_MonthProfit`, `Sp_chart_TodayReceivables`, `Sp_chart_TodayReceive`, `Sp_chart_expenses` | Financial: profit, receivables, expense rollups |
  83 +| `Sp_chart_EquipmentLoad`, `Sp_chart_EquipmentLoad1`, `Sp_chart_EquipmentLod1`, `Sp_chart_EquipmentLast`, `Sp_chart_sMachine_speed`, `Sp_chart_Bottleneck` | Shop-floor: equipment utilisation, last-running state, current bottleneck |
  84 +| `Sp_chart_OrderProcess`, `Sp_chart_WorkOrderProcess` | Order / work-order progress timelines |
  85 +
  86 +Each follows the standard `(IN sLoginId, IN sBrId, IN sSuId, ...) →
  87 +result-set` shape so generic dispatch can call it. The
  88 +[multi-tenant scoping](../../concepts/multi-tenancy.md) flows through
  89 +naturally — every chart is automatically tenant-filtered.
  90 +
  91 +## Pre-built dashboard modules in this dev DB
  92 +
  93 +`/indexPage/commonChar` is the shared route. The dev DB has 6 modules
  94 +mapped to it:
  95 +
  96 +| Module sId | 中文 |
  97 +|---|---|
  98 +| `19211681019715464089035510` | 销售图表分析 (Sales chart analysis) |
  99 +| `19211681019715481435115760` | 财务图表分析 (Financial chart analysis) |
  100 +| `19211681019715481435298200` | 生产图表分析 (Production chart analysis) |
  101 +| `19211681019715708435449190` | 销售大数据分析 ("sales big-data analysis") |
  102 +| `19211681019715708471874620` | 采购大数据分析 (Procurement big-data analysis) |
  103 +| `101251240115015889205266000` | 采购价格分析查询 (Procurement price analysis) |
  104 +
  105 +All six are metadata-driven via `gdsconfigcharmaster` rows — no Java
  106 +code change needed to add or modify them.
  107 +
  108 +## KPI subsystem
  109 +
  110 +`kpi*` is a **per-employee performance-scoring** layer separate from
  111 +the chart rendering. The shape:
  112 +
  113 +| Table | Role | Live row count |
  114 +|---|---|---:|
  115 +| `kpimaster` | Per-employee per-period KPI rollup. The volume table — one row per employee per scored event. | 124,524 |
  116 +| `kpidetail` | Detail rows backing each `kpimaster` aggregate. | 1,308 |
  117 +| `kpimodule` | KPI definitions — which modules / metrics participate. | 44 |
  118 +| `kpimoduleuser` | Per-user KPI assignments. | 0 (unassigned in dev DB) |
  119 +| `kpimoduleuserday` | Daily KPI bucket per user. | 1 |
  120 +| `kpislavel` | KPI level / band definitions. | 0 |
  121 +
  122 +Java side:
  123 +
  124 +- `KpiServiceImpl.java` (833 lines, in `xlyBusinessService/.../KPIService/`) — the read/write API for KPI events.
  125 +- `BusinessModelKpiServiceImpl.java` (901 lines) — the computation layer that turns business-event data into KPI rows.
  126 +- `FlushModleKpiThread.java` — background recompute worker.
  127 +- `KpimasterCloum.java` enum (xlyPersist) — column-name constants.
  128 +
  129 +Procs:
  130 +
  131 +- `Sp_KPI_DetailByEmployee` — per-employee detail report.
  132 +- `Sp_KPI_SumByEmployee` — per-employee summary rollup.
  133 +- `spKPImodule` — recompute KPI for a module.
  134 +
  135 +There is also a sizable customer override under
  136 +`script/客户/`: e.g., `script/标版/30100101/spKPImodule.sql` and
  137 +several `Sp_SalesOrder_Kpi*` procs (matches the
  138 +[per-customer SQL override channel](../../slices/05-customer-sql-override.md)
  139 +— customers who want different KPI rules ship their own proc).
  140 +
  141 +## Why this matters
  142 +
  143 +xly's BI layer demonstrates the data-driven thesis at scale:
  144 +
  145 +1. **Adding a new dashboard card requires no Java change** — a PM
  146 + inserts a `gdsconfigcharmaster` row pointing at a `Sp_chart_*` proc,
  147 + sets `sCharType` and `iWidth`, the SPA picks it up on the next
  148 + `getModelBysId` cache miss.
  149 +2. **Adding a new chart proc** does require a SQL author (the proc
  150 + has to follow the standard tenant-scoped shape so generic dispatch
  151 + can call it through `CharServiceImpl`).
  152 +3. **No OLAP cube, no MDX, no semantic layer.** Each chart is a
  153 + purpose-built SQL stored procedure. This trades reusability for
  154 + simplicity — perfect-fit aggregations, no general-purpose ad-hoc
  155 + query builder.
  156 +
  157 +## What this is *not*
  158 +
  159 +- **Not a self-service BI tool.** Customers cannot point at any
  160 + table and build a chart through drag-and-drop; new charts require
  161 + a SQL stored procedure and an admin who knows how to register the
  162 + metadata row.
  163 +- **Not real-time analytics infrastructure.** Charts run their procs
  164 + on cache miss against the OLTP MySQL schema. There is no separate
  165 + warehouse, no incremental aggregation pipeline, no streaming layer.
  166 + Heavy charts on large customers will execute heavy SQL on the live DB.
  167 +- **Not column-store / OLAP-engine-backed.** The `olap4j` jars in
  168 + `xlyPersist/build.gradle` have zero Java imports — they're
  169 + classpath-only dead weight. xly uses MySQL's regular row-store via
  170 + MyBatis through generic procedure dispatch.
en/docs/reference/maintainer/tech-stack.md
@@ -120,7 +120,7 @@ third-party code. @@ -120,7 +120,7 @@ third-party code.
120 | commons-jexl3 | 3.1 | `xlyPersist/build.gradle` | (Pulled in by jxls; no direct imports detected.) | 120 | commons-jexl3 | 3.1 | `xlyPersist/build.gradle` | (Pulled in by jxls; no direct imports detected.) |
121 | EasyExcel | 4.0.3 (local jars: `easyexcel-4.0.3.jar` + `-support-4.0.3.jar` + `-core-4.0.3.jar`) | `xlyPersist/build.gradle` | 10 files in `xlyBusinessService/src/` import `com.alibaba.excel.*`. | 121 | EasyExcel | 4.0.3 (local jars: `easyexcel-4.0.3.jar` + `-support-4.0.3.jar` + `-core-4.0.3.jar`) | `xlyPersist/build.gradle` | 10 files in `xlyBusinessService/src/` import `com.alibaba.excel.*`. |
122 | JasperReports | `jasperreports-6.0.0.jar` + `jasperreports-fonts-6.0.0.jar` (local jars) | `xlyPersist/build.gradle` | 11 files import `net.sf.jasperreports.*` (xlyPersist=5, xlyEntry=3, xlyBusinessService=3). | 122 | JasperReports | `jasperreports-6.0.0.jar` + `jasperreports-fonts-6.0.0.jar` (local jars) | `xlyPersist/build.gradle` | 11 files import `net.sf.jasperreports.*` (xlyPersist=5, xlyEntry=3, xlyBusinessService=3). |
123 -| OLAP4J | `olap4j-1.2.0.jar` + `olap4j-xmlaserver-1.2.0.jar` (local jars) | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `org.olap4j.*`. | 123 +| OLAP4J | `olap4j-1.2.0.jar` + `olap4j-xmlaserver-1.2.0.jar` (local jars) | `xlyPersist/build.gradle` (the `-xmlaserver` line is also commented out) | **0 Java imports of `org.olap4j.*` anywhere in source.** Dead jars on the classpath; xly's BI/dashboard layer ([bi-engine.md](bi-engine.md)) is stored-proc-driven, not OLAP-cube-driven. |
124 | ZXing | core 3.4.0 + javase 3.4.0 | `xlyPersist/build.gradle` | 5 files import `com.google.zxing.*` (xlyPersist=4, xlyEntry=1). | 124 | ZXing | core 3.4.0 + javase 3.4.0 | `xlyPersist/build.gradle` | 5 files import `com.google.zxing.*` (xlyPersist=4, xlyEntry=1). |
125 | Barcode4J | `barcode4j-light` 2.0 | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `org.krysalis.barcode4j.*`. | 125 | Barcode4J | `barcode4j-light` 2.0 | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `org.krysalis.barcode4j.*`. |
126 | Pinyin4j | 2.5.0 | `xlyPersist/build.gradle` | 1 file: `xlyPersist/src/main/java/com/xly/utils/ChineseCharacterUtil.java`. | 126 | Pinyin4j | 2.5.0 | `xlyPersist/build.gradle` | 1 file: `xlyPersist/src/main/java/com/xly/utils/ChineseCharacterUtil.java`. |
en/mkdocs.yml
@@ -113,6 +113,7 @@ nav: @@ -113,6 +113,7 @@ nav:
113 - "SQL templates (xlyEntry/templesql/)": reference/maintainer/sql-templates.md 113 - "SQL templates (xlyEntry/templesql/)": reference/maintainer/sql-templates.md
114 - "Multi-service deployment": reference/maintainer/deployment.md 114 - "Multi-service deployment": reference/maintainer/deployment.md
115 - "Metadata-management services (xlyManage)": reference/maintainer/management-services.md 115 - "Metadata-management services (xlyManage)": reference/maintainer/management-services.md
  116 + - "BI / KPI / Charts engine": reference/maintainer/bi-engine.md
116 - "Activiti integration": reference/maintainer/activiti.md 117 - "Activiti integration": reference/maintainer/activiti.md
117 - 5. API Reference: 118 - 5. API Reference:
118 - api-reference/index.md 119 - api-reference/index.md