<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: racioteka</title>
    <description>The latest articles on DEV Community by racioteka (@racioteka).</description>
    <link>https://dev.to/racioteka</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4184610%2Fbb029a44-ee07-41af-b399-d191a13ddf64.png</url>
      <title>DEV Community: racioteka</title>
      <link>https://dev.to/racioteka</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/racioteka"/>
    <language>en</language>
    <item>
      <title>Статичний каталог на Python і JavaScript: як порівнювати дані без хибних результатів</title>
      <dc:creator>racioteka</dc:creator>
      <pubDate>Wed, 14 Oct 2026 21:03:50 +0000</pubDate>
      <link>https://dev.to/racioteka/statichnii-katalogh-na-python-i-javascript-iak-porivniuvati-dani-biez-khibnikh-riezultativ-f5l</link>
      <guid>https://dev.to/racioteka/statichnii-katalogh-na-python-i-javascript-iak-porivniuvati-dani-biez-khibnikh-riezultativ-f5l</guid>
      <description>&lt;p&gt;Каталог можна зібрати зі статичних HTML-сторінок і додати фільтри на JavaScript. Але користь такого продукту залежить не лише від швидкості: важливо, щоб невідома ціна не перетворювалася на нуль, а одна програма в кількох містах не рахувалася як кілька різних пропозицій.&lt;/p&gt;

&lt;p&gt;Покажемо ці рішення на прикладі &lt;a href="https://racioteka.com.ua/" rel="noopener noreferrer"&gt;Раціотеки&lt;/a&gt; — українського каталогу для порівняння сервісів доставки готових раціонів. Основні сторінки проєкту генеруються на Python із табличних даних. Клієнтські фільтри працюють на JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Розділіть сервіс, програму та доступність у місті
&lt;/h2&gt;

&lt;p&gt;У каталозі є три різні сутності:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Сервіс&lt;/strong&gt; — компанія, яка пропонує доставку.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Програма&lt;/strong&gt; — конкретний раціон цієї компанії.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Доступність&lt;/strong&gt; — зв’язок програми з містом та умовами доставки.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Наприклад, одна програма може бути доступна у двох містах. Це дві міські пропозиції, але одна програма. Таке розділення потрібне і для фільтрів, і для коректних підрахунків у заголовках.&lt;/p&gt;

&lt;p&gt;У Раціотеці генератор читає окремі CSV-файли для сервісів, програм, міських записів і доставки. HTML формується під час збірки; основний текст не потребує виконання JavaScript, щоб з’явитися на сторінці.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Невідома ціна — це не нуль
&lt;/h2&gt;

&lt;p&gt;У JavaScript &lt;code&gt;Number("")&lt;/code&gt; повертає &lt;code&gt;0&lt;/code&gt;. Якщо без перевірки перетворювати порожнє поле ціни на число, програма без відомої вартості може виглядати безкоштовною та потрапити в підбірку найдешевших.&lt;/p&gt;

&lt;p&gt;Тому у фільтрі спочатку перевіряється наявність значення:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;priceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Коли користувач задає бюджет, картка з невідомою ціною не проходить цей фільтр. Це не означає, що пропозиція дорога: даних просто недостатньо, щоб підтвердити відповідність бюджету.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Для діапазонів перевіряйте перетин
&lt;/h2&gt;

&lt;p&gt;Калорійність програми може бути діапазоном. Пошук лише за точним збігом пропустить відповідні варіанти.&lt;/p&gt;

&lt;p&gt;Умовний приклад: програма має діапазон 1400–1600 ккал, а користувач шукає 1500–1700 ккал. Діапазони перетинаються, тому така програма має залишитися в результатах.&lt;/p&gt;

&lt;p&gt;Логіка перевірки:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;overlaps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;programMin&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;selectedMax&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;programMax&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectedMin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Перед порівнянням треба перевірити, що потрібні межі відомі. У Раціотеці відповідні перевірки відкидають записи, які неможливо зіставити з установленими межами фільтра.&lt;/p&gt;

&lt;p&gt;Сам фільтр допомагає знайти програми в каталозі. Він не визначає особисту потребу людини в калоріях.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Перевіряйте результат генерації
&lt;/h2&gt;

&lt;p&gt;Помилка спільного шаблону може повторитися на багатьох сторінках. Тому перед релізом потрібна перевірка згенерованого HTML.&lt;/p&gt;

&lt;p&gt;У проєкті перевіряються кількість H1, canonical, політика індексації, локальні посилання, потрібні ресурси та наявність очікуваних сторінок. Окрема перевірка вимагає, щоб відома ціна програми була більшою за нуль.&lt;/p&gt;

&lt;p&gt;Такі перевірки знаходять структурні помилки. Вони не підтверджують актуальність тарифів: ціни та умови доставки потрібно звіряти з джерелами окремо.&lt;/p&gt;

&lt;h2&gt;
  
  
  Що застосувати у власному каталозі
&lt;/h2&gt;

&lt;p&gt;Почніть із моделі даних і правил для відсутніх значень. Потім визначте, як працюють діапазони та підрахунки. Лише після цього будуйте картки й фільтри.&lt;/p&gt;

&lt;p&gt;Спробуйте на власному каталозі три сценарії: запис без ціни, частковий перетин діапазонів і одна програма в кількох містах. Якщо результати зрозумілі та передбачувані, у продукту вже є добра основа для чесного порівняння.&lt;/p&gt;

</description>
      <category>python</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I built a comparison catalog for meal delivery in Ukraine - and stopped opening 20 browser tabs</title>
      <dc:creator>racioteka</dc:creator>
      <pubDate>Wed, 14 Oct 2026 12:26:03 +0000</pubDate>
      <link>https://dev.to/racioteka/i-built-a-comparison-catalog-for-meal-delivery-in-ukraine-and-stopped-opening-20-browser-tabs-23p8</link>
      <guid>https://dev.to/racioteka/i-built-a-comparison-catalog-for-meal-delivery-in-ukraine-and-stopped-opening-20-browser-tabs-23p8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd3ohbxa3ga5kwrxwa9hy.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd3ohbxa3ga5kwrxwa9hy.jpeg" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choosing a meal delivery service (ready-made rations) in Ukraine used to mean opening 20+ websites and comparing them manually: price per day, calories, delivery zones, diets, goals. Every service has its own menu format, its own pricing logic, its own definition of "one meal". It's a classic directory problem.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;&lt;a href="https://racioteka.com.ua" rel="noopener noreferrer"&gt;Racioteka&lt;/a&gt;&lt;/strong&gt; — a catalog that aggregates dozens of Ukrainian meal-delivery services in one place, with filters by city, goal, diet and calories, plus a calorie calculator and a side-by-side comparison tool.&lt;/p&gt;

&lt;p&gt;Here's what I learned building it.&lt;/p&gt;

&lt;p&gt;The problem: everything is "almost comparable"&lt;/p&gt;

&lt;p&gt;The services are similar on the surface: daily rations, X meals per day, Y kcal, delivered in the morning. But the details are messy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pricing&lt;/strong&gt;: some quote per day, some per week, some per "program". One service includes delivery, another adds it at checkout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calories&lt;/strong&gt;: ranges like "1200–1500 kcal" vs exact numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meals&lt;/strong&gt;: 3, 4, or 5 meals per day — and "snack" means different things to different brands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diets&lt;/strong&gt;: keto, vegan, gluten-free, lactose-free, sugar-free — with overlapping definitions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core engineering task was &lt;strong&gt;normalization&lt;/strong&gt;: mapping all this chaos into a single schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified normalization shape&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Example Food&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;kyiv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lviv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;pricePerDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;850&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UAH&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;calories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;mealsPerDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;goals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;weight-loss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fitness&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;detox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;diets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vegan&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gluten-free&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;delivery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;free&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;city + suburbs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have a clean shape, everything else becomes easier — filtering, sorting, comparing.&lt;/p&gt;

&lt;p&gt;The filters that matter&lt;/p&gt;

&lt;p&gt;Users come with different intents. The filter set we settled on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;City&lt;/strong&gt; — most services are local (Kyiv, Lviv, Odesa, Ivano-Frankivsk...). A national catalog without city filtering is useless.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal&lt;/strong&gt; — weight loss, maintenance, muscle gain, detox, medical nutrition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diet&lt;/strong&gt; — keto, vegan, vegetarian, pescatarian, gluten-free, lactose-free, sugar-free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calories / price&lt;/strong&gt; — the two numeric dimensions everyone compares.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing revolutionary — but getting the &lt;em&gt;category taxonomy&lt;/em&gt; right is 80% of the product. We iterate on it constantly.&lt;/p&gt;

&lt;p&gt;The calorie calculator&lt;/p&gt;

&lt;p&gt;A common question: "How many kcal do I actually need?" Instead of making users guess, we added a calculator based on the &lt;strong&gt;Mifflin–St Jeor equation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Men:   BMR = 10*weight + 6.25*height − 5*age + 5
Women: BMR = 10*weight + 6.25*height − 5*age − 161
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we multiply by an activity factor (1.2 sedentary … 1.725 very active). The result plugs directly into the calorie filters — a nice "wow, it understands me" moment.&lt;/p&gt;

&lt;p&gt;The comparison tool&lt;/p&gt;

&lt;p&gt;The most requested feature: &lt;strong&gt;compare two programs side by side&lt;/strong&gt;. We show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;price per day (and total for N days)&lt;/li&gt;
&lt;li&gt;calories per day and per meal&lt;/li&gt;
&lt;li&gt;number of meals&lt;/li&gt;
&lt;li&gt;delivery zones and schedule&lt;/li&gt;
&lt;li&gt;included diets / exclusions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It sounds trivial, but the UX detail matters: users want to compare &lt;em&gt;their two shortlisted options&lt;/em&gt;, not a table of all 30 services. So the flow is: filter → pick 2 → compare.&lt;/p&gt;

&lt;p&gt;Business model: the directory play&lt;/p&gt;

&lt;p&gt;Racioteka is free for users and takes &lt;strong&gt;no commission&lt;/strong&gt; — orders happen directly on the service's website. We're a discovery layer.&lt;/p&gt;

&lt;p&gt;Revenue directions (in progress):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Featured listings&lt;/strong&gt; — priority placement for services that want more visibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B2B / corporate&lt;/strong&gt; — companies ordering meal plans for teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Affiliate / promo codes&lt;/strong&gt; — when it makes sense for users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part of the directory model: the catalog itself becomes a &lt;em&gt;backlink source&lt;/em&gt; for every service listed. Which means the services have an incentive to keep their data accurate and even link back. It's a positive loop.&lt;/p&gt;

&lt;p&gt;Lessons learned&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data quality beats features.&lt;/strong&gt; A catalog with wrong prices is worse than no catalog. We manually verify and always show "confirm with the service" disclaimers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Taxonomy is the product.&lt;/strong&gt; Invest in the category tree early; refactoring it later is painful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local matters.&lt;/strong&gt; For Ukraine, delivery zones and cities are the #1 filter. "National" services barely exist — almost everyone is city-specific.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't build a marketplace first.&lt;/strong&gt; Start with the directory (information), prove traffic, then add transactions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Try it&lt;/p&gt;

&lt;p&gt;If you're in Ukraine (or curious about the market), check out &lt;strong&gt;&lt;a href="https://racioteka.com.ua" rel="noopener noreferrer"&gt;Racioteka&lt;/a&gt;&lt;/strong&gt; — it's free.&lt;/p&gt;

&lt;p&gt;If you've built a directory or comparison product, I'd love to hear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How did you handle data normalization?&lt;/li&gt;
&lt;li&gt;What's your taxonomy strategy?&lt;/li&gt;
&lt;li&gt;Directory vs marketplace — which did you start with?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Drop your thoughts in the comments 👇&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>startup</category>
      <category>product</category>
    </item>
  </channel>
</rss>
