Shipping e_core_notifications: one notifications layer for every Existence app.
Local, scheduled, and push notifications, plus an inbox, deep links, and topic subscriptions, now live behind a single tested package. Here is what we built, and why we stopped writing notification code by hand.
For most of the past year, every Existence app shipped its own notification code. Six apps, six slightly different ways to ask for permission, schedule a reminder, or show a badge. It worked, until we needed to change something and found ourselves making the same edit six times. So we did what e_core is for: we built it once. e_core_notifications is now live, and every app that adopts it gets the whole notification stack behind a single import.
The problem with copy-paste notifications
Notifications look simple from the outside: a banner, a sound, a number on an icon. Underneath, they are a thicket of platform differences: permission flows that behave differently on iOS and Android, local versus scheduled delivery, push tokens, channels, deep links, and the small matter of remembering what the user has already seen. Every one of our apps had solved these problems independently, which meant every bug had to be fixed independently too. A single improvement to how we handle a denied-permission state was, in practice, six pull requests.
That is exactly the tax e_core exists to remove. If more than one app needs it, it belongs in a package: tested once, owned once, used everywhere.
The goal was never “a notifications library.” It was to never write permission-handling code by hand again.
What we shipped
The first release of e_core_notifications covers the full lifecycle an app actually needs:
- Permissions: one request flow with clear granted and denied states, so the UI never has to guess.
- Local & scheduled notifications: fire immediately, or schedule for later, and cancel cleanly.
- Push via FCM: token management plus topic subscribe and unsubscribe, so broadcasting to a segment is a single call.
- A notification inbox: received notifications persist with read and unread state and an unread badge count.
- Deep links: tapping a notification routes straight to the right screen.
One package, not a framework
Consistent with the rest of e_core, notifications ship as an independent package, not a bundle you have to swallow whole. An app that only needs local reminders does not drag in Firebase; an app that wants the full push-and-inbox experience gets it from the same single dependency. You install e_core_notifications and you get notifications, nothing more, nothing you did not ask for.
To prove the package does what it claims, we built a demo in the example app that exercises every path: permission requests, immediate and scheduled sends, cancellation, the inbox with read and unread states, badge counts, deep-link navigation, and live FCM tokens for manual push testing. If a capability is not in the demo, we do not consider it shipped.
Migrating off v1
Shipping the package was only half the work. The other half was removing the old notification code it replaces. We audited every consuming app for lingering v1 imports, documented the migration path, and did not call the job done until nothing pointed back at the old implementation. A new package that leaves the old one limping alongside it is not a simplification, it is a second thing to maintain.
What is next
With the foundation in place, the interesting work moves up a layer: richer notification types, smarter grouping, and giving people finer control over what reaches them and when. But the principle underneath stays what it has always been at Existence: build it once, test it properly, and let every app reach for exactly what it needs. One clear line at a time.