What it is
The internal panel the bank uses to manage merchants and the promotions it runs with them. Bonus points, cashback, and the other campaign types the bank offers merchants and customers are configured and administered here.
It is the administrative side of something customers only ever see the output of: a cashback offer that appears on a card, or points that land after a purchase, is a record someone created and maintained in a panel like this one. The work is in making that configuration legible and safe to operate — the people using it are managing live commercial arrangements with real merchants.
The merchant tree
The panel's central control is a tree. A merchant contains its brands, and a brand contains its POS terminals, and an operator picks what a campaign applies to by checking nodes in that hierarchy — checking a node selects everything beneath it. It is the component the whole tool is steered from, it holds a lot of nodes, and it was very buggy.
Selection that cascades down a hierarchy is deceptively hard: the checked state of any node is partly its own and partly a function of its descendants, so the bugs show up as a tree that disagrees with itself. That matters more here than in most places, because the thing being selected is the set of real merchants, brands, and terminals a live promotion will apply to. An operator has to be able to trust that what looks selected is what is selected.
I rebuilt how that selection works and made the component hold up at the sizes it actually runs at.
Result
The tree is reliable — checking a node cascades correctly through its subtree — and it stays responsive with the full merchant hierarchy loaded.
The wider performance work was less glamorous and paid off just as broadly: removing code that had been repeated in several places, and cutting out unnecessary loops over large JSON payloads. Much of the app's cost was in walking the same large structures more times than anything needed, and that is the kind of waste that never appears as one slow feature — it is spread thinly across everything, which is exactly why it survives so long.
Built in Angular. It was one of two internal applications I worked on at the bank, alongside the customer CRM, and like that one it is internal software with no public URL.