GM
EN/ES
Back to projects

Developer tooling / Windows

DevProxy Studio

A modular reverse proxy that exposes local applications to the network and captures, persists and inspects every HTTP exchange passing through it.

Role: Architecture, backend and desktop experience Duration: Own project, four phases delivered 2026

The problem

Testing a local application from a real device — a phone, an industrial tablet — requires exposing it to the network, and understanding what is failing requires seeing the traffic. Existing tools solve one or the other: discovering what is listening, exposing it and then inspecting the conversation means chaining three separate utilities.

Capture path — disk never touches the hot path The request crosses the proxy and is enqueued; a separate worker persists in batches. Request CLIENT Proxy KESTREL · YARP Queue BOUNDED CHANNEL Worker BACKGROUND SQLite BATCHED WRITES The channel is bounded: under sustained pressure it drops records instead of growing without limit.
Capture path — disk never touches the hot path

Constraints

  • Capture must not add latency to the traffic crossing the proxy
  • Each proxy must start, stop and restart without affecting the others
  • The interface must stay responsive while thousands of records are written

Decisions

Chose Queue each exchange in a bounded channel and persist it in batches from a background worker
Instead of Writing to the database on the same path that serves the request
Because The proxy's hot path must not wait on disk. The bounded channel also caps memory — under pressure it drops instead of growing without limit.
Chose A dedicated host per proxy, with an independent life cycle
Instead of A shared host with rule-based routing
Because Restarting one proxy's configuration should not interrupt the others. Isolation costs memory and saves incidents.
Chose Separate the domain from the interface, the persistence and the proxy library
Instead of Building on the desktop application directly
Because All three external dependencies are replaceable; the product rules are not. The dependency direction reflects that.

Outcome

  • Independent proxy life cycles — start, stop and restart per instance
  • Non-blocking capture with batched persistence
  • Request and response inspector with formatting, decompression and upstream error diagnostics
  • Discovery of listening ports and their owning process, exposed to the network in one click

The hot path and the cold path

The decision that defines this project is where the write happens. A proxy that persists every exchange inside the request path adds disk latency to every call passing through it, which ruins the tool exactly when it is most needed: under load.

Capture enqueues into a bounded channel and a background worker writes in batches. The channel is bounded on purpose: under sustained pressure, records are dropped rather than consuming unbounded memory. Incomplete diagnostics are recoverable; a process that exhausts the machine’s memory is not.

Why the layers

The domain knows nothing about the interface, the database or the proxy library. All three are replaceable and the product rules are not. The practical consequence showed up when port discovery was added: it came in as a new adapter, without touching the core.

Why it belongs here

Because it is a case where the architecture is justified by a concrete reason — protecting latency and memory — rather than by the habit of splitting things into layers.