SoW: Desk management / Account families

Master: SoW: Desk management. Not scheduled. No step of the master SoW needs this work.

Objective. AX records that a trading account is a subaccount of one master account. The record groups a customer's accounts for display, for account creation, and for transfer mandates. It grants no permission and shares no margin.

Uses: customers and trading_accounts.customer_id from Customer account access. Account creation and transfers from Accounts and transfers.

Current behavior

Decisions

  1. A family is a parent pointer. A subaccount is an ordinary trading_accounts row with master_account_id set. It has its own venue identity, balances, margin, limits, and permissions.
  2. One level. A master has no parent. A subaccount has no subaccounts. A CHECK constraint enforces the first rule and the write paths enforce the second.
  3. A family stays inside one customer. The subaccount's customer_id equals the master's.
  4. A family grants nothing. Access uses account_permissions and the customer manager right. Account creation uses the W6 creation mandate. Transfers use the W10 and W11 pair mandates. No permission bit is added.
  5. Only AX sets the master flag. AX also adopts an existing account into a family.
  6. No backfill. Existing accounts stay without a parent.

Schema

ALTER TABLE trading_accounts
    ADD COLUMN is_master BOOLEAN NOT NULL DEFAULT FALSE,
    ADD COLUMN master_account_id CHAR(16) REFERENCES trading_accounts(id),
    ADD CONSTRAINT master_has_no_parent
        CHECK (NOT (is_master AND master_account_id IS NOT NULL));
CREATE INDEX trading_accounts_master_account_id_idx
    ON trading_accounts (master_account_id);

Invariants that a CHECK cannot reach. The write paths enforce them and a recon check reports violations:

trading_accounts is on every logical replication publication. The new columns reach the api-gateway, order-gateway, and trade-engine replicas with no publication change.

Use by other steps

Step Use of the family
11, customer requests an account A creation mandate can name a master account as its scope. The new account gets master_account_id, the master's customer_id, and the master's maker and taker fees.
12, internal transfers AX can approve the pairs master to subaccount and subaccount to master for a named user in one action. A pair of two subaccounts needs its own mandate.
8, self-trade prevention AX can put a family in one group. The parent pointer does not do so by itself.

Routes

PUT  /admin/accounts/{id}/master          { is_master }
PUT  /admin/accounts/{id}/parent          { master_account_id | null }
GET  /accounts/{master_id}/subaccounts    -> [TradingAccountResponse]

GET /accounts/{master_id}/subaccounts returns the subaccounts on which the caller holds List. The admin CLI accounts command gains set-master and set-parent.

GUI

Bitnomial edition

The Bitnomial edition cannot create venue identity on request. An admin pairs each account with its btnl_* identity. The family columns and the admin routes work there. Customer account creation does not.

Unchanged

Delivery

Stage Scope Reviewers
A Schema, replica types, and recon checks. No route reads the columns. high-risk
B Admin routes, admin CLI commands, and the subaccount list route. backend
C Creation-mandate scope and pair-mandate approval by family. Needs steps 11 and 12 of the master SoW. backend
D Customer selector grouping and the admin family tree. frontend

Open questions

  1. Does AX detach a subaccount only when its balance is zero and it has no open positions?
  2. What is the maximum number of subaccounts per master? The EP3 participant namespace is finite.
  3. How does a subaccount's transaction history label a transfer that a user with no grant on that subaccount started?
  4. Can the Bitnomial accounts_monitor consumers read rows that carry the family columns?