Desktop engineering when the machine is in a branch
Most software runs on a server you can restart or a browser someone can refresh. A self-service terminal in a bank branch 1,000km away is neither. That one fact changes how you build.
What I mean by desktop engineering
By desktop engineering here I mean software that runs on a physical machine in the field, not a page served from a computer you control. In this case the machine is an in-branch self-service terminal: a touch screen with a card reader, a biometric scanner, and a printer attached. I built the TypeScript terminal interface and the channel service layer behind it. That layer routes each request to the right backend service. It was team-delivered work at one of South Africa's largest retail banks. The terminals serve millions of customers across 880+ branches.
You cannot refresh a broken screen
When a kiosk fails, a customer is standing in front of it. No one can refresh the page for them, and the nearest engineer may be a province away. So the thing you optimise for is not user experience first. It is recoverability. Every error state needs a clear path back to a working state, and a partial failure must never leave the session half-done.
Keep the part on the glass thin
The terminal interface does 2 things: show the screen and capture input. The decisions live in the channel service layer behind it. Keeping the interface thin is not tidiness. It is what lets a backend integration change without redeploying software to every terminal in the country. The machine on the counter stays still while the system behind it moves.
Hardware does not behave
A card reader, a biometric scanner, and a printer each carry their own firmware, and that firmware is not the same across terminal batches. A peripheral can fail in the middle of an interaction. The job is to handle that without dropping the customer into a broken state: catch the failure, recover the session, and give the person a way forward.
The network is not on your side
Across 880+ branches, network conditions vary from one town to the next. Each service call gets a strict timeout, so a slow backend cannot hang the screen. Retries use exponential backoff: each retry waits longer than the last, so a struggling service is not buried under more requests. And the retry policy is tuned to balance the customer's wait against the load on the system.
You debug from telemetry, not the machine
When a terminal fails 1,000km away, you cannot put your hands on it. You work from what it sent back: detailed logs, a clear taxonomy of errors, and enough signal to reason about the failure from telemetry alone. That habit, trusting the record over the story, is the one I lean on most now. It runs through the automation I build for businesses that cannot afford a silent failure.
You cannot refresh a machine you cannot reach. So you build one that recovers on its own.
The terminal work was team-delivered. My part was the TypeScript interface and the channel service layer. If you work on kiosks, field-deployed hardware, or resilience under bad networks, I would enjoy the conversation.