DEV Community

Deepak K
Deepak K

Posted on

Prompts to Production — A Full Stack Application by Sonnet with Catalyst

If you're anything like me, you think vibe coding is the most overhyped term in software development right now.

Not because it doesn't work. But because most people doing it are using Claude like a fancy autocomplete. They paste an error message. They ask for "a login page." They copy the output, watch it break, and go back to the chat feeling like they must be doing something wrong.

They're not wrong. They're just treating the most powerful agentic tool in history like a search engine.

Here's the reality. Most developers vibe coders, indie hackers, and even experienced engineers use AI in a way that guarantees mediocre output. They start every session from scratch. They describe what they want without explaining what they have. And when Claude produces code that doesn't fit, they blame the model.

I'm not here to talk down on anyone. I've shipped more spaghetti with Claude than I care to admit. But the pattern of developers trying to build with AI and hitting the same walls, over and over, holds true and there's a reason most of them never make it past a localhost preview.

So whether you want to build your first cross-platform app, get past the point where the backend logic breaks, or finally ship something to production users on mobile and web — I want to share 7 ideas you probably haven't encountered on AI-assisted development, full-stack architecture, and agentic workflows.

This isn't a tutorial. It's a shift in how you think about building with AI.

Let's begin.


I — You aren't shipping because Claude has no memory of what you built

Here's the uncomfortable truth about every new Claude session.

It doesn't know your app. It doesn't know your database schema, your auth pattern, your deployment target, or the CORS configuration you spent 4 hours debugging last Tuesday. Every conversation starts from absolute zero, a blank context window with infinite potential and zero relevant knowledge about what you're actually building.

Most developers respond to this by providing partial context. They paste the component that broke. They describe the feature they want. They attach the error log.

And Claude does its best. Which means it produces code that looks reasonable in isolation, follows common patterns, and has nothing to do with the architecture you already have.

Think about what this means in practice. You paste a broken auth function. Claude produces a clean solution using a different session model than you've built, a different token pattern than your backend expects, and a header name that your middleware will never catch. Not because Claude is wrong. Because Claude is designing for a generic app that doesn't exist, rather than the specific system you've already built.

The problem isn't your prompts. The problem is that your prompts have no memory.

Every session you start without context is a session where you're paying Claude to reinvent your architecture from scratch.

There's a fix for this, and it's the most important thing I can tell you about building with AI. But to get there, we need to go one layer deeper.


II — Your AI builds generic apps. Your architecture is specific.

When we built TracE, a cross-platform productivity app running on Expo React Native, a custom Express backend on Catalyst serverless, and Catalyst DataStore with ZCQL, we hit this problem on day one.

Claude would produce components that looked exactly right. Clean TypeScript. Proper hooks. Reasonable prop types.

And then we'd wire them into the actual app and nothing would work. Not because the code was bad. Because the code assumed a different world.

It assumed a REST API with standard Authorization headers, but our backend uses a custom X-TE-Token header to avoid Catalyst's gateway intercepting standard auth headers. It assumed localStorage for token storage, but our app runs on both mobile and web, and expo-secure-store doesn't work on web, so we have a platform-specific storage wrapper in AuthContext.tsx. It assumed import for native modules, but any native module imported statically will crash the app on an OTA update.

None of these are obscure requirements. They're just specific to our stack. And Claude had no way to know any of them.

The breakthrough came when we stopped describing what we wanted and started giving Claude the entire system to work from.

We built a single reference file tracE.md that captured everything a new Claude session would need to implement any feature immediately. The full stack and infrastructure. Every database table with column-level notes. Every backend route with its auth requirements and expected payload. The critical patterns and gotchas we'd learned the hard way. The exact deploy workflow from local dev to production.

We put it at the top of every Claude session, before any request.

The difference was immediate. Claude stopped guessing. It started building for the specific system we had. Feature requests that used to require 3–5 back-and-forth rounds landed correctly on the first pass. Bugs that required "explain the whole context" before Claude could help were resolved with a single prompt.

The architecture file is not documentation. It's Claude's working memory for your app.


III — Why vibe-coded apps collapse at the third layer

There's a pattern I've watched repeat across every developer who starts building with AI and eventually stops. It follows three stages that map almost perfectly to the layers of a full-stack application.

Layer 1 — The Interface. Everyone gets this far. Claude is exceptional at UI. Ask it to build a task card component, a date picker, a search overlay, an animated input bar, and it will deliver something that looks great in 90 seconds. This is where vibe coding earns its reputation. This is also where most tutorials stop.

Layer 2 — The Data Layer. State management, data hooks, optimistic updates, polling, pagination. Things start to get harder here. Claude can still produce good code, but the decisions become interdependent. How your data hook is structured determines how every component refreshes. How you handle optimistic updates determines whether your UI feels instant or laggy. The code Claude produces in isolation won't integrate cleanly with the architecture you're building toward. Sessions without context start producing real technical debt here.

Layer 3 — The Production Layer. Auth, backend routes, deployment, multi-device sessions, platform-specific behavior, CORS, environment switching, native versus OTA update constraints. This is where most vibe-coded apps stop shipping. Not because the developer gave up, but because the context requirements exploded beyond what a casual prompt could carry.

Consider the TeSessions problem in TracE. We originally had a single sessionToken column in the TeUsers table. Simple. Worked fine. Until we added the web app.

Web login overwrote the mobile token. Logging in on a browser logged out the phone. A classic multi-device session problem, one that every serious auth system solves, but one that requires understanding your specific data model to fix correctly.

The solution was a new TeSessions table: one row per active session, unique token per device, middleware querying the table instead of the user record. Straightforward once you see it. But if you described this problem to Claude without the existing schema, you'd get a generic session management implementation that doesn't match what you've already built.

With the full schema in context, Claude diagnosed the issue, proposed the TeSessions table, wrote the migration, updated the auth middleware, and modified the login and logout routes in a single exchange.

Layer 3 isn't where developers fail. It's where developers without context fail.


IV — The architecture file is the unlock for agentic development

"Cybernetics: the art of getting what you want."
— Norbert Wiener

In engineering, a feedback control system can only navigate toward a target if it has two things: a clear goal and an accurate model of its current state. A ship's autopilot doesn't just know where it's going it knows the ship's current heading, speed, and position at every moment. Without that model, corrections are random. With it, every adjustment is purposeful.

Claude works the same way.

When you prompt Claude without context, you're asking a highly capable system to navigate toward a goal with no model of where it currently is. The output will reflect general best practices, not your specific system. It will look right but integrate wrong.

When you give Claude a complete architecture file, you're providing both the goal and the model. The target is whatever feature or fix you're describing. The model is the entire state of the system: the stack, the schema, the patterns, the constraints, the known gotchas. Now every output is a calibrated correction rather than an educated guess.

Here's what a useful architecture file actually contains:

The stack layer. Not just "React Native and Node." The exact SDK versions, the build tool, the serverless platform, how the web app is served (in TracE's case: as static files from inside the same Catalyst function, a same-origin architecture that eliminates CORS entirely). The URLs for production, development, and local environments.

The database schema. Every table, every column, and critically the why behind non-obvious decisions. The reason TeSessions exists is captured in the trace.md: "TeUsers had a single sessionToken column web login overwrote mobile's token, logging it out." That one sentence prevents Claude from regressing to the old pattern when it refactors adjacent code.

The API contract. Every route, its method, whether it requires auth, its expected payload. When Claude generates frontend code that calls /auth/login, it knows to send X-TE-Token in responses and expect it in headers not because it guessed, but because the contract is in the file.

The critical patterns. The decisions that have non-obvious consequences. In TracE: native modules use try { require(...) } catch instead of static imports, because static imports crash on OTA. ZCQL has a 300-row limit and needs pagination. Date strings from the Catalyst backend use a space separator before milliseconds, not a T, which breaks standard ISO parsing. These aren't edge cases they're facts about the system that Claude needs to know before touching any related code.

The gotchas. The mistakes you've already made. In TracE, we captured in the architecture file that the Zoho ZGS gateway strips CORS preflight headers for deployed functions, making the Slate URL completely unusable from the browser. We captured that ?? doesn't catch empty strings from Catalyst's ZCQL you have to use ||. We captured that if login shows "Failed to fetch" in the browser, the first thing to check is whether catalyst serve is running at all.

These aren't impressive technical facts. They're the specific, hard-won knowledge that makes the difference between Claude producing correct code and Claude producing plausible-looking code that breaks in production.

Build this file once. Update it as the system evolves. It compounds.


V — The Full-Stack Prompting Protocol: From Idea to Production

This is the protocol I'd follow if I were starting a new application with Claude today, using everything we learned building TracE.

It's structured in stages because that's how full-stack development actually works. The stages aren't rigid, but the order matters.

Stage 1 — Architecture First

Before writing a single line of application code, spend one session building the architecture file with Claude.

Describe the app, the problem it solves, and the user. Describe your infrastructure constraints, in our case, Catalyst because it was already available, but this applies equally to Vercel, Railway, or Fly. Let Claude propose a stack. Push back on anything that introduces unnecessary complexity. Then document the decisions.

A good architecture session produces: the stack with version specifics, the database schema with table and column rationale, the API surface with route-level contracts, the auth model, the deployment pipeline, and the first set of known constraints.

The output of Stage 1 isn't code. It's the reference file that makes all subsequent code correct.

Stage 2 — Layer by Layer

Build the application in order: data model → backend routes → data hooks → UI components.

Most developers start with UI because it's satisfying to see something. Resist this. The data model determines everything downstream. A schema decision you make in the first week will be load-bearing for every feature you build afterward.

With Claude, prompt each layer in context of the architecture file. When building backend routes, paste the relevant table schemas. When building data hooks, paste the relevant route contracts. When building UI components, paste the hook interfaces. Every prompt is a layer, and every layer has the layer below it as context.

Stage 3 — The Agentic Loop

This is where Claude becomes a genuine development partner rather than an isolated tool.

A single agentic loop looks like this: describe a feature, including the relevant sections of your architecture file → Claude produces the implementation → you test it → you report the exact error or behavior, including what you expected vs. what happened → Claude corrects it with the full context of what it just built.

The key is keeping the architecture file in the session. The correction step is where context-free prompting falls apart and context-rich prompting accelerates. Claude isn't guessing at your system when it debugs. It's reasoning about a specific system it already understands.

Stage 4 — Deployment Context

When you're ready to deploy, add the deployment workflow to the architecture file before prompting Claude to help with anything deployment-related.

In TracE, this means the distinction between catalyst deploy --only functions (which deploys to development) and promoting via the Catalyst console (which deploys to production). It means the web build pipeline: expo export --platform web, copy dist to functions/.../public, then deploy. It means OTA update via eas update --branch production for JS-only changes, vs. a new native build via eas build when you've added a package with native modules.

These aren't complex steps. But without them in context, Claude will produce deployment instructions based on a generic setup that may not apply to your specific platform configuration.

Stage 5 — OTA vs Native Decision Making

This is the last layer most tutorials never reach, and it's where production apps live or die.

If your app uses Expo, there are two categories of change: things that can be pushed without a new build (JS changes, component updates, new screens, logic changes) and things that cannot (new native modules, changes to app.json plugins, anything that touches the native layer). The distinction determines your release timeline hours vs. days.

Capture this decision framework in your architecture file. In TracE, we captured the exact pattern for wrapping native modules: try { require('expo-image-picker') } catch { Alert... }. This single pattern means that when a new OTA update drops, devices that don't have the latest native build won't crash, they'll see a graceful error message.

Prompt Claude to help you think through every new feature along this axis before building it. "Will this require a native build, or can it ship OTA?" answered before coding, not after.


VI — Turn Claude into a system, not a session

Most developers use Claude in bursts. A feature, a bug, a refactor. Then they close the tab and start over next time.

This is the equivalent of hiring a brilliant contractor, explaining your entire project to them, then letting them leave and hiring a brand new person the next morning.

There are three types of AI-assisted development work, and understanding them changes how you structure your time:

Building — intense focused sessions creating something that doesn't exist yet. A new feature, a new data model, a new screen. This is where the architecture file pays off most visibly. Deep work. Claude as the implementation engine for ideas you've already thought through.

Maintenance — consistent, narrower work keeping what you've built alive. Bug fixes, refactors, dependency updates, response time improvements. Claude is excellent at this. The key is scoping tightly: give Claude the specific file, the specific behavior, the specific expected output. No need for the full architecture file every time, just the relevant section.

Recovery — the work that most developers skip entirely. Stepping back from the system to ask: what is actually important right now? What technical debt is load-bearing? What's the next architectural decision that will constrain everything downstream? This is where you update the architecture file. Where you add the new gotchas you've just discovered. Where you think rather than build.

Recovery is where Claude becomes a thinking partner rather than a coding tool. Paste the current architecture file. Describe where the product is heading. Ask what decisions need to be made before the next build sprint. The output isn't code, it's clarity.

The best version of AI-assisted development isn't a faster way to write code. It's a faster way to think through your system, then write code that reflects that thinking.


VII — The game is context, precision, and iteration

Here's how you turn everything we just covered into something you can actually use.

Pull out a new page and write down these 6 things:

Anti-vision — The developer you refuse to become. The one who has been building the same app in localhost for 18 months. Who has 14 unfinished projects. Who uses Claude for 20 minutes a day to fix syntax errors and feels like they're behind everyone else. That version of you exists if you keep prompting without architecture.

Vision — The developer you are building toward. A full-stack application, running in production, on mobile and web, maintained in 20-minute sessions because Claude knows the system and can implement features on the first pass. A product with real users, real feedback, and a real improvement cycle. That developer doesn't have more hours than you. They have better context.

1-year goal — One shipped product. Not a side project. A system with a backend, authentication, real data, production deployment, and at least one person using it who isn't you.

1-month project — The architecture file and the data layer. Before any UI. Before any feature work. The schema, the routes, the auth model, the deployment pipeline — documented, understood, and in Claude's context for every session going forward.

Daily levers — One architecture-first prompt per day. Not "write me a component." A prompt that starts with the relevant section of your reference file, describes the specific feature or fix, and gives Claude the context to produce something that actually integrates. One prompt. One correct implementation. One step closer to shipped.

Constraints — What you won't do. You won't start a Claude session without the architecture file. You won't copy an output without understanding what it does and where it fits. You won't build another UI component before the data layer is solid.

Why does this matter?

Because this structure creates a feedback loop that tightens with every session. Your architecture file gets more accurate. Claude's outputs get more correct. Your ability to scope features gets sharper. Your debugging cycles get shorter.

The game isn't writing code faster. The game is building a system that gets easier to build with every decision you make clearly and document precisely.

Claude is the render engine. Your architecture is the level design. And the prompts, the precise, context-rich, system-aware prompts are how you play.

The more intentionally you play, the stronger the system becomes. And at some point, it becomes less like prompting and more like thinking because the architecture file is so complete that the feature almost writes itself.

That's the version of vibe coding worth building toward.

— Deepak K


TracE is a cross-platform productivity application built with Expo React Native, Express.js on Catalyst serverless, and Catalyst DataStore. The architecture and prompting approach described in this article was used throughout its development.

Top comments (0)