Inspiration
Reminders are personal — but life isn't. We forget things across devices, across contexts, and across the people we share responsibilities with. Existing reminder apps either lock you into one platform or treat reminders as isolated, single-device notes. Nudge was born from the frustration of missing reminders on a desktop that were set on a phone, and the inability to share recurring household tasks with family or teammates without a heavyweight project management tool.
The goal: build a truly cross-platform, real-time syncing reminders app that works everywhere — phones, tablets, desktops, and the web — with shared group reminders (Tribes) and a freemium model powered by RevenueCat.
What it does
Nudge is a cross-platform reminders app that runs on 7 platforms (Android, iOS, macOS, Windows, Linux, Web, and Android home screen widgets). Key capabilities include:
- Cross-device sync: Local-first SQLite storage with Firestore real-time listeners. Reminders appear on all linked devices in under 500ms. Offline changes queue and sync automatically when connectivity returns.
- Tribes: Shared group reminders with invite codes. Create a Tribe, invite members with a 6-character code, and publish reminders that fan out to every member's personal collection via Cloud Functions.
- Persistent notifications: Due-app style nagging with 6 OS-scheduled retriggers at 5-minute intervals. Survives device reboots via boot receivers. ProGuard safe.
- Natural language input: Type "Remind me to call mom tomorrow at 3pm" and Nudge parses the date, time, and title automatically.
- Device linking: Desktop platforms (Windows/Linux) authenticate via 6-character codes — no OAuth browser dependency needed. End-to-end auth in ~10 seconds.
- Home screen widgets: Android widgets showing today's reminders, a quick-add button, and an overdue count badge.
- Premium gating via RevenueCat: Free tier (10 reminders, 2 devices, 1 Tribe) and Premium tier ($3.99/mo for unlimited everything). Uses
purchases_flutterSDK andpurchases_ui_flutterfor paywall UI.
How we built it
Architecture: Layered architecture with clear separation — Presentation (BLoC pattern with flutter_bloc), Domain (pure Dart entities and business logic), Data (repository implementations coordinating SQLite + Firestore sync), and External (Firebase, RevenueCat, platform APIs).
Frontend: Flutter 3.38.7 / Dart 3.10.4. State management via BLoC. Dependency injection with get_it + injectable. Local storage uses sqflite on mobile, sqflite_common_ffi on desktop, and flutter_secure_storage for tokens.
Backend: Firebase ecosystem — Auth (Google/Apple Sign-In), Firestore (real-time sync), FCM (push notifications), Crashlytics (crash reporting). Four Gen 2 Cloud Functions written in TypeScript on Node.js 20:
onMemberJoin/onMemberLeave— atomically update Tribe member countsonTribeReminderPublish— fan-out reminder copies to all Tribe members (batched writes, 500/batch)onDeviceLinkClaim— generates custom Firebase auth tokens for desktop device linking
Sync strategy: Optimistic local writes to SQLite (UI reflects immediately), background push to Firestore, and Firestore snapshot listeners on other devices merge changes using last-write-wins on updatedAt. Soft deletes with deletedAt field.
CI/CD: GitHub Actions pipeline with 7 parallel platform builds. Triggers on push to main (full test + build), PRs (test only), version tags (build + GitHub release with all artifacts), and manual dispatch with selectable platforms.
Challenges we ran into
- Desktop notifications: Flutter's notification ecosystem is mobile-first. We needed
flutter_local_notificationsfor mobile/macOS and a separatelocal_notifierpackage for Windows/Linux, with platform-specific scheduling logic. - Persistent (nagging) notifications: Scheduling 6 retriggers that survive reboots required Android boot receivers and careful ProGuard configuration to avoid class stripping.
- Device linking without OAuth: Windows and Linux lack reliable OAuth browser flows. We designed a polling-based 6-character code system with Firestore + Cloud Functions that completes authentication in ~10 seconds.
- Cross-platform SQLite: Mobile uses
sqflite, but desktop requiressqflite_common_ffiwith native library bundling. Unified via a repository abstraction. - Tribe reminder fan-out: Distributing a reminder to all Tribe members required batched Firestore writes (max 500 per batch) in a Cloud Function, with owner-skip logic to avoid duplication.
Accomplishments that we're proud of
- 7-platform support from a single Flutter codebase with platform-specific adaptations where needed
- Sub-500ms sync latency between devices on good connections
- 370 tests covering BLoC, repository, entity, and widget layers
- Working RevenueCat integration with freemium gating and paywall UI
- Interactive tutorial overlay with spotlight coach marks for onboarding
- WCAG AA accessibility compliance throughout the app
- Complete CI/CD pipeline that builds and releases for all 7 platforms via GitHub Actions
What we learned
- RevenueCat's
purchases_flutterSDK made subscription management significantly simpler than direct StoreKit/BillingClient integration — especially the paywall UI component. - Local-first architecture with background sync is crucial for reminder apps. Users expect instant UI feedback; network latency should be invisible.
- Cloud Functions Gen 2 with TypeScript provides a clean server-side execution model for operations like fan-out writes that shouldn't happen client-side.
- Desktop Flutter is maturing but still requires workarounds for notifications, window management, and authentication flows.
What's next for Nudge
- Smart scheduling: ML-based suggestions for optimal reminder times based on user patterns
- Tribe chat: Lightweight messaging within Tribes for context around shared reminders
- Calendar integration: Two-way sync with Google Calendar and Apple Calendar
- Voice input: Speech-to-text reminder creation on all platforms
- Wear OS / watchOS companions: Quick reminder creation and completion from wrist devices ## What we learned
Log in or sign up for Devpost to join the conversation.