The Idea Hit Me at the Gym
I've been saving ads and landing pages for years. Screenshots in random folders. Bookmarks I never revisit. Emails forwarded to myself with subject lines like "good ad" that mean nothing three weeks later.
Every marketer I know has the same problem. We all do competitive research. None of us organize it well.
I was mid-set at the gym when the full product concept clicked: a swipe file platform where you can save anything — URLs, emails, screenshots, videos — and AI organizes it automatically. Not a bookmark manager. Not a Pinterest board. A real tool built for people who study ads and funnels for a living.
I pulled out my phone, typed up the concept in about 200 words, and sent it to Ari. By the time I got home, the project was scaffolded.
Day 1: Architecture Decisions
The first thing Ari had to do was make a bunch of boring-but-critical decisions. Here's what we landed on and why.
Next.js 16 (Single Codebase)
API routes and frontend in one repo. File-based routing for the backend (/api/items/[id]/route.ts), server components for the marketing pages, client components for the dashboard. One deploy, one process, one thing to monitor.
I didn't want to manage a separate API server. For an MVP, the fewer moving parts the better.
SQLite Over Postgres
This is the one that makes backend engineers nervous. Here's why it was the right call:
- Zero config. No connection strings, no managed database service, no credentials to rotate.
- Single file. Backups are literally copying one file.
- Synchronous reads.
better-sqlite3in Node.js means no async complexity for queries. - Fast enough. For a single-server, read-heavy workload with early users, SQLite handles it easily.
The migration path is clear: when we hit ~50 concurrent users or need multi-server, we switch to Postgres. That's a good problem to have.
VPS Over Vercel
Vercel is great until you need system-level tools. We needed yt-dlp for video downloads, ffmpeg for processing, Postfix for inbound email handling. None of that runs on serverless.
A $10/month Ubuntu VPS gives us full control. PM2 for process management, Certbot for SSL, Nginx as reverse proxy. Total infrastructure cost: less than a single Vercel Pro seat.
The Stack Summary
- Framework: Next.js 16 + TypeScript + Tailwind
- Database: SQLite via better-sqlite3
- Auth: JWT cookies (httpOnly, secure, 7-day expiry)
- Hosting: Ubuntu VPS + Nginx + PM2
- Scraping: Apify (managed actors)
- AI: Google Gemini 2.5 Flash (auto-tagging + analysis)
- Payments: Stripe (Pro $19/mo, Team $49/mo)
- SSL: Certbot (auto-renewal)
Day 1-2: Core Features
Ari built the core loop first: capture → store → organize → search.
URL Capture
Paste any URL. Apify scrapes the page — headline, body copy, images, CTA elements, full-page screenshot. Smart routing sends Facebook URLs to one actor, Instagram to another, generic pages to the crawler. OG metadata extraction as fallback.
File Upload
Drag and drop images, videos, PDFs, audio files. Everything gets stored and indexed. Video files can be analyzed on-demand by Gemini — it extracts hook structure, offer presentation, CTA approach, emotional triggers, pacing notes.
AI Auto-Tagging
Every item that enters the system gets tagged automatically by Gemini 2.5 Flash. Content type, funnel stage (TOFU/MOFU/BOFU), primary emotion, industry vertical. Cost: about $0.001 per tag. At that price, there's no reason not to tag everything.
Collections
Folders for organizing items. Simple, but necessary. Drag items into collections, filter by collection, search within collections.
Day 2-3: The Features That Became Differentiators
The basic CRUD was done fast. The features that took more time — and more iteration — turned out to be the ones that actually matter.
Email-to-Swipe Capture
This started as a "nice to have" that I almost cut. Now it's one of the best features.
Every user gets a unique inbound email address (like you@in.swipebase.net). Forward any marketing email to it, and it becomes a swipe item. The system extracts the sender, subject, all links, resolves redirects, strips tracking params, and stores the full HTML.
The technical implementation was gnarly. Postfix pipe transport feeding into a Node.js script, sender whitelisting for spam protection, message_size_limit bumped to 50MB because iPhone photos are massive. The mailparser npm package has to be explicitly in package.json or production deploys silently break email processing.
But the user experience is dead simple: see a great email → forward it → it's in your swipe file.
iOS Shortcut (The Battle)
This one was a war of attrition against Apple's walled garden.
Attempt 1: PWA share target. iOS doesn't support it. Dead end.
Attempt 2: Generate .shortcut files programmatically. iOS blocks unsigned shortcut files. Dead end.
Attempt 3: Auto-read clipboard on page load. iOS requires a user gesture. Dead end.
What actually worked: A manually-built shortcut distributed via iCloud link. The user installs it once, enters their API key, and then sharing any URL from any app triggers a capture. We had to add GET support to the /api/quick-capture endpoint because iOS Shortcuts defaults to GET requests.
Three failed approaches before finding one that worked. That's the real engineering process — not the clean architecture diagram, but the graveyard of ideas that didn't survive contact with reality.
On-Demand Video Download
We don't proactively download every video — that would be a waste of storage and bandwidth. Instead, there's a "Download Video" button in the detail modal. Click it, yt-dlp runs on the server, handles TikTok/Instagram/Facebook/YouTube URLs, and stores the file locally.
Background process with polling for completion. Simple, resource-efficient, and it handles the nightmare of platform-specific video URL formats that expire after hours.
The Gotchas (A.K.A. The Real Story)
Every "we built X in Y hours" post conveniently skips the part where everything breaks. Here's what actually went wrong.
Windows → Linux Deploy Gap
I develop on Windows. The VPS runs Ubuntu. better-sqlite3 is a native module — the compiled binary is platform-specific. You can't build on Windows and deploy to Linux.
The fix: the deploy script sends source code to the VPS and runs npm install && npm run build remotely. Sounds obvious in retrospect. Cost us hours figuring out why the app crashed on first deploy.
PowerShell Mangles Everything
Ari runs in PowerShell on my Windows machine. PowerShell does... things to JSON, to escape characters, to string interpolation. Nginx configs with $host and $uri variables? PowerShell tries to interpolate them.
The rule we learned fast: write Python scripts for everything. Python handles SSH, SFTP, JSON, and string formatting without mangling anything. Every deployment, server operation, and API call is now a Python script. No exceptions.
iOS Auto-Zoom on Inputs
If any input field has a font-size below 16px, iOS Safari zooms in when you tap it. The fix is simple (font-size: 16px minimum, plus maximum-scale=1 in the viewport meta), but you only discover it after deploying and testing on an actual iPhone.
The .ne TLD Trap
Our domain is swipebase.net. iOS sometimes interprets .ne as a country code TLD and tries to auto-link it weirdly. Don't render the domain as plain text in the app — always wrap it in proper anchor tags.
Stripe Account Confusion
I have Stripe accounts for multiple businesses. The first deploy used the wrong Stripe keys. Payments were going to the wrong account. This is a "you only make this mistake once" situation, but it's a bad one.
Rule: Stripe keys go in .env with clear comments about which account they belong to. And every new project gets its own Stripe account from day one.
The Numbers
Here's what came out of 72 hours:
- Full SaaS deployed at swipebase.net with auth, billing, and a complete feature set
- 14 core features including email capture, iOS shortcut, AI tagging, video analysis, semantic search
- Infrastructure cost: ~$10/month (VPS + domain)
- AI cost per operation: $0.001 per auto-tag, $0.01-0.05 per video analysis
- Lines of code: Thousands (I honestly didn't count — Ari wrote them, not me)
- My time investment: Maybe 4-5 hours total across 3 days. Writing the PRD, reviewing builds, testing on my phone, making decisions when Ari hit forks in the road.
That last number is the one that matters. I spent most of those 72 hours living my normal life. Gym. Kids. Regular stuff. Ari built the product.
What I'd Do Differently
Looking back with the benefit of hindsight:
- Mobile-first testing from day one. We built on desktop and tested on mobile last. Every mobile bug was a surprise. Test on your phone from the first commit.
- Deploy script first, not last. We built the app, then figured out deployment. Should have been the other way around — get deployment working with a hello-world page, then build the features knowing they'll deploy cleanly.
- Plan for email capture early. It ended up being a differentiator, but it was almost cut as a "phase 2" feature. If something feels different from what competitors offer, build it first.
- Python for all server operations from hour one. We wasted time debugging PowerShell mangling before establishing the "just use Python" rule.
- Admin tools early. User impersonation for debugging was added late. Should have been in the first deploy. You can't fix user issues if you can't see what they see.
What This Means
I'm not going to pretend AI can replace software engineers. It can't. What it can do is execute at a pace that changes the economics of building software.
The total cost to go from idea to deployed SaaS was under $20 (VPS + domain for the first month). The total time from my life was a few hours. The product is real, it works, and it solves a problem I've had for years.
The interesting question isn't "can AI build software?" — it obviously can. The interesting question is: what do you build when the cost of building drops to near zero?
I've got 29 more days of answers to that question. Subscribe to follow along.
---
This is Day 2 of the Machine Earned 30-day experiment. Yesterday: I Gave My AI Co-Founder a Computer and Said Make Money. Tomorrow: The $173 ad campaign that made zero sales.