# The master / slave document pattern

> **Two unrelated "master / slave" concepts coexist in this codebase.**
> This page is about the **document-row** pattern: one header row plus N
> detail rows for a quotation / sales order / work order. The
> **DataSource** master / slave (write-vs-read connection routing via
> `MasterDataSourceConfig` / `SlaveDataSourceConfig` in `xlyApi` and
> `xlyInterface`, paired with `mastermapper/MasterBaseMapper.xml` /
> `slavemapper/SlaveBaseMapper.xml` co-located in those services) is
> a different concept covered in the [Tech-stack HikariCP row](../reference/maintainer/tech-stack.md#2-persistence)
> and indirectly in the runtime page. The two senses overlap in name only.

Almost every business document in xly — a quotation, a sales order, a work
order, a payment voucher — is stored as **one header row plus N detail
rows**. xly's term for this is **master / slave**. The master holds the
document's identity and totals; each slave row is a line item, a stage, a
material, a product, a charge.

The pattern is everywhere:

| Document | Master | Slave family |
|---|---|---|
| Quotation | `quoQuotationMaster` | `quoQuotationSlave`, `quoQuotationMaterials`, `quoQuotationProcess`, `quoQuotationFreight`, `quoQuotationParam`, `quoQuotationControl`, `quoQuotationControlCombine`, `quoQuotationPacking` (and a parallel `*_tmp` family used during in-progress edits — `quoquotationcalc_tmp`, `quoquotationmaster_tmp`, etc.) |
| Work order | `mftWorkOrderMaster` | `mftWorkOrderSlave`, `mftWorkOrderMaterials`, `mftWorkOrderProcess`, `mftWorkOrderPacking`, `mftWorkOrderControl`, `mftWorkOrderControlCombine`, `mftWorkOrderParam`, `mftWorkOrderChangeApply` (plus a `*_tmp` family — `mftworkordercalc_tmp`, `mftworkorderslavemoney_tmp`, etc. — that does not have a non-`_tmp` counterpart) |
| Sales order | `salSalesOrderMaster` | `salSalesOrderSlave`, `salSalesOrderMaterials`, `salSalesOrderProcess`, `salSalesOrderControl`, `salSalesOrderControlCombine`, `salSalesOrderAddress`, `salSalesOrderParam`, … |
| Cost analysis | `accOrderCostAnalysis` (no `Master` suffix) | `accOrderCostAnalysisOperation` |
| The framework's own forms | `gdsconfigformmaster` | `gdsconfigformslave`, `gdsconfigformcustomslave`, `gdsconfigformuserslave` |

The convention is universal enough that the wiki uses **"master"** and
**"slave"** as terms of art. They mean header and detail respectively;
the naming is legacy from the codebase and worth preserving because it
appears verbatim in 14k+ table and column names.

## Conventions inside the pattern

- The slave row's join column is typically named `sMasterId` or
  `sParentId` (it's a [semantic FK](semantic-fk.md), not enforced).
  Sometimes it follows a more specific pattern like `sQuoId` for
  quotation slaves, `sWoId` for work-order slaves; check the slave
  table's columns to be sure.
- Master and all its slaves share the same multi-tenant scope columns
  (`sBrandsId`, `sSubsidiaryId`).
- "Control" slave variants (e.g., `mftWorkOrderControl`,
  `quoQuotationControl`) hold compound or aggregate state — totals,
  status flags, computed columns. They are still slaves of the master.
- Sub-detail tables are named with extra suffixes like
  `…SlaveChildren` or `…ControlCombine`, joining a slave row.

## Why master / slave matters for the wiki

- Almost every form in [Slice 1](../slices/01-hello-world.md)-style
  navigation is the *master* of its document family. The slaves are
  loaded as nested grids or as second forms when a master row is
  selected.
- The framework's own form metadata
  ([`gdsconfigformmaster`](../auto-catalog/tables/gdsconfigformmaster.md)
  / [`gdsconfigformslave`](../auto-catalog/tables/gdsconfigformslave.md))
  is itself an instance of the pattern — the framework documents itself
  using the same convention it asks PMs to follow.
- The customization overlays
  ([`gdsconfigformcustomslave`](../auto-catalog/tables/gdsconfigformcustomslave.md),
  [`gdsconfigformuserslave`](../auto-catalog/tables/gdsconfigformuserslave.md))
  are sibling slave tables, not *deeper* pattern levels. See [Slice 4](../slices/04-custom-field.md).

## "Slave" — naming caveat

The term carries connotations in English that are absent from the
Chinese 主表 / 从表. The wiki preserves "slave" verbatim because the
codebase, schema, and auto-catalog use it in 14k+ identifiers and any
translation would diverge from what developers actually grep.

That preservation has a cost. The naming was a poor choice in the
first place — `主表 / 从表` translates straightforwardly as
`master / detail` or `header / line`, both of which would have
matched both English convention and the actual relational
semantics. The cost of retaining "slave" is borne by every English-
speaking maintainer who has to type or read the term, and by any
future rebrand effort that has to do the schema-wide rename xly
should have done at the start. The wiki documenting it once here
doesn't remove the cost; it just acknowledges it.
