You need to sign in before continuing.
Commit 568e3c49d8ba3b7bba47f7b56fe4e0c304a59d46
1 parent
19f073a9
Audit wiki against live code/DB; regenerate catalog; add API Reference
Verified every factual claim in the hand-written prose against the
codebase under ../xly/ and the live xlyweberp_saas_ai schema, and fixed
the drift:
- semantic-fk: clarified — zero FKs on xly tables; the ones that exist
are all on bundled Activiti / Quartz schemas, which the runtime
doesn't join through.
- multi-tenancy / runtime / slice 2: corrected RequestAddParamUtil shape
(16 keys, 56 lines), noted the parallel xlyApi copy.
- slice 1: corrected line ranges for addUpdateDelBusinessData;
clarified that sTableNameList is a cache-invalidation gate, not an
authorisation gate; corrected the gdsroute claim — unregistered paths
are NOT 404'd server-side, the SPA uses gdsroute as a client-side
whitelist (web-verified).
- runtime: fixed controller package paths
(Gdsmodule/Gdsconfigform/Gdsconfigtb live in systemweb/, not
businessweb/); added CheckFlowController.
- sql-templates / proc-dispatch: 8 scaffolds, not 7 (sSqlStr.sql).
- master-slave: removed table names that don't exist (accOrderCostAnalysisMaster,
quoQuotationCalc, mftWorkOrderCalc, mftWorkOrderSlaveMoney);
added the *_tmp family that does.
- permissions: full rewrite. The original page described
gdsjurisdiction as a per-(module, role, button) rule table backed by
empty plat_base_authority_* lookups; reality is gdsjurisdiction is a
per-module catalog of buttons/actions, with sysjurisdiction carrying
the actual role/user grants.
- Removed environment-specific facts (row counts, sizes, timestamps,
per-DB enumerations) so the wiki documents the framework, not one
particular DB snapshot.
Auto-catalog generator (en/scripts/gen_catalog.py):
- Rewritten to query MySQL directly via ~/.my.cnf (replaces the
recon/*.tsv pipeline).
- Stripped ephemeral fields from output (Rows, Data size, Created,
Updated on tables; Created, Last altered on routines; Definer on
views).
- Strips the schema-name prefix from VIEW_DEFINITION so view bodies
are portable across deployments.
- Wipes and rewrites docs/auto-catalog/{tables,views,procedures,functions}/
on each run.
- Auto-catalog regenerated.
New API Reference chapter (5):
- concepts/api-surface.md introduces the three-tier design (xlyEntry
internal, xlyApi external, xlyInterface webhooks).
- api-reference/{index,internal,external,webhooks,messaging}.md cover
each surface, with the data-driven /api/invoke{sApiCode} pattern,
sysapi schema, token flow, and the SpringFox Swagger UI location on
xlyInterface.
- mkdocs nav: chapters renumbered (Auto-Catalog → 6, Glossary → 7,
Contributing → 8); glossary/contributing wrapped as section indexes
to render correctly under navigation.sections.
Other:
- Bilingual top-level README (Chinese + English).
- requirements.txt: pymysql added for the new generator.
Showing
3112 changed files
with
1945 additions
and
9086 deletions
Too many changes to show.
To preserve performance only 100 of 3112 files are displayed.
README.md
| 1 | +# xly ERP 框架 Wiki | |
| 2 | + | |
| 3 | +本仓库包含 xly ERP 框架 Wiki 的两个语言版本。 | |
| 4 | + | |
| 5 | +简体中文文档由英文版翻译得到;如果中英文内容冲突,以英文版为准。 | |
| 6 | + | |
| 7 | +```text | |
| 8 | +xly-wiki/ | |
| 9 | +├── en/ 英文 MkDocs 项目 | |
| 10 | +├── zh/ 简体中文 MkDocs 项目 | |
| 11 | +└── site/ 共享生成输出,已被 git 忽略 | |
| 12 | +``` | |
| 13 | + | |
| 14 | +## 构建 | |
| 15 | + | |
| 16 | +```bash | |
| 17 | +.venv/bin/mkdocs build -f en/mkdocs.yml | |
| 18 | +.venv/bin/mkdocs build -f zh/mkdocs.yml | |
| 19 | +``` | |
| 20 | + | |
| 21 | +输出目录: | |
| 22 | + | |
| 23 | +```text | |
| 24 | +site/en/ | |
| 25 | +site/zh/ | |
| 26 | +``` | |
| 27 | + | |
| 28 | +## 本地预览 | |
| 29 | + | |
| 30 | +单独预览任一语言: | |
| 31 | + | |
| 32 | +```bash | |
| 33 | +.venv/bin/mkdocs serve -f en/mkdocs.yml | |
| 34 | +.venv/bin/mkdocs serve -f zh/mkdocs.yml | |
| 35 | +``` | |
| 36 | + | |
| 37 | +要测试语言切换按钮,需要先构建两种语言,并从共享输出目录启动静态服务: | |
| 38 | + | |
| 39 | +```bash | |
| 40 | +.venv/bin/mkdocs build -f en/mkdocs.yml | |
| 41 | +.venv/bin/mkdocs build -f zh/mkdocs.yml | |
| 42 | +python3 -m http.server 8000 -d site | |
| 43 | +``` | |
| 44 | + | |
| 45 | +然后打开 `http://127.0.0.1:8000/zh/` 或 `http://127.0.0.1:8000/en/`。 | |
| 46 | + | |
| 47 | +静态托管时发布共享的 `site/` 目录。 | |
| 48 | + | |
| 49 | +--- | |
| 50 | + | |
| 1 | 51 | # xly ERP Framework Wiki |
| 2 | 52 | |
| 3 | 53 | This repository contains both language versions of the xly ERP framework wiki. |
| ... | ... | @@ -42,6 +92,6 @@ To test the language switcher, build both languages and serve the shared output |
| 42 | 92 | python3 -m http.server 8000 -d site |
| 43 | 93 | ``` |
| 44 | 94 | |
| 45 | -Then open `http://127.0.0.1:8000/en/` or `http://127.0.0.1:8000/zh/`. | |
| 95 | +Then open `http://127.0.0.1:8000/zh/` or `http://127.0.0.1:8000/en/`. | |
| 46 | 96 | |
| 47 | 97 | For static hosting, publish the shared `site/` directory. | ... | ... |
en/docs/api-reference/external.md
0 → 100644
| 1 | +# External API (`xlyApi`) | |
| 2 | + | |
| 3 | +`xlyApi` is the API surface external integrators consume. It runs as | |
| 4 | +its own Spring Boot WAR (entry class | |
| 5 | +`xlyApi/src/main/java/com/xly/ApiApplicationBoot.java`) at context-path | |
| 6 | +`/xlyApi`, with its own `application-*.yml` files. | |
| 7 | + | |
| 8 | +The defining design choice: **most external endpoints are not hard-coded | |
| 9 | +in Java — they are rows in `sysapi`**. New external APIs are *registered | |
| 10 | +as data*, like the rest of xly. The runtime's job is to look up the | |
| 11 | +`sApiCode`, validate the caller, and execute whatever the metadata says. | |
| 12 | + | |
| 13 | +## The data-driven dispatcher — `/api/invoke/{sApiCode}` | |
| 14 | + | |
| 15 | +The single most important endpoint: | |
| 16 | + | |
| 17 | +``` | |
| 18 | +POST /xlyApi/api/invoke/{sApiCode} | |
| 19 | +Authorization: Bearer <token> (or query param ?authorizationt=<token>) | |
| 20 | +Content-Type: application/json | |
| 21 | +{ ...request body, passed through as `sBody` to the handler... } | |
| 22 | +``` | |
| 23 | + | |
| 24 | +Handler: `ApiController.invoke()` at | |
| 25 | +`xlyApi/src/main/java/com/xly/api/web/ApiController.java`. | |
| 26 | + | |
| 27 | +The flow: | |
| 28 | + | |
| 29 | +1. Read the `Authorization` header (fallback: `authorizationt` query | |
| 30 | + parameter). | |
| 31 | +2. Look up the `sysapi` row keyed by `sApiCode` (via | |
| 32 | + `ApiServiceImpl.invoke` → | |
| 33 | + `SELECT … FROM sysapi WHERE sApiCode = #{sApiCode}`). | |
| 34 | +3. If the row's `bHasToken` flag is set, validate the token against | |
| 35 | + `sysapithirdtoken` (or the equivalent token store the row points at). | |
| 36 | +4. Run the SQL template stored in `sysapi.sDataSql` with the request | |
| 37 | + body merged into the parameter map. | |
| 38 | +5. Log the call to `sysapilog`. | |
| 39 | +6. Return the result wrapped in `AjaxResult`. | |
| 40 | + | |
| 41 | +So adding a new external API is an admin/PM task: insert a row into | |
| 42 | +`sysapi`, supply the SQL template, set the flags, give the integrator | |
| 43 | +the `sApiCode` and a token. No Java code change. | |
| 44 | + | |
| 45 | +### `sysapi` columns of interest | |
| 46 | + | |
| 47 | +| Column | Meaning | | |
| 48 | +|---|---| | |
| 49 | +| `sApiCode` | The path variable consumers send. Must be unique per tenant. | | |
| 50 | +| `sApiName` | Human label. | | |
| 51 | +| `sApiUrl` / `sApiUrlRef` | Computed URL — `sApiUrlRef + sApiCode` — for outbound dispatches. | | |
| 52 | +| `sMethod` | The HTTP method this API expects (`GET`, `POST`, …). | | |
| 53 | +| `sHeader`, `sBody`, `sBodyNode`, `sBodyType` | Templates describing the inbound request shape. | | |
| 54 | +| `sDataSql` | The SQL template the runtime executes. References to `#{xxx}` are filled from request params. | | |
| 55 | +| `sDataTest`, `sDataTestNode` | Sample request/response used by the BACK API tester (`POST /api/apiTest`). | | |
| 56 | +| `bHasToken` | `1` → require a token in `Authorization`; `0` → public. | | |
| 57 | + | |
| 58 | +## API administration endpoints | |
| 59 | + | |
| 60 | +`/api/list/...`, `/api/data/...`, `/api/add`, `/api/edit`, `/api/remove` | |
| 61 | +are the admin surface for managing `sysapi` rows themselves (the BACK | |
| 62 | +"自定义接口" screen calls these). `POST /api/getSqlTemple` produces a | |
| 63 | +SQL skeleton for a given API name; `POST /api/apiTest` runs an end-to-end | |
| 64 | +dry-run against the test fixture in `sDataTest`. | |
| 65 | + | |
| 66 | +## Token endpoints — `/token/*` | |
| 67 | + | |
| 68 | +| Endpoint | Method | Purpose | | |
| 69 | +|---|---|---| | |
| 70 | +| `/token/getToken?corpid=&corpsecret=` | POST | Issue a bearer token for an integrator's `(corpid, corpsecret)` pair. | | |
| 71 | + | |
| 72 | +The token returned is what `/api/invoke/{sApiCode}` expects in | |
| 73 | +`Authorization`. The full implementation is in | |
| 74 | +`xlyApi/src/main/java/com/xly/api/web/TokenController.java` and its | |
| 75 | +service. | |
| 76 | + | |
| 77 | +For *third-party* tokens that xly itself fetches (so it can call | |
| 78 | +out-of-cluster APIs on behalf of a customer), see `/thirdtoken/*`, | |
| 79 | +backed by `sysapithirdtoken` (table comment: 第三方token获取接口). | |
| 80 | + | |
| 81 | +## Other curated surfaces | |
| 82 | + | |
| 83 | +These are smaller specialised APIs hosted in the same WAR: | |
| 84 | + | |
| 85 | +| Endpoint root | Controller | Purpose | | |
| 86 | +|---|---|---| | |
| 87 | +| `/online/api/{sApiCode}` | `OnlineController` | Read-only execution of a `sysapi` row (no write). Useful for public-data endpoints. | | |
| 88 | +| `/online/onlineword/{sApiCode}` | `OnlineController` | Variant returning a "word"-style template payload. | | |
| 89 | +| `/online/onlinelist`, `/online/getToken` | `OnlineController` | Listing of online APIs and their token issuance. | | |
| 90 | +| `/pro/get/{sProName}` | `ProContentController` | Fetch metadata about a stored procedure by name. | | |
| 91 | +| `/pro/getData/{sProName}` | `ProContentController` | Execute the named stored procedure and return its result-set. | | |
| 92 | +| `/pro/alert/{redisId}`, `/pro/getAlertValue/{redisId}` | `ProContentController` | Read alert/notification values keyed by Redis id. | | |
| 93 | +| `/pro/executeSql` | `ProContentController` | Execute a parameterised SQL template (admin-tier). | | |
| 94 | +| `/thirdparty/*` | `ThirdPartyController` | CRUD over third-party-API definitions and the `checkPartyApi` validator. Backed by `sysapithirdparty`. | | |
| 95 | +| `/thirdtoken/*` | `ThirdTokenController` | CRUD over outbound-token configs. Backed by `sysapithirdtoken`. | | |
| 96 | +| `/brand/*` | `BrandController` | CRUD over the partner-supplier list (`sysapibrand`). | | |
| 97 | +| `/json/*`, `/json/jsonEdit/{sDomId}` | `JsonController` | JSON-tree edit helpers used by the BACK API editor. | | |
| 98 | +| `/interfaceDefine/callthirdparty/{interfaceInvoke}` | `InterfaceController` | Dispatch an outbound call defined in `sysapithirdparty`. | | |
| 99 | +| `/gpt/chatGpt` | `GptController` | Pass-through for the experimental GPT/chat surface — out-of-scope of the framework wiki. | | |
| 100 | + | |
| 101 | +## Backing tables (DB-level surface) | |
| 102 | + | |
| 103 | +These tables hold the API metadata. All carry `sBrandsId` / | |
| 104 | +`sSubsidiaryId` for tenant scoping. | |
| 105 | + | |
| 106 | +| Table | Role | | |
| 107 | +|---|---| | |
| 108 | +| `sysapi` | API definitions used by `/api/invoke`. | | |
| 109 | +| `sysapilog` | Per-call audit log. | | |
| 110 | +| `sysapibrand` | Partner / supplier directory. | | |
| 111 | +| `sysapithirdparty` | Outbound third-party endpoint definitions. | | |
| 112 | +| `sysapithirdtoken` | Outbound third-party token configs. | | |
| 113 | +| `sysapidbtodb` | DB-to-DB sync API definitions. | | |
| 114 | +| `sysapidbtodblog` | DB-to-DB sync run log. | | |
| 115 | + | |
| 116 | +## How an integrator uses this | |
| 117 | + | |
| 118 | +A typical first integration: | |
| 119 | + | |
| 120 | +1. **Have an admin register your API.** Insert a row into `sysapi` (via | |
| 121 | + the BACK self-service screen or directly): pick `sApiCode`, write | |
| 122 | + `sDataSql`, set `bHasToken = 1` if you want token auth, save. | |
| 123 | +2. **Get a token.** `POST /xlyApi/token/getToken?corpid=<your_id>&corpsecret=<your_secret>`. | |
| 124 | +3. **Call the API.** `POST /xlyApi/api/invoke/<your_sApiCode>` with the | |
| 125 | + token in `Authorization` and your payload as the JSON body. | |
| 126 | +4. **Inspect the log.** `sysapilog` records every call, the response | |
| 127 | + `iStatus`, and the body. The BACK admin screen surfaces the same. | |
| 128 | + | |
| 129 | +## What this API is *not* | |
| 130 | + | |
| 131 | +- **Not OpenAPI-described** — the contract for any given `sApiCode` is | |
| 132 | + whatever its `sysapi.sDataSql` and `sBody` rows say. Get the spec | |
| 133 | + from the team that registered the API, not from a `/swagger` | |
| 134 | + endpoint here. | |
| 135 | +- **Not a thin wrapper over `xlyEntry`'s internal API** — these are | |
| 136 | + intentionally separate surfaces. Calling `/business/*` on `xlyEntry` | |
| 137 | + from outside is not supported. | |
| 138 | +- **Not the inbound webhook receiver** — push events from third | |
| 139 | + parties go through [`xlyInterface`](webhooks.md). | ... | ... |
en/docs/api-reference/index.md
0 → 100644
| 1 | +# 5. API Reference | |
| 2 | + | |
| 3 | +xly exposes three distinct HTTP surfaces, hosted in three separate Spring | |
| 4 | +Boot services. Each is documented on its own page below; the conceptual | |
| 5 | +overview lives in [concepts/api-surface](../concepts/api-surface.md). | |
| 6 | + | |
| 7 | +| Page | Service | Context path | Use when | | |
| 8 | +|---|---|---|---| | |
| 9 | +| [Internal API](internal.md) | `xlyEntry` | `/xlyEntry` | You are extending the SPA or maintaining the framework runtime. | | |
| 10 | +| [External API](external.md) | `xlyApi` | `/xlyApi` | You are integrating an outside system that calls xly. | | |
| 11 | +| [Webhooks](webhooks.md) | `xlyInterface` | `/xlyInterface` | A third-party system needs to push events into xly. | | |
| 12 | +| [Messaging](messaging.md) | `xlyEntry` + `xlyErpJms*` | n/a (ActiveMQ / RocketMQ) | An asynchronous, fan-out integration is more appropriate than a synchronous HTTP call. | | |
| 13 | + | |
| 14 | +## Reading order | |
| 15 | + | |
| 16 | +If you arrived here as an external integrator, start with | |
| 17 | +[External API](external.md). If you're a Java developer extending the | |
| 18 | +framework, start with [Internal API](internal.md) (most of the universal | |
| 19 | +CRUD machinery is documented in the | |
| 20 | +[Maintainer runtime chapter](../reference/maintainer/runtime.md); | |
| 21 | +this chapter cross-links to it). | |
| 22 | + | |
| 23 | +## Cross-cutting facts | |
| 24 | + | |
| 25 | +- **Auth.** Internal calls use the SPA's session cookie + the | |
| 26 | + `@CurrentUser` argument resolver. External calls use bearer tokens | |
| 27 | + obtained from `/xlyApi/token/getToken`. Webhooks have per-channel | |
| 28 | + conventions (signature header, query-param secret). | |
| 29 | +- **Tenant scoping.** Every authenticated controller method, in every | |
| 30 | + service, runs `RequestAddParamUtil.me().addParams(params, userInfo)` | |
| 31 | + before doing any work — see | |
| 32 | + [the multi-tenancy concept page](../concepts/multi-tenancy.md). A | |
| 33 | + request that bypasses this is a multi-tenant bug. | |
| 34 | +- **Logging.** External calls are logged to `sysapilog`; internal calls | |
| 35 | + use the framework's standard `syslog4j` setup; webhooks log to | |
| 36 | + whatever the per-channel handler chooses. | ... | ... |
en/docs/api-reference/internal.md
0 → 100644
| 1 | +# Internal API (`xlyEntry`) | |
| 2 | + | |
| 3 | +The `xlyEntry` service hosts the SPA's runtime API. It is the largest of | |
| 4 | +the three tiers — its controllers compile into the same WAR as the | |
| 5 | +framework's metadata-driven runtime, and most calls hit one of a handful | |
| 6 | +of universal endpoints that read or write any module. | |
| 7 | + | |
| 8 | +This API is **not a stable contract for external callers**. Endpoint | |
| 9 | +shapes change as the framework changes. External integrations belong on | |
| 10 | +the [External API](external.md). This page exists for maintainers and | |
| 11 | +SPA-extension authors. | |
| 12 | + | |
| 13 | +For the request-lifecycle and code-level walkthrough, see the | |
| 14 | +[Maintainer runtime chapter](../reference/maintainer/runtime.md). This | |
| 15 | +page is the catalog of HTTP entry points. | |
| 16 | + | |
| 17 | +## The universal CRUD surface — `/business/*` | |
| 18 | + | |
| 19 | +| Endpoint | Method | Purpose | | |
| 20 | +|---|---|---| | |
| 21 | +| `/business/getModelBysId/{moduleId}` | GET | Returns the form layout for a module — the five-key composite (`formData`, `gdsformconst`, `gdsjurisdiction`, `billnosetting`, `report`). | | |
| 22 | +| `/business/getBusinessDataByFormcustomId/{formId}` | POST | Returns rows of business data for a form, paginated. Branches to `getBusinessDataByGroup` when `sGroupList` is set. | | |
| 23 | +| `/business/getBusinessDataByIndex` | POST | First / last / next / previous-record navigation. | | |
| 24 | +| `/business/addBusinessData` | POST | Single insert. | | |
| 25 | +| `/business/addUpdateDelBusinessData` | POST | Bundled add+update+delete in one transactional call. The frontend names the target table directly via `sTable`. | | |
| 26 | +| `/business/getSelectDataBysControlId/{sId}` | POST | Dropdown population for a single control, by control `sId`. | | |
| 27 | +| `/business/getSelectLimit/{sId}` | POST | Paginated variant of the dropdown call. | | |
| 28 | + | |
| 29 | +These endpoints are documented in detail by [Slice 1](../slices/01-hello-world.md) | |
| 30 | +(`getModelBysId` + grid load + save) and | |
| 31 | +[Slice 3](../slices/03-report.md) (the view-backed read variant). The | |
| 32 | +handler classes are in | |
| 33 | +`xlyEntry/src/main/java/com/xly/web/businessweb/`. | |
| 34 | + | |
| 35 | +## Metadata-management endpoints | |
| 36 | + | |
| 37 | +For builder-side actions (creating modules, defining forms, declaring | |
| 38 | +virtual tables) there is a parallel surface in | |
| 39 | +`xlyEntry/src/main/java/com/xly/web/systemweb/`: | |
| 40 | + | |
| 41 | +| Endpoint root | Controller | Purpose | | |
| 42 | +|---|---|---| | |
| 43 | +| `/gdsmodule/*` | `GdsmoduleController` | Module-tree CRUD, including `getModuleTreePro`, `addGdsmodule`, `updateGdsmodule`. | | |
| 44 | +| `/gdsconfigform/*` | `GdsconfigformController` | Form-master and form-slave metadata CRUD. | | |
| 45 | +| `/gdsconfigtb/*` | `GdsconfigtbController` | Virtual-table master/slave metadata CRUD. | | |
| 46 | + | |
| 47 | +## Specialised runtime endpoints | |
| 48 | + | |
| 49 | +| Endpoint root | Controller | Purpose | | |
| 50 | +|---|---|---| | |
| 51 | +| `/configform/*` | `BusinessConfigformController` | Per-user / per-group display customization. | | |
| 52 | +| `/treegrid/*` | `BusinessTreeGridController` | Tree-grid endpoints (the proc-backed path is implemented in this branch). | | |
| 53 | +| `/procedureCall/*` | `GenericProcedureCallController` | Generic stored-procedure invocation by name + parameters — see [generic procedure dispatch](../reference/maintainer/proc-dispatch.md). | | |
| 54 | +| `/panel/*` | `ConfigformPanelController` | Panel-layout persistence in `gdsconfigformpanel`. | | |
| 55 | +| `/checkFlow/*` | `CheckFlowController` | Activiti workflow surface (approve / reject / view) — only meaningful in deployments that run a flow. | | |
| 56 | + | |
| 57 | +## Reporting and printing | |
| 58 | + | |
| 59 | +The print surface lives under `xlyEntry/src/main/java/com/xly/web/report/`: | |
| 60 | + | |
| 61 | +- `PrintReportController` — current jxls / iText print path. | |
| 62 | +- `PrintReportControllerOld` — legacy print path retained for older | |
| 63 | + templates. | |
| 64 | + | |
| 65 | +The frontend's "打印" / "导出" buttons hit these controllers, which load a | |
| 66 | +template from `sysreport`, run the matching view-backed query, and stream | |
| 67 | +a binary file back. See [Slice 3](../slices/03-report.md#6-printable-reports-when-present) | |
| 68 | +for the flow. | |
| 69 | + | |
| 70 | +## Authentication | |
| 71 | + | |
| 72 | +Every controller method that participates in business data is annotated | |
| 73 | +with `@Authorization` and receives a resolved `UserInfo` via | |
| 74 | +`@CurrentUser`. The session-to-`UserInfo` mapping is the framework's | |
| 75 | +own (cookie + Redis-backed session); see | |
| 76 | +[the multi-tenancy concept page](../concepts/multi-tenancy.md). | |
| 77 | + | |
| 78 | +A request that reaches a controller without authentication does not | |
| 79 | +get past `@Authorization`; if it does (e.g., an unannotated method), | |
| 80 | +that method also bypasses the universal tenant injection in | |
| 81 | +`RequestAddParamUtil` — and is therefore a multi-tenant bug. | |
| 82 | + | |
| 83 | +## What this API is *not* | |
| 84 | + | |
| 85 | +- **Not stable** — endpoint shapes change with the framework. | |
| 86 | +- **Not authenticated for outside callers** — there is no API-key flow | |
| 87 | + here; cookies/sessions are not what an integrator wants. | |
| 88 | +- **Not documented for self-service** — the surface is too large and | |
| 89 | + too generic to publish as an OpenAPI doc. External integrators get | |
| 90 | + the curated [External API](external.md) instead. | ... | ... |
en/docs/api-reference/messaging.md
0 → 100644
| 1 | +# Messaging (ActiveMQ / RocketMQ) | |
| 2 | + | |
| 3 | +Not every integration in xly is a synchronous HTTP call. The framework | |
| 4 | +runs two message brokers, each with a different role: | |
| 5 | + | |
| 6 | +| Broker | Used for | Producer | Consumer | | |
| 7 | +|---|---|---|---| | |
| 8 | +| **ActiveMQ / JMS** | Cache invalidation, in-cluster fan-out events. The metadata-change pipeline ([cache invalidation](../reference/maintainer/cache-invalidation.md)) rides on this. | `xlyErpJmsProductor` | `xlyErpJmsConsumer` | | |
| 9 | +| **RocketMQ** | Other integration flows where the ActiveMQ assumptions don't fit. | `RocketMQServiceImpl` (in `xlyBusinessService`) | (varies — service-specific) | | |
| 10 | + | |
| 11 | +This page is a pointer rather than a deep dive — exact queue names and | |
| 12 | +payloads are documented at the consumer-thread level in | |
| 13 | +`xlyErpJmsConsumer/src/main/java/com/xly/xlyerpjmsconsumer/`. | |
| 14 | + | |
| 15 | +## ActiveMQ / JMS — the cache-invalidation channel | |
| 16 | + | |
| 17 | +Producer-side queue declarations live in | |
| 18 | +`xlyErpJmsProductor/src/main/java/com/xly/xlyerpjmsproductor/config/P2pQueue.java`. | |
| 19 | +Notable destinations the framework uses today (read the file for the | |
| 20 | +full list): | |
| 21 | + | |
| 22 | +| Constant | Purpose | | |
| 23 | +|---|---| | |
| 24 | +| `ERP_JMS_ACTIVEMQ_CHANGE_GDS_MODULE` | "Module metadata changed" — triggers `ConsumerChangeGdsModuleThread` to bust the relevant Redis caches across nodes. See [Cache invalidation on metadata change](../reference/maintainer/cache-invalidation.md). | | |
| 25 | +| `ERP_JMS_ACTIVEMQ_CHANGE_ELE_CUSTOMER` | Customer-master change fan-out. | | |
| 26 | +| `ERP_JMS_ACTIVEMQ_CHANGE_ELE_EMPLOYEE` | Employee-master change fan-out. | | |
| 27 | +| `ERP_JMS_ACTIVEMQ_CHANGE_ELE_MACHINE` | Shop-floor machine-master change fan-out. | | |
| 28 | +| `ERP_JMS_ACTIVEMQ_UPD_SALE_ORDER`, `ERP_JMS_ACTIVEMQ_UPD_WORK_ORDER`, `ERP_JMS_ACTIVEMQ_UPD_PRODUCTION_REPORT` | "Document was updated" notifications consumed by background workers (totals recalculation, downstream invalidations). | | |
| 29 | +| `ERP_JMS_ACTIVEMQ_DEL_SALE_ORDER`, `ERP_JMS_ACTIVEMQ_DEL_WORK_ORDER`, `ERP_JMS_ACTIVEMQ_DEL_PRODUCTION_REPORT` | Document-delete notifications. | | |
| 30 | + | |
| 31 | +Each destination has a corresponding `Consumer*Thread` class under | |
| 32 | +`xlyErpJmsConsumer/.../thread/` that handles the message asynchronously. | |
| 33 | + | |
| 34 | +## RocketMQ — other flows | |
| 35 | + | |
| 36 | +`RocketMQServiceImpl` and its companion `RocketMQService` interface | |
| 37 | +sit in `xlyBusinessService/src/main/java/com/xly/service/`. They cover | |
| 38 | +non-cache-invalidation flows (for example, `MQCompensateServiceImpl` | |
| 39 | +handles compensation/retry semantics that ActiveMQ's destinations don't | |
| 40 | +express well). RocketMQ topics are configured per environment. | |
| 41 | + | |
| 42 | +## Manual cache-invalidation poke | |
| 43 | + | |
| 44 | +If a metadata change happens via raw SQL (no JMS event), the cache | |
| 45 | +across nodes will not bust automatically. The supported override is | |
| 46 | +`BusinessCleanRedisDataImpl` in `xlyBusinessService/.../service/impl/` — | |
| 47 | +it can publish an invalidation event directly. See | |
| 48 | +[cache invalidation on metadata change](../reference/maintainer/cache-invalidation.md) | |
| 49 | +for the broader troubleshooting path. | |
| 50 | + | |
| 51 | +## What this is *not* | |
| 52 | + | |
| 53 | +- **Not a public integration channel.** External integrators do not | |
| 54 | + publish or subscribe to these brokers. They are *internal* fan-out | |
| 55 | + for the cluster. | |
| 56 | +- **Not the only way to invalidate caches.** The HTTP write paths in | |
| 57 | + `xlyEntry` already publish JMS events when they should; the manual | |
| 58 | + poke is for edge cases. | ... | ... |
en/docs/api-reference/webhooks.md
0 → 100644
| 1 | +# Inbound Webhooks (`xlyInterface`) | |
| 2 | + | |
| 3 | +`xlyInterface` is the smallest of the three Spring Boot WARs. Its job is | |
| 4 | +to **receive HTTP requests pushed in from third-party systems** — | |
| 5 | +WeChat, partner factories, vendor portals — and route them to xly | |
| 6 | +handlers. Entry class | |
| 7 | +`xlyInterface/src/main/java/com/xly/InterfaceApplicationBoot.java`, | |
| 8 | +context-path `/xlyInterface`. | |
| 9 | + | |
| 10 | +This is the only one of the three services that ships **Swagger UI** — | |
| 11 | +the partner-facing audience benefits most from interactive try-it-out | |
| 12 | +documentation. The build pulls | |
| 13 | +`io.springfox:springfox-swagger-ui:2.9.2` and | |
| 14 | +`io.springfox:springfox-swagger2:2.9.2`. The UI is served at the | |
| 15 | +SpringFox default once the service is running: | |
| 16 | + | |
| 17 | +``` | |
| 18 | +http://<host>/xlyInterface/swagger-ui.html | |
| 19 | +``` | |
| 20 | + | |
| 21 | +(or the equivalent JSON descriptor at | |
| 22 | +`http://<host>/xlyInterface/v2/api-docs`). | |
| 23 | + | |
| 24 | +## The data-driven receiver — `/interfaceDefine/*` | |
| 25 | + | |
| 26 | +Mirror of the [external API's `/api/invoke`](external.md) pattern, but | |
| 27 | +for inbound calls: | |
| 28 | + | |
| 29 | +| Endpoint | Method | Purpose | | |
| 30 | +|---|---|---| | |
| 31 | +| `/interfaceDefine/invoke/{interfaceInvoke}` | POST | Dispatch an inbound payload to the handler that `{interfaceInvoke}` names. | | |
| 32 | +| `/interfaceDefine/callthirdparty/{interfaceInvoke}` | POST | Forward to a configured outbound endpoint. (Mirrors the `/interfaceDefine/callthirdparty/...` endpoint that also exists on `xlyApi`; the inbound side here is paired with the data-driven inbound dispatcher.) | | |
| 33 | + | |
| 34 | +Handler: `xlyInterface/src/main/java/com/xly/web/InterfaceController.java`. | |
| 35 | + | |
| 36 | +The `{interfaceInvoke}` path variable looks up a metadata row that | |
| 37 | +declares the SQL or stored procedure to run, the parameter mapping, and | |
| 38 | +the response shape. Same data-driven philosophy as the rest of xly: | |
| 39 | +new inbound endpoints are added by inserting rows, not by writing Java. | |
| 40 | + | |
| 41 | +## Hard-coded vendor receivers | |
| 42 | + | |
| 43 | +A small number of receivers don't go through `/interfaceDefine` because | |
| 44 | +they have to match a partner's fixed URL spec. | |
| 45 | + | |
| 46 | +| Endpoint | Method | Purpose | | |
| 47 | +|---|---|---| | |
| 48 | +| `/Push` | POST | Vendor (WeChat / similar) push receiver. | | |
| 49 | +| `/Pull` | POST | Vendor pull-pattern receiver. | | |
| 50 | +| `/getKey/{key}` | GET | Public key fetch for a partner-named `key`. | | |
| 51 | +| `/getKeyTest` | GET | Test-mode variant of `/getKey`. | | |
| 52 | +| `/send/sendQw` | POST | Enterprise-WeChat (企业微信) outbound message. | | |
| 53 | + | |
| 54 | +Handlers: `xlyInterface/src/main/java/com/xly/web/WX_VendorWeb.java` | |
| 55 | +and `xlyInterface/src/main/java/com/xly/wechat/test/SendQwController.java`. | |
| 56 | + | |
| 57 | +## Authentication | |
| 58 | + | |
| 59 | +Webhook auth varies by partner. There is no single token-issuance | |
| 60 | +endpoint here (unlike `xlyApi`). Each handler picks its own scheme: | |
| 61 | +signature header, query-param secret, or pre-shared key validation | |
| 62 | +against `sysapibrand`. Read the specific controller before integrating. | |
| 63 | + | |
| 64 | +## Where the metadata lives | |
| 65 | + | |
| 66 | +The `/interfaceDefine/*` dispatcher consults metadata rows that name | |
| 67 | +the inbound handler. Inspect `sysapi`-family tables (`sysapi`, | |
| 68 | +`sysapibrand`, `sysapithirdparty`) plus any `interface*` tables in the | |
| 69 | +schema's auto-catalog for the current handler set. The bookkeeping | |
| 70 | +overlaps with the [External API](external.md)'s — the two services | |
| 71 | +share the API-definition data even though they expose it on different | |
| 72 | +URLs. | |
| 73 | + | |
| 74 | +## What this service is *not* | |
| 75 | + | |
| 76 | +- **Not authenticated by xly's session cookie.** Third-party callers | |
| 77 | + do not have a user session. Auth is per-handler, not framework-wide. | |
| 78 | +- **Not for outbound calls.** Outbound dispatches (xly calling a | |
| 79 | + partner) go through `xlyApi`'s `/interfaceDefine/callthirdparty/*` | |
| 80 | + or `/thirdparty/*` controllers. The duplication is intentional: | |
| 81 | + inbound and outbound have very different security postures. | ... | ... |
en/docs/auto-catalog/functions/CALC_MATERIALS_SMAIL.md
en/docs/auto-catalog/functions/FUN_DISTINCTJSON_REMOVE_BYNAME.md
en/docs/auto-catalog/functions/FUN_GET_CALCPLAN_DATE_END.md
en/docs/auto-catalog/functions/FUN_GET_CALC_DATE.md
en/docs/auto-catalog/functions/FUN_GET_CALC_DATE_END.md
en/docs/auto-catalog/functions/FUN_GET_DATE_BC.md
en/docs/auto-catalog/functions/FUN_GET_DATE_BC_ADDTIME.md
en/docs/auto-catalog/functions/FUN_GET_DATE_BC_STARTDATE.md
en/docs/auto-catalog/functions/FUN_GET_DATE_BC_STARTDATE_NEW.md
en/docs/auto-catalog/functions/FUN_GET_DATE_BC_STARTDATE_NEWTYPE.md
en/docs/auto-catalog/functions/FUN_GET_DATE_BC_STARTDATE_NOW.md
en/docs/auto-catalog/functions/FUN_GET_DATE_DIFF_MINUTE.md
en/docs/auto-catalog/functions/FUN_GET_DATE_KT.md
en/docs/auto-catalog/functions/FUN_GET_DATE_KT_ADD.md
en/docs/auto-catalog/functions/FUN_GET_DATE_UKT.md
en/docs/auto-catalog/functions/FUN_GET_DATE_UKT_ADD.md
en/docs/auto-catalog/functions/FUN_GET_DATE_YX.md
en/docs/auto-catalog/functions/FUN_GET_DECOMPOSECUSTOMIZE.md
en/docs/auto-catalog/functions/FUN_GET_to_pinyin.md
en/docs/auto-catalog/functions/FUN_JSON_CHAR.md
en/docs/auto-catalog/functions/FUN_JSON_INT.md
en/docs/auto-catalog/functions/FUN_MATERIALS_SMAIL.md
en/docs/auto-catalog/functions/F_Gb2Big.md
en/docs/auto-catalog/functions/Fn_ParseParams.md
en/docs/auto-catalog/functions/Fn_find_modleAllId.md
en/docs/auto-catalog/functions/Fn_find_pinyin.md
en/docs/auto-catalog/functions/Fn_find_pinyin_copy1.md
en/docs/auto-catalog/functions/Fn_fristPinyin.md
en/docs/auto-catalog/functions/Fn_json_extract.md
en/docs/auto-catalog/functions/Fn_spit_length.md
en/docs/auto-catalog/functions/Fn_split_string.md
en/docs/auto-catalog/functions/Fun_AnalysisListJson.md
en/docs/auto-catalog/functions/Fun_AnalysisListJsonEnter.md
en/docs/auto-catalog/functions/Fun_AnalysisListJsonOld.md
en/docs/auto-catalog/functions/Fun_AnalysisListJsonTwo.md
en/docs/auto-catalog/functions/Fun_AnalysisListJson_copy1.md
en/docs/auto-catalog/functions/Fun_Cashier_GetMaterialsPrice.md
en/docs/auto-catalog/functions/Fun_Cashier_GetMaterialsPrice_Quo.md
en/docs/auto-catalog/functions/Fun_Cashier_GetMaterialsPrice_new.md
en/docs/auto-catalog/functions/Fun_Cashier_GetProductPrice.md
en/docs/auto-catalog/functions/Fun_Cashier_GetProductPrice_new.md
en/docs/auto-catalog/functions/Fun_Exclusion_algorithm.md
en/docs/auto-catalog/functions/Fun_FormulaReplace.md
en/docs/auto-catalog/functions/Fun_Formula_Process.md
en/docs/auto-catalog/functions/Fun_Gb2Big_ChineseToBig.md
en/docs/auto-catalog/functions/Fun_GetAddBillNo.md
en/docs/auto-catalog/functions/Fun_GetAddMapJson.md
en/docs/auto-catalog/functions/Fun_GetAuxiliaryQtyUnit.md
en/docs/auto-catalog/functions/Fun_GetBarId.md
en/docs/auto-catalog/functions/Fun_GetBillStatus.md
en/docs/auto-catalog/functions/Fun_GetBookStickQty.md
en/docs/auto-catalog/functions/Fun_GetCalcMaterialsKs.md
en/docs/auto-catalog/functions/Fun_GetCalcMaterialsKs1.md
en/docs/auto-catalog/functions/Fun_GetCh.md
en/docs/auto-catalog/functions/Fun_GetFatherProductId.md
en/docs/auto-catalog/functions/Fun_GetGb.md
en/docs/auto-catalog/functions/Fun_GetHumpDiff.md
en/docs/auto-catalog/functions/Fun_GetJson_Length.md
en/docs/auto-catalog/functions/Fun_GetLimitDate.md
en/docs/auto-catalog/functions/Fun_GetListByJson_ByKey.md
en/docs/auto-catalog/functions/Fun_GetListByJson_ByKey_split.md
en/docs/auto-catalog/functions/Fun_GetListByJson_ByKey_wrap.md
en/docs/auto-catalog/functions/Fun_GetListBy_BysCombineChild.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByKey.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByKey1.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByKey2.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByKey5.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByKey6.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByKeyNew.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByKey_copy1.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByName.md
en/docs/auto-catalog/functions/Fun_GetListJson_ByNameAPS.md
en/docs/auto-catalog/functions/Fun_GetLoginUser.md
en/docs/auto-catalog/functions/Fun_GetLoginUserLanguage.md
en/docs/auto-catalog/functions/Fun_GetLoginUserLanguage_copy1.md
en/docs/auto-catalog/functions/Fun_GetLoginUserName.md
en/docs/auto-catalog/functions/Fun_GetLoginUserType.md
en/docs/auto-catalog/functions/Fun_GetLookCustomer.md
en/docs/auto-catalog/functions/Fun_GetLookProcess.md
en/docs/auto-catalog/functions/Fun_GetMachineLenWidth.md
en/docs/auto-catalog/functions/Fun_GetMachineLenWidthAPS.md
en/docs/auto-catalog/functions/Fun_GetMachineWorkEndDate.md
en/docs/auto-catalog/functions/Fun_GetMachineWorkStartDate.md
en/docs/auto-catalog/functions/Fun_GetMachineWorkWorkType.md
en/docs/auto-catalog/functions/Fun_GetMaterialsQtyUnit.md
en/docs/auto-catalog/functions/Fun_GetMaterialsQtyUnitSupple.md
en/docs/auto-catalog/functions/Fun_GetNum.md
en/docs/auto-catalog/functions/Fun_GetNumFirst.md
en/docs/auto-catalog/functions/Fun_GetPackQty.md
en/docs/auto-catalog/functions/Fun_GetProcessAuxiliaryQty.md
en/docs/auto-catalog/functions/Fun_GetReelAuxiliaryQtyUnit.md
en/docs/auto-catalog/functions/Fun_GetReportId_byLogType.md
en/docs/auto-catalog/functions/Fun_GetSystemSetting.md
en/docs/auto-catalog/functions/Fun_GetTestCount.md