For years my hobby has been writing small games and apps to learn new languages and frameworks. In 2017 that hobby produced Text2Store: an Electron app, React before hooks existed, plenty of vanilla JS, that could read an iPhone backup already sitting on your computer and show you the messages inside. Reverse engineering Apple's SQLite schema taught me a lot. Six months in I abandoned it, because the next level was syncing a device over USB, and I did not have the time.
A month ago I revived it with Claude Code. This series is the honest engineering record of what happened next: 974 commits in 31 days, from "the source is gone" to a shipping product on two platforms. Not a highlight reel; the crashes, blank pages, and process-lifecycle archaeology are the interesting parts, and they are all here.
Step zero: I had to steal my own app
The 2017 source died with my old Bitbucket account. What survived was a compiled copy of the app on a third-party download mirror. So the first task I gave Claude was reverse engineering my own binary: unpacking the Electron archive, reading the bundled JS, and reconstructing what the app knew about Apple's backup format. The schema knowledge from 2017, the message joins, attachment paths, and the odd timestamp epoch Apple uses, came back out of the artifact. If you remember one thing from this series, let it be: your side projects deserve a remote you will not lose.
Why Tauri, honestly
The rewrite is Tauri v2: a Rust backend with the operating system's own webview for UI, WebKit on macOS and WebView2 (Chromium) on Windows. The honest reasons, not the brochure ones:
- Real system APIs. Backing up an iPhone means talking to USB devices, spawning helper processes, and touching file-system internals (a later chapter covers verifying APFS clones with fcntl). Rust makes those calls native, not bridged.
- The compiler is a reviewer. A solo dev shipping with an AI pair benefits enormously from a language that refuses to compile whole categories of mistake.
- The webview trade. You get small binaries and a mature UI stack; you also inherit two browser engines' quirks. Two of the hardest chapters in this series exist only because of that trade. I would make it again, but with open eyes.
The stack, since people ask
- App: Tauri v2, Rust backend, React + TypeScript + Tailwind frontend.
- Device sync: the excellent open-source pymobiledevice3, bundled as a frozen sidecar process; USB and Wi-Fi. We upstreamed a fix rather than forking quietly, and GPL compliance is handled the boring, correct way: the sidecar stays a separate process and we publish the corresponding source.
- Exports: PDF via the platform webview's print machinery (a saga), CSV and text from Rust, RSMF for eDiscovery validated against Relativity's published validator, and a verified export built on SHA-256 manifests plus RFC 3161 trusted timestamps from DigiCert.
- Licensing and AI relay: Cloudflare Workers + D1, email sign-in, no keys in the client. AI summaries run on Gemini Flash Lite through a relay, with zero data retention approved by Google, so nobody is reading your texts, including us.
- Payments: Paddle as merchant of record.
What a real phone taught us that a green test suite did not
The app has a real test suite and a preview harness that screenshots every UI state. All of it was green the day a friend volunteered his iPhone, which held ten years of history and one conversation of more than 84,000 messages. First run: crashed and burned. The two chapters that follow, the 84,000-message thread and killing a WebKit process on purpose, are what it took. The lesson I would pass to any team: automated tests verify the assumptions you had; a real user's data attacks the assumptions you did not know you were making.
The product this produced is at text2store.com. Whether anyone buys it, honestly, matters less to me than what this month proved about what these tools can do. But if you know someone who needs their texts off their phone, you know where to send them.