We built a pet medication tracker because every other app failed us
Source: Dev.to
Last year my partner and I adopted a dog š¶, and with him came a lot of love⦠and a lot of responsibility.
I first tried Google Calendar, but work meetings, birthdays, and pet reminders all got mixed together.
After testing several petācare appsāsome overādesigned, others missing notificationsāwe decided to build the tool we actually needed.
ZooMinder: What It Does
- Multiple pets ā Add each pet with a photo and birthdate.
- Treatments & medications ā Record dosage, frequency (daily, weekly, custom intervals) and timeāspecific doses.
- Vet appointments ā Store clinic info, vet name, phone, and address in one place.
- Upcoming doses ā Clear timeline of the next doses across all pets.
- History ā Full timeline of past doses and appointments per pet.
- Local notifications ā Custom ābarkā sound alerts that fire even when the app is closed.
- Offlineāfirst ā Works without internet; data syncs to the cloud when youāre back online.
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Flutter (DartāÆ3.10+) |
| Local DB | SQLite via sqflite |
| Backend & Auth | Supabase |
| Notifications | flutter_local_notifications + custom sound |
| Navigation | go_router |
| i18n | Flutterās intl (EnglishāÆ+āÆSpanish) |
| Ināapp purchases | in_app_purchase |
| Sync | Custom offlineāfirst sync service |
OfflineāFirst Sync
The app stores everything locally in SQLite first. Each record carries a synced flag. When the device regains connectivity, a SyncService pushes unsynced records to Supabase and pulls remote changes, resolving conflicts with timestamps (updated_at).
// Every model carries its sync state
class Treatment {
final bool synced;
final DateTime updatedAt;
// ā¦
}This design lets the app run on a plane, in a rural area, or anywhere without signalāyour petās schedule never depends on WiāFi.
Notifications
Dedicated Android notification channels are created for medications and appointments, each using a custom sound. The service schedules up to three upcoming notifications per treatment and recalculates whenever treatments are added or modified.
static const _medicationChannel = AndroidNotificationChannel(
'medication_reminders_v2',
'Medication Reminders',
importance: Importance.high,
sound: _customSound,
playSound: true,
);Lessons Learned
- Offlineāfirst is worth it but painful ā Sync logic with conflict resolution took more time than all the UI combined, yet the UX payoff is huge.
- Notifications are a minefield ā Android permission models, battery optimizations, and timezone handling make even a simple 8āÆam daily reminder surprisingly complex.
- Scope creep is real ā What started as ātrack medicationsā grew into appointment management, doseāhistory timelines, vetāclinic storage, premium subscriptions, and multiālanguage support. Learning to say ānoā to features is essential.
- Family projects keep you honest ā When your coādeveloper is also your partner and first user, feedback is immediate and brutally honest. š
Whatās Next š
- Family plans ā Share pets between household members so everyone can track medications and appointments from their own account.
- Assign responsibilities ā Delegate tasks (e.g., Mom handles the morning dose, Dad the evening one) so each person knows their role.
- Vetāoriented tools ā Features that let vets share treatment plans and visit summaries directly within ZooMinder, fostering better communication with pet owners.
Availability
ZooMinder is available on the Google Play Store. If you have pets and struggle to keep track of their medications and vet visits, give it a try.
Contribute & Feedback
Weād love your feedback. If youāre a Flutter developer, feel free to chat about the offlineāfirst patterns we used.
Found a bug, have a suggestion, or want to become a beta tester? Send me a DM here on dev.to. As a thankāyou, I can give you full access to the premium version of the app.
![Dog picture placeholder]
#flutter #flutterdev #dart #mobiledev #android #sideproject #indiedev
Built with Flutter, Supabase, and a lot of dog hair on the keyboard.
Have a great day! šš¾