// case study

From one-file prototype to App Store product

A solo founder arrived with a 2,000-line app.py that genuinely worked. He left with a signed macOS application, a Stripe subscription stack, a marketing site, and a release pipeline he runs himself.

scope Refactor, packaging, subscriptions, marketing site, App Store submission
stack Electron · React · TypeScript · Python · PyTorch · Supabase · Stripe
time ~10 weeks of senior engineering

Processing thousands of RAW images went from hours to less than 5 minutes.

Tyler, founder, MVK AI
From one-file prototype to App Store product screenshot
// the short version

A prototype that worked. A product that sells.

A solo founder came to us with a working AI prototype that lived inside a single 2,000-line app.py file. It genuinely worked. It did what he needed it to do, used his fine-tuned model to cull a photo shoot the way he would cull it, and he had been using it himself for months. He did not have a bug. He had a product without a business around it.

He needed us to take that prototype and make it something he could sell. Refactor the monolith. Package it into an installable macOS app. Add Stripe subscriptions and a free tier. Build a marketing site. Submit it to the App Store. Handle versioning and updates going forward.

That is what we did. MVK AI now ships as a signed macOS application with a public marketing site, a working free-trial tier, and a $19/month Pro subscription, while keeping the product’s core privacy guarantee intact: 100% of photo processing happens on the user’s own machine, with no images ever leaving their computer.

// why this case is different

Stable is the starting line, not the finish line.

Most of the "vibe-coded rescue" content on the internet stops at the moment the app is stable. As if stable is the finish line. For a founder with a real product and real customers, stable is the starting line. Stable is where you actually have to go build a business.

The MVK AI engagement covered all of it: the refactor, the packaging, the monetization layer, the marketing site, and the submission and distribution plumbing. A narrow refactor engagement would have fixed the code and left the founder with the same problem he started with: a working app he could not sell.

Scope is the point. The only version of this engagement that makes sense is the complete one.

// what the client arrived with

A working tool. Not yet a product.

The founder is a working photographer who built what he needed for himself. He learned enough Python to string together a pipeline. The model worked well, the logic was sound, the code was generously a single file. None of this is a criticism. The founder built the right thing for where he was.

[01]

Everything lived in app.py.

Flask routes, model loading, image preprocessing, inference, result caching, file I/O, and CLI entry point. All one file, no modules, no boundaries. Any change to one thing risked every other thing.

[02]

The model loaded at global scope.

First-run startup time was painful. Hot reload during development was worse. The Electron layer would have shown a frozen window during the first 2.3 GB of model load.

[03]

No separation between app and environment.

Python dependencies, model weights, and code were coupled in a way that made distribution impossible. Another photographer could not run this without the right Python, the right CUDA/MPS setup, the right PyTorch build, and a willingness to read stack traces.

[04]

Error handling was minimal.

If the model failed to load, an image was corrupt, or the user’s machine ran out of memory mid-batch, the user got a crash, not a useful message.

[05]

No auth, no subscription model, no distribution story.

Because there was not a product yet. There was a tool the founder used. Our job was to build everything the prototype did not have to.

From the initial concept to launch, they handled everything from AI model integration to web design and backend development with real attention to detail. What stood out most was their ability to take complex ideas and translate them into a clean, functional, and well-designed application.

Tyler, founder, MVK AI
From one-file prototype to App Store product screenshot
// what we built

Five tracks, all running in parallel.

The engagement broke into five tracks. Each one had a clear "done" condition. Each one shipped.

[01]

The refactor.

The app.py monolith became a pnpm-managed monorepo: apps/desktop (Electron shell), apps/web (React UI), apps/server (modular Python Flask), and shared packages for UI, types, and utils. Model load moved behind a lazy initializer with a progress callback. Inference moved to a background worker so the UI stays responsive during batch runs. Errors now surface as typed exceptions translated into actionable user messages.

[02]

The packaging.

The track with the least glamour and the most surface area. Bundling the Python runtime, dependencies, and 2 GB PyTorch model into a signed and notarized macOS .app that passes Apple Gatekeeper. Apple Silicon (MPS) build with an Intel fallback. Electron Builder configured for signed DMG output. Auto-updater wired against a release feed. A release script the founder can run himself.

[03]

Monetization.

A working three-tier model: Free (100 images), Pro ($19/month, unlimited), Enterprise (custom). Stripe subscriptions, checkout, customer portal, and full webhook handling for the subscription lifecycle. Entitlement syncing through Supabase. Free-tier enforcement in the desktop app, since the server is local. Trial and grace-period logic, all handled explicitly.

[04]

The marketing site.

mvk.ai is a Next.js site on Vercel. Dark theme, fast load, clear value prop at the top, download CTA front and center, pricing transparency below the fold. SEO configured for the long-tail queries photographers actually search. Analytics and conversion tracking wired to download and Stripe checkout.

[05]

Distribution and ongoing release management.

Apple Developer account, App Store submission, review cycle, and a versioning strategy the founder runs himself. Internal documentation explaining what to do when a release ships, when Apple rejects a build, when a user reports a crash. Then we handed it over. The founder runs his own releases now.

// the architecture decision that mattered most

Privacy as architecture, not policy.

The product’s strongest differentiator, stronger than the UI, the AI model, or the price, is the privacy promise. Your photos never leave your machine. For a wedding photographer sitting on 2,000 unpublished images from a client’s private event, this matters enormously. Any competitor that sends images to a cloud API for processing loses this buyer on day one.

That promise had to be engineered, not marketed. The desktop app holds the React UI, the local Flask server, the PyTorch model, and the user’s photos. None of that touches the network. The Supabase cloud holds authentication, subscription status, and the user’s plan. It does not know what you photographed, how many shots you took, what you kept, what you culled, or anything else about your actual work. It literally cannot. The data path does not exist.

This separation is enforced by the code, not by policy. The Flask server has no outbound network capability in the shipping build. If we ever wanted to add a cloud feature later, it would require a deliberate architectural decision and a user-facing opt-in, not a flag flip.

This is the kind of decision vibe-coding tools do not make on your behalf. The default path of least resistance for any AI-enabled app built by an AI assistant is to send the data to a cloud API and get a result back. For MVK AI, that path would have killed the product. The engineering judgment to build it differently is exactly the 30% AI cannot finish.

From one-file prototype to App Store product screenshot
// before / after

A working tool, then a shipping product.

The prototype did its job by proving the product was real. Everything below is what it took to build the business around it.

Metric
Prototype
Shipping product
Code structure
Single app.py, ~2,000 lines
Monorepo, ~40 modules, strict boundaries
Batch processing (thousands of RAWs)
Hours
Under 5 minutes
Distribution
Run from terminal with manual Python setup
Signed macOS .app, drag-to-Applications
Platform support
Developer’s own machine
macOS (Intel + Apple Silicon)
Model load
Global scope, blocks startup
Lazy, backgrounded, progress UI
Error handling
Stack traces to terminal
Typed exceptions, actionable user messages
Auth
None
Supabase (email, Google, Facebook)
Monetization
None
Stripe: Free / Pro / Enterprise
Subscription enforcement
N/A
Entitlement checks at launch and key actions
Trial / grace periods
N/A
Full Stripe lifecycle handling
Marketing site
None
mvk.ai on Vercel, SEO-configured
App Store presence
No
Submitted, approved, published
Release pipeline
Copy files manually
`pnpm release` - versioned, signed, notarized, published
Auto-updates
No
Electron auto-updater against release feed
Privacy posture
"I run it myself"
Architecturally enforced: no outbound image traffic
Handoff-ability
Operable only by the founder
Documented; founder ships his own releases

Every row is a specific, independently verifiable shift. Published with the founder’s permission.

// next step

Got a working prototype and no business around it?

If your prototype is working but you cannot figure out how to ship it as a product, book a production audit. A senior engineer reads your code and your product, maps out what it takes to get to shipping, and gives you the honest estimate.

Book a production audit