A founder came to us with an app that “just needed a few tweaks before launch.” It had a login screen, a working feed, push notifications, the works. Investors had seen the demo and liked it. The problem: every screen fetched its own copy of the user’s data with no shared state, so editing a profile in one place silently left five other places showing stale information. There was no way to “tweak” that. The data layer had to be rebuilt from the ground up. What looked like 90% done was closer to 40% done, and the 40% that existed was actively fighting the 60% still to come.
This isn’t a rare story. It’s the default outcome when speed is optimized above everything else, which is exactly what low-code builders and junior freelancers are good at producing. Fast is not the problem. Fast with no plan for what happens after launch is the problem.
Why “it looks done” and “it is done” are different claims
A demo has to satisfy one audience: whoever’s watching the screen. Production software has to satisfy a much larger set of demands at once — real network conditions, concurrent users, edge cases in the data, App Store review, a second engineer who didn’t write the original code. Most tools optimized for speed-to-demo quietly skip that second list, because nobody’s checking for it in a demo.
The tells we look for during a code audit are consistent enough that we can usually spot them in the first hour:
- No real state management. Every screen re-fetches and re-computes its own version of the truth instead of sharing one source. Works fine with one test user clicking around; breaks the moment two features touch the same data.
- Auth and permissions bolted on, not designed in. A login screen exists, but there’s no server-side check stopping a user from editing someone else’s data if they simply change an ID in the request. This is invisible in a demo and catastrophic in production.
- No error states. The happy path works. Turn off wifi mid-request, or submit a form twice by double-tapping, and the app either freezes or corrupts data quietly.
- Platform-specific shortcuts that don’t scale. Low-code tools especially tend to generate UI that looks native but can’t actually do things like background processing, deep linking, or camera/biometric access without a rewrite of that whole layer.
- No tests, no CI, no way to know if a change broke something else. Every new feature request becomes a game of whack-a-mole because nothing catches regressions.
None of these show up when someone taps through a demo in a pitch meeting. All of them show up the week you have real users, real load, or a second developer trying to extend the codebase.
Why this gets “finished” instead of fixed
The uncomfortable part is that most contracts aren’t structured to catch this. A freelancer is usually paid to deliver features, not to deliver an architecture that survives contact with the next six months of feature requests. So they build the fastest thing that satisfies the spec, hand it over, and move to the next client. The founder doesn’t find out the foundation is wrong until they hire someone to add the next feature — and that person tells them the honest, unwelcome truth: this needs to be rebuilt, not extended.
Low-code platforms have a version of the same problem baked into the tool itself. They’re genuinely excellent for validating an idea fast and cheap. But the visual builder that got you a demo in two weeks was never designed to hand off to custom backend logic, complex offline behavior, or anything that needs fine-grained control over performance or security. At some point the tool’s convenience becomes the ceiling on what the product can do, and there’s no gradual off-ramp — just a wall.
How to check before you sign a second contract
You don’t need to read code yourself to catch this. You need to ask questions that a corner-cutting build can’t survive:
- “Can I see this fail?” Ask the team to turn off your wifi mid-action, or submit a form twice fast. A production-minded build has an answer for what happens. A demo-only build usually just breaks.
- “Where does permission-checking happen?” If the honest answer is “in the app,” not on the server, anyone with basic tools can bypass it entirely.
- “What would it take to add [a real feature you’ll actually need], like offline mode or a second user role?” A vague answer or a long pause is information. So is “we’d need to rebuild the data layer first.”
- Get a second opinion before the next contract, not after. A short code audit from someone with no stake in the original build is cheap insurance against paying twice for the same feature.
The goal isn’t to distrust every fast build — plenty of quick MVPs are built soundly by people who know what they’re doing. The goal is to stop assuming “it works when I click it” and “it’s built correctly” are the same claim. They aren’t, and the gap between them is exactly where budgets and timelines quietly double.
This is the exact gap we work in at orithLabs — auditing existing codebases to tell you honestly what’s solid and what needs rebuilding, and building new features (including AI integrations) on architecture meant to survive past launch day. We’ve done this on our own shipped products, Crumb Count and Kompete, and we’re straightforward about what’s actually built versus what’s roadmap. If you’re staring at a “mostly done” build and aren’t sure which 40% it is, that’s a conversation worth having before the next contract, not after.