Inspiration
Whisker Community started from a problem I have experienced firsthand while helping community cats: rescue work is often scattered across social media posts and private groups, and rescuers are usually spammed or shadowed banned.
One animal may need veterinary care, transport, donations, temporary foster care, and eventually adoption. Different people may be willing to help with each part, but updates quickly become buried in a feed. It becomes difficult to tell what a rescue still needs, who has already offered help, and what eventually happened to the animal.
I wanted to build something that treats rescue as an ongoing community effort rather than a single social media post.
What it does
Whisker Community gives rescuers and supporters one place to organize rescue cases, campaigns, and community help.
A rescuer can create a case, document its progress, request specific types of help, and coordinate foster or adoption workflows. Community members can discover cases, respond to help requests, participate in campaigns, and follow a rescue as its status changes.
The app also includes rescue history, controlled contact sharing, reporting and moderation tools, blocked-user filtering, ownership-based actions, and safeguards around important workflow transitions.
For people who want to support the continued development of the project, Whisker Community also includes an optional one-time lifetime Supporter Pack powered by RevenueCat. Core rescue and community functionality remains free.
How I built it
Whisker Community is my first Android app.
I built it natively in Kotlin using Jetpack Compose and Material 3. Firebase provides Google authentication, Cloud Firestore, Cloud Storage, and Cloud Functions for the backend. RevenueCat manages the lifetime Supporter Pack entitlement and purchase restoration.
A major part of the architecture was making workflows behave consistently across different users and devices. Actions such as accepting a foster offer or finalizing an adoption cannot depend only on what one device currently has in memory. Important transitions are persisted in Firestore, protected by security rules, and, where necessary, performed atomically through Cloud Functions.
I also used Firebase's emulator tooling and automated Android tests to exercise authorization rules, workflow transitions, storage behavior, and cross-account scenarios before deploying changes to production.
Challenges
The hardest problems were not individual screens. They were the relationships between them.
Foster care was a good example. A rescue can move from needing foster care, to receiving offers, to being placed, to eventually ending foster care. Historical records still need to remain available without accidentally being interpreted as the current state. Multiple people may also make offers at the same time, which means accepting one offer must safely resolve the others.
During final adversarial testing, I found cases where historical foster offers could interfere with later adoption finalization and where an old accepted foster request could incorrectly make a new foster cycle appear already placed. Fixing those bugs required treating the workflow as a state machine rather than simply updating individual documents.
Authorization was another challenge. A helper should be able to make or withdraw an offer without gaining permission to edit the rescue itself. Owners should see different actions from other community members. Blocked users should disappear from relevant discovery surfaces. These behaviors had to agree across the Android client, Firestore rules, and backend functions.
There were also all of the less glamorous parts of shipping a real app: image handling, cache invalidation, location filtering, release testing, Firebase production cleanup, Google Play closed testing requirements, app signing, privacy declarations, and preparing the production release.
What I learned
The biggest lesson was that building an app and shipping an app are very different milestones.
I learned Kotlin and Jetpack Compose while building the product, but I also had to learn how Android releases, signing certificates, Google Play testing tracks, Firebase security rules, production migrations, and store compliance fit together.
I also learned the value of adversarial testing late in development. A feature can appear correct when tested from one account while still breaking when another user acts on the same data later. Testing workflows across accounts and across time exposed problems that ordinary happy-path testing did not.
Most importantly, I learned to think less in terms of screens and more in terms of states, permissions, and transitions. For a community application where several people may interact with the same rescue, that distinction matters.
What's next
Whisker Community is designed around community animal rescue today, but there is still room to make coordination easier.
Future work can include richer notifications, better ways to surface urgent or nearby needs, stronger community recognition, improved rescue analytics, and tools that help local rescue groups coordinate across larger areas.
The long-term goal remains simple: make it easier for people who care about community animals to turn that concern into organized, useful action.
Shipaton #RevenueCat #PeacePrize #BuildInPublic
Built With
- android
- cloud-firestore
- firebase
- google-play
- jetpack-compose
- kotlin
- revenuecat

Log in or sign up for Devpost to join the conversation.