User Journey: Onboard a counterparty

Table of Contents

This page documents a user journey: A tenant administrator brings a new trading counterparty on board: its legal identity, its identifiers, its contacts, and the netting agreements and collateral terms the tenant trades under.

A user journey describes what one person is trying to do, before anything is built. It is a design document that outlives any sprint, so it names the screens, the entity fields each screen shows, and the operations and messages each step needs.

1. Goal

"I want to bring a new counterparty on board once — the legal entity, the names we recognise it by, the people we contact, and the agreements and collateral terms we trade under — so that the desk can trade with it and every screen resolves it to the same entity." The journey is done when the counterparty reads in the list, resolves by an authoritative identifier, and its agreements, netting sets and collateral terms read back.

2. Actor and trigger

The actor is the person who maintains the tenant's reference data: an account holding the Operations role, or a tenant administrator, acting inside their own tenant. The trigger is a new trading relationship, a legal name or group change, or an ORE document that names a counterparty the tenant does not hold. The journey starts at Counterparties, or at the Onboard a counterparty button there, and ends at Outcome, at History, or at Refused.

A counterparty is a tenant-wide record. The party-counterparty junction decides which of the tenant's parties can see it, and a party sees only the counterparties its junction rows name.

3. Steps

  1. See the counterparties. The person opens Counterparties. The system lists the tenant's counterparties: short code, full name, party type, status, business centre, identifiers, contact count, version, and last modifier. The person searches by code, name or identifier value, and filters by Active, Closed or All. The person chooses Onboard a counterparty.
  2. Identity. The person enters the short code, the full name, the transliterated name when the registered name is not Latin, the party type, the status, the business centre, and the parent counterparty. The system offers the party types, the party statuses, the business centres, and the counterparties already stored. The short code is the natural key and is unique in the tenant. The full name need not be unique: branches share a name under distinct short codes. The parent is optional.
  3. Identifiers. The person adds each identifier the tenant recognises this counterparty by: a scheme and a value. The system shows the list, marks the identifier the tenant resolves the counterparty by, and refuses a duplicate. The system takes the LEI first, then the BIC, as the authoritative identifier. An ORE alias is unique across the tenant. The system also shows which parties may trade with the counterparty.
  4. Contacts. The person adds a contact for each purpose the tenant uses: Legal, Operations, Settlement and Billing. A contact carries the street address, the city, the state, the country, the postal code, the phone, the email and the web page. The natural key is the counterparty and the contact type, so the system keeps one row per type.
  5. Legal agreements. The person records each netting agreement with the counterparty: the agreement number, the type, the governing law and a description. Under an agreement the person records its netting sets, and under a set its identifiers, its collateral terms (the CSA), and the currencies the CSA accepts as collateral. The two parties of an agreement are fixed and never change across its versions. A set with no agreement holds trades that do not net.
  6. Review. The system shows one summary of everything the person entered and the operations the confirm will send. Nothing is written yet.
  7. Confirm. The person chooses Confirm and write. The system writes the counterparty, its identifiers, its contacts, its agreements, its netting sets, its netting set identifiers, its collateral terms, its eligible currencies, and the visibility rows. It then shows the outcome: the short code, the identifiers, the contacts, the agreements, and the version written, with links to trade with the counterparty, to see who can see it, and to onboard another.
  8. Check the history. The person opens the history. The system lists every version with who changed it, when, and why, and shows the field-level difference from the version before. The person can read the counterparty, its identifiers and its contacts as they stood in a version, and can revert to an older version, which the system writes as a new version.
  9. Handle a refusal. When the server refuses a write, the system keeps what the person typed and states what was refused, from which step, and that the record did not change. The person corrects the value, or keeps the value already stored, and continues.

No step waits on the server after its reply, and the journey keeps no state.

4. Four-eyes controls

A change that touches data other functions rely on needs a second person, and the person who asks cannot decide. Book types and the controls on each records the rule for each act of this journey:

  • A new counterparty, a change to its identity, parent, status or business centre, an identifier, and a link to a party that may see it: Operations decides.
  • A netting agreement, a netting set or a collateral term: Market Risk decides, because these set the exposure to the counterparty.
  • A contact: not gated. It is written directly.

Review marks each change as needing a named function or no approval. When any change is gated, the confirm becomes Raise request: the system raises one approval request (inbox.v1.ops.raise_approval), shows it waiting, and leaves the record as it was. A decider from the named function opens the request with inbox.v1.ops.get_approval, reads what would change and the check, and approves or declines with a comment (inbox.v1.ops.decide_approval). The request applies only when every named function has approved, and one decline ends it. The prototype draws the waiting, decide and declined states (?state=waiting, ?state=decide, ?state=declined); the check it draws is that the counterparty has one authoritative identifier, which ?check=identifier makes fail.

The approval operations exist. No request kind is seeded for these acts, a request holds no pending change, and nothing applies the change when the last decider approves, so a screen cannot yet raise or apply a gated change. The deferred four-eyes authorisation framework is that missing piece. The deciders are Operations, Finance and Market Risk, and the Acme dataset holds no Finance account; the task Add the missing book-control actors to Acme adds it.

5. Screens and wireframes

One list screen and one journey screen. Counterparties is the list, with its search and its tabs. Onboard a counterparty is one screen: a flat step rail on the left, and the current step on the right. The steps are Identity, Identifiers, Contacts, Legal agreements, Review, Outcome and History. Nothing is written until the person confirms on Review, so Review is the last step that reads and Outcome is the first that reports a write.

wireframe_onboard_a_counterparty.png

Figure 1: Counterparty onboarding: the counterparty list, the step rail with the identity step, and the identifiers, contacts, agreements, review, outcome, history and refused states.

6. Prototype

The prototype is the design record for the screens above.

Directory
doc/prototypes/parties/onboard-a-counterparty/
States
landing, counterparty, identifiers, contacts, agreements, review, done, refused, history
Refusals
?fail=duplicate, ?fail=missing and ?fail=duplicate_set_id, with ?fail=1 for the first kind

The landing screen carries the list and its search. The journey screen carries the rail and one step at a time. The state is chosen from the query string and is reachable from the foot bar.

7. Entities composed

Entity What it contributes Model
counterparty The list row and the identity form: short code, full name, transliterated name, party type, status, business centre, parent counterparty ores.refdata.counterparty
counterparty_identifier The identifiers list and the add form: scheme, value, description ores.refdata.counterparty_identifier
counterparty_contact_information The contacts list and the contact editor: type, address, phone, email, web page ores.refdata.counterparty_contact_information
netting_agreement The agreement panel: number, type, governing law, description ores.refdata.netting_agreement
netting_set The sets under an agreement: code, call type, initial margin type, risk weight, description ores.refdata.netting_set
netting_set_identifier A set's names: scheme and value, such as the ORE id ores.refdata.netting_set_identifier
csa The collateral terms of a set: thresholds, minimum transfer amounts, frequencies, MPOR ores.refdata.csa
csa_eligible_currency The eligible collateral list: currency and position ores.refdata.csa_eligible_currency
business_centre The business centre picker and the list column ores.refdata.business_centre
party_counterparty The visibility rows: which parties may trade with the counterparty ores.refdata.party_counterparty
party_type The party type picker ores.refdata.party_type
party_status The status picker ores.refdata.party_status
party_id_scheme The identifier scheme picker, with max_cardinality and display_order ores.refdata.party_id_scheme
contact_type The contact type picker ores.refdata.contact_type
currency The eligible collateral picker ores.refdata.currency

The counterparty and its agreements, sets and CSAs are versioned, so each has a history. The agreement's two parties are fixed. The identifiers, the contacts, the netting set identifiers and the eligible currencies are versioned child rows, and the junction keeps versions too, but no operation reads them for this screen; see What is missing.

8. Operations and messages

Step Operation Subject Status
See the counterparties List the counterparties, then the page's identifiers and contacts refdata.v1.counterparties.list, then refdata.v1.counterparty_identifiers.list and refdata.v1.counterparty_contact_informations.list with counterparty_id_one_of set to the page exists
Identity Offer the party types refdata.v1.party_types.list exists
Identity Offer the party statuses refdata.v1.party_statuses.list exists
Identity Offer the business centres refdata.v1.business_centres.list exists
Identity Read the centres the counterparty deals through refdata.v1.counterparty_business_centres.list_by_counterparty_id exists
Identity Write the centres the counterparty deals through refdata.v1.counterparty_business_centres.put_many exists
Identity Offer the parent counterparties refdata.v1.counterparties.list exists
Identifiers Offer the identifier schemes refdata.v1.party_id_schemes.list exists
Identifiers Read the identifiers refdata.v1.counterparty_identifiers.list_by_counterparty_id exists
Identifiers Read who can see this counterparty refdata.v1.party_counterparties.list_by_party_id exists
Identifiers Read who can see it, from the counterparty side refdata.v1.party_counterparties.list_by_counterparty_id exists
Contacts Offer the contact types refdata.v1.contact_types.list exists
Legal agreements List the counterparty's agreements and their sets refdata.v1.netting_agreements.list_by_counterparty_id, refdata.v1.netting_sets.list_by_netting_agreement_id partial
Legal agreements List a set's identifiers refdata.v1.netting_set_identifiers.list_by_netting_set_id exists
Legal agreements Read a set's CSA refdata.v1.csas.list_by_netting_set_id exists
Legal agreements Read the CSA's eligible currencies refdata.v1.csa_eligible_currencies.list_by_csa_id exists
Legal agreements Fill the eligible currency picker refdata.v1.currencies.list exists
Confirm Write the counterparty refdata.v1.counterparties.put exists
Confirm Write the identifiers refdata.v1.counterparty_identifiers.put_many exists
Confirm Write the contacts refdata.v1.counterparty_contact_informations.put_many exists
Confirm Write the agreements refdata.v1.netting_agreements.put exists
Confirm Write the netting sets refdata.v1.netting_sets.put exists
Confirm Write the netting set identifiers refdata.v1.netting_set_identifiers.put_many exists
Confirm Write the collateral terms refdata.v1.csas.put exists
Confirm Write the eligible currencies refdata.v1.csa_eligible_currencies.put_many exists
Confirm Record which parties can see it refdata.v1.party_counterparties.put exists
Confirm Stage the eight writes as one act refdata.v1.ops.put_counterparty_composite exists
Check the history List the versions refdata.v1.counterparties_versions.list exists
Check the history Read one version refdata.v1.counterparties_versions.get exists
Check the history Read the composite as of a version refdata.v1.ops.get_counterparty_composite_as_of exists
Check the history Read the identifiers' versions refdata.v1.counterparty_identifiers_versions.list exists
Check the history Read the contacts' versions refdata.v1.counterparty_contact_informations_versions.list exists
Check the history Read the field-level difference in one reply refdata.v1.history.get (entity_type ores.refdata.counterparty, ores.refdata.counterparty_identifier, ores.refdata.counterparty_contact_information) exists
Check the history Revert by writing the old values refdata.v1.counterparties.put exists
Handle a refusal Read the record, the version and the field the refusal left behind result.code and result.message on the subject that failed exists

The review step sends no operation of its own: it shows what the confirm will send.

The field-level difference is read, not computed: refdata.v1.history.get returns every version of the record with the fields that changed from the version before, and the same request serves the child rows under their own entity_type. A child row's own versions are also readable from refdata.v1.counterparty_identifiers_versions.list and refdata.v1.counterparty_contact_informations_versions.list, which return the raw rows.

The landing list is read in one call per child type per page: the counterparty list, then refdata.v1.counterparty_identifiers.list and refdata.v1.counterparty_contact_informations.list with counterparty_id_one_of set to the identifiers on the page. A single reply that carried the counterparty with its identifiers and contacts was the other candidate, and it is dropped: it would give one entity's list reply a shape no other entity's list reply has, and the filtered child read already costs one call per child type per page rather than one per row.

9. What is missing

  1. A counterparty's agreements and sets are not read in one reply. The screen reads the agreements, then one call per agreement for its sets, then one call per set for its identifiers, its CSA and the CSA's eligible currencies. The candidate is a composite read of the counterparty's agreements, sets and collateral terms. refdata.v1.ops.get_counterparty_composite_as_of carries the counterparty, its identifiers and its contacts, and not these.

The tenant-administrator item this section used to carry is closed. Operations now holds the counterparty permissions the journey needs, so the screen is reachable by the people who run reference data and not only by a tenant administrator.

10. Related journeys

  • Keep a party's details current — the tenant's own legal entity; its identifier and contact panels are the same shape, and it owns the party side of the visibility junction
  • New party — a counterparty is visible only to the parties that journey creates, so a person goes there before the counterparty can be traded by a new party
  • Maintain a classification list — the party type, party status, contact type and party identifier scheme pickers read lists from there

11. Related knowledge

  • Counterparties — the manual chapter: the entity, its hierarchy, its identifiers, its contacts and its history
  • Parties — the internal mirror of the counterparty; the identifier schemes and the contact shape live there
  • Netting sets — the agreements, the netting sets and the collateral terms this journey records
  • Business Centres — the centre code the identity step picks
  • Reference Data — versioning, provenance and change reasons
  • UX Language

12. See also

Emacs 29.3 (Org mode 9.6.15)