๐๏ธ Reference State
Status: Implemented (Feb 2026)
The Reference State manages domain entities that act as "dictionaries" or master data. These entities are rarely mutated rapidly by the system itself but are created, updated, or deleted by the user (CRUD operations).
๐๏ธ Stores
All these stores are located in src/lib/stores/reference/ (with one exception).
| Store | API Endpoint | Purpose |
|---|---|---|
brokerStore |
/brokers?include_inaccessible=true |
Brokers the user can see: the accessible ones with their user_role, plus the inaccessible ones with user_role: null. Lookups by id from any component (tables, selectors, badges) and role helpers (canEditBroker, getEditableBrokers). |
assetStore |
/assets/query |
All accessible financial instruments (Stocks, ETFs, Crypto, โฆ), looked up by id. |
currencyStore |
/utilities/currencies |
ISO 4217 currencies with symbols and flags; reloaded when the language changes. |
countryStore |
/utilities/countries |
ISO 3166-1 countries (alpha-3 and alpha-2 codes, name, flag), looked up by alpha-3; reloaded when the language changes. |
sectorStore |
/utilities/sectors |
The standard financial sectors (GICS-based: Technology, Health Care, Financials, โฆ) and their emoji. |
fxRoutesStore |
/fx/providers/routes |
The configured FX pairs and the currencies they reach โ the two endpoints of each configured pair. Currency selectors with configuredOnly, the FX pair dialog and the risk panels use it to offer only what the user can actually convert. invalidateFxRoutes() forces a reload, e.g. after a pair is created. |
transactionTypeStore |
/transactions/types |
List of valid Tx Types (BUY, SELL, DIVIDEND) and their behavioral rules. (Located in transactions/) |
๐ Architecture & Flow
brokerStore and assetStore are built on createEntityStore (documented in
Core Infrastructure), the generic cache for user-scoped lists that
modals create, edit and delete. The other stores are read-only module caches with the same shape:
an idempotent ensureโฆLoaded() that shares the in-flight request, and, except for countries and
sectors, a reactive version counter.
---
config:
layout: elk
---
graph TD
EntityStore["๐ ๏ธ createEntityStore (generic factory)"]
API["๐ Backend API (FastAPI)"]
Modals["Create / edit / delete modals"]
subgraph Reference_Stores ["Reference Stores"]
B_Store["๐ฆ brokerStore"]
A_Store["๐ผ assetStore"]
C_Store["๐ถ currencyStore"]
R_Store["๐ฑ fxRoutesStore"]
T_Store["๐ transactionTypeStore"]
end
subgraph UI_Components ["UI Components"]
Dropdown["Forms & Dropdowns (AssetSelect, CurrencySearchSelect, TransactionTypeSearchSelect)"]
Tables["DataTables (TransactionsTable, โฆ)"]
end
EntityStore -. "builds" .-> B_Store
EntityStore -. "builds" .-> A_Store
API -->|"GET (load)"| B_Store
API -->|"GET (load)"| A_Store
API -->|"GET (read-only)"| C_Store
API -->|"GET (read-only)"| R_Store
API -->|"GET (read-only)"| T_Store
Modals -->|"merge / invalidate"| B_Store
Modals -->|"merge / invalidate"| A_Store
B_Store -->|"Subscribe"| Dropdown
A_Store -->|"Subscribe"| Dropdown
C_Store -->|"Subscribe"| Dropdown
R_Store -->|"Subscribe"| Dropdown
T_Store -->|"Subscribe"| Dropdown
B_Store -->|"Subscribe"| Tables
A_Store -->|"Subscribe"| Tables
๐ Reactivity & Caching
The stores are session caches; they never write to the backend themselves.
- Load once:
ensureBrokersLoaded(),ensureAssetsLoaded(),ensureCurrenciesLoaded(language)and the otherensureโฆLoaded()functions fetch on the first call; later calls resolve at once or share the request in flight.refreshAllBrokers()/refreshAllAssets()discard the cache and fetch again. - Reactivity: components subscribe to a version counter (
brokerStoreVersion,assetStoreVersion,currencyStoreVersion,fxRoutesVersion,typesVersion) and read the data through plain getters (getBrokerInfo(id),getAssetInfo(id), โฆ), which re-run when the counter moves. - After a mutation: the modal that saved calls
mergeBrokers/mergeAssets(a partial upsert that keeps the fields the patch does not carry) or evicts the entry withinvalidateBroker/invalidateAfterMutation, which also marks the cache as not loaded so the nextensureโฆLoaded()fetches again. There is no optimistic update to roll back: the cache changes only after the server has answered.
๐ผ๏ธ Broker icon hydration
A component that only has a partial broker ({id, name}) can ask for its icon fields with
ensureBrokerIconFieldsLoaded(brokerId); BrokerIcon does it when given a brokerId and no icon
field. The store calls GET /brokers/{id} and merges the answer, sharing a request already in
flight for the same broker.
Since 1.2 each broker is asked at most once per cache generation: the first answer, success
or error, settles the id (settledIconFieldIds), because a broker with no icon, portal URL or
import plugin is a valid state, not missing data. Before this, every answer bumped the cache
version, the icon effect ran again and found the fields still missing, and a page could request
the same broker in a loop. invalidateBroker, refreshAllBrokers and the session reset release
the settled ids, and an answer from an old session settles nothing.