Business entities and virtual accounts are separate hierarchies. They connect through relationships that support many-to-many links, multiple relationship types between the same pair, and effective dating.
Schema: entity_accounts
| field | type | notes |
|---|---|---|
id | bigint | PK |
business_entity_id | bigint | FK |
virtual_account_id | bigint | FK |
relationship_type | string | owner, beneficiary, controller, signatory, viewer, trustee, related_party, manager, custodian |
valid_from | date | required |
valid_to | date | nil while active |
metadata | map | |
inserted_at / updated_at | utc_datetime |
A unique index allows multiple relationship types between the same entity and
account, but prevents duplicates of the same (entity, account, type) triple.
Functions
Logistiki.Relationships.link_entity_account(entity, account, relationship_type, attrs \\ %{})
Logistiki.Relationships.unlink_entity_account(entity, account, relationship_type)
Logistiki.Relationships.list_accounts_for_entity(entity, opts \\ [])
Logistiki.Relationships.list_accounts_for_entity_tree(entity, opts \\ [])
Logistiki.Relationships.list_entities_for_account(account, opts \\ [])Effective dating
list_* functions accept an :at option (a Date) to filter relationships
active at a point in time, and a :relationship_type option to filter by type.
Why this matters for balances
Relationships are how entity balances are computed:
balance_for_entity/2aggregates accounts linked to an entitybalance_for_entity_tree/2aggregates accounts linked to an entity or any of its descendants (using the business-entity closure table)
This lets you ask "what is the total client liability for the Acme Holdings subtree?" without duplicating account trees for reporting dimensions.