Business Affiliate: Data Model
The Business Affiliate module stores an organization’s identity and contact information in business_affiliate, with each role that organization plays (vendor, customer, carrier, operator, manufacturer, other) broken out into a child row in business_role. This page is the field-complete reference for both tables and their DTOs; see Data Models — Reading Guide for the shared envelope shapes referenced throughout, and for why this module predates the occurrence pattern.
Entities and relationships
Section titled “Entities and relationships”business_role is a same-module child table (parent_eid, no FK). Other modules pin a specific role, not the affiliate directly — Item pins a MANUFACTURER role and a VENDOR role (per supply), and Orders pins a VENDOR role for its supplier binding.
Stored shape
Section titled “Stored shape”business_affiliate
Section titled “business_affiliate”| Column | Type | Null | Role |
|---|---|---|---|
id | UUID | NOT NULL (PK) | identity |
effective_as_of | timestamp | NOT NULL | identity |
recorded_as_of | timestamp | NOT NULL, default current_timestamp(3) | identity |
bts_author (was author) | varchar(255) | NOT NULL | bookkeeping |
eid | UUID | NOT NULL | identity |
previous | UUID | NULL | identity |
retired | boolean | NOT NULL, default false | bookkeeping |
created_by, created_at_effective, created_at_recorded | varchar / timestamp(3) | NOT NULL | bookkeeping |
tenant_id | UUID | NOT NULL | identity |
ba_name | varchar(255) | NOT NULL | payload |
legal_name, legal_legal_name, legal_country, legal_tax_id, legal_registration_id, legal_naics_code | varchar | NULL | payload — CompanyInformation component |
contact_salutation/first_name/middle_name/last_name/job_title/email/phone | varchar(255) | NULL | payload — Contact component |
contact_postal_address_address_line_1/_2/city/state/postal_code/country | varchar | NULL | payload — nested PostalAddress |
contact_postal_address_geo_location_latitude/longitude/altitude | double precision | NULL | payload — nested GeoLocation |
contact_emails, contact_phones, contact_addresses, contact_sites | JSONB | NULL | payload — Contact map fields |
main_address_address_line_1/_2/city/state/postal_code/country | varchar | NULL | payload — PostalAddress component |
main_address_geo_location_latitude/longitude/altitude | double precision | NULL | payload |
other_contacts | JSONB | NULL | payload — Map<String, Contact> |
other_addresses | JSONB | NULL | payload — Map<String, PostalAddress.Value> |
bts_author_sub (was oidc_sub), bts_note (was note), bts_created_by_sub | varchar | NULL | bookkeeping |
Constraints: PK id. Unique: none — see Schema notes; name uniqueness is enforced only in application code.
business_role
Section titled “business_role”| Column | Type | Null | Role |
|---|---|---|---|
id | UUID | NOT NULL (PK) | identity |
effective_as_of | timestamp | NOT NULL | identity |
recorded_as_of | timestamp | NOT NULL, default current_timestamp(3) | identity |
bts_author (was author) | varchar(255) | NOT NULL | bookkeeping |
eid | UUID | NOT NULL | identity |
previous | UUID | NULL | identity |
retired | boolean | NOT NULL, default false | bookkeeping |
created_by, created_at_effective, created_at_recorded | varchar / timestamp(3) | NOT NULL | bookkeeping |
parent_eid | UUID | NOT NULL | identity — parent-linking metadata, not a SQL FK |
role | varchar(255) | NOT NULL | payload — BusinessRoleType enum |
notes | varchar(8192) | NULL | payload |
ba_name | varchar(255) | NOT NULL | bookkeeping — denormalized copy of the parent’s ba_name |
bts_author_sub (was oidc_sub), bts_note (was note), bts_created_by_sub | varchar | NULL | bookkeeping |
Constraints: PK id. Unique: none — see Schema notes. No embedded-component families — all payload columns are scalar.
Projected shape
Section titled “Projected shape”BusinessAffiliate
Section titled “BusinessAffiliate”| Field | Type | Stored or computed | Notes |
|---|---|---|---|
eId, name, legal, contact, mainAddress, contacts, addresses | mixed | Stored | 1:1 with business_affiliate columns |
BusinessRole
Section titled “BusinessRole”| Field | Type | Stored or computed | Notes |
|---|---|---|---|
eId, name, role, notes | mixed | Stored | 1:1 with business_role columns |
BusinessAffiliateRoleDetails (read model, GET .../with-details/{entity-id})
Section titled “BusinessAffiliateRoleDetails (read model, GET .../with-details/{entity-id})”| Field | Type | Stored or computed | Notes |
|---|---|---|---|
businessAffiliate | BusinessAffiliate | Stored | direct read |
roles | List<BusinessRoleType> | Computed | roleService.rolesFor(...).map { it.role } |
VendorLookupResult / BusinessRoleReference.Value (response DTO, GET .../lookup/vendors — the shape used everywhere a module pins a role)
Section titled “VendorLookupResult / BusinessRoleReference.Value (response DTO, GET .../lookup/vendors — the shape used everywhere a module pins a role)”| Field | Type | Stored or computed | Notes |
|---|---|---|---|
name | String | Computed | joined from the parent affiliate |
eId | EntityId? | Computed | the role’s own eId (aliased brTable.eId) |
affiliateEId | EntityId? | Computed | the parent affiliate’s eId |
rId | RecordId? | Computed | always null for lookup results — floating |
retired | Boolean | Computed | always false for lookup results |
provenance | Provenance.Value? | Computed | aliased from the role’s own author/recorded-time |
role | BusinessRoleType | Computed | @Transient — stamped by the caller, not read from any column |
This BusinessRoleReference.Value shape is what appears embedded on the manufacturer field of Item and the reference field of Orders’ SupplierBinding — same DTO, per-slot role stamp.
BusinessAffiliateLookupResult, BusinessAffiliateRoles (list/lookup DTOs)
Section titled “BusinessAffiliateLookupResult, BusinessAffiliateRoles (list/lookup DTOs)”| Field | Type | Stored or computed | Notes |
|---|---|---|---|
matches | List<BusinessAffiliateLookupEntry> | Computed | fuzzy-match query, de-duplicated and limited |
roles | List<BusinessRole> | Stored | direct list of child records |
Cross-module references
Section titled “Cross-module references”| From | Field/Column | Target | Kind |
|---|---|---|---|
| Item | manufacturer | BusinessRole (MANUFACTURER) | floating; pins to a tombstone rId on role retirement |
| Item | item_supply.supplier | BusinessRole (VENDOR) | floating; pins to a tombstone rId on role retirement |
| Orders | SupplierBinding.reference | BusinessRole (VENDOR) | floating; pins on retirement; frozen post-Submit |
business_role.parent_eid | business_affiliate.eid | same-module parent-child | no SQL FK — BusinessRoleReferenceComponent flattens the reference into <prefix>_* columns with no FK |
The <prefix>_* reference-cluster shape these consumers embed (entity_id, record_id, name, retired, provenance_*) is the one described once in Data Models — Reading Guide.
API surface
Section titled “API surface”Follows the request/response call-shape convention in The Orders v2 Call Shape.
| Method | Path | Purpose | Main refusals |
|---|---|---|---|
| (framework) | create, readByEid, readByRId, update, delete, query, history, bulk | Standard data-authority CRUD on BusinessAffiliate | |
| GET | {entity-id}/with-details | The affiliate plus its enabled roles | |
| GET | {entity-id}/roles | List roles for an affiliate | |
| POST | {entity-id}/roles | Create a role | |
| PUT | {entity-id}/roles/{business-role} | Update a role | |
| DELETE | {entity-id}/roles/{business-role} | Delete a role | |
| GET | lookup | Fuzzy name lookup, optional role filter | |
| GET | lookup/vendors (canonical, reference-data/business-affiliate) | Fuzzy VENDOR-role lookup, ready-to-link references — the FE’s vendor-linking capability |
Notifications
Section titled “Notifications”Emits UpdateEntity (BA rename), and NewEntity/UpdateEntity/DeleteEntity for BusinessRole. Item’s ItemRoleListener and Orders’ OrderSupplierRoleListener both subscribe to the role channel: a VENDOR update propagates a name change to every linking item_supply/order (Orders only touches DRAFT orders — never SUBMITTED or terminal ones); a VENDOR delete marks the reference retired; MANUFACTURER events drive the equivalent cascade in Item only.
Schema notes
Section titled “Schema notes”- No database unique constraint on affiliate name. Uniqueness on
(ba_name, tenant_id)is enforced only in application code (BusinessAffiliateValidator.validateForCreate/validateForUpdate), not a SQLUNIQUEconstraint. - Same gap on
business_role— no SQLUNIQUEconstraint exists on this table at all. - This module predates the occurrence-kind pattern. No
*OccurrenceKindtype exists for eitherBusinessAffiliateorBusinessRole; both implement the genericEntityPayloadinterface and surface mutations through the genericDataAuthorityNotification.NewEntity/UpdateEntity/DeleteEntitycases rather than a module-specific kind enum. (Contrast Orders, which does haveOrderOccurrenceKind— the pattern exists elsewhere in the stack but wasn’t brought into this module.)
Copyright: © Arda Systems 2025-2026, All rights reserved