Safe Passage to AI
- Web front end to be added
- Mobile apps to be developed
graph TD
UI(["HTMX Web UI<br/>(Browser)"])
APP(["Web Server<br/>.NET Container"])
DB(["Azure SQL<br/>(Managed)"])
WIN(["Win32 Monolith<br/>(Azure VM)"])
CLOUD(["Azure Cloud<br/>Logging · Backups · Monitoring · Security"])
UI -->|HTTPS| APP
APP -->|SQL| DB
APP -->|IPC / ACL| WIN
APP & DB & WIN -->|hosted in| CLOUD
Native Mobile UI requirement will basically explode the complexity
Classic Strangler Fig pattern applies here. The web front end becomes the entry point; the Win32 monolith is progressively hollowed out from behind it.
Key architectural decision: Do NOT attempt to expose the Win32 GUI directly. Treat the existing monolith as a black box with a new service boundary cut in front of it.
Introduce a thin backend service (the ACL) that is a “Facade” to the Win32 monolith:
graph LR
B(["Browser"])
WF(["Web Server"])
ACL(["Anti Coruption Layer"])
WIN(["Win32 Monolith<br/>COM · RPC · named pipes · CLI"])
DB(["RDBMS"])
B -->|HTTPS| WF
WF -->|Proto Buf| ACL
ACL -->|IPC| WIN
WIN -->|IPC| DB
ProtoBuf contract; the monolith sees no changesAim for JSON Free architecture. That leads to much faster and much safer system.
Once the ACL is in place, each functional domain can be extracted one at a time:
graph LR
B(["Browser"])
WF(["Web Server"])
GW(["API Gateway"])
SvcA(["New Service A<br/>(containerised)"])
SvcB(["New Service B<br/>(containerised)"])
ACL(["ACL"])
WIN(["Win32 residual<br/>(shrinking)"])
DB(["Legacy Data"])
DBN(["New Data"])
B -->|HTTPS| WF
WF --> GW
GW --> SvcA --> DB
GW --> SvcB --> DBN
GW --> ACL
ACL -->|IPC| WIN
WIN -->|IPC| DB
Extract modules in order of: highest business value first, lowest coupling second.
Modularization is diffuclt technicaly. Also logicalt because it has to be business driven. One business function =~ One module
graph LR
AGENT(["AI Agent<br/>(LLM-driven)"])
NEW(["New Service<br/>(containerised)"])
ACL(["ACL<br/>(ProtoBuf)"])
MCP(["MCP Server<br/>(JSON / HTTP)"])
DB(["Legacy DB<br/>(RDBMS)"])
WIN(["Win32 Monolith"])
AGENT -->|tool call| MCP
NEW -->|ProtoBuf| ACL
ACL -->|IPC| WIN
MCP -->|SQL| DB
WIN -->|SQL| DB
The AI Agent is a backend component. It is never exposed directly to the browser. A New Service invokes it when it needs AI reasoning (e.g. summarise customer history, suggest next action). The Agent fetches legacy data (if it needs legacy data) via the MCP Server and returns a result to the calling service.
graph LR
B(["Browser"])
WF(["Web Server"])
GW(["API Gateway"])
SVC(["New Service"])
AGENT(["AI Agent<br/>(LLM-driven)"])
LLM(["LLM"])
MCP(["MCP Server"])
DB(["Legacy DB"])
B -->|HTTPS| WF
WF --> GW
GW --> SVC
SVC -->|invoke| AGENT
AGENT -->|tool call| MCP
AGENT -->|prompt| LLM
MCP -->|SQL| DB
| Question | Why it matters |
|---|---|
| Does the Win32 monolith have any existing IPC surface? | Determines ACL integration cost |
| Is state held in a DB or in-process? | In-process state = harder extraction |
| Is the GUI tightly coupled to business logic? | Likely yes — plan for logic duplication during transition |
| Who owns the Win32 source? | Rewrite risk vs. wrap risk |
Recommended stack for ACL (pragmatic, containerisable):
Web frontend — decouple completely from day one. SPA (React/Vue) or server-rendered — that decision is independent of the modernisation path.
The guiding principle: the monolith shrinks, it does not get rewritten in one shot. The ACL protects the new system from the old system’s semantics until extraction is complete.
QUESTION: What is the Win32 monolith’s existing IPC surface, if any?
© dbj@dbj.org , CC BY SA 4.0