# Refacto Engineering Mario Balug, software architect and product-minded engineer. Based in Zagreb, Croatia. Working remotely with teams across Europe. Website: https://refacto-engineering.balug.net/ Contact: https://refacto-engineering.balug.net/contact (contact form; there is no public email address) ## From idea to production, without the overhead of a full development team. I design and build custom software, cloud platforms and AI-powered workflows from idea to production. One experienced technical partner, direct communication and no unnecessary layers. Best suited to MVPs, internal tools, integrations, automation and small-to-medium production systems. ## What I can build Anything from a simple internal app to a distributed platform. Most projects mix several of these. ### Custom software and mobile apps Internal tools, dashboards, customer portals and workflow systems that replace spreadsheets and manual steps, plus hybrid mobile apps for iOS and Android with the backend behind them. Examples: Approval workflows, Operations dashboards, Client portals, Hybrid mobile apps ### AI integration and automation Assistants, search and automation built into the software you already run, connected to your real data and APIs. Examples: Support assistants, Document search, Agent workflows ### Cloud and backend systems APIs and services that stay fast and understandable as load and team size grow. Databases, messaging, infrastructure. Examples: Go, REST and event-driven APIs, PostgreSQL, ClickHouse, NATS JetStream, MQTT, Docker, Kubernetes, GCP, OIDC and SSO, Fine-grained authorization, Observability ### IoT, edge and industrial integration Both sides of connected hardware: services on Linux devices that talk to equipment over Modbus and vendor-specific protocols, and the cloud side that manages, monitors and controls the fleet. Works with the cloud you already use. Examples: Modbus and industrial protocols, Embedded Linux services, Device-to-cloud, Fleet monitoring ### Speech and AI platforms Streaming speech-to-text, transcription pipelines and integrations with external AI providers, built for production load. Examples: Real-time streaming, Provider failover, Transcript workflows ### Architecture and technical consulting A second opinion or a plan before you commit: architecture reviews, MVP scoping, modernization and hard production bugs. Examples: Architecture review, Technology selection, Roadmap planning ## Projects A selection of projects I've designed, built and taken to production, from mobile apps and internal tools to industrial edge systems and cloud platforms. Client details are kept confidential; screens are illustrations. ### Fleet platform for battery storage Energy and IoT. The cloud system behind a growing number of battery storage cabinets: it collects their measurements, keeps the history, controls who can see which sites, and lets engineers work on units remotely. Stack: Go, MQTT, NATS, ClickHouse, PostgreSQL #### The problem The company runs a growing number of battery storage cabinets at customer sites. They needed to see every cabinet in one place, give each customer and installer access only to their own systems, and fix problems remotely instead of sending a technician. #### What I built The cloud side of the system. It collects measurements from every cabinet, keeps the history, decides who can see and change what, and offers all of it through APIs to the operations console, the owners' mobile app and partners. #### Architecture 1. Battery cabinet: measures power, energy, temperature and alarms 2. Gateway on site: sends the readings over the internet 3. Message broker: receives messages from all devices (MQTT) 4. Normalizer: converts data from each hardware generation into one format (Go) 5. Message queue: holds data until each consumer has processed it (NATS JetStream) 6. Database for measurements: stores the history for charts and reports (ClickHouse) 7. APIs and apps: operations console, owners' mobile app, partner integrations Each step has one job. If the database is slow or being upgraded, data waits in the queue instead of being lost. #### Key decisions and why - **Own platform instead of a ready-made IoT product.** I evaluated existing IoT platforms first. None of them let an owner give access to an installer or share part of a fleet with another company, and that is how this business works. So we built the core ourselves. - **Permissions based on who is connected to what.** Access is described as relationships: this company owns this fleet, this technician services this site until Friday. One permission service (OpenFGA) answers every 'can this person do this?' question, including access that expires and sharing between companies. - **One data format for old and new hardware.** Older and newer cabinets send data in different formats. The data is converted into one format as soon as it arrives, so dashboards, alarms and reports work the same for every unit. New firmware only needs a new converter. - **Summaries calculated in advance.** Minute, hour and day totals are calculated while the data comes in. A chart for a whole year opens as quickly as one for the last five minutes, and searching alarms stays quick as the number of cabinets grows. - **Mobile app for owners.** Owners check their battery system in an iOS and Android app built with React Native and Expo. Small fixes go out as over-the-air updates (Expo EAS), so users get them without waiting for an app store review. - **Sites on a map.** Site locations are stored as geographic data (PostGIS). The console loads only the sites inside the visible part of the map, so it stays quick with many sites. Technology: Go, MQTT, NATS JetStream, ClickHouse, PostgreSQL, PostGIS, OpenFGA, Zitadel, GCP, React Native, Expo EAS ### Edge services for industrial equipment Industrial and edge. Programs on Linux gateways that read and control equipment over Modbus and vendor protocols, hold data while the connection is down, and send it to the cloud platform the customer uses. Stack: Linux, Go, Modbus TCP/RTU, MQTT #### The problem On site, inverters, meters and controllers each use their own protocol. Their data has to reach the cloud even when the connection drops now and then, and support engineers need access to the gateway without a VPN to every site. #### What I built The software on the Linux gateway next to the equipment. A few small programs read the devices, keep their settings and send data to the cloud. On top of that, a way for engineers to open a remote session when they need one. #### Architecture 1. Equipment: inverters, meters, sensors, controllers 2. Protocol drivers: one small program per protocol (Modbus TCP/RTU, vendor protocols) 3. Local message broker: the programs on the gateway talk through it (MQTT) 4. Cloud connector: the only part that talks to the cloud 5. Cloud platform: receives data, sends commands and settings back Support for a new device type means one new driver. Nothing else on the gateway changes. #### Key decisions and why - **Several small programs instead of one big one.** Drivers, the device list, settings and the cloud connection run separately. If the driver for one device crashes, the rest of the gateway keeps working, and each part can be updated on its own. - **Clear message structure.** Messages are split into three groups: data going up to the cloud, commands going down to devices, and internal messages. It is always clear which program may read or change what. - **Remote access without a VPN.** There is no VPN tunnel to every site. An engineer requests a session from the cloud, the gateway connects out, the session uses one-time keys and closes by itself after a while. No ports are opened on the customer's network. Technology: Linux, Go, Modbus TCP/RTU, Mosquitto (MQTT), SSH, WebSocket ### Speech-to-text platform Speech and AI. Dictation for Windows that works in any app: Word, Notepad, a browser. The desktop app streams audio to a backend in the cloud and types the text into the active window about 100 to 200 ms later. Stack: Python, Cloud Run, Cloud Armor, streaming audio #### The problem People wanted to dictate instead of typing, in any program they use, on normal Windows PCs with whatever microphone they had, and see the text while they were still talking. #### What I built A Windows app that records the microphone and types the recognised text into whatever app is in focus: Word, Notepad, a browser or anything else. Behind it, a backend in the cloud receives the audio and sends it to an external speech-to-text service. #### Architecture 1. Microphone: on the user's Windows PC 2. Desktop app: records audio and removes background noise 3. Load balancer and firewall: first stop for every request (Google Cloud Armor) 4. Backend: receives the audio as it is recorded (Python on Cloud Run) 5. Speech-to-text service: external AI service that turns audio into text 6. Text in any app: typed into the active window, about 100 to 200 ms after speaking Words appear while the user is still speaking and are corrected once the sentence is finished. #### Key decisions and why - **Works in every application.** The text is typed into whichever window is active, the same way a keyboard would. People dictate straight into Word, email, a browser form or the company's own software, without copying and pasting. - **Streaming instead of uploading.** The app sends audio in small pieces while the user speaks, instead of uploading a recording at the end. Text comes back in about 100 to 200 milliseconds. - **Backend on Cloud Run.** The backend runs in containers on Google Cloud Run. More instances start when many people dictate at the same time and stop when they don't, so we pay for actual use. - **Firewall in front of the backend.** Every request first goes through a Google Cloud load balancer with Cloud Armor, which blocks malicious traffic and limits abuse before it reaches the application. - **Speech provider can be changed.** The desktop app never talks to the speech provider directly, only the backend does. We can compare or replace providers without releasing a new version of the app. - **Recording that works on any PC.** Microphones and audio drivers differ a lot between PCs. Starting and stopping a recording is handled carefully, so clicking quickly several times does not leave the microphone stuck. Technology: Windows desktop, Python, Audio streaming, Noise suppression, Google Cloud Run, Cloud Load Balancing, Cloud Armor ### Diagnostics assistant for operators AI operations. An AI assistant in the operations console. It can only use a fixed set of tools, looks up live data and past cases, opens tickets for the right team, and asks a person before changing anything. Stack: LLM, MCP server, existing APIs, human approval #### The problem Operators spent a lot of time going through charts, logs and old notes to answer questions like why a unit lowered its output last night, and then had to open a ticket for the right team. #### What I built An AI assistant in the operations console. It answers questions using live data and a knowledge base, opens tickets in the right place, and writes down every solved problem so it can use it next time. #### Architecture 1. Question: typed in the operations console 2. AI model: decides what it needs to look up or do 3. Tool server: offers only approved tools, each one calls an existing API (MCP) 4. Data and knowledge base: live measurements, history and reports from earlier cases 5. Approval: a person confirms actions that change something 6. Ticket and report: ticket goes to the right team; a report is saved for next time The model has no direct access to databases or systems. It can only use the tools it is given, and each tool has its own limits. #### Key decisions and why - **A fixed set of tools.** The assistant connects to an MCP server (Model Context Protocol) that gives it a short list of tools. Each tool calls one existing API with the same permission checks as everything else, so the AI can only do what those tools allow. - **Approval depends on the action.** Looking something up happens right away. Anything that changes a system waits until a person approves it. - **It learns from solved cases.** After a problem is solved, the assistant writes a short report into the knowledge base. When something similar happens again, it finds that report and gets to the answer sooner. - **Tickets go to the right team.** Depending on the type of problem, the ticket is created in a different system or queue, so nobody has to sort them by hand. Technology: LLM, MCP server, REST APIs, Knowledge base, Human approval ### Mobile app and cloud API for device control Mobile and connected devices. A cloud API and an iOS and Android app for switching devices, setting schedules and checking energy use at home. Commands go through a hub in the house that talks to lights, heating and locks. Stack: React Native, Expo, Go, Zigbee, Z-Wave, MQTT #### The problem People wanted to control the devices in their home from one app: switch them, set schedules and check energy use, on iPhone and Android, with different rights for different members of the household. #### What I built The cloud API and the mobile app. The app talks to the API, and the API talks to a hub installed in the home, which controls the devices. #### Architecture 1. Mobile app: one app for iOS and Android (React Native, Expo) 2. Cloud API: accounts, homes, permissions, schedules (Go) 3. Hub in the home: small device that controls the others (C++) 4. Devices: lights, heating, locks, sensors over Zigbee, Z-Wave, Wi-Fi and MQTT A tap in the app goes through the API to the hub and on to the device. The new state is sent back to every phone in the household. #### Key decisions and why - **One app for iPhone and Android.** The app is built with React Native and Expo, so one codebase goes to both app stores and still has push notifications and other phone features. - **Every device looks the same to the app.** Devices use different wireless standards. The hub converts Zigbee, Z-Wave, Wi-Fi and MQTT devices into one model, so for the app a light is a light, whoever made it. - **API in Go.** The API keeps a connection open to many hubs and phones at the same time. Go handles that well with little memory. - **Different rights for different people.** Several people can share a home, each with their own permissions, so not everyone can change everything. Technology: React Native, Expo, Go, C++, Zigbee, Z-Wave, Wi-Fi, MQTT, Push notifications ### Admin console for thousands of users Business software. An internal tool, similar to a CRM, where administrators manage settings for thousands of users. Sign-in with the company account and a log of every change. Stack: Python, Google Firebase, single sign-on, audit log #### The problem Administrators managed settings for thousands of users. They needed one place to find a user, change their configuration safely and later see who changed what. #### What I built An admin tool similar to a CRM: search users, edit and apply their configuration, sign in with the company account, and keep a full history of changes. #### Architecture 1. Administrator: signs in with the company account (single sign-on) 2. Admin tool: find users, edit settings, look at history 3. Backend: checks permissions and applies the change (Python) 4. Google Firebase: stores users and configurations, handles sign-in 5. Audit log: who changed what, and when Each change is checked, applied and written to the log in one step. #### Key decisions and why - **Google Firebase for storage and sign-in.** Firebase provides the database, sign-in and hosting, so there are no servers to maintain, and thousands of users need no extra setup. - **Company sign-in.** Administrators use their existing company account (single sign-on). There are no separate passwords, and people who leave the company lose access automatically. - **History of every change.** Every configuration change is saved with who made it and when. Support questions, audits and undoing a change are easy. Technology: Python, Google Firebase, Single sign-on, Audit log ### Event processing pipelines Cloud backend. Backend services that take in a constant flow of messages from devices and other systems, process and store them without losing any, and pass them on to customers' systems. Stack: Go, NATS JetStream, GKE, monitoring #### The problem A large number of messages comes in from devices and other systems all the time. They have to be processed, stored and passed on to other systems and customers, and none can be lost when one part slows down. #### What I built A processing library in Go and the setup it runs on. It receives messages, sends each one to the right handler, slows down intake when a handler can't keep up, and delivers results to the database and to customers' systems. #### Architecture 1. Devices and systems: send messages (MQTT) 2. Receiving service: takes in and checks every message (Go) 3. Message queue: keeps messages until they are processed (NATS JetStream) 4. Handlers: each kind of processing runs separately 5. Database and webhooks: measurement database and customers' own systems If the database slows down, messages wait in the queue. Nothing is dropped. #### Key decisions and why - **Slow down instead of losing data.** When one handler falls behind, only its intake slows down. Messages are not dropped and the database is not overloaded. - **Handlers subscribe to patterns.** A handler can ask for, say, 'all alarms from any site'. When several handlers want the same messages, each message is still fetched only once. - **Sending events to customers.** Customers receive events through webhooks, fed from the message queue. If a customer's system is offline for a while, the events wait for it. - **Runs on Kubernetes (GKE).** The services run on Google Kubernetes Engine. Crashed parts restart on their own, more copies start when traffic grows, and monitoring shows what each part is doing. - **Checked the numbers before choosing a broker plan.** Before picking a hosted MQTT broker plan, I calculated real message volumes in both directions. That avoided a plan that would have been too small or too expensive as the number of devices grows. Technology: Go, MQTT, NATS JetStream, ClickHouse, Webhooks, Kubernetes (GKE), GCP, Monitoring ## Methodology A clear four-phase process with one accountable engineer from start to finish. At every stage you know what is being built, why, and what it will cost. 1. **Discovery.** We define the business problem, who it affects and how success will be measured. I review existing systems and constraints, and confirm whether custom software is the right investment at all. Outcome: Agreed goals and scope. 2. **Solution design.** Architecture, technology choices, security model and a phased delivery plan, set out in a concise written proposal with a realistic estimate for each phase. Outcome: Written proposal and estimate. 3. **Iterative delivery.** Working software from the first weeks, with regular demos and progress updates. Priorities can be adjusted between iterations without renegotiating the whole project. Outcome: Regular releases you can try. 4. **Launch and support.** Production deployment with monitoring, backups and documentation. After launch: maintenance and further development, or a structured handover to your own team. Outcome: Live, documented system. ## About me I started in 2018 as an embedded Linux engineer, writing C++ for devices. From there I moved up the stack to applications, cloud services and edge devices. After four years of hands-on development I became tech lead of a team of ten, responsible for the main technical decisions across the whole stack. Today I design and build distributed systems as an architect, on my own or with a team, depending on what the project needs. That path is why I am at home on every layer, from a device on a site to the cloud and the app a customer uses. My background in electrical engineering helps whenever software meets hardware. ### Education - MSc, Electrical Engineering, Faculty of Electrical Engineering and Computer Science (FERI), University of Maribor, Slovenia, 2016 to 2018 - BSc, Electrical Engineering: Automation and Process Computing, Zagreb University of Applied Sciences, Croatia, 2013 to 2016 ### Experience - 2018: Embedded Linux engineer. C++ on Linux devices, close to the hardware. - Then: Full-stack developer. Applications, cloud services and edge devices, end to end. - 2022: Tech lead. Led a team of ten across the full stack and made the main technical decisions. - Today: Software architect. Design and build distributed systems with different technologies and requirements, alone or with a team. ### Why work directly with me Not an agency, and not just a developer. A senior technical partner who turns a business problem into working software. - **Senior expertise.** Years of building and running production systems, from simple tools to distributed platforms. - **Direct communication.** You talk to the person designing and writing the code. Nothing is lost in translation. - **Fewer handoffs.** Product, architecture, backend and deployment decisions are made by one person who sees all of them. - **Faster iteration.** A change of plan is a conversation, not a re-planning meeting across four roles. - **Product thinking.** I build what solves the problem, which is sometimes less than what was first specified. - **End-to-end ownership.** From the first sketch to the production alert at 2 a.m. One person is responsible. - **Pragmatic technology.** Proven tools chosen for your situation, not for my CV. Boring where it should be. - **Security by default.** Access control, encryption and audit trails are part of the first design, not a task left for the end. ## AI is used where it creates real business value. AI is one component inside a larger system: connected to your data, limited to what it should touch, and measured against the work it replaces. Sometimes the best recommendation is not to use it. ### Usually a good fit - Answering questions from your documents, tickets or operational data - Extracting and classifying information from emails, forms and PDFs - Assistants inside existing software that can call your own APIs - Spotting anomalies in telemetry or business metrics - Speech-to-text for calls, meetings and dictation - Automating repetitive work your team does by hand every day ### Usually not worth it - Decisions that need to be exactly right every time, with no review - Problems a database query or a simple rule already solves - Adding a chatbot because competitors have one ## Security is part of the design, not a final checklist. Connected devices, customer data and AI agents all widen the ways a system can be misused. I build with that in mind from the first sketch, using proven tools and simple rules that your team can understand and keep up. - **Access control.** Who can see and do what, down to individual sites, devices or records. Multi-tenant from day one when customers share a platform. - **Identity and sign-in.** Single sign-on, OIDC and MFA through proven identity providers instead of home-made login code. - **Devices and edge.** Each device with its own identity, encrypted connections to the cloud, and remote access that is approved, time-limited and recorded. - **Data protection.** Encryption in transit and at rest, secrets kept out of code, and only the personal data you actually need. - **AI with limits.** Assistants and agents get the narrowest access that does the job. Read-only by default, with a person approving anything that changes data. - **Visibility.** Audit logs, alerts and monitoring that show who did what and when, so incidents are found early and explained quickly. ### How I manage security risk Good defaults are not enough on their own. Each project also gets a simple, repeatable process for finding risks, tracking vulnerabilities and deciding what to do about them. #### Threat modelling Find what can go wrong before it is built. I draw how data moves through the system and mark every point where it passes from one level of trust to another, for example from a device on a customer site into the cloud. Each part is then checked against the six STRIDE questions: can someone pretend to be someone else, change data, deny they did something, read what they shouldn't, take the service down, or get more rights than they should? For the most serious risks, an attack tree lists the actual steps an attacker would need, which shows where blocking them is cheapest. Outcome: A list of threats with agreed countermeasures, updated when the architecture changes. #### Vulnerability management Know what is inside the product, and which vulnerabilities matter. Every build produces a software bill of materials (SBOM, in CycloneDX or SPDX format) that lists each component, including the ones pulled in indirectly. Scanners such as Trivy or Grype check that list against known vulnerabilities on every build and again when new ones are published. Most reported vulnerabilities do not affect the product in practice, for example because the vulnerable function is never called. VEX statements record that decision with a reason, so the team works only on what matters and customers get a clear answer when they ask. Outcome: An SBOM and VEX file for every release, and a short list of real issues. #### Risk management Decide what to fix first, and write it down. Each risk is rated by how likely it is and how much damage it would do. For each one there is a decision: fix it, reduce it, accept it, or move it elsewhere, for example to a supplier or insurance. Every risk has an owner and a date, and the list is reviewed regularly. It is written so management can read it and make decisions, not only engineers. Outcome: A risk register management can read, with owners and deadlines. ### Selling connected devices or software in the EU? The EU Cyber Resilience Act turns much of this into obligations for manufacturers of connected devices and software, including desktop and mobile apps. Reporting actively exploited vulnerabilities has applied since September 2026, and the full set of requirements, including knowing your components and handling vulnerabilities during the support period, applies from December 2027. The process above is a practical way to be ready for both. ## Tell me about the problem. You don't need to know the solution yet. Describe what's slow, manual, fragile or missing. I'll reply within two working days with questions or a first idea of how to approach it. https://refacto-engineering.balug.net/contact