Key takeaways
- Treat POC and MVP as different architectures, not renamed
.envfolders. - Draw ingress and egress as separate boxes; is not VNet integration.
- Inventory private DNS zones and which VNets they link to before you call it private.
- Harden Entra (managed identity, app roles, Conditional Access) when the network hardens.
- Move secrets to Key Vault references over private networking; do not promote POC placeholders.
- Let networking and identity gate the stage label; configuration files follow.
A public POC proves the product loop. A private MVP proves you can survive locked-down networking.
Those are different architectures. Do not fake the second by adding more env files.
POC optimizes for learning the agent loop. MVP optimizes for who can reach what on which plane.
Named model: stage by plane
- Ingress: public or IP-filtered for POC; private endpoint for the MVP shell and critical APIs.
- Egress: regional VNet integration for MVP (route-all when egress must be inspected).
- Private DNS: zone inventory plus which VNets they link to, so names resolve to private IPs.
- Identity: managed identity for the app, Entra plus app roles for users, clear agent-platform reachability.
- Rule: networking and identity gate the stage label. Env files follow. A public hostname with POC secrets is still a demo.
Figure 1. Stage by plane. POC can be public or IP-filtered. MVP needs private ingress, private egress, linked DNS, and hardened identity. Renaming folders does not move the plane.
Context and constraint
Agent shells can go from "works on my machine" to "blocked by private DNS" in a single step. The model did not regress. The network plane changed.
Public ingress (or a tight IP allowlist) is a legitimate POC choice. Private endpoints, VNet integration, private DNS zones, and Key Vault references are the MVP choice. They are not the same diagram with different .env values.
Microsoft is explicit about the split on App Service: a private endpoint covers inbound private access to the app. Regional VNet integration covers outbound calls from the app into the virtual network. You often need both. Mixing them up in a README is how teams ship "MVP" that still answers on the public hostname.
Figure 2 is the Learn private-endpoint pattern for App Service. Treat it as inbound control, not as a synonym for "everything private."

Figure 2. Private endpoint pattern for App Service. Inbound private access is not outbound private access. Source: Microsoft Learn: App Service private endpoints.
Stage the differences you actually mean
Write an architecture table before you clone folders.
POC. Public or IP-filtered ingress. Faster iteration. Agent platform endpoints that may still be internet-reachable. Short-lived secrets or scoped App Settings. Enough Entra to sign people in and prove app roles. Good for shell behavior, streaming chat, and upload loops.
MVP. Private endpoints on the shell API and on data-plane dependencies that must not be public. VNet integration so the app can call private Key Vault, storage, and platform endpoints. Private DNS linked to the integration VNet so names resolve to private IPs. Clearer identity: managed identity for the app, app roles for users, Conditional Access where required. Network, private DNS, and monitoring owners become first-class.
What stays shared: product shapes (SPA, API, agent interfaces), the authorization model, and the role test matrix. What must never carry forward: leftover connection strings, old registry credentials, and "temporary" public allow rules.
1. Draw ingress and egress as separate boxes
Inbound private access is not outbound private access. Private endpoints put the app (or a dependency) on a private IP for callers on the network. VNet integration lets App Service workers reach private resources through a delegated subnet. Microsoft documents that those subnets must not be the same. If your diagram has one cloud labeled "private," redraw it. Figure 3 is the split.
Figure 3. Ingress and egress are separate boxes. Private endpoint locks who can reach the shell. VNet integration locks how the shell reaches Key Vault, storage, and platform endpoints.
2. Treat private DNS as a product dependency
The failure mode is almost always DNS: the hostname still resolves publicly, or privately for one subnet and not another. Link Azure Private DNS zones to the VNet the app integrates with. If you run custom DNS, make sure it forwards correctly. Do not debug this as an application bug for three days.
3. Harden Entra when the network hardens
User-facing agent apps still need a clear identity story when networking locks down. Entra decides who may open the shell. App roles on the API still decide which agent features and routes exist. Network isolation reduces who can touch the plane. It does not replace per-agent authorization. Both layers matter; they solve different threats.
Figure 4 is the Learn reminder that user-facing apps still need an identity story when the network hardens.

Figure 4. User-facing apps still need a clear identity story when networking hardens. Source: Microsoft Learn: authentication flows and app scenarios.
4. Move secrets out of "gitignored forever"
POC App Settings and local .env files are fine for a spike. MVP should use Key Vault references (or equivalent) reached over private networking where the platform standard requires it. Long-lived secrets in cloneable templates become the next incident.
5. Inventory registries, plans, and roles
Container registries, App Service plan SKUs, and managed identity role assignments are not interchangeable across stages without a diagram. Private MVP often needs a higher plan tier for VNet integration and private endpoints. Budget that as architecture, not as a surprise cost.
Failure modes
Env file theater.
Twelve templates named poc, mvp, prod that only change URLs while networking stays public. The README says MVP. The public internet says otherwise.
Private endpoint without private DNS. The app looks private in the portal and still resolves wrong. Symptoms look like random 403s and timeouts.
VNet integration assumed to lock ingress. Outbound integration does not make the app private. You still need private endpoints or access restrictions for inbound control.
Identity postponed until "after networking." You harden the plane and leave every signed-in user as a trusted agent operator. Network controls protect the plane; they do not replace per-feature authorization.
POC secrets promoted wholesale. Old placeholders, shared keys, and public storage endpoints hitch a ride into MVP because someone copied the folder.
One subnet for everything. Private endpoints and VNet integration fight over the same delegated subnet. The platform will not invent capacity for you.
What to copy / what not to copy
Copy
- Ingress model per stage (public or IP-filtered for POC; private endpoint for MVP shell and critical APIs).
- Outbound model for MVP (regional VNet integration, route-all if egress must be inspected).
- Private DNS zone inventory and which VNets they link to.
- Identity for app (managed identity), users (Entra + app roles), and agent platform reachability.
- Secret store location and rotation; no long-lived secrets in gitignored files as the long-term plan.
- Promotion rule: networking and identity gate the stage label; configuration files follow. Public exceptions need an owner and a review date.
Figure 5. Promotion gates, not env theater. Network and identity first. Secrets follow over private reach. Only then does the stage earn the MVP label.
Do not copy blindly
Private MVP is slower to stand up. You need network, DNS, and identity owners in the room. POC velocity drops when every change waits on a private link.
You lose convenience: portal demos and curl from outside the VNet. Plan VPN or a bastion path instead of quietly reopening public ingress. On-behalf-of flows get harder to debug when egress is locked; keep identity tests separate from network tests so you know which plane broke.
Primary references: App Service private endpoints, App Service VNet integration, and authentication flows and app scenarios.
If your MVP is still reachable on a public hostname with POC secrets, you do not have an MVP. You have a louder demo.