Inspiration:
The idea for EasySell didn't come from a market report it came from watching how neighbourhood shops actually work. A shopkeeper in Dhaka opens before sunrise and closes near midnight, selling a few hundred small things to a few hundred neighbours a day, almost entirely from memory. Sales get written in a notebook when there's time, and skipped when the queue is four deep. Multiply that by hundreds of transactions a day, and the small gaps a sale never logged, a fast-mover that runs out unnoticed, a month-end total nobody quite trusts add up to real money quietly lost.
What made this feel urgent rather than theoretical was the scale behind it: UNCDF's landscape study counted over 1.3 million retail micro-merchants in Bangladesh alone, turning over more than US$18 billion a year, with roughly two million people depending on that income. These aren't businesses that lack the discipline to keep records they lack a tool that was ever built for them. Point-of-sale systems, barcode scanners, and inventory software all assume capital, hardware, and staff a one-person shop simply doesn't have. We wanted to build the version of that technology that actually fits a shop the size of a small room.
What it does:
EasySell turns a phone into a point-of-sale and inventory system for small grocery shops. You add each product once, and from then on you can sell it three ways scan it with the camera, say the sale out loud, or add it by hand. It tracks stock, customer credit (khata), and real profit, with reports available for any day, week, month, or date range. There's no barcode scanner to buy, no computer to set up, and nothing to configure before a shop can start using it.
How we built it:
The app is built with Flutter and Riverpod on the front end, with Supabase Postgres, Auth, and Storage on the back. Every sale goes through a single atomic Postgres function that locks the product row, blocks overselling, and freezes the cost and selling price onto the transaction at the moment of sale, so historical profit stays correct even after prices change later. Row Level Security scopes every table to the shop it belongs to, so one shop's data is never visible to another. Camera and voice input both run through Edge Functions calling Gemini 3.6 Flash, and each request sends the shop's own product catalog along as a candidate list which turns recognition into a closed-set match against products the shop actually stocks, rather than open-world guessing.
Challenges we ran into:
Some of our hardest bugs were silent rather than loud. Postgres quietly rounded our discount maths: PL/pgSQL rounds on assignment to a declared numeric typmod, which undid the flooring logic our entire discount design depended on nothing crashed, the totals were just wrong. A related issue showed up between Dart and Postgres, which disagreed on the final bill because quantity was stored as numeric(10,3) and the client and server rounded it differently. Beyond the arithmetic, our first scan flow was simply too slow to use in a real shop one photo, wait, confirm, repeat meant ten items took about 75 seconds and 40 taps, which is far too much friction for someone with a queue of customers. We also hit a subtler bug where backgrounding the app mid-camera-init leaked a bound controller, which took a generation counter to fix properly.
Accomplishments that we're proud of:
We're proud that scanning ten items now takes about 20 seconds instead of 75, because recognition runs in the background while you keep shooting instead of blocking on each photo. We're proud that a sale can never record without decrementing stock, and that stock can never go negative even under concurrent sales that guarantee holds at the database level, not just in the UI. The app currently passes 443 tests with clean static analysis and Row Level Security enforced on every table, and it's fully localized in Bengali, including Bengali numerals, rather than just having translated strings bolted on top.
What we learned:
The biggest lesson was that money code needs a different level of rigour than UI code. Our worst bugs were arithmetic, not crashes, and several of them passed code review because reviewers checked the logic without checking the totals. We also learned that speed is itself a safety feature a per-item confirmation sheet felt safer on paper, but it was slow enough that people would tap through it without actually reading it, whereas batching review into a single tray turned out to be both faster and more likely to be read properly. Finally, we learned to be suspicious of tests that pass too easily: one test we'd credited with closing a bug turned out to still pass with the fix fully reverted, because it was only proving an invariant that already held, not the fix itself.
What's next for EasySell
The next priority is offline-first storage, so a shop can keep selling even when the network drops something that matters a great deal given how uneven connectivity still is in many parts of Bangladesh. Alongside that, we plan to add barcode scanning as a complement to vision recognition for packaged goods that already carry a barcode, staff accounts so an owner can see who sold what, and AI-driven insights and trend forecasting built directly on top of the sales history the app is already collecting.
Built With
- claudecode
- dart
- flutter
- gemini
- go-router
- postgresql
- supabase
Log in or sign up for Devpost to join the conversation.