Inspiration
Pholu started from something very personal.
My girlfriend and I were talking about how two people can remember the exact same moment completely differently. One person remembers what happened, another remembers how it felt, and sometimes both versions are important.
That made me think about where our memories actually live today.
Photos sit in camera rolls, stories disappear inside chat histories, voice notes get forgotten, and family memories end up scattered across different phones, cloud services, and social platforms.
I wanted to build something different.
Pholu is designed to be a private place for your life, not another social network.
No followers. No likes. No pressure to post publicly.
Just a place where individuals, couples, and families can preserve memories together and rediscover them later.
What Pholu Does
Pholu is a private memory app where users can save:
- Photos and videos
- Voice notes
- Journal entries
- Everyday moments
- Shared memories with partners or family
- Personal reflections and different perspectives on the same event
Users can create personal, shared, or family spaces and decide exactly what they want to keep private and what they want to share.
Pholu also includes AI features that can help analyse photos, understand videos and audio, transcribe voice notes, organise memories, suggest information, and help users search through their own history.
The long-term idea is simple:
Instead of scrolling through thousands of photos trying to find something, you should be able to ask Pholu about your own life.
How I Built It
Pholu is built using React Native and Expo, allowing me to maintain one application for both iOS and Android.
The app follows a local-first architecture.
Memories are stored locally in an encrypted SQLite database first, meaning the app can continue working even when the user is offline.
The core stack includes:
- React Native + Expo for the mobile application
- TypeScript across the app
- Zustand for application state
- expo-sqlite for local memory storage
- Supabase Postgres for accounts, shared spaces, invitations, quotas, subscriptions, and synchronisation
- Supabase Storage for encrypted shared media
- Supabase Edge Functions for trusted server-side operations
- RevenueCat for subscriptions and entitlement management
- AI services for image, video, audio, transcription, and memory understanding
Personal memories can remain entirely local.
When someone chooses to place a memory inside a shared or family space, Pholu synchronises the encrypted data through the backend so the other members of that space can access it.
This approach gives users much more control over which parts of their life actually need to leave their device.
Building AI Into a Private Memory App
One of the most interesting parts of Pholu has been working out how AI should fit into a product built around privacy.
I did not want AI to become a reason to automatically upload someone's entire memory library.
Instead, AI operations are handled intentionally and routed through trusted server-side functions.
The client never contains sensitive provider keys.
AI usage is also metered on the server rather than trusting the application to enforce its own limits.
I built Postgres functions that atomically consume AI quota depending on the user's subscription tier.
This prevents someone from modifying the app locally and giving themselves unlimited requests.
I also learned that different types of AI usage need different limits.
For example, processing a large collection of voice recordings should not consume the same allowance someone needs to ask a simple question about their memories.
That led me to separate chat and media-processing quotas.
RevenueCat and Server-Enforced Subscriptions
RevenueCat handles the purchase and entitlement side of Pholu's subscriptions.
The challenge was making sure the backend could safely trust a user's subscription level.
Simply allowing the mobile application to write:
subscription_tier = "pro"
would obviously be insecure.
So I built a Supabase Edge Function that verifies the user's entitlement directly with RevenueCat before updating their subscription tier in the database.
The client can request a subscription refresh, but it cannot choose the result.
That subscription tier is then used by Postgres to enforce features such as:
- Space limits
- Family spaces
- Family membership limits
- AI quotas
- Paid functionality
This became one of the biggest architectural lessons from the project:
The UI can explain what a user is allowed to do, but the server has to enforce it.
Challenges I Faced
Local-first synchronisation
Local-first architecture makes the app faster and more private, but it also introduces a lot of complexity.
I had to think about situations such as:
- A user losing connection during synchronisation
- The same memory changing on multiple devices
- Background sync happening during sign-out
- Large batches of media uploads
- Database migrations happening before the UI loads
- Shared memories appearing correctly for every member
One bug caused the app to sometimes throw:
no such table: spaces
The database existed, but a screen could occasionally query it before the schema had finished initialising.
Fixing that required changing the database lifecycle rather than simply catching the error.
I also introduced transaction queuing after finding cases where background jobs could still be writing while another part of the application attempted to close the database.
Shared-space notifications
Notifications were another unexpected challenge.
A personal memory can remain completely local, but a shared memory needs to notify other members of the space.
That means the backend needs to know that a shared event happened while still avoiding unnecessary access to private memories.
I have been building a server-side activity and notification pipeline for things like:
- New shared memories
- Comments
- Space invitations
- New members
- Shared-space activity
Handling duplicate notifications, offline devices, and synchronisation between several people has been much more complicated than simply calling a push-notification API.
Encryption and shared media
Pholu supports encrypted shared media, which creates another set of problems.
Photos, videos, and audio need to be prepared, encrypted, uploaded, downloaded, and correctly restored on another device.
Large imports also have to be processed carefully.
Trying to encrypt and upload a hundred high-resolution photos simultaneously can quickly exhaust the memory available to a mobile application.
I solved this by batching media processing and treating synchronisation as a queue of jobs instead of trying to process everything at once.
What I Learned
The biggest thing I learned from building Pholu is that the difficult part of an app rarely lives in the demo.
Saving a photo is easy.
Saving a photo while offline, encrypting it, synchronising it, sharing it with several people, enforcing subscription limits, recovering after a failed upload, and making sure it is still there after the user reopens the app is the real engineering problem.
I also learned to think much more carefully about trust boundaries.
The mobile client should never be trusted to decide things like:
- Subscription status
- AI quotas
- Membership limits
- Permissions
- Server-side access
Those rules belong as close to the database and backend as possible.
On the product side, I learned that adding more features is not always the same as making the product better.
Pholu only works if it continues to feel simple and personal.
What I'm Proud Of
Pholu began as a small idea based on a conversation between two people.
It has grown into a real application involving:
- Local-first storage
- Encryption
- Shared family spaces
- AI memory understanding
- Subscription infrastructure
- Offline support
- Media processing
- Synchronisation
- Multiple languages
- A custom design system
I am building the product independently, covering the product design, branding, UX/UI, architecture, development, testing, and overall direction.
The thing I am most proud of is that the original idea has stayed intact despite the technology becoming much more complex.
Pholu is still not trying to become another social network.
It is trying to become a better place to remember.
What's Next
My current focus is improving reliability across:
- Shared spaces
- Notifications
- Backup and restore
- Subscription flows
- AI-generated stories
- Memory synchronisation
- Onboarding
I also want to make Pholu's AI much better at understanding someone's memories over long periods of time.
One feature I am especially interested in is Life Story, where Pholu can turn years of memories, photos, journal entries, and personal context into a meaningful biography rather than a generic AI summary.
Longer term, I want users to be able to explore their memories across devices, preserve family history across generations, and export everything whenever they want.
The user should always remain the owner of their memories.
Pholu exists to help preserve them — not to own them.
Built With
- ai
- android
- authentication
- cloud-sync
- eas
- encryption
- expo-sqlite
- expo.io
- ios
- llm
- local-first
- mobile-app
- offline-first
- openai-api
- postgresql
- push-notifications
- react-native
- revenuecat
- row-level-security
- sqlite
- supabase
- supabase-edge-functions
- supabase-storage
- typescript
- zustand
Log in or sign up for Devpost to join the conversation.