# Multi-service deployment

xly is not a single Spring Boot WAR. The repository contains several
deployable modules plus a few library-like WAR modules that are also used
as dependencies by `xlyEntry`.

## Topology at a glance

```mermaid
flowchart LR
    classDef library fill:#f5f5f5,stroke:#999,stroke-dasharray:3 3
    classDef boot fill:#e8f0fe,stroke:#4285f4

    subgraph clients [Operator-facing]
      BACK["BACK SPA<br/>http://&lt;host&gt;:8597"]
      FROUNT["FROUNT SPA<br/>http://&lt;host&gt;:8598"]
    end
    EXT([External integrators])
    HOOKS([Third-party webhooks])

    subgraph boots [Deployable Spring Boot apps]
      direction TB
      XENTRY["xlyEntry<br/>:8080  /xlyEntry<br/>EntryApplicationBoot"]:::boot
      XAPI["xlyApi<br/>:8090 (local) / :8080<br/>/xlyApi · ApiApplicationBoot"]:::boot
      XIF["xlyInterface<br/>:8080  /xlyInterface<br/>InterfaceApplicationBoot"]:::boot
      XPLC["xlyPlc<br/>:8000 (dev) / :8080<br/>/xlyEntry · PlcApplicationBoot"]:::boot
      XFACE["xlyFace<br/>:8091 (local) / :8080<br/>/xlyFace (out of doc scope)"]:::boot
      XEJMSC["xlyErpJmsConsumer<br/>(no port; inherits)<br/>JmsConsumerApplicationBoot"]:::boot
    end

    subgraph libs [Library modules — not standalone runnable]
      direction TB
      XMANAGE[xlyManage]:::library
      XBSERVICE[xlyBusinessService]:::library
      XPERSIST[xlyPersist]:::library
      XENTITY[xlyEntity]:::library
      XFLOW[xlyFlow]:::library
      XMSG[xlyMsg]:::library
      XEJMSP[xlyErpJmsProductor]:::library
      XPLATC[xlyPlatConstant]:::library
    end

    subgraph infra [Shared infrastructure]
      DB[("MySQL<br/>xlyweberp_*")]
      REDIS[(Redis :16379<br/>shared cache + session)]
      AMQ([ActiveMQ :61616])
      MONGO[("MongoDB<br/>(wired but unused)")]
    end

    BACK -->|nginx| XENTRY
    FROUNT -->|nginx| XENTRY
    FROUNT -->|nginx| XAPI
    EXT --> XAPI
    HOOKS --> XIF

    XENTRY --- XMANAGE
    XENTRY --- XBSERVICE
    XENTRY --- XFLOW
    XBSERVICE --- XPERSIST
    XAPI --- XPERSIST
    XIF --- XPERSIST
    XPERSIST --- XPLATC
    XPERSIST --- XENTITY
    XBSERVICE --- XMSG
    XIF --- XMSG
    XBSERVICE --- XEJMSP

    XENTRY --> DB
    XAPI --> DB
    XIF --> DB
    XPLC --> DB
    XFLOW --> DB

    XENTRY --> REDIS
    XAPI --> REDIS
    XEJMSC --> AMQ
    XEJMSP -. publishes .-> AMQ
    XENTRY -. publishes .-> AMQ
```

The reverse-proxy maps the operator-facing ports (8597 / 8598) onto the
internal Spring Boot apps (mostly :8080 with distinct context paths).
The library modules don't run on their own — they're packaged into the
deployable WARs as dependencies. `xlyFlow` and `xlyPlc` share xlyEntry's
context-path `/xlyEntry`, so a real deployment routes by host or
upstream rather than by path.

## The main modules

### Deployable Spring Boot applications

| Service / module | Role | Default profile / port | Boot class |
|---|---|---|---|
| **xlyEntry** | Main runtime and builder/admin surface. Hosts `/business/*`, `/gdsmodule/*`, `/gdsconfigform/*`, `/gdsconfigtb/*`, reporting, login, and other framework controllers. | `dev` → 8080, context `/xlyEntry` | `EntryApplicationBoot` |
| **xlyApi** | API-oriented module for `/api/*`, `/online/*`, `/pro/*`, `/thirdparty/*`, and related endpoints. | `local` (default in repo) → 8090, dev/win/linux → 8080, context `/xlyApi` | `ApiApplicationBoot` |
| **xlyInterface** | External-integration module with Swagger dependencies and third-party integration code. | `dev` → 8080, context `/xlyInterface` | `InterfaceApplicationBoot` |
| **xlyPlc** | Shop-floor PLC bridge ([Slice 6](../../slices/06-hardware.md)). | `dev` → 8000, named profiles (15S, S10, T0, T1, CT, yt, pro) → 8080, context `/xlyEntry` *(shares xlyEntry's context-path)* | `PlcApplicationBoot` |
| **xlyFace** | Face-recognition module. In build (`settings.gradle` keeps it active per user) but **out of documentation scope** for this wiki. | `win` (default in repo) → 8080, local → 8091, context `/xlyFace` | `XlyFaceApplicationBoot` |
| **xlyErpJmsConsumer** | JMS consumer worker. Has a Boot main but no `application*.yml` of its own — runtime config inherits from peer services. | n/a (inherits) | `JmsConsumerApplicationBoot` |

### Library modules (in `settings.gradle`, not standalone runnable)

| Module | Role |
|---|---|
| **xlyManage** | Backend metadata-management services (`Gds*ServiceImpl` family); pulled into xlyEntry. |
| **xlyBusinessService** | Business-logic service tier (`BusinessBaseServiceImpl` and ~100 sibling `*ServiceImpl` classes); pulled into xlyEntry. |
| **xlyFlow** | Workflow / Activiti code. `XlyFlowApplicationBoot.java` is fully commented out on this branch; consumed as a library through xlyEntry. Also shares context-path `/xlyEntry`. |
| **xlyEntity** | Shared entity / DTO classes (~83 Java files, including 22 Mongo `@Document` classes). |
| **xlyPersist** | Persistence helpers (DAOs, MyBatis mapper XMLs, `RequestAddParamUtil`, etc.). |
| **xlyMsg** | Notification helpers (DingTalk, WeChat, email); no Boot main. |
| **xlyErpJmsProductor** | JMS producer code (queue declarations in `P2pQueue.java`); no Boot main. |
| **xlyPlatConstant** | Shared utility constants (`MultiThreadServer`, `TimeContant`) consumed by `xlyPersist`. The single active Plat* module. |

Each has its own `application.yml` + several `application-<profile>.yml`
files. The active profile is selected at startup via
`-Dspring.profiles.active=…`.

## Disabled in `settings.gradle`

The cleanup branch comments out 17 `include` lines. Three are non-Plat
modules present on disk:

- `xlyErpTask` — long-running background tasks.
- `xlyRxtx` — native serial-port library. May be re-enabled when xlyPlc
  needs direct serial access (some press models use TCP/Ethernet
  instead).
- `xlyFile` — older file-management module, superseded by
  `xlyPlatFileUpload` (also commented out).

The remaining 14 commented-out includes are `xlyTestService`,
`xlyTestController`, and the full `xlyPlat*` family except
`xlyPlatConstant` — i.e. `xlyPlatTask`, `xlyPlatJmsProductor`,
`xlyPlatJmsConsumer`, `xlyPlatReportForm`, `xlyPlatFileUpload`,
`xlyPlatMarketingService`, `xlyPlatUserService`, `xlyPlatSmsService`,
`xlyPlatMerchantController`, `xlyPlatWebsocket`, `xlyPlatPayService`,
`xlyPlatCainiaoWaybillSevice`. (`xlyTestService` / `xlyTestController`
directories are not on disk; only `TestController.java` exists inside
`xlyEntry/.../businessweb/` as a stub.)

A maintainer cleaning up the codebase should consider whether to delete
the on-disk-but-excluded `xlyErpTask` / `xlyRxtx` / `xlyFile`
directories or keep them as historical reference. They take up disk
space but do not affect the build.

## Plat* family

The `xlyPlat*` modules (`xlyPlatMerchantController`, `xlyPlatUserService`,
`xlyPlatPayService`, `xlyPlatMarketingService`, `xlyPlatCainiaoWaybillSevice`,
`xlyPlatSmsService`, `xlyPlatReportForm`, `xlyPlatFileUpload`,
`xlyPlatJmsConsumer`/`Productor`, `xlyPlatTask`, `xlyPlatWebsocket`)
are the **B2B printing-platform layer** and remain out-of-scope for
this wiki. The single exception is `xlyPlatConstant`, which is still
`include`d in `settings.gradle` and consumed as a shared constants
utility by `xlyPersist` (`MultiThreadServer`, `TimeContant`).

## How services find each other

Three communication channels:

1. **Shared database** — every service reads/writes the same MySQL
   schema. Most cross-service "communication" is implicit through
   shared tables.
2. **Messaging** — both ActiveMQ/JMS and RocketMQ exist in the codebase.
   ActiveMQ/JMS carries base-data merge and document fan-out jobs; Redis
   cache invalidation is synchronous `@CacheEvict` in the BACK save path
   (see [cache invalidation on metadata change](cache-invalidation.md)).
3. **HTTP REST** — for synchronous calls (e.g., xlyApi calling xlyEntry's
   `/business/*` endpoints).

There is no service registry / discovery mechanism beyond the
`application-<profile>.yml` files, which hardcode peer URLs per
environment.

## URL routing in deployed environments

The workspace `.env.local` points `BACK` at port `8597` and `FROUNT` at
port `8598` in the live environment. That is enough to identify the two
operator-facing surfaces, but the reverse-proxy and context-path mapping
are deployment details rather than code-backed facts in this repository.

## Profile permutations

Profiles split by service:

- **xlyEntry**: `dev`, `local`, `win`, `linux`, `15s`, `s10`, `saas`,
  `bgj` (lowercase). `dev` is the in-repo default.
- **xlyApi**: `local` (default in repo), `dev`, `linux`, `win`.
- **xlyInterface**: `dev` only.
- **xlyFlow**: `dev` (datasource-only).
- **xlyFace**: `win` (default), `dev`, `linux`, `local`.
- **xlyPlc**: `dev` (default) plus 7 press-model profiles
  (`15S`, `S10`, `T0`, `T1`, `CT`, `yt`, `pro` — uppercase / mixed-case,
  distinct from xlyEntry's lowercase `15s` / `s10`).

The press-model profiles (`T0`, `T1`, `CT`, `yt`, `pro`, `15S`, `S10`)
are **xlyPlc-specific** — they don't exist for the other services. The
cross-service profiles cover combinations of:

- Operating system (`linux` / `win`)
- Environment (`dev`, `local`, `saas`, `bgj`)
- Customer/edition (`15s`, `s10` for xlyEntry)

A given deployment selects exactly one profile per service. The
mapping from "this customer" → "these profiles" lives in deployment
ops documentation, not the codebase.

## Open: production URL routing

> **Deferred (outside the repository's reach).** The nginx /
> reverse-proxy config that maps the public `:8597` / `:8598` to the
> internal Spring Boot context-paths lives in deployment-ops
> infrastructure, not in this codebase. The wiki has no way to verify
> it against src/db/web; this section is a placeholder waiting for
> the deployment-side config to be linked or vendored.

The exact nginx / reverse-proxy config for `8597` / `8598` is not in this
repository. Add it here only when the deployment-side config is available.
