Business Affiliate Module
Status: Live. This module is built and running. The engineering reference for what ships today is kept at Business Affiliate (Q2 2026). This page describes the module as currently designed; the reference-data lifecycle and version-pin behavior below are the design target the running system is converging on.
What the runtime actually holds — tables, DTOs, cross-module references and API surface as they exist today — is Business Affiliate: Data Model. Where this page describes design ahead of the build, that page is the one that says what is stored.
Purpose
Section titled “Purpose”A Business Affiliate is an external party a tenant does business with — a vendor, a customer, a carrier, an operator, and so on. Each affiliate carries the descriptive details you would expect: a name, contacts, and addresses.
A supplier is not a separate thing. It is a business affiliate seen through its vendor role. This is the single most important idea in the module: rather than keeping a “supplier” list apart from a “customer” list apart from a “carrier” list, the system keeps one list of affiliates, and each affiliate carries one or more roles that say what it acts as.
Every change to an affiliate — an edit to its details, a role granted or removed, its eventual retirement — is recorded as a new version, and the full version history is kept. Other modules do not copy an affiliate’s details; they hold a version pin: a reference to the affiliate as of a specific version. That one idea replaces the copied-name bookkeeping this page used to describe — what a document shows depends on which version it reads, not on change notifications catching up.
Context
Section titled “Context”Business Affiliate is a leaf of the domain map: it depends on no other domain module, and three modules pin into it. Clients sit to the left of the servers they depend on; every arrow is a dependency the client calls, and together they form a DAG.
What this module consumes:
- Nothing — Business Affiliate sits at the bottom of the module dependency chain and has no domain module below it.
What its clients consume from it:
- Item — item supplies resolve their supplier here (finding the matching vendor role, or creating the affiliate name-only on the fly) and pin the vendor’s version.
- Orders — a draft order’s supplier binding pins a vendor version (re-pinning as the draft floats); Submit requires a linked, unretired vendor and freezes the pin.
- Receiving — a receiver captures the carrier that delivered as a carrier-role pin, frozen with the captured facts.
Functional decomposition
Section titled “Functional decomposition”The module is one service with two endpoints — managing affiliates, and the resolve-or-create surface its consumers call when a supplier is named.
- BusinessAffiliate service — owns the affiliates and their roles. It provides the Affiliates API (create, update, delete; queries, including filtering by role; the version and pin reads its consumers use) and the Supplier resolution API (resolve a named supplier to its vendor role, or create the affiliate — name only — with a vendor role on the fly; the reuse-not-duplicate behavior in Scenarios). Resolution is a convenience over the same affiliate records — nothing else in the module depends on it.
Main entities
Section titled “Main entities”An affiliate owns a set of roles, each typed by what the affiliate does in that capacity. Every change writes a new version of the affiliate; modules that need a supplier or a carrier hold a pin to one of those versions together with a selector for the role they use.
- Business Affiliate — the external party itself, with its name, contacts, and addresses.
- Affiliate version — one recorded state of the affiliate: its lifecycle status plus the roles it holds at that version. Editing the affiliate or changing its roles writes the next version; nothing is overwritten.
- Business Role — a capacity the affiliate acts in: Vendor, Customer, Carrier, Operator, or Other. One affiliate can bear several roles at once (a company can be both a vendor and a customer).
- Version pin — what another module holds when it needs a supplier or a carrier: a reference to the affiliate at a specific version, plus the role it selected in that version. A pin always resolves — the version it names is history and history is kept. A pin can also be absent: a supply source or a draft order may name a supplier informally by name only, before any affiliate is linked (see Scenarios).
Lifecycle
Section titled “Lifecycle”Business affiliate
Section titled “Business affiliate”The affiliate carries the shared reference-data lifecycle — versioned records, Live → Retired, version pins, gates at the point of choice — stated once in the Reference-Data Module Pattern:
What is specific to affiliates is how the rest of the system behaves when this slow-changing data does change:
- Adding a role is additive. An affiliate can pick up a new role — a customer becoming a vendor too — without disturbing its existing roles or anything that already references them.
- A rename never breaks what points at the affiliate. Documents that read the current version (a draft order, a list screen) show the new name on their next read; documents frozen on a pinned version (a submitted order) keep showing the name they were agreed under. No propagation machinery is involved — each reader shows the version it holds.
- Retirement doesn’t erase or invalidate what points at the affiliate. Pins keep resolving — a submitted order keeps its vendor exactly as agreed. What retirement changes is the gate: no new commitment can pick the retired affiliate.
Business role
Section titled “Business role”A business role deliberately has no lifecycle of its own — the role itself is immutable, and everything that changes about roles is carried by the affiliate’s versions:
- Granting or revoking a role is an affiliate version. The affiliate’s role membership is part of its versioned state — a customer picking up the vendor role writes the next affiliate version, with the role set as of that version.
- A role never changes hands or shape. A role belongs to one affiliate for its entire existence and keeps its type; “changing” a role means replacing it in the next version’s membership.
- Retired affiliates keep their roles readable. Retirement carries the role membership forward as history — pins into any version keep resolving the roles that version held.
Notifications
Section titled “Notifications”Every action recorded against an affiliate is observable to the rest of the system — see how modules stay in sync. Beyond that generic channel, this module announces nothing and listens for nothing.
That is a deliberate outcome of the version-pin design, and a change from earlier designs of this module:
- Rename propagation dissolved. There are no embedded supplier-name copies left to refresh. Current readers read the current version; pinned readers read their pin.
- Stale-marking dissolved. Whether a reference points at a retired affiliate is a derived reading — compare the pinned affiliate’s current status — not a flag that must be set by a listener when the vendor goes away.
Business Affiliate sits at the bottom of the module dependency chain alongside Item: it depends on no other domain module, so it has nothing to react to.
Scenarios
Section titled “Scenarios”Four moments show how suppliers are resolved, versioned, and retired end to end. The caller in these diagrams is whoever is driving the workflow — a purchasing screen, an import job, or an orchestrating service.
A supply source can name a supplier informally, before that supplier has ever been entered as an affiliate. The system creates a real affiliate — with just a name populated — and its vendor role on the fly. A “name-only” supplier is an ordinary affiliate that nobody has filled in yet, not a special half-reference.
Naming the same supplier again does not create a second affiliate — the existing vendor role is reused.
Renaming a vendor is a single edit here — it writes a new version. Nothing is pushed out to referencing documents; instead, each document shows the version it reads: floating readers pick up the new name on their next read, frozen documents keep the name they were agreed under.
Retiring a vendor honors what was already committed and blocks what has not started. Existing pins keep resolving; new commitments — a new supply source in Item, submitting a draft order in Orders — are refused at their gates.
Operations
Section titled “Operations”| Action | What it does | When it is allowed |
|---|---|---|
| Create | Enter an affiliate with its initial roles. Born Live. | Any time. |
| Update | Edit details or change the role set — each update writes a new version. | While the affiliate is Live. |
| Delete | Retire the affiliate — terminal; the version history stays readable. | While the affiliate is Live. |
| Query / filter by role | List affiliates, optionally filtered to a role such as Vendor. | Any time. |
| Resolve or create a supplier | When another module names a supplier, the system finds the matching vendor — or creates the affiliate (name only) and its vendor role on the fly. | On demand from a consuming module. |
Consuming modules apply the retirement gate at their own commitment points: Item refuses a new supply source naming a retired vendor; Orders refuses submitting an order bound to one (and requires a linked vendor to submit at all — a name-only supplier can carry a draft but not a submission). Receiving captures the carrier that actually showed up, so its carrier pin is deliberately ungated.
Guarantees
Section titled “Guarantees”- A role belongs to exactly one affiliate. Roles are never shared between affiliates, across their entire version histories.
- An affiliate can act in several roles at once — vendor and customer, for example — without duplicating the affiliate.
- The same supplier is reused, not duplicated. Naming a supplier that already exists links to the existing vendor role rather than creating a second one.
- A retired affiliate re-enters no new commitments, and everything already committed against it stays exactly as agreed.
- The shared reference-data guarantees apply: version pins never dangle, and retirement is terminal and history-preserving.
How it relates to its neighbors
Section titled “How it relates to its neighbors”- Item — an item’s supply sources pin their supplier’s vendor role; a supply source may also stay name-only until a vendor is linked.
- Orders — a draft order’s supplier binding floats with the current version while the draft is edited, and freezes on its pinned version at submission. Submitting requires a linked, unretired vendor.
- Receiving — a receiver captures the carrier that delivered, as a carrier-role pin frozen with the delivery’s captured facts.
Copyright: © Arda Systems 2025-2026, All rights reserved