Afterly
Tracks what you own after you buy it: warranties, EMI schedules, service reminders, resale value. It reads the receipts straight out of your inbox without ever touching an email that is none of its business.
- ~30
- Emails reach the model per scan
- 3
- Tiers of duplicate matching
- 0
- Bank or medical mail read

Status
Live
Platforms
Android (React Native)
Role
Sole designer, engineer, and operator
Stack
Imports purchases from Gmail behind a whitelist, a blacklist, and a sensitive-content filter
Regex narrows the inbox to a handful of candidates before any model sees it, which is what makes the feature affordable to run
Three-tier matching attaches an invoice to a product you already own instead of duplicating it
Cloud-authoritative sync with a local offline cache and a replayable pending-operation queue
Play Billing purchases verified server-side in an Edge Function, never trusted from the client
The idea
Buying something is well served by software. Owning it is not. The warranty expiry, the EMI schedule, the service interval, what it is worth if you sell it. All of it lives in an inbox nobody searches and a drawer nobody opens.
Afterly is the ledger for the part that comes after the purchase. It is also the smallest of my live products by usage, which makes it the honest one to write about: what is interesting here is the constraints, not the traction.
Reading an inbox you should not be reading
The feature that makes the product work, pulling purchases straight from Gmail, is also the one that asks for the most trust. An app with inbox access can see medical results, bank statements, and everything else in there.
So the Edge Function narrows hard before anything else happens. Mail must come from a whitelist of known retailers. A blacklist drops food delivery and grocery outright, because consumables are not things you own. A sensitive-content filter excludes anything matching bank, statement, credit, loan, mortgage, tax, payroll, salary, health, medical, prescription, or insurance. Whatever survives must still contain one of order, receipt, invoice, purchase, or confirmation.
The reason to stack those in that order is that excluded mail never reaches the model at all. Privacy that depends on asking a model to behave is not privacy. The filter runs first, in code, and the sensitive mail is discarded before there is anything to send.
Making the AI affordable
The same filter that protects the inbox is what makes the feature economically viable. The regex pass reduces a scan to roughly thirty candidate emails, and only those reach GPT-4o-mini for extraction.
That is the difference between reading an inbox and reading a shortlist. Handing every message to a model would have made the feature cost more to run than the tier it sits behind; filtering first keeps it comfortably inside it, and the cost scales with what survives the filter rather than with how much mail someone happens to get.
It is the same instinct as the debate planner in RoastPit: work out what the model is genuinely needed for, then do everything else in cheaper code first.
Not creating a second pair of headphones
An invoice arriving five days after you added a product by hand should attach to that product, not duplicate it. Matching runs in three tiers: a per-user check on the email id so one message is never imported twice, fingerprint matching against products already owned, and then a review screen showing the candidate with a confidence score.
The last tier is the one that matters. Automatic merging is wrong often enough that being wrong silently is worse than asking, so the system proposes and the person decides.
Offline, and what is authoritative
The sync contract is written at the top of the product service: the cloud is the source of truth, local storage is an offline cache. Writes land locally first and queue a background sync, so the app stays usable with no connection.
The queue needs one piece of care that is easy to miss. Operations referencing temporary local ids are stripped before a retry, because replaying them would push records pointing at products the server has never heard of.
Purchases are verified in an Edge Function rather than trusted from the device. Entitlement decided on the client is entitlement decided by whoever is holding the client.