What It Takes to Turn a Useful Tool Into Infrastructure

Aug 20, 2026 | Blog

Reading Time: 4 minutes

There's a particular moment every genuinely useful internal tool eventually reaches, and it has nothing to do with features. It's the moment someone in leadership asks, quietly, "what happens if this breaks while I'm on a flight?" That question is the real test. Not "does it work" — "can we depend on it."

The MITS AI Letter Writer has spent its first chapter proving the first question. This final piece is about the second one — the unglamorous, deliberately boring engineering work of making sure a tool that now touches every single joiner and exit at MITS Staffing can be trusted the way payroll software has to be trusted.

Today: ASP.NET Core 9 MVCOutput on the file system, one folder per candidate, no databaseThin controllersBusiness logic pushed into services, nothing reaches for a raw newDependency injectionWired through Program.cs, so every service is swappable and testableThe secretAPI key in appsettings.json today. Fine for a laptop, not for productionObservabilityILogger throughout, candidate and employee group carried in context
The unglamorous layers are what turn a working tool into infrastructure.

Why "It Works on My Machine" Isn't Good Enough Here

Right now, the system runs as an ASP.NET Core 9 MVC application storing its output directly on the file system — a Result folder, one subfolder per candidate, no database involved. That's a completely reasonable way to build version one. It's also, by design, not the shape a tool takes once it needs to survive multiple instances, multiple environments, and multiple people depending on it at once. File-system storage doesn't hold up across a multi-instance deployment, which is precisely why the next architectural step already has a name: move Result output to Azure Blob Storage, so "where did that candidate's letters go" has one consistent answer no matter which server instance handled the request.

The Secret Nobody Should See

Every AI-powered tool has one uncomfortable dependency: an API key that costs real money and grants real access every time it's used. Today, that key lives in appsettings.json for local development — completely appropriate for a laptop, completely inappropriate for a shared server. The plan for anything beyond local dev is Azure Key Vault with managed identity, so the OpenAI credential never sits in a config file at all, and it carries only the narrow permission it actually needs: chat completions, nothing broader, nothing an attacker could pivot from into some other part of the org's infrastructure. Least privilege isn't a compliance checkbox here — it's what keeps one compromised HR tool from becoming a much bigger story.

The Quiet Discipline of Layers

Underneath the AI headlines, the codebase follows a deliberately old-fashioned discipline: SOLID design, thin controllers, business logic pushed into services, dependency injection wired through Program.cs so nothing ever reaches for a service with a raw new. It's not exciting to write about. It's exactly why the system can keep growing — new letter types, new employee groups, new salary rules — without every change becoming a nervous, all-hands regression hunt. The architectural roadmap already sketches the next evolution too: separating Web, Application, Domain, and Infrastructure into distinct layers, the kind of structure that sounds like overkill for a small internal tool and sounds exactly right for one that's quietly become load-bearing.

What "Production Ready" Actually Means Here

Authentication is a good example of doing things in the right order rather than the impressive order. Today there's no login — deliberately, because this is an internal tool living inside a trusted network, and adding auth complexity before it's needed just adds surface area without adding safety. But the plan is explicit and already written down: the moment this tool is reachable beyond the local network, Azure AD / Microsoft Entra ID goes in front of it, no exceptions, no "we'll get to it later." Knowing exactly when a safeguard becomes mandatory — and holding that line — is a different skill from building the safeguard itself, and it's the one that actually prevents incidents.

Observability tells the same story. Every operation already logs through ILogger, with candidate name and employee group carried in context so any log line can be traced back to a real person's file. AI call durations get logged. Exceptions get logged with full context — which candidate, which letter type, which template — because when something does go wrong at 11 PM, "an error occurred" helps nobody, and a proper trace helps everyone. Application Insights, structured JSON logs, and correlation IDs are next once this moves beyond a local deployment, so a failure six months from now on candidate seven hundred and something doesn't require guesswork to diagnose.

The Version of the Story That Doesn't Make a Good Demo

None of this is the part of an AI project that gets a slide with a big arrow and an exclamation mark. GPT-4o reading a messy offer letter and correctly inferring an employee group — that's the demo. Key Vault, managed identity, structured logging, layered architecture, an explicit auth plan sitting ready before it's forced by circumstance — that's the part that decides whether the demo is still working, correctly, quietly, a year later, without anyone thinking about it.

That's really the whole arc of this project, start to finish. It began by asking a very human question: why is someone still typing offer letters at midnight? It's ending, for now, by asking an equally human one: what does it take for six hundred people to trust a piece of software with their employment paperwork, not just once, but every single time, for years?

The honest answer is that trust isn't built in the AI call at all. It's built in everything quietly wrapped around it.

MITS AI Letter Writer · part 5 of 5Fifth and final piece in this series on the MITS AI Letter Writer project.