Every enterprise engineering team has a version of this story. A product manager writes a requirements document. Engineering reads it and estimates. A designer mocks something that doesn't quite fit the requirements. The PRD gets revised. Engineering re-estimates. The design is revised. Six weeks pass. The thing that ships doesn't match what anyone imagined at the start.
This is not a people problem. The people are fine. It is a tooling problem. The gap between "idea" and "working software" has always been too wide and too lossy to cross with documents.
The root cause is structural. The person with the idea has no way to show what they mean. They can only describe it, and description is lossy. The engineer who receives the description is doing interpretation, not implementation. Every step away from the original idea compounds the loss.
| Document-driven | Branch-first |
|---|---|
| Write PRD | Create feature branch |
| Commission design | Build UI against typed fixtures |
| Estimate | Push branch → preview URL |
| Revise (repeat) | Stakeholder sign-off |
| Build | Engineering hardening |
| Ship | Ship |
The industry has tried to fix this with better processes — design sprints, prototyping sessions, user story mapping. None of them close the gap. They improve the description. The gap is still there.
The workflow
Here is what it looks like when the architecture is right.
On Monday morning, a product manager has an idea. They:
- Clone the monorepo and create a feature branch
- Build a UI in the presentation layer against typed fixtures — no API code, no database
- Push the branch; a preview environment spins up automatically
- Share a URL with the stakeholder that afternoon
By two in the afternoon, the branch has a thumbs-up. By Tuesday morning, engineering picks it up. Their job is decomposition and productionization:
- Extract reusable components into the shared component library
- Implement the API handlers and define the database schema
- Write the validators and swap the fixtures for real API calls
- Write the end-to-end tests
They are not interpreting a vision. They are hardening an implementation that already proved itself with the people who matter.
The creative risk is retired before engineering touches the keyboard. The question of whether this is the right thing to build has already been answered. What remains is the question of how to build it properly, which is the question engineers are actually good at answering.
The product manager didn't write a spec. They wrote a branch. The branch is the spec.
The architecture
The architecture that makes this workflow possible has a clear shape: a monorepo containing a presentation layer, a business and API layer, a shared schema package, a component library, and end-to-end tests. The layers are separated by purpose, not by deployment boundary.
graph LR PL["Presentation"] -->|API calls| BL["API Layer"] PL & BL -->|imports| SP["Shared Schema"] BL --> DB[(Database)] CL["Component Library"] -.->|used by| PL
- Presentation layer — handles rendering and user interaction. Calls the API. Knows nothing about tenants, permissions, or data persistence. This is what makes it safe for a non-engineer to work in: they can build freely here without being able to break anything below it.
- Business / API layer — headless. Serves the presentation layer, mobile clients, third-party integrations, and public API consumers through the same surface. Multi-tenancy, role-based access control, and compliance boundaries are enforced here, invisible to clients above.
- Shared schema package — the type definitions for every data shape in the system. Both layers validate against it. The fixtures the product manager used to build the prototype are typed against it. Everyone works from the same source of truth, in the same repository.
- Component library — shared UI primitives, built once, used across all surfaces.
- End-to-end tests — validate the full integration path once engineering wires the real API.
One implementation: Next.js (presentation), NestJS (API), Zod (schemas), PostgreSQL (database), Redis (cache and queue), Storybook (components), Playwright (end-to-end). The pattern holds regardless of which specific tools you choose.
MCP and the agentic enterprise
Every enterprise application is now being asked the same question: how do we expose our capabilities to agents?
Most teams treat this as a separate workstream. A new surface. New authentication. New schema definitions. A dedicated team to own it. The premise is wrong.
graph LR WEB["Web"] & MOB["Mobile"] & MCP["MCP Server"] & PUB["Public API"] --> BL["API Layer"]
The presentation layer was always just one client among several. If your business layer is headless and your schemas are shared, adding an MCP server is additive, not structural. You point it at the same handlers, the same validators, the same authorization guards. The agent gets the same trustworthy, multi-tenant-aware interface that your web client gets — because it is the same interface.
Enterprise teams building a separate AI layer on top of their existing application are doing the work twice. The schema package that defines your API responses also defines your MCP tool signatures. The agent is just another client.
If you are building this architecture today, you are not preparing for the agentic future. You are already there.
The schema is the contract
Fixtures are not fake data. They are typed assertions about what real data looks like.
When a product manager builds a feature branch against fixtures, they are writing a spec implicitly: the API should return data in this shape, and the UI should behave this way when it does. Engineering's job is to make that spec real. When they implement the endpoint, they are satisfying a contract the prototype already proved works with stakeholders. There are no surprises about data shape. There is no negotiation between what the UI expects and what the API returns. The schema is a single package that both sides import. It cannot drift.
This is also what makes MCP tool definitions trustworthy. The same schema that validates an API response validates an MCP tool's output. An agent consuming your capabilities is working from the same contract a product manager used to build a prototype on a Tuesday afternoon.
The organization's knowledge about its own data shapes exists in one place, enforced everywhere, readable by humans and agents alike.
The schema is not a technical detail. It is organizational infrastructure.
The real cost of distribution
The case for microservices is usually made in terms of scale and team independence. The cost is rarely measured as carefully.
Start with the workflow cost. Split the API into services and the prototype workflow breaks immediately:
- Fixtures now span service boundaries
- Schemas drift independently — the user service defines a type, the permissions service defines its own, they diverge over months of separate development, and the PM's fixture no longer matches what any service actually returns
- Preview environments require spinning up multiple services and their dependencies
- The product manager can no longer prototype without infrastructure support, which means a ticket, which means a sprint, which means the idea is already six weeks from validation
Then there is the operational cost. Change a shared type in a distributed system and you are not making one change. You are making a change, waiting for CI to publish a package, going into another repository to bump the version, waiting for that pipeline to complete, repeating for each downstream consumer. A change that takes minutes in a monorepo takes days across services. Each handoff is a place where something can go wrong: a secret misconfigured, a version pinned incorrectly, a pipeline that fails on a Friday afternoon and waits until Monday to tell you.
The monorepo reduces this to a single CI run, a single secret store, a single pull request that contains the entire change. When something breaks, there is one place to look.
Enterprise teams often frame the monolith as a scaling risk they are managing. The distributed system is a complexity cost they are not measuring.
Enterprise compatibility
The objection worth addressing directly: enterprise requirements seem to push toward complexity. Multi-tenancy. SOC 2. HIPAA. Multiple client types. Public APIs. Mobile applications. Surely these require dedicated services.
They don't:
- Multi-tenancy is an API-layer concern, handled in middleware and guards, invisible to the presentation layer
- Compliance boundaries are enforced at the same layer
- Multiple clients — web, mobile, agent — are served by the same headless API
- A public API is another consumer of the business layer, with its own authentication surface and rate limiting, not a separate service with its own codebase and CI pipeline
The monolith can be decomposed later, at a specific bottleneck, with evidence. Not pre-emptively, as coordination infrastructure for a problem that has not appeared yet.
Pre-emptive decomposition is the thing that feels like architecture and costs like it too.
The ask
The org chart changes when anyone can build.
Product managers who can prototype stop writing requirements that get lost in translation. They stop waiting for engineering bandwidth to find out whether an idea is worth pursuing. They find out on Tuesday and know by Wednesday. Engineers who receive branches instead of PRDs spend their time on craft, not interpretation. They make real decisions — what to extract, what to harden, what to throw away — instead of reverse-engineering intent from a document.
The feedback loop between idea and shipped feature collapses. The agent is another member of that loop, capable of building and reviewing and implementing alongside the humans, on the same codebase, with the same contract.
One question before your next sprint planning: could a non-engineer on your team have built the feature branch you are about to implement?
If the answer is no, the architecture is the bottleneck. Not the people.
Further reading
- MonoRepo — Martin Fowler on the case for keeping all your code in one place
- Trunk-Based Development — the branching strategy that keeps prototyping fast and merges cheap
- Model Context Protocol — the open standard for connecting language models to tools and data sources