Oh man, Stephen, you're gonna get a lot of conflicting views on this one, posting it here. :)

For what it's worth I am on your side given a bunch of constraints that match my prior experience. So I have typically worked on small scrappy IT teams at companies that are working on something else -- whether maintaining a Roku channel or putting together the heating ducts and plumbing assemblies for a building or making sure your marketing companies are not making illegal promises to customers that you can't fulfill. Inside those teams there is some sort of pain that we are meant to alleviate -- say, executives are spending too much time telling accounting in slipshod fashion their estimates for how much money they anticipate will be coming in from various prospective contracts, and roughly when it will come. The idea is born: an app which accounting can grab information from, automatic emails to the executives, and a user interface that fits the executives like a glove so that this is a better-than-painless experience for the people who actually use it.

Given this context, I agree that you want to repeatedly iterate on the frontend of the product over and over until the actual users start to change the nature of their complaints. Their complaints started with: "I need to put in a Flotsam which is also a Jetsam, how do I do that?" / "What do you mean, I thought flotsam and jetsam were different things?" / "Well for established Wakes they are, but not when we are looking at a new Surf. Then sometimes they are different but sometimes something is both, until that Surf becomes a Wake." So it is a failure of your domain model to match theirs.

And you are right, being able to have that domain model in a couple of JSON structures really helps with your ability to refactor everything around, especially if you have a type system which can just tell you "look that function is still designed around the last iteration and it's gonna break now with this new structure."

Those problems are really hard to fix when that data structure has already been broken apart into tables to be stored in a relational database and then ossified into various Data Access Objects and API calls which perform the updates.

By contrast with this approach you have a time where the product has succeeded in matching the user's domain model, which comes when they say something like "hey I changed this in this other system but I am not seeing the change in your app" or maybe just "hey I ran into a bug where it looks like the software is no longer saving my changes." Something that reveals that they think this software is in beta rather than pre-alpha development. You have a conversation like, "It was never saving your changes, that's a forthcoming feature." / "Uh, how was this ever supposed to work if it didn't save my changes?" / "No, like, that has been part of the design from day one, but that turns out to be a really costly part of the development effort so we wanted to get you to sign off that this is exactly the app you want before we start to build that layer of persistence." / "Oh. Well where can I sign up? I really want this app!"

Also really good for the idea of "build one to throw away", once you have fixed up your domain model then it can be nice to start from a clean slate.

Let me also say where you are limited: sometimes you do have a reasonably good guess at the domain model. For example you might be doing anthropological work as a developer, sitting in on meetings and getting a sense for how people talk about a system, before building the app. Or, you are interfacing with an external API and its domain model is presented to you directly in its documentation. Or, you are designing a game engine and the decisions are up to you -- the "users" are people who will have to play the game later.

Here it is helpful to build back-to-front. In fact there is a really nice REST principle which you may wish to emulate if you can, called HATEOAS. If you can do it, it makes things so much simpler. The basic idea about HATEOAS is the exact inversion of what you are saying: a polymorphic frontend, rather than a frontend which knows what API calls to make and in what sequence. So the idea is to have an intentionally crappy frontend -- it is crappy because it is generic, the backend tells it "here are the many different sorts of objects tracked by the system, and here are the things you can do with them," and it configures up a crappy UI based on this skeleton which the backend gives it. UIs created procedurally by robots reading data structure descriptions will never be as pretty and fits-your-hands-exactly as ones you create yourself. And the key technology which enables this front-end polymorphism is precisely linking: a web browser is able to show all web sites and is agnostic about how exactly everything connects because the web server tells it how everything connects. So if you have a survey app, when you get a survey from the backend the backend also tells you something about "to submit a new response to this survey, POST it to this URL, and validate the contents against this schema first." The crappy UI probably shows you the 10 questions for the survey up above, and then down by the "submit new response" form it contains 10 answer fields and you have to scroll between the top and the bottom for each question. Very inconvenient, because it is generic.

But on the flip-side, you usually get a good-enough-for-developers-for-now UI on the frontend, and now you can modify the domain model and services purely on the backend.

My white whale is probably to combine both of these together someday. :)