<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[MasterBek Builds]]></title><description><![CDATA[MasterBek Builds]]></description><link>https://masterbek-builds.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6a3f79c1a5a6ca57804560e1/f6447c0e-7838-41d4-8305-66f3b289c7a4.png</url><title>MasterBek Builds</title><link>https://masterbek-builds.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 21 Sep 2026 19:03:16 GMT</lastBuildDate><atom:link href="https://masterbek-builds.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[What I learned building a Flutter app that aggregates deals
]]></title><description><![CDATA[I’m currently building a Flutter app called DiscountHub that aggregates coupons, promo codes, product deals and store promotions from different sources.
At first, the idea looked simple: collect offer]]></description><link>https://masterbek-builds.hashnode.dev/what-i-learned-building-a-flutter-app-that-aggregates-deals</link><guid isPermaLink="true">https://masterbek-builds.hashnode.dev/what-i-learned-building-a-flutter-app-that-aggregates-deals</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Mobile apps]]></category><category><![CDATA[backend]]></category><category><![CDATA[startup]]></category><category><![CDATA[product]]></category><dc:creator><![CDATA[Ulug'bek]]></dc:creator><pubDate>Sat, 27 Jun 2026 09:18:56 GMT</pubDate><content:encoded><![CDATA[<p>I’m currently building a Flutter app called DiscountHub that aggregates coupons, promo codes, product deals and store promotions from different sources.</p>
<p>At first, the idea looked simple: collect offers from multiple stores and show them in one place.</p>
<p>But after working on the project, I realized that deal aggregation is not really a “collect more data” problem. It is mostly a data quality problem.</p>
<h2>The easy part: collecting offers</h2>
<p>Getting raw offers from different sources is not the hardest part.</p>
<p>Many stores, marketplaces and affiliate networks provide feeds, APIs or structured data. On paper, this looks straightforward:</p>
<ul>
<li><p>fetch offers</p>
</li>
<li><p>normalize the data</p>
</li>
<li><p>save them in the database</p>
</li>
<li><p>show them in the app</p>
</li>
</ul>
<p>But raw deal data is often messy.</p>
<p>The same product can appear in different formats. Some feeds include prices, some do not. Some promotions include images, others only include text. Some links work today and break tomorrow.</p>
<p>That is where the real work starts.</p>
<h2>The harder part: filtering bad data</h2>
<p>One of the biggest lessons I learned is that more offers do not always make the product better.</p>
<p>If the app shows expired discounts, broken links, unclear promotions or low-quality offers, users lose trust very quickly.</p>
<p>Some examples of problems I had to deal with:</p>
<ul>
<li><p>products that disappear from the original store</p>
</li>
<li><p>expired promotions still appearing in feeds</p>
</li>
<li><p>missing images</p>
</li>
<li><p>unclear promo descriptions</p>
</li>
<li><p>wrong or incomplete price data</p>
</li>
<li><p>duplicate offers</p>
</li>
<li><p>affiliate links that need validation</p>
</li>
<li><p>different currencies and languages</p>
</li>
<li><p>stores that provide many rows, but very few useful deals</p>
</li>
</ul>
<p>So instead of focusing only on quantity, I had to focus more on rules like:</p>
<ul>
<li><p>should this offer be public?</p>
</li>
<li><p>is the discount real?</p>
</li>
<li><p>does the link still work?</p>
</li>
<li><p>is the promotion useful for users?</p>
</li>
<li><p>should this store be shown as product deals, promo-only, or hidden?</p>
</li>
</ul>
<h2>Why link validation matters</h2>
<p>For a deals app, link quality is critical.</p>
<p>If a user taps a deal and the original store page is broken, the app immediately feels unreliable.</p>
<p>That means the backend cannot just import everything blindly. It needs some level of validation and cleanup.</p>
<p>In my case, I had to think about:</p>
<ul>
<li><p>blocking known broken product URLs</p>
</li>
<li><p>detecting products that return 404</p>
</li>
<li><p>avoiding false positives from temporary rate limits</p>
</li>
<li><p>keeping expired items out of public results</p>
</li>
<li><p>separating real broken links from temporary server errors</p>
</li>
</ul>
<p>This is a lot less exciting than building UI, but it matters much more for user trust.</p>
<h2>Promo codes are different from product deals</h2>
<p>Another thing I learned is that promo codes and product deals should not be treated the same way.</p>
<p>A product deal usually needs:</p>
<ul>
<li><p>product title</p>
</li>
<li><p>image</p>
</li>
<li><p>old price</p>
</li>
<li><p>new price</p>
</li>
<li><p>discount percentage</p>
</li>
<li><p>product URL</p>
</li>
</ul>
<p>But a promo code or store promotion may only have:</p>
<ul>
<li><p>title</p>
</li>
<li><p>short description</p>
</li>
<li><p>code</p>
</li>
<li><p>start/end date</p>
</li>
<li><p>store URL</p>
</li>
</ul>
<p>Trying to force both into the same UI can make the product feel messy.</p>
<p>So I separated the experience: product deals are shown as deal cards, while promo codes and store promotions have their own section.</p>
<p>That made the app easier to understand and also helped avoid showing empty or broken image placeholders for promotions that do not have images.</p>
<h2>Flutter UI lessons</h2>
<p>On the Flutter side, one lesson was that “no data” and “missing data” states are very important.</p>
<p>It is easy to design the perfect card when every field exists. But real data is not like that.</p>
<p>Some offers do not have images. Some stores do not have active promotions. Some filters return fewer results than expected.</p>
<p>So the UI needs to handle:</p>
<ul>
<li><p>loading states</p>
</li>
<li><p>empty states</p>
</li>
<li><p>missing images</p>
</li>
<li><p>long text</p>
</li>
<li><p>different currencies</p>
</li>
<li><p>different screen sizes</p>
</li>
<li><p>slow network responses</p>
</li>
</ul>
<p>For a shopping/deals app, the UI also needs to feel fast. Users do not want to wait too long just to browse offers.</p>
<h2>Backend lessons</h2>
<p>The backend became more important than I expected.</p>
<p>A simple “get deals” endpoint is not enough when the data comes from many sources.</p>
<p>The backend needs to handle:</p>
<ul>
<li><p>source-specific cleanup</p>
</li>
<li><p>freshness rules</p>
</li>
<li><p>filtering</p>
</li>
<li><p>pagination</p>
</li>
<li><p>promotion cleanup</p>
</li>
<li><p>link rules</p>
</li>
<li><p>store visibility</p>
</li>
<li><p>API limits</p>
</li>
<li><p>scheduled sync jobs</p>
</li>
</ul>
<p>One useful decision was to avoid showing everything forever. Deals and promotions need freshness rules, otherwise old data stays visible and makes the product worse.</p>
<h2>The main lesson</h2>
<p>My biggest takeaway so far:</p>
<p>A deals app is not valuable because it has many offers. It is valuable when users can trust that the offers are useful.</p>
<p>That changed how I think about the product.</p>
<p>Instead of asking “how can I import more deals?”, I now ask:</p>
<ul>
<li><p>how can I improve quality?</p>
</li>
<li><p>how can I remove bad data faster?</p>
</li>
<li><p>how can I make the UI honest when data is missing?</p>
</li>
<li><p>how can I make users trust the app?</p>
</li>
</ul>
<h2>What I’m working on next</h2>
<p>The next things I want to improve are:</p>
<ul>
<li><p>better deal validation</p>
</li>
<li><p>better promo code filtering</p>
</li>
<li><p>more reliable store sources</p>
</li>
<li><p>better handling for expired offers</p>
</li>
<li><p>Android release</p>
</li>
<li><p>clearer onboarding and positioning</p>
</li>
</ul>
<p>This project taught me that building a real product is not only about features. It is also about boring but important details: cleanup, validation, edge cases and trust.</p>
<p>Project website: <a href="https://discounthub.uz">https://discounthub.uz</a></p>
]]></content:encoded></item></channel></rss>