I built Banyan, a little app for collecting and keeping family stories, and I shipped it to the App Store by myself: designed it, built it, submitted it, handled the App Review back-and-forth, all of it. It's live here, and the code's on GitHub.
The thing I kept coming back to while building it is how much family history only exists in one person's head. The reason behind some decision, the story behind an old photo nobody can place, your grandparent's first memory. Nobody writes that stuff down, and "tell me a story" gets you nothing. I wanted something that made capturing it feel less like an interview and more like a nudge.
One naming note up front: it first shipped as Roots, and the App Store listing officially flips to Banyan on July 1st. If you tap through before then and see the old name, that's why. Same app, better name.
what it actually does
The core idea is simple. You make a person (a parent, a grandparent, a friend) and you start collecting things about them or from them. Each memory can be a voice recording, a video, a written story, or a photo, with in-app playback and a scrubber so you can seek around the longer clips. Memories get grouped two ways at once: by person, and by theme - Childhood, Love & Relationships, Growing Up, Family Stories, and so on. Each theme comes with guided prompts, because "tell me a story" gets you a blank stare and "what's the first house you remember living in?" gets you twenty minutes.
The other half is sharing. You can keep a person's memories private, or open up a collaborative family space and invite relatives in with role-based permissions (Owner, Admin, Editor, Viewer). The idea is that capturing your grandmother's stories shouldn't be a solo chore. Your siblings and cousins should be able to add the pieces only they remember.
the hard parts (this is the fun part)
A consumer app that "just" records media and syncs it sounds straightforward until you actually try to make it feel good. A few things ate most of my time, and they're the parts I'm proudest of.
Offline-first, so it never feels like it's loading. The thing that makes most small apps feel cheap is the spinner: open a screen, wait for the network, then finally see your data. I didn't want that. So every screen reads instantly from a local cache (AsyncStorage, the app's small on-device key-value store), shows you something immediately, and then reconciles in the background against live Firestore listeners (onSnapshot, which pushes updates the moment data changes on the server). The UI never blocks on the network. The catch is that "what's true" now lives in two places at once, the cache and the server, and keeping those two honest with each other, especially while media is uploading, was most of the data-layer work.
Permissions that actually mean something. Role-based access (RBAC) is easy to fake. Hide a button if the user is a "Viewer" and call it a day. The problem is that hiding a button is theater. Anyone who knows how the app talks to the database can just ask the database directly. So the permissions model (canCreate / canEdit / canDelete) drives both the interface and the actual security rules enforced down at the Firestore layer. The button being gone and the server refusing the write are two versions of the same rule, not a UI trick sitting on top of an open door.
Deleting an account, completely. This one is unglamorous and non-negotiable. Apple's guidelines (specifically 5.1.1(v)) say that if your app lets people create an account, it has to let them fully delete it, and not the "email us and we'll get to it" kind, a real in-app teardown. Doing that right means tearing down every trace in the correct order: the uploaded media in Cloud Storage, the nested Firestore records, the reserved username, and finally the auth user itself, re-authenticated and deleted last, because the second the user is gone you've lost the permission to clean up everything else. Get the ordering wrong and you leave orphaned data behind. Getting it right was a genuinely satisfying little puzzle.
what shipping alone actually taught me
I've worked on plenty of things where a platform team owned the infrastructure, a design system already existed, and someone else handled the store submission. Banyan was the opposite. Every decision, from "what radius do the cards have" to "how does account deletion survive App Review," was mine to make and mine to get wrong. I built a small centralized theme (colors, spacing, radius, shadows, typography) early, mostly out of self-defense, because I figured out fast that without one I'd be re-deciding the same five values on every single screen.
The biggest lesson wasn't technical, though. It's how much of "shipping" is the boring tail end: the deletion flow, the App Review back-and-forth, the empty states, the offline behavior nobody notices unless it's broken. The recording feature was the fun part, and it was maybe a fifth of the work. The rest of it is what makes it an actual app you can download instead of a demo I show people on my phone. Owning that whole tail, end to end, is exactly what I wanted out of building this, and now I've done it.
If you've got a family story you've been meaning to capture, Banyan's the nudge.