<?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: Max Bantsevich</title>
    <description>The latest articles on DEV Community by Max Bantsevich (@mrbantsevich).</description>
    <link>https://dev.to/mrbantsevich</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F563650%2F77f06200-f3d5-4558-b63d-ba6e33be48c7.png</url>
      <title>DEV Community: Max Bantsevich</title>
      <link>https://dev.to/mrbantsevich</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mrbantsevich"/>
    <language>en</language>
    <item>
      <title>Building a Custom E-commerce Analytics Dashboard in Hours with Admiral</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Tue, 13 Jan 2026 11:48:32 +0000</pubDate>
      <link>https://dev.to/dev_family/building-a-custom-e-commerce-analytics-dashboard-in-hours-with-admiral-5hco</link>
      <guid>https://dev.to/dev_family/building-a-custom-e-commerce-analytics-dashboard-in-hours-with-admiral-5hco</guid>
      <description>&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;Recently, we needed to add seller analytics to our e-commerce project. You know the drill: key metrics, charts, data exports, order funnels — the usual set of features that clients expect in their admin panels.&lt;/p&gt;

&lt;p&gt;Typically, building a custom analytics dashboard from scratch takes weeks. But we managed to put it together in just a couple of hours using Admiral, our open-source framework for admin panels.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Admiral?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/dev-family/admiral" rel="noopener noreferrer"&gt;Admiral&lt;/a&gt; is an open-source framework for rapidly building admin panels that works with any backend. Most people use it for quick CRUD operations, but it's capable of much more.&lt;/p&gt;

&lt;p&gt;The key advantage: you're not locked into a specific stack or architecture. Admiral adapts to your backend, not the other way around.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Built
&lt;/h2&gt;

&lt;p&gt;Here's what we assembled for our seller analytics dashboard:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📈 Key Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Revenue tracking&lt;/li&gt;
&lt;li&gt;Order count&lt;/li&gt;
&lt;li&gt;Average order value&lt;/li&gt;
&lt;li&gt;Repeat sales&lt;/li&gt;
&lt;li&gt;Week-over-week trends with historical data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🔄 Business Process Visualization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order funnel by status&lt;/li&gt;
&lt;li&gt;Aggregated counts and totals&lt;/li&gt;
&lt;li&gt;Visual representation of the sales pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🛍️ Sales by Category&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Breakdown of all orders by product categories&lt;/li&gt;
&lt;li&gt;Visual charts for quick insights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;↩️ Returns &amp;amp; Cancellations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dedicated analytics block&lt;/li&gt;
&lt;li&gt;Counts and monetary amounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🎟️ Promo Code Analytics&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usage statistics&lt;/li&gt;
&lt;li&gt;Application counts&lt;/li&gt;
&lt;li&gt;Total discount amounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📊 Data Export&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-click export to XLSX and CSV for every block&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Secret Sauce: Cursor Rules
&lt;/h2&gt;

&lt;p&gt;What made this fast? We've developed cursor rules specifically for Admiral that speed up the development of custom interfaces dramatically.&lt;/p&gt;

&lt;p&gt;With these rules, building beautiful and functional dashboards isn't just quick — it's actually enjoyable. The rules handle the boilerplate, letting you focus on the business logic specific to your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;This isn't an out-of-the-box feature that comes with Admiral. This is a &lt;strong&gt;custom dashboard&lt;/strong&gt; we built for specific project needs in a couple of hours.&lt;/p&gt;

&lt;p&gt;That's the point: Admiral gives you the flexibility to build arbitrary interfaces quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom dashboards&lt;/li&gt;
&lt;li&gt;Complex data visualizations&lt;/li&gt;
&lt;li&gt;Tailored analytics&lt;/li&gt;
&lt;li&gt;Whatever your project actually needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No fighting with pre-built components that almost fit your use case. No compromising on features because extending the framework is too painful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Admiral is open source and works with any backend. Whether you need simple CRUDs or complex custom interfaces, it adapts to your needs.&lt;/p&gt;

&lt;p&gt;Check it out: &lt;a href="https://github.com/dev-family/admiral" rel="noopener noreferrer"&gt;https://github.com/dev-family/admiral&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What kind of admin interfaces are you building? Have you found a framework that gives you the right balance of speed and flexibility?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>UX/UI in 2026: Why Beautiful Design No Longer Guarantees Success</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Wed, 17 Dec 2025 12:10:36 +0000</pubDate>
      <link>https://dev.to/dev_family/uxui-in-2026-why-beautiful-design-no-longer-guarantees-success-1ca2</link>
      <guid>https://dev.to/dev_family/uxui-in-2026-why-beautiful-design-no-longer-guarantees-success-1ca2</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.family/blog/article/uxui-ai-and-trends-that-actually-work-in-2026" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; AI commoditized "pixel-perfect" design. In 2026, designers compete on strategy and metrics, not aesthetics. Here's what actually works now.&lt;/p&gt;




&lt;p&gt;Hi Dev.to! 👋&lt;/p&gt;

&lt;p&gt;I'm a product designer who just spent 3 weeks deep-diving into what's actually working in UX/UI 2026. Not what looks pretty on Dribbble, but what moves business metrics and helps developers ship better products.&lt;/p&gt;

&lt;p&gt;The main thesis? &lt;strong&gt;Design is becoming infrastructure, not decoration.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🤖 The AI Shift: What Changed for Designers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The reality:&lt;/strong&gt;&lt;br&gt;
Tools like Figma AI, Galileo AI, and Magician now generate clean layouts in seconds. I can literally type "dashboard for restaurant management app" and get 5 professional-looking variants instantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this means:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Pixel-perfect" is no longer a competitive advantage&lt;/li&gt;
&lt;li&gt;Visual styling is commoditized&lt;/li&gt;
&lt;li&gt;Designers must compete on strategy, not aesthetics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The new value:&lt;/strong&gt;&lt;br&gt;
Understanding user behavior, metrics, and business logic. AI handles the pixels; humans handle the "why."&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;// Old designer value proposition&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;designer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;making things beautiful&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pretty screens&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// New designer value proposition&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;designer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;skill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;understanding behavior + metrics&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;interfaces that move numbers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📊 Outcome-Driven UX: Every Screen Needs a Metric
&lt;/h2&gt;

&lt;p&gt;In 2026, every screen you build must answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What behavior are we changing?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Which metric are we moving?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How quickly will we see results?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mandatory metrics:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Activation&lt;/strong&gt;&lt;br&gt;
→ Time to first value&lt;br&gt;
→ How fast does user "get it"?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retention&lt;/strong&gt;&lt;br&gt;
→ Day 1, Day 7, Day 30&lt;br&gt;
→ Do they come back?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conversion&lt;/strong&gt;&lt;br&gt;
→ Free → Paid, Browse → Buy&lt;br&gt;
→ Actual revenue impact&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NPS&lt;/strong&gt;&lt;br&gt;
→ Would they recommend?&lt;br&gt;
→ Real satisfaction metric&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LTV&lt;/strong&gt;&lt;br&gt;
→ Long-term user value&lt;br&gt;
→ Are we building sustainable business?&lt;/p&gt;
&lt;h3&gt;
  
  
  Real example from our work:
&lt;/h3&gt;

&lt;p&gt;We redesigned an onboarding flow for a SaaS product:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE:
- 7 steps to first value
- 35% completion rate
- Day 7 retention: 18%

AFTER (outcome-driven approach):
- 3 steps to first value  
- 67% completion rate
- Day 7 retention: 34%

The design wasn't "prettier" - it was more strategic.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🌍 Regional UX Models Going Global
&lt;/h2&gt;

&lt;p&gt;One-size-fits-all UX is dead. Products now adapt interfaces based on regional patterns:&lt;/p&gt;

&lt;h3&gt;
  
  
  Asia (Grab, Gojek, WeChat)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;density&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;high&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;whitespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;minimal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;features-per-screen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;many&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"super-app"&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;strong&gt;Why:&lt;/strong&gt; Users expect everything immediately accessible. Dense = efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  India (Zomato, Paytm)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;trust-signals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prominent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;explanations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;detailed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hyper-localized&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"trust-first"&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;strong&gt;Why:&lt;/strong&gt; Users approach new products cautiously. Design must explain and build trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  US/Europe (Notion, Linear, Apple)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;whitespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;generous&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;visual-noise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;minimal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"minimalist"&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;strong&gt;Why:&lt;/strong&gt; Users value clarity and breathing room. Less = more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The key insight:&lt;/strong&gt; Modern products detect user location/context and adapt UI accordingly. Same backend, different front-end patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  🥽 New Platforms = New UX Patterns
&lt;/h2&gt;

&lt;p&gt;As developers, you're probably already building for these:&lt;/p&gt;

&lt;h3&gt;
  
  
  AR/VR (Apple Vision Pro, Meta Quest)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Traditional UI thinking&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clickable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tap/click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Spatial UI thinking&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spatial-object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gaze + pinch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;floating-at-50cm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;physics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gravity-affected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wearables (Apple Watch, smart glasses)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Screen-based thinking&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;full-screen modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button tap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Wearable thinking&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;glanceable-card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto-after-3s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;interaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quick-action-only&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key differences:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gesture-first flows&lt;/strong&gt; (not tap/click)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eye-control navigation&lt;/strong&gt; (gaze as input)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-UI&lt;/strong&gt; (ambient, contextual interfaces)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spatial design&lt;/strong&gt; (3D, depth, physical space)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎨 Visual Trends That Actually Work
&lt;/h2&gt;

&lt;p&gt;Not just "looks cool" - these drive behavior:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Motion-First Design
&lt;/h3&gt;

&lt;p&gt;Animations aren't decoration - they're explanation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Bad: Decoration */&lt;/span&gt;
&lt;span class="nc"&gt;.button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Good: Behavioral signal */&lt;/span&gt;
&lt;span class="nc"&gt;.button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-2px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c"&gt;/* Communicates: "I'm clickable and will respond" */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.loading-state&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pulse&lt;/span&gt; &lt;span class="m"&gt;1.5s&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c"&gt;/* Communicates: "I'm working, wait for me" */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Warm Minimalism
&lt;/h3&gt;

&lt;p&gt;Less noise, more breathing room, warmer palettes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Old minimalism: cold */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0066FF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Warm minimalism: human */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FAFAF9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1A1A1A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#FF6B35&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--surface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#F5F5F4&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;h3&gt;
  
  
  3. Liquid Glass + Depth
&lt;/h3&gt;

&lt;p&gt;Borrowed from visionOS, now everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.glass-panel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;inset&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&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;h3&gt;
  
  
  4. Accessibility as Base Layer
&lt;/h3&gt;

&lt;p&gt;Not optional anymore:&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;// Automated checks in CI/CD&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accessibilityChecks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;colorContrast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;=4.5:1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// WCAG AA minimum&lt;/span&gt;
  &lt;span class="na"&gt;focusVisible&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;keyboardNav&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;screenReaderLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all-interactive-elements&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;motionPreference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;respect-prefers-reduced-motion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🛠️ Practical Implementation for Developers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Integrate UX Metrics in Your Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Track UX metrics like features&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trackUXMetric&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ux_metric&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;span class="na"&gt;metric_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 'activation' | 'retention' | 'conversion'&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getCurrentComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example: Track time to first value&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onboardingStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// ... user completes onboarding ...&lt;/span&gt;
&lt;span class="nf"&gt;trackUXMetric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;activation&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;span class="na"&gt;time_to_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;onboardingStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;completed&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Build Adaptive Interfaces
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Detect and adapt to regional patterns&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getUXDensity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userLocale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;densityMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asia&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="s1"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// More content per screen&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;india&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="s1"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// Balanced with trust signals  &lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us&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="s1"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// Generous whitespace&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eu&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="s1"&gt;low&lt;/span&gt;&lt;span class="dl"&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;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getRegion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userLocale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;densityMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;medium&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;span class="c1"&gt;// Apply density to layout&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;low&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;24px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nf"&gt;getUXDensity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userLocale&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Respect Familiar Patterns
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Don't reinvent the wheel&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bottom-tab-bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// Familiar to everyone&lt;/span&gt;
  &lt;span class="na"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sidebar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;// Expected pattern&lt;/span&gt;
  &lt;span class="c1"&gt;// NOT: 'gesture-only-hidden-menu' (users will struggle)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Innovation through details, not structure&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enhancedNavigation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transitions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;smooth-60fps&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;haptic-on-tap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;persisted-across-sessions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📈 Companies Doing This Right
&lt;/h2&gt;

&lt;p&gt;Real examples to learn from:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notion&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Familiar patterns (blocks, pages, database views)&lt;/li&gt;
&lt;li&gt;Wins on details (smooth animations, smart defaults)&lt;/li&gt;
&lt;li&gt;Every feature tied to engagement metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Linear&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Super predictable structure&lt;/li&gt;
&lt;li&gt;Fast keyboard shortcuts (developer-focused)&lt;/li&gt;
&lt;li&gt;Minimal visual noise, maximum clarity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Duolingo&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gamification based on retention data&lt;/li&gt;
&lt;li&gt;A/B tests everything (3-5 day cycles)&lt;/li&gt;
&lt;li&gt;Bright accents guide behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Shopify&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean merchant dashboard&lt;/li&gt;
&lt;li&gt;Regional payment method adaptation&lt;/li&gt;
&lt;li&gt;Onboarding optimized for activation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎯 The Controversial Part
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you design based on "beauty" or "speed to ship," AI will likely win.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Designers who focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User behavior patterns&lt;/li&gt;
&lt;li&gt;Business metrics
&lt;/li&gt;
&lt;li&gt;Strategic thinking&lt;/li&gt;
&lt;li&gt;Collaboration with developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...will be in the top 5% of the market.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Quick Implementation Checklist
&lt;/h2&gt;

&lt;p&gt;For your next feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; [ ] Define which metric this feature should improve
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Choose familiar patterns over novel ones
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add smooth transitions (not just instant state changes)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Ensure 4.5:1+ color contrast (WCAG AA)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Test with keyboard navigation
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add loading/error states with clear feedback
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Track actual usage metrics (not just launches)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Run quick A/B test (3-5 days, not months)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Adapt for regional patterns if targeting multiple markets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🔮 Bottom Line
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;2026 isn't about making prettier interfaces.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding behavior&lt;/li&gt;
&lt;li&gt;Moving metrics&lt;/li&gt;
&lt;li&gt;Building adaptable systems&lt;/li&gt;
&lt;li&gt;Collaborating strategically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI can generate the pixels. Developers + designers who understand the "why" behind the "what" will build products that actually work.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full deep-dive (18 min read):&lt;/strong&gt; &lt;a href="https://dev.family/blog/article/uxui-ai-and-trends-that-actually-work-in-2026" rel="noopener noreferrer"&gt;https://dev.family/blog/article/uxui-ai-and-trends-that-actually-work-in-2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's your experience?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are you tracking UX metrics in your projects?&lt;/li&gt;
&lt;li&gt;Have you adapted interfaces for different regions?&lt;/li&gt;
&lt;li&gt;How do you use AI in your design/dev workflow?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's discuss in the comments! 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. If you're building products and want to dive deeper into any of these patterns, happy to answer questions in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ux</category>
      <category>design</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Why Security Updates Still Matter More Than Ever</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Wed, 10 Dec 2025 12:02:37 +0000</pubDate>
      <link>https://dev.to/mrbantsevich/why-security-updates-still-matter-more-than-ever-h94</link>
      <guid>https://dev.to/mrbantsevich/why-security-updates-still-matter-more-than-ever-h94</guid>
      <description>&lt;p&gt;Over the past few days, the tech community has been discussing a new wave of automated attacks exploiting a recently disclosed critical vulnerability in Next.js.&lt;/p&gt;

&lt;p&gt;Events like these serve as a reminder of something we all know — yet too often postpone:&lt;br&gt;
security isn’t a one-time setup. It’s a constant, ongoing responsibility.&lt;/p&gt;

&lt;p&gt;When a major vulnerability goes public, automated scanners begin sweeping the entire internet within minutes. They detect unpatched versions and immediately attempt to deploy malicious payloads. These aren’t targeted attacks — they’re fully automated systems that exploit any available opening.&lt;/p&gt;

&lt;p&gt;Here are a few practices that can prevent most of the damage:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep dependencies up to date.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Even a single outdated library can open the door to automated exploitation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install security patches as soon as they’re released.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Time is critical. Attackers automate everything — we need to react fast.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Monitor your infrastructure continuously.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unexpected files, strange processes, unusual traffic patterns — early detection is key.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Treat security as ongoing maintenance, not a checkbox.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A secure application requires constant attention.&lt;/p&gt;

&lt;p&gt;Situations like the current global attack wave highlight the same truth every time:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;your product stays secure only as long as it stays maintained.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>security</category>
      <category>nextjs</category>
      <category>webdev</category>
      <category>news</category>
    </item>
    <item>
      <title>🧠 How Different AI Agents Write Code from the Same Instructions: Cursor vs Copilot vs Windsurf</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Mon, 29 Sep 2025 10:38:42 +0000</pubDate>
      <link>https://dev.to/mrbantsevich/how-different-ai-agents-write-code-from-the-same-instructions-cursor-vs-copilot-vs-windsurf-2f0l</link>
      <guid>https://dev.to/mrbantsevich/how-different-ai-agents-write-code-from-the-same-instructions-cursor-vs-copilot-vs-windsurf-2f0l</guid>
      <description>&lt;p&gt;We recently ran an experiment: we took the same set of coding instructions and gave them to three different AI coding agents — Cursor, Copilot, and Windsurf — to see how each would handle the task.&lt;br&gt;
The results turned out to be pretty interesting, showing the strengths and weaknesses of each tool in terms of rule compliance, accuracy, and developer experience.&lt;/p&gt;

&lt;p&gt;What’s inside the article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A breakdown of how each tool handles rules (types, activation, nesting, etc.)&lt;/li&gt;
&lt;li&gt;Testing code generation (CRUD) from the same description&lt;/li&gt;
&lt;li&gt;Detailed comparison: who nailed it, and who missed the mark&lt;/li&gt;
&lt;li&gt;Insights on when Cursor is the best choice — and when Windsurf might be a solid alternative&lt;/li&gt;
&lt;li&gt;Why Copilot still struggles with custom rule handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;➡️ Key takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cursor followed the rules most accurately and delivered the cleanest results.&lt;/li&gt;
&lt;li&gt;Windsurf required a bit more effort to “guide” it, but it performed reasonably well with adjustments.&lt;/li&gt;
&lt;li&gt;Copilot, with its current rule support, wasn’t able to produce results close to the intended structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want to dive deeper, check the code samples, and see the detailed comparison? Read the full article here:&lt;/p&gt;

&lt;p&gt;👉 Cursor vs Copilot vs Windsurf: How Different AI Agents Write Code from the Same Instructions&lt;/p&gt;

&lt;p&gt;I’d love to hear your thoughts:&lt;/p&gt;

&lt;p&gt;Which of these tools have you used in your workflow?&lt;br&gt;
Do you have your own coding rules or prompt strategies?&lt;br&gt;
Did anything in the results surprise you?&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>githubcopilot</category>
      <category>windsurf</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to verify your cookie consent is working 🍪🍪</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 08 May 2025 07:59:28 +0000</pubDate>
      <link>https://dev.to/dev_family/how-to-verify-your-cookie-consent-is-working-i4f</link>
      <guid>https://dev.to/dev_family/how-to-verify-your-cookie-consent-is-working-i4f</guid>
      <description>&lt;p&gt;Got your cookie banner set up with Google Consent Mode? Now comes the critical step – verifying that it’s actually respecting user choices.&lt;/p&gt;

&lt;p&gt;Here’s how to ensure everything is working smoothly:&lt;br&gt;
1️⃣ Use Browser DevTools. Before and after consent, check cookies and requests to ensure compliance. Is Google Analytics firing only after consent? Are non-essential cookies blocked before? Make sure your users’ privacy is protected.&lt;br&gt;
2️⃣ Google Tag Assistant. This Chrome extension shows consent status changes in real time, so you can track whether analytics and ads are only enabled when users say "yes".&lt;/p&gt;

&lt;p&gt;And don’t forget about a detailed cookie policy that aligns with regional laws (GDPR, CCPA). &lt;/p&gt;

&lt;p&gt;📘 Learn more in &lt;a href="https://dev.family/blog/article/how-to-customize-the-consent-cookie-banner-to-comply-with-gdpr-google-consent-mode-and-country-specific-laws?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=max&amp;amp;utm_content=how-to-customize-the-consent-cookie-banner-to-comply-with-gdpr-google-consent-mode-and-country-specific-laws" rel="noopener noreferrer"&gt;our full guide&lt;/a&gt; with examples of cookie policy for EU and US&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>cookie</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Evolution of Architectural Patterns in Back-End Development: From MVC to Microservices</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 08 May 2025 07:51:48 +0000</pubDate>
      <link>https://dev.to/mrbantsevich/the-evolution-of-architectural-patterns-in-back-end-development-from-mvc-to-microservices-4keb</link>
      <guid>https://dev.to/mrbantsevich/the-evolution-of-architectural-patterns-in-back-end-development-from-mvc-to-microservices-4keb</guid>
      <description>&lt;p&gt;An architectural pattern is the foundation of any large-scale software project, and the choice of pattern significantly impacts how successfully a back-end system can evolve and be maintained. For a long time, the traditional MVC (Model-View-Controller) pattern was considered the go-to approach for building web applications.&lt;/p&gt;

&lt;p&gt;Modern MVC implementations often incorporate advanced concepts like dependency injection (DI) and inversion of control (IoC), making it possible to extend and scale the architecture far beyond its original simplicity. However, even these more complex MVC structures come with limitations – especially when it comes to scalability and maintaining increasingly complex business logic.&lt;/p&gt;

&lt;p&gt;Despite the capabilities of today’s MVC frameworks, many teams still rely on basic, unextended MVC.&lt;/p&gt;

&lt;p&gt;In this article, we’ll take a closer look at how back-end architectural patterns have evolved – from the classic MVC model, commonly used in early-stage projects, to more advanced approaches like SOA (Service-Oriented Architecture), DDD (Domain-Driven Design), Modular Monoliths, and ultimately, Microservices.&lt;/p&gt;

&lt;p&gt;Our goal is to highlight how transitioning between architectures can address real-world issues around maintenance, testability, and scalability, and to offer guidance on choosing the right architecture based on your project’s specific needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges of Traditional MVC
&lt;/h2&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F5alts9s6kbfrq2b20ykz.png" 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.amazonaws.com%2Fuploads%2Farticles%2F5alts9s6kbfrq2b20ykz.png" alt="Image description" width="800" height="493"&gt;&lt;/a&gt;&lt;br&gt;
The main advantages of MVC are fast development and a low entry barrier. It’s a straightforward and intuitive architectural pattern that developers can quickly learn and implement. Additional time costs are caused by the distribution of business logic across controllers, project growth, testing difficulties, and duplication of logic.&lt;/p&gt;

&lt;p&gt;The primary issues arise from the scattering of business logic across controllers, project growth, testing difficulties, and code duplication. This problem becomes especially apparent when there are no modular tests, or when parts of the code base cannot be reused in different parts of the application.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Frbeekazxsfxwgzendtn8.png" 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.amazonaws.com%2Fuploads%2Farticles%2Frbeekazxsfxwgzendtn8.png" alt="Image description" width="800" height="722"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In large-scale projects, this typically results in a set of large controllers, where business logic is either not reused at all or offloaded into static utility functions or domain models. This approach often leads to developer frustration, as modifying any part of the system can trigger unforeseen consequences.&lt;/p&gt;

&lt;p&gt;Today’s MVC frameworks offer modern capabilities that mitigate many of these issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;IoC and DI integration – frameworks like ASP.NET MVC, Laravel, and Spring MVC come with built-in dependency injection containers, increasing modularity and simplifying testing;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clear separation between views and controllers – using ViewModels, templating systems, and dedicated service layer helps structure communication between layers more cleanly;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extensibility through additional layers – when it’s necessary, MVC can be augmented with separate layers for business logic, domain modeling, and infrastructure, resulting in a more flexible and scalable architecture.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, despite these improvements, there are still some limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Scattered business logic – even with service layers and repository patterns in place, logic often ends up split between controllers, models, and other components, making long-term maintenance more difficult;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scaling challenges – as the project grows, managing dependencies and introducing new features can lead to tangled codebases, requiring frequent refactoring to stay manageable;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing limitations – although DI helps, tight coupling between layers sometimes results in a reliance only on integration testing, rather than clean unit tests.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we’ve identified the core issues, let’s walk through how project architecture typically evolves. We'll explore when a shift to a different pattern may become necessary, whether it’s possible to anticipate that transition, and how to proactively prepare for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stages of Architectural Evolution
&lt;/h2&gt;

&lt;p&gt;As a project grows, it accumulates new features, more data, and an increasing number of users. To keep the system from becoming overly complex or difficult to maintain, its architecture needs to evolve accordingly.&lt;/p&gt;

&lt;p&gt;Let’s say we start a project using the previously discussed MVC pattern and successfully launch an MVP. As the product gains traction, the client decides to continue development. Over time, we begin to encounter growing pain – maintaining and updating both existing and new business logic becomes increasingly challenging. At this stage, it often makes sense to consider switching to a more robust architectural approach in order to speed up development and reduce bugs.&lt;/p&gt;

&lt;p&gt;Below are some architectural models that, in my experience, are well-suited for fast-scaling products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adopting Domain-Driven Design (DDD)&lt;/strong&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fj18xp9d9fe2l0s2tsc0b.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fj18xp9d9fe2l0s2tsc0b.png" alt="Image description" width="800" height="675"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Domain-Driven Design focuses on a deep understanding of the business domain. The core idea behind DDD is to build a rich domain model and leverage concepts like bounded contexts, aggregates, entities, and value objects to organize and encapsulate business logic. While DDD helps structure internal application logic, it doesn’t prescribe specific deployment strategies or component interaction models.&lt;/p&gt;

&lt;p&gt;Key benefits and characteristics of transitioning to DDD include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reduced complexity through a clearly and explicitly described domain layer. Each domain has a specific responsibility, and its interactions are confined within defined Bounded Contexts;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easier integration of new features if domain layer are properly structured – new logic naturally fits into existing domain boundaries;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Changes require deep domain understanding, encouraging developers to model real business processes rather than just code for functionality;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Minimized risk of chaotic logic – when built around DDD principles, the system can absorb changes in a consistent and predictable way;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Feature expansion happens naturally, either by creating new domains or extending existing ones within their context.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Transitioning to a Modular Monolith&lt;/strong&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fpykisczojdgvomrvl547.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fpykisczojdgvomrvl547.png" alt="Image description" width="800" height="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Modular Monolith architectural approach defines clear boundaries and dependencies between modules while keeping the application as a single deployable unit. It offers many of the benefits of modularity—such as improved maintainability, testability, and scalability at the development level—without introducing the complexity of a fully distributed system.&lt;/p&gt;

&lt;p&gt;Key advantages and characteristics of adopting a Modular Monolith include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reduced complexity through separation into well-defined modules with clear interfaces, each of which can be developed and tested independently;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lower risk of regression– when modules are properly isolated, changes made to one area are less likely to unintentionally break others;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A natural path to microservices – a well-structured module can eventually be extracted into an independent service with minimal effort;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Safe refactoring and updates – while modifications may require tests across modules, a clean modular structure minimizes risk;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simplified code maintenance thanks to clearly separated concerns and encapsulated logic within each module.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choosing the Right Approach&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ultimately, the choice of architectural approach depends on the specifics of the project, the team, and how comfortable they are with concepts like DDD. However, the comparison table below outlines key differences based on several aspects:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fg0gjotcrmvymlq4hwyec.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fg0gjotcrmvymlq4hwyec.png" alt="Image description" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the project evolves, contextual models or modules tend to grow in complexity or become increasingly independent. At some point, these components may even require different runtime environments or programming languages. That’s when microservices or SOA (Service-Oriented Architecture) come into play.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Moving to Microservices and SOA&lt;/strong&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fsh2fz1hmm0cye1hkzj13.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fsh2fz1hmm0cye1hkzj13.png" alt="SOA" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fppgnd4jr1nod9xq1f8h3.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fppgnd4jr1nod9xq1f8h3.png" alt="Microservices" width="800" height="756"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main advantage of this approach is the ability to split the application into independent services, each responsible for a specific task – such as email notifications or payment processing. This enables high flexibility, scalability, and independent deployment of individual components.&lt;/p&gt;

&lt;p&gt;However, this approach requires a well-thought-out infrastructure for orchestration, monitoring, and inter-service communication.&lt;br&gt;
While SOA and Microservices aim for the same goal – decomposition of systems into separate components – they differ in scale, implementation style, and operational complexity.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F4m0xw5apr31gmgrp8zt5.png" 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.amazonaws.com%2Fuploads%2Farticles%2F4m0xw5apr31gmgrp8zt5.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Transitioning to a microservices or SOA-based system allows each component to be tailored to a specific task independently of the rest of the system. For instance, a dedicated data processing service can be optimized for handling high-throughput workloads, while an analytics service might run sophisticated algorithms.&lt;/p&gt;

&lt;p&gt;Because components operate autonomously, changes to one service don’t disrupt the whole system. In contrast, modular monoliths and DDD often rely on conceptual boundaries (like Bounded Contexts), and changes in one module can still affect others.&lt;/p&gt;

&lt;p&gt;Another key benefit is technology flexibility. You can use Python for data processing, Go for high-performance services, and Node.js for rapid prototyping – all within the same system.&lt;/p&gt;

&lt;p&gt;Workloads in real-world systems are rarely uniform. The ability to scale individual services helps manage resources more effectively and can significantly reduce infrastructure costs.&lt;/p&gt;

&lt;p&gt;And here are all the transitioning benefits:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fagwyodxv5lv754eoutby.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fagwyodxv5lv754eoutby.png" alt="Image description" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both approaches have their strengths, and the choice between them should be driven by your system’s specific needs. Here's an additional comparison between SOA and Microservices:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fk5m1r0zugp43y4o12pdo.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fk5m1r0zugp43y4o12pdo.png" alt="Image description" width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Own experience and project examples
&lt;/h2&gt;

&lt;p&gt;From my own experience, I’ve worked on two major projects where architectural issues and technical debt forced teams to rethink their systems. Both have decided to move to a different architecture. But the path wasn’t easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1: Migrating to a Modern MVC Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This was a medium sized project where the architecture transition took about three months and was handled by only two developers. The main task was a full refactor to align the codebase with a modern MVC structure and upgrade the framework from Laravel 5.8 to Laravel 8.0.&lt;br&gt;
Before the migration, the application used a classic setup: a REST API with logic embedded directly in models, and overloaded controllers handling routing and business logic. Reusability attempts were limited to helper functions, which eventually led to tight coupling.&lt;/p&gt;

&lt;p&gt;Key challenges during the transition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Bug spikes after redistributing logic due to changes in architectural principles;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pressure from the business for fast delivery, making iteration and debugging more difficult;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Separating concerns into services and layers to reduce coupling and achieve atomicity logic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most difficult part was splitting business logic. Over the years, various teams contributed to the codebase, resulting in duplicated logic and inconsistencies. Business logic existed at every level – from middleware to models – making refactoring extremely complex. As we progressed, new edge cases emerged that required expanding or modifying existing solutions, triggering cascades of service rewrites and test updates. Some services grew to 1,000-2,000 lines of code and had to be split, which impacted dependencies and revealed issues with recursive DI chains.&lt;/p&gt;

&lt;p&gt;Despite these difficulties, the migration brought significant benefits: cleaner architecture, improved test coverage, and easier maintenance accelerated feature development. Overall development speed increased by approximately 25%, and the bug rate dropped by 30%, validating the value of the refactor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2: A Journey Through Compromise&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This project had over 450 controllers but only 90 services – a sign of inconsistent architecture caused by multiple large teams working with different standards. As a result, it was nearly impossible to trace where business logic existed.&lt;/p&gt;

&lt;p&gt;The project suffered from frequent bugs, low maintainability, poor scalability, and optimization bottlenecks. Despite the clear need for change, aligning over 100 developers across more than five teams (plus separate groups of managers, analysts, architects, DevOps, etc.) was a massive challenge. It took over six months just to move from idea to action. As usual, the business was reluctant to allocate resources for addressing technical debt.&lt;/p&gt;

&lt;p&gt;Instead of a full microservices rewrite, a compromise was reached: each team would begin migrating their components to microservices. The legacy monolith remained operational, with integrations to new services handled through databases, Redis, Prometheus, and dedicated microservice APIs.&lt;/p&gt;

&lt;p&gt;The DevOps team faced a steep learning curve, particularly around service orchestration in Go, which was new to them. To minimize risk, low-traffic components were migrated first.&lt;/p&gt;

&lt;p&gt;Key challenges in this case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Learning and adaptation – Go was unfamiliar to the team. A lead engineer was hired, and internal upskilling programs were launched, but inexperience led to data inconsistencies, system crashes, and even revenue losses;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bottlenecks – high-load areas exposed critical failure points requiring urgent fixes;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Team stress – constant bugs, unstable infrastructure, and a flood of problems led to a sense of looming failure.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After a painful stabilization phase – including bug fixes and bottleneck optimizations – the situation began to improve. The architecture became more transparent, development accelerated, and testing helped catch issues early. Teams gained autonomy, scalability increased, and API standardization brought clarity and independence.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;✍ Key takeaway. Migrating to a new architecture is always challenging – for developers, managers, DevOps, and product owners alike. But the payoff is real: autonomous teams, resilient services, and a more flexible system benefit both engineering and the business.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Choose the Right Architecture Pattern
&lt;/h2&gt;

&lt;p&gt;When selecting an architectural pattern, consider the following criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Testability – the architecture should support unit and integration testing across functional blocks;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Readability &amp;amp; Maintainability – a well-structured codebase makes changes easier and reduces the likelihood of bugs;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Logic Reusability – dividing functionality into atomic components prevents duplication and accelerates new feature development;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Flexibility &amp;amp; Scalability – The system must be adaptable to evolving project requirements, allowing incremental enhancements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on the architectural models discussed, here’s a breakdown to help guide your decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Purpose and scope of use differ between the approaches – DDD focuses on modeling business logic, while SOA and Modular Monolith are aimed at structuring the application from the perspective of deployment and dependency management;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deployment – SOA is built around independently deployable services. In contrast, a Modular Monolith is deployed as a single application, even though it has a well-defined internal modular structure. DDD, on the other hand, does not prescribe a specific deployment strategy;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Communication SOA happens over the network – typically via REST or SOAP – which introduces concerns like latency, reliability, and security. A Modular Monolith avoids these issues since modules interact with each other directly within the same process;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When it comes to managing complexity, DDD helps by clearly separating domain logic into bounded contexts, making business logic easier to reason about. SOA and Modular Monolith, however, manage complexity through technical separation and deployment boundaries.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While all three approaches aim to split a system into logical components, they each serve a different purpose: DDD is about domain modeling, SOA is about building distributed systems, and Modular Monolith is about maintaining a modular yet unified application structure.&lt;/p&gt;

&lt;p&gt;It's important to remember that choosing an architectural pattern depends on the specifics of the project, the available budget, and the client’s long-term goals. In some cases, it makes sense to start with a simpler architecture – like MVC – and gradually move toward DDD as the project grows and the business logic becomes more complex.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Modern MVC implementations using IoC and DI are powerful and well-suited for small to mid-sized projects. However, as systems grow and business logic becomes more complex, challenges arise around scalability, code fragmentation, and maintainability.&lt;/p&gt;

&lt;p&gt;Alternative architectures – such as SOA, DDD, Modular Monolith, and Microservices – offer clear boundaries, component isolation, and development flexibility, making them better suited for large and fast-evolving products.&lt;/p&gt;

&lt;p&gt;When choosing your architecture, weigh the specifics of your project: testability, scalability, long-term maintainability, and business goals. There’s no one-size-fits-all, and sometimes it makes sense to start with a simpler MVC model and evolve to DDD or microservices as the product matures.&lt;/p&gt;

&lt;p&gt;In the next article I’ll dive into real-world use cases for each architectural pattern and compare them in practice.&lt;/p&gt;

&lt;p&gt;Here was &lt;a href="https://dev.family/?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=max&amp;amp;utm_content=the-evolution-of-architectural-patterns-in-back-end-development-from-mvc-to-microservices" rel="noopener noreferrer"&gt;dev.family&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>backend</category>
      <category>microservices</category>
      <category>mvc</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The future of voice commerce: how to use speech recognition and voice search in 2025</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 13 Mar 2025 11:24:28 +0000</pubDate>
      <link>https://dev.to/mrbantsevich/the-future-of-voice-commerce-how-to-use-speech-recognition-and-voice-search-in-2025-5fk</link>
      <guid>https://dev.to/mrbantsevich/the-future-of-voice-commerce-how-to-use-speech-recognition-and-voice-search-in-2025-5fk</guid>
      <description>&lt;p&gt;🗣️66% of businesses see a voice-enabled customer experience as critical to their future, yet only 28% of businesses have adopted it.&lt;/p&gt;

&lt;p&gt;From drive-thru automation to personalized orders – voice commerce is changing the way customers interact with brands. &lt;br&gt;
On the one hand business got:&lt;br&gt;
👌🏻 Automated service support&lt;br&gt;
👌🏻Smart and personalized offerings &lt;br&gt;
👌🏻Increased conversion rate&lt;/p&gt;

&lt;p&gt;On the other hand, there are still bugs and errors in speech processing that result in:&lt;br&gt;
🫠 Errors in speech interpretation&lt;br&gt;
🫠🫠 Privacy concerns&lt;br&gt;
🫠🫠🫠 Customer frustration with glitches&lt;/p&gt;

&lt;p&gt;See how voice tech is reshaping restaurant &amp;amp; retail in &lt;a href="https://dev.family/blog/article/the-future-of-voice-commerce-how-to-use-speech-recognition-and-voice-search-in-2025?utm_source=dev_to&amp;amp;utm_medium=post&amp;amp;utm_campaign=the-future-of-voice-commerce-how-to-use-speech-recognition-and-voice-search-in-2025" rel="noopener noreferrer"&gt;our new article&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Telegram mini-app development and testing specifics: from initialisation to launch</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Tue, 11 Mar 2025 10:58:06 +0000</pubDate>
      <link>https://dev.to/dev_family/telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch-1ofh</link>
      <guid>https://dev.to/dev_family/telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch-1ofh</guid>
      <description>&lt;p&gt;We receive more and more requests for Telegram mini apps development. Why is this happening? Telegram continues to grow actively, and companies want to reach this audience by offering convenient solutions within the messenger, where their customers spend a significant part of their time.&lt;br&gt;
The dev.family team has already talked about these and other benefits for business in one of &lt;a href="https://dev.family/blog/article/product-launch-on-messenger-apps-telegram-web-app-opportunities-for-businesses?utm_source=dev-to&amp;amp;utm_medium=article&amp;amp;utm_campaign=telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch&amp;amp;utm_content=product-launch-on-messenger-apps-telegram-web-app-opportunities-for-businesses" rel="noopener noreferrer"&gt;our articles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From a technical point of view, mini apps also have their advantages: they allow full-fledged applications to be launched directly in Telegram, without the need to develop separate native mobile versions. This significantly reduces development and support costs and speeds up the product's time to market.&lt;/p&gt;

&lt;p&gt;In this article, I will share my own experience of developing Telegram mini apps and answer the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are Telegram mini apps?&lt;/li&gt;
&lt;li&gt;How are they different from other platforms?&lt;/li&gt;
&lt;li&gt;What are the development prospects for Telegram mini apps?&lt;/li&gt;
&lt;li&gt;How to properly test Telegram mini apps, taking into account the peculiarities of the platform?&lt;/li&gt;
&lt;li&gt;How to set up the environment for a future application and initialise the Telegram apps SDK?&lt;/li&gt;
&lt;li&gt;What are the nuances of Telegram mini apps development?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What are Telegram mini apps and why are they so popular
&lt;/h2&gt;

&lt;p&gt;Today, Telegram mini apps allow us to open any website from within the messenger. The technology is implemented with the help of a special WebView browser shell – a system component that is responsible for integrating web pages into other applications and adapting to the device's operating system.&lt;/p&gt;

&lt;p&gt;A Telegram mini app can be any application that can be written in JavaScript or any tool that can be compiled into it. For example, React, Next.js, Angular or even React Native for Web.&lt;/p&gt;

&lt;p&gt;The product can either be a standalone solution or part of a business ecosystem. We have already told you in our &lt;a href="https://dev.family/blog/article/how-to-build-a-web-app-part-i-developing-on-react-native-web?utm_source=dev-to&amp;amp;utm_medium=article&amp;amp;utm_campaign=telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch&amp;amp;utm_content=how-to-build-a-web-app-part-i-developing-on-react-native-web" rel="noopener noreferrer"&gt;Telegram mini app tutorial &lt;/a&gt;how to integrate a ready-made React Native application into Telegram using the react-native-web package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development prospects for Telegram mini apps&lt;/strong&gt;&lt;br&gt;
The number of Telegram users is gradually approaching one billion. Imagine giving them access to a cross-browser application that runs on any operating system, be it iOS, Android, Windows, macOS or Linux. And it doesn't require any mobile development. Now you can add the mini app to the desktop of your device and open it full screen as a standalone application. And it seems we are only at the beginning of its development path.&lt;/p&gt;

&lt;p&gt;The functionality of Telegram mini apps and the possibility of integrating additional services and tools is quite wide: we can use accelerometer, gyroscope, biometrics, have access to geolocation, receive push notifications and much more.&lt;/p&gt;

&lt;p&gt;Of course, many things can be done using the standard browser API. But Telegram simplifies user interaction, permissions, payments, data exchange and bot management by providing all the necessary tools. And thanks to Telegram's built-in security, mini apps can be more secure than traditional web apps.&lt;/p&gt;

&lt;p&gt;I am sure that in the future Telegram will develop the mini apps format towards mobile development. There will be more and more opportunities to access the hardware features of devices, such as Bluetooth, NFC, Wi-Fi, flashlight, contacts, calendar and so on.&lt;/p&gt;

&lt;p&gt;Working with Telegram mini apps is also very convenient for the user: if the messenger is already installed on the device with a connected account, there is no need to download anything additional. All the functionalities are already available in Telegram.&lt;/p&gt;

&lt;p&gt;Businesses, in turn, get a convenient mobile app without having to resort to mobile development, which is usually more expensive than web development. Once we write an app competently, we can run it in the browser, mobile and desktop versions of Telegram, getting more opportunities and conversions for less cost.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to properly test and debug the Telegram mini app
&lt;/h2&gt;

&lt;p&gt;Let's go ahead and start with the peculiarities of testing Telegram mini apps, because we'll talk about them later in the development section. So it is important to set the context. The main difficulty is the inability to launch the project as easily as in a browser via localhost, and the lack of a developer console. However, these problems are easily solved.&lt;/p&gt;

&lt;p&gt;As we have already seen, the Telegram mini app is a website that, when linked to, will run in the Telegram environment. So we need to pass a link that displays the development environment. This is done using port forwarding.&lt;/p&gt;

&lt;p&gt;There are two ways of doing this.&lt;/p&gt;

&lt;p&gt;In the first case, we use the third-party utility ngrok. But it only has a monthly limit on the number of connections, so this option is not very suitable for development.&lt;/p&gt;

&lt;p&gt;In the second case we can use VSCode, where we need to open our project and run it as localhost. Next, open the terminal, go to the 'Ports' tab, type in the port number and you will get a link to the redirected port, which can now be used to access our localhost. We will use this link as the link to the mini app in the chatbot.&lt;br&gt;
It looks like this: &lt;a href="https://d0etr6gh-3000.euw.devtunnels.ms" rel="noopener noreferrer"&gt;https://d0etr6gh-3000.euw.devtunnels.ms&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A redirected port can be created as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private – no one but you will be able to access it;&lt;/li&gt;
&lt;li&gt;Public – the port will be available to everyone if we want to share the link to the application with others.&lt;/li&gt;
&lt;/ul&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fl0ij6zaa9coe2xnc24xr.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fl0ij6zaa9coe2xnc24xr.png" alt="Image description" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we can launch our Telegram mini app and follow the development process in real time, because Hot Reload works just like in a browser.&lt;/p&gt;

&lt;p&gt;But how do you debug an application without access to the developer console? To do this, let's learn about Eruda.&lt;/p&gt;

&lt;p&gt;Eruda is a mobile development console that can be launched in any environment. All you need to do is click on the button that is embedded in your application after initialising this library.&lt;br&gt;
This is what it looks like:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fhwx5dvu9yw9ld45i78q0.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fhwx5dvu9yw9ld45i78q0.png" alt="Image description" width="714" height="1398"&gt;&lt;/a&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fcotktw1zuf5nylr67ntx.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fcotktw1zuf5nylr67ntx.png" alt="Image description" width="716" height="1394"&gt;&lt;/a&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Filmo28jfsaamwx1jimkv.png" 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.amazonaws.com%2Fuploads%2Farticles%2Filmo28jfsaamwx1jimkv.png" alt="Image description" width="718" height="1414"&gt;&lt;/a&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Ft1d08r24fegoqg48oy4n.png" 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.amazonaws.com%2Fuploads%2Farticles%2Ft1d08r24fegoqg48oy4n.png" alt="Image description" width="732" height="1206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below we'll go through how to create a mini app in Telegram from scratch and set up an initial template to initialise the &lt;strong&gt;telegram-apps/sdk-react package&lt;/strong&gt; and the app itself. We will see how easy it is to integrate the Eruda package into our project.&lt;/p&gt;

&lt;p&gt;You can also read the documentation and connect the package in a different way. Either way, it will only take a few lines of string.&lt;br&gt;
In addition, I would like to mention one more thing that relates to testing.&lt;/p&gt;

&lt;p&gt;If you try to open the app in a browser, you will see the following error:&lt;br&gt;
&lt;em&gt;&lt;strong&gt;“Unable to retrieve launch parameters from any known source. Perhaps, you have opened your app outside Telegram?”&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fff6wy3z3sowiwl1ale9j.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fff6wy3z3sowiwl1ale9j.png" alt="Image description" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The message says that the mini app cannot be launched outside the Telegram environment.&lt;/p&gt;

&lt;p&gt;Let's move from theory to practice.&lt;/p&gt;

&lt;p&gt;However, we can configure our application to open in a browser. We will not be able to get real data from Telegram, but we will add mock data that will mimic the environment we need.&lt;/p&gt;
&lt;h2&gt;
  
  
  Development of Telegram mini app from scratch
&lt;/h2&gt;

&lt;p&gt;We have already described the process of creating a chatbot in Telegram using BotFather in &lt;a href="https://dev.family/blog/article/how-to-build-a-web-app-part-ii-deploying-telegram-mini-app?utm_source=dev-to&amp;amp;utm_medium=article&amp;amp;utm_campaign=telegram-mini-app-development-and-testing-specifics-from-initialisation-to-launch&amp;amp;utm_content=how-to-build-a-web-app-part-ii-deploying-telegram-mini-app" rel="noopener noreferrer"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So let's move on to the code itself.&lt;/p&gt;

&lt;p&gt;The next step is to initialise the mini app project. In general, the Telegram developers have gone to the trouble of preparing a selection of &lt;a href="https://github.com/Telegram-Mini-Apps#templates" rel="noopener noreferrer"&gt;ready-made template&lt;/a&gt; that you can use depending on the technology. For example, here are variants for &lt;a href="https://github.com/Telegram-Mini-Apps/nextjs-template" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; and &lt;a href="https://github.com/Telegram-Mini-Apps/reactjs-template" rel="noopener noreferrer"&gt;React.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;✍ Does it make sense to use Next.js? Unfortunately, mini apps are not currently able to fully adapt to SSR, ISR and other rendering methods. Communication with Telegram happens through the use of a window object, which is impossible to get on the server side.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So if your application involves user identification or a chatbot, you will not be able to do this on the server and queries will have to be executed on the client. However, this does not change the fact that Next.js has additional benefits, features and optimisations over React and can still be used for mini app development.&lt;/p&gt;

&lt;p&gt;Let's go back to the code. We took one of the ready-made templates and adapted it for our purposes, removing anything unnecessary and adding additional logic. To work with Telegram mini apps, we used the &lt;strong&gt;@telegram-apps/sdk-react package&lt;/strong&gt;. Let's talk about it in a bit more detail.&lt;/p&gt;

&lt;p&gt;We have a provider that is used in the root barkout to initialise this package and wrap the whole app.&lt;/p&gt;

&lt;p&gt;It looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html lang={locale} className={`${GeologicaFont.variable}`}&amp;gt;
&amp;lt;body&amp;gt;
         &amp;lt;TelegramSDKInitProvider&amp;gt;
           &amp;lt;AppInitProvider&amp;gt;
               &amp;lt;div className={styles.layout}&amp;gt;{children}&amp;lt;/div&amp;gt;
           &amp;lt;/AppInitProvider&amp;gt;
         &amp;lt;/TelegramSDKInitProvider&amp;gt;
     &amp;lt;/body&amp;gt;
   &amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens here and why do we need two providers?&lt;/p&gt;

&lt;p&gt;First, all the logic is executed inside TelegramSDKInitProvider: the package is initialised so that we can get the user data and use the Telegram API in our application. We check the environment and mock the data if we are in development mode. This is to imitate the Telegram environment to run the application in the browser.&lt;/p&gt;

&lt;p&gt;If we are in a production environment, it makes more sense to show an error or inform the user that the app needs to run inside Telegram. And ideally, add a link and QR code to the interface to go directly to the messenger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'

import { type PropsWithChildren } from 'react'

import { useClientOnce } from '@/src/hooks/useClientOnce'
import { useTelegramMock } from '@/src/hooks/useTelegramMock'

import { telegramSDKInit } from './init'

export function TelegramSDKInitProvider({ children }: PropsWithChildren) {
 if (process.env.NODE_ENV === 'dev') {
   useTelegramMock()
 }

 useClientOnce(() =&amp;gt; {
   telegramSDKInit(false)
 })

 return children
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the &lt;strong&gt;useTelegramMock&lt;/strong&gt; hook we use a check provided by the package itself – &lt;strong&gt;isTMA&lt;/strong&gt;. This allows us to determine if we are in the Telegram environment. If we are not, we mock the data, if we are, we exit the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { isTMA, mockTelegramEnv, parseInitData } from '@telegram-apps/sdk-react'

import { useClientOnce } from './useClientOnce'

export function useTelegramMock(): void {
 useClientOnce(() =&amp;gt; {
   let shouldMock: boolean
   const MOCK_KEY = '____mocked'

   if (isTMA('simple')) {
     shouldMock = !!sessionStorage.getItem(MOCK_KEY)
   } else {
     shouldMock = true
   }

   if (!shouldMock) {
     return
   }

   const initDataRaw = new URLSearchParams([
     [
       'user',
       JSON.stringify({
         id: 99281932,
         first_name: 'Arthur',
         last_name: 'Mocked',
         username: 'arthurmocked',
         language_code: 'en',
         is_premium: true,
         allows_write_to_pm: true,
         photoUrl:
           'https://t.me/i/userpic/320/haNXSpRmeucJyo-oXFbNrifxZ-Au0PjvhpJ2l6h4ozcTbTT8yvNKIZABSCLpjtIp.svg',
       }),
     ],
     ['hash', '89d6079ad6762351f38c6dbbc41bb53048019256a9443988af7a48bcad16ba31'],
     ['auth_date', '1716922846'],
     ['start_param', 'debug'],
     ['chat_type', 'sender'],
     ['chat_instance', '8428209589180549439'],
   ]).toString()

   mockTelegramEnv({
     themeParams: {
       accentTextColor: '#6ab2f2',
       bgColor: '#17212b',
       buttonColor: '#5288c1',
       buttonTextColor: '#ffffff',
       destructiveTextColor: '#ec3942',
       headerBgColor: '#17212b',
       hintColor: '#708499',
       linkColor: '#6ab3f3',
       secondaryBgColor: '#232e3c',
       sectionBgColor: '#17212b',
       sectionHeaderTextColor: '#6ab3f3',
       subtitleTextColor: '#708499',
       textColor: '#f5f5f5',
     },
     initData: parseInitData(initDataRaw),
     initDataRaw,
     version: '8',
     platform: 'tdesktop',
   })
   sessionStorage.setItem(MOCK_KEY, '1')

   console.info(
     '⚠️ As long as the current environment was not considered as the Telegram-based one, it was mocked. Take a note, that you should not do it in production and current behavior is only specific to the development process. Environment mocking is also applied only in development mode. So, after building the application, you will not see this behavior and related warning, leading to crashing the application outside Telegram.',
   )
 })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use our own data. For example, from your Telegram account.&lt;br&gt;
Now we can run our app both in Telegram and in any browser.&lt;/p&gt;

&lt;p&gt;Next, we run &lt;strong&gt;telegramSDKInit&lt;/strong&gt;, which initialises the SDK package and performs the initial configuration of the application. For example, configuring the full screen mode or the behaviour of closing the app with vertical swipes.&lt;/p&gt;

&lt;p&gt;This is also where we initialise the Eruda mobile console that I mentioned in the testing section. The initialisation happens only once – when the app is launched, which is controlled by the &lt;strong&gt;useClientOnce&lt;/strong&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
 $debug,
 backButton,
 expandViewport,
 init as initSDK,
 initData,
 miniApp,
 swipeBehavior,
 themeParams,
 viewport,
} from '@telegram-apps/sdk-react'

export function telegramSDKInit(debug: boolean): void {
 $debug.set(debug)

 initSDK()
 expandViewport()

 if (backButton.isSupported()) {
   backButton.mount()
 }

 miniApp.mount()
 themeParams.mount()
 swipeBehavior.mount()
 initData.restore()

 void viewport
   .mount()
   .then(() =&amp;gt; {
     viewport.bindCssVars()
     miniApp.bindCssVars()
     themeParams.bindCssVars()
     viewport.requestFullscreen()
     swipeBehavior.disableVertical()
   })
   .catch((e: unknown) =&amp;gt; {
     console.error('Something went wrong mounting the viewport', e)
   })

 debug &amp;amp;&amp;amp; import('eruda').then((lib) =&amp;gt; lib.default.init()).catch(console.error)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the &lt;strong&gt;AppInitProvider&lt;/strong&gt; logic is executed, where we show the download status instead of the content, as our app is not ready to use yet. Here we already have access to the Telegram API, so we get the data we need (e.g. user data). Next, we will either record the user ID in cookies or perform an authorisation request, passing the necessary data from Telegram.&lt;/p&gt;

&lt;p&gt;Once all the manipulations are done, we can display the rest of the application.&lt;/p&gt;

&lt;p&gt;An AppInitProvider could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use client'

import { initData, useSignal } from '@telegram-apps/sdk-react'
import { setCookie } from 'cookies-next'
import type { PropsWithChildren } from 'react'
import { useCallback, useEffect, useState } from 'react'

import { postAuthLogin } from '@/src/api/schema'
import TelegramMiniAppLoader from '@/src/components/ui/TelegramMiniAppLoader'
import Title from '@/src/components/ui/Title'
import { AUTH_TOKEN, TELEGRAM_USER_ID } from '@/src/constants'

const AppInitProvider = ({ children }: PropsWithChildren) =&amp;gt; {
 const [isAppReady, setIsAppReady] = useState(false)
 const [error, setError] = useState(null)

 const initDataState = useSignal(initData.state)
 const initDataStateRaw = useSignal(initData.raw)

 const userId = initDataState?.user?.id

 const logError = useCallback((message: string) =&amp;gt; {
   console.error(message)
   setError(message)
 }, [])

 const authenticateUser = useCallback(
   async (rawData: string) =&amp;gt; {
     try {
       const { data } = await postAuthLogin({ init_data: rawData })

       if (data) {
         setCookie(AUTH_TOKEN, data.token)
         setIsAppReady(true)
       } else {
         logError(`Auth token is missing. Response: ${JSON.stringify(data)}`)
       }
     } catch (err) {
       logError(
         `Authentication failed: ${err instanceof Error ? err.message : JSON.stringify(err, null, 2)}`,
       )
     }
   },
   [logError],
 )

 const initApp = useCallback(() =&amp;gt; {
   if (!userId) {
     logError(`Telegram user ID is absent. User ID: ${userId}`)
     return
   }

   setCookie(TELEGRAM_USER_ID, userId)

   if (!initDataStateRaw) {
     logError('Telegram raw data is undefined.')
     return
   }

   authenticateUser(initDataStateRaw)
 }, [userId, initDataStateRaw, authenticateUser, logError])

 useEffect(() =&amp;gt; {
   console.log('Initializing app with raw data:', initDataStateRaw)
   initApp()
 }, [initApp, initDataStateRaw])

 if (error) {
   return {error}
 }

 return isAppReady ? &amp;lt;&amp;gt;{children} : 
}

export default AppInitProvider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our application is now fully initialised and ready to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Specifics of Telegram mini app development
&lt;/h2&gt;

&lt;p&gt;Let's look at the key issues and challenges you need to understand to ensure a stable application and user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebView limitations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since Telegram mini apps are based on the WebView interface, not all of the features we use in browsers will work here.&lt;/p&gt;

&lt;p&gt;In our app we use iFrame. And if we want to open it in full screen, we can use the &lt;strong&gt;requestFullScreen&lt;/strong&gt; method. Unfortunately, this doesn't work for WebView. Also, some icons may display differently or not at all. Especially if gradients are used inside. Problems can also occur when using WebSocket, which might requires additional configuration. It is therefore important to spend extra time on development to fix any bugs.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fu3buyirb2jdcpqtvphfv.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fu3buyirb2jdcpqtvphfv.png" alt="Image description" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, I have often seen comments on forums that using WebView causes performance degradation. Especially on low-power devices and when there are a lot of complex animations. Some developers even include the ability to disable animations in the app so users don't experience performance issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency on Telegram API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Despite the popularity of Telegram, the platform also has its own bugs that can affect your app. Here's a case study example.&lt;br&gt;
Telegram automatically handles situations where a virtual keyboard is opened on mobile devices and automatically moves content so that they do not overlap. On the one hand, this is very convenient – developers don't have to write additional logic if, for example, the input field is at the bottom of the screen. On the other hand, at the time of writing, this feature still does not work correctly on iOS devices, which can lead to some limitations for users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitation in working with query parameters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you try to pass initial parameters to a mini app link, Telegram will simply cut them out. According to the Telegram mini app documentation, we can only pass one parameter called startapp. The process looks like this: &lt;a href="https://t.me/botusername/appname?startapp=someParamValue" rel="noopener noreferrer"&gt;https://t.me/botusername/appname?startapp=someParamValue&lt;/a&gt;&lt;br&gt;
But if you need to pass multiple parameters, you can use the following trick: we still pass one parameter in the reference, but it has many other parameters nested within it with a specific delimiter. For example, '_ _'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://t.me/botusername/appname?startapp=param1value__param2value__par
am3value
const [param1, param2, param3] = lp.startParam.split("__");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Client-side nature of app&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is also important to remember that mini apps run primarily on the client side. This limits the use of server-side rendering (SSR), because to use the Telegram API you need access to the window object, which is only available on the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peculiarities of the Telegram platform
&lt;/h2&gt;

&lt;p&gt;To create a Telegram mini app, you need to understand the specifics of the platform itself and the specifics of working with WebView.&lt;br&gt;
For beginners, I recommend to pay attention to the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Telegram WebApp API&lt;/strong&gt; – interact with buttons, events, get user data. Study the library documentation if you plan to use it to work with Telegram;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permission handling&lt;/strong&gt; – proper handling of initData and signature verification. Authorisation is taken to a new level here, eliminating the need to constantly create and store tokens on the client side;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform limitations&lt;/strong&gt; – specifics of rendering, navigation and integration with front-end frameworks (e.g. Next.js);&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interface customisation – working with dark and light themes, WebView customisation, and developing workarounds for platform limitations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;✍ This may seem complicated and time-consuming, but learning new things is an important part of being a programmer. In the future, Telegram will certainly continue to develop its API and expand support for device hardware capabilities.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The sooner you start working with this format, the sooner you'll learn to develop cross-platform solutions, get a deeper understanding of external API integration, and gain experience with scalable applications for an audience of billions.&lt;/p&gt;

&lt;p&gt;The dev.family team has been in touch 💜💚&lt;br&gt;
See you soon!&lt;/p&gt;

&lt;p&gt;P.S. As per tradition, here are the links to the artefacts:&lt;br&gt;
Telegram mini apps documentation: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://core.telegram.org/bots/webapps" rel="noopener noreferrer"&gt;https://core.telegram.org/bots/webapps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The documentation of the package for interacting with the Telegram API is telegram-apps/sdk-react: &lt;a href="https://docs.telegram-mini-apps.com/packages/telegram-apps-sdk-react/2-x" rel="noopener noreferrer"&gt;https://docs.telegram-mini-apps.com/packages/telegram-apps-sdk-react/2-x&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Templates from Telegram developers: &lt;a href="https://github.com/Telegram-Mini-Apps#templates" rel="noopener noreferrer"&gt;https://github.com/Telegram-Mini-Apps#templates&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telegram mini apps template for Next.js: &lt;a href="https://github.com/Telegram-Mini-Apps/nextjs-template" rel="noopener noreferrer"&gt;https://github.com/Telegram-Mini-Apps/nextjs-template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telegram mini apps template for React.js. &lt;a href="https://github.com/Telegram-Mini-Apps/reactjs-template" rel="noopener noreferrer"&gt;https://github.com/Telegram-Mini-Apps/reactjs-template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Eruda documentation: &lt;a href="https://github.com/liriliri/eruda" rel="noopener noreferrer"&gt;https://github.com/liriliri/eruda&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ngrok: &lt;a href="https://ngrok.com/docs/pricing-limits/free-plan-limits/" rel="noopener noreferrer"&gt;https://ngrok.com/docs/pricing-limits/free-plan-limits/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to add a card to Apple Wallet and Google Wallet 📱 in React Native?</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 07 Nov 2024 12:30:21 +0000</pubDate>
      <link>https://dev.to/dev_family/how-to-add-a-card-to-apple-wallet-and-google-wallet-in-react-native-4keb</link>
      <guid>https://dev.to/dev_family/how-to-add-a-card-to-apple-wallet-and-google-wallet-in-react-native-4keb</guid>
      <description>&lt;p&gt;Mobile developers can use Apple Wallet and Google Wallet integrations for different types of apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Boarding pass storage and hotel reservations;&lt;/li&gt;
&lt;li&gt;Card for short-term rental;&lt;/li&gt;
&lt;li&gt;Passes for buildings or events;&lt;/li&gt;
&lt;li&gt;Scan tickets for travel or subscriptions;&lt;/li&gt;
&lt;li&gt;Store loyalty cards and gift vouchers;&lt;/li&gt;
&lt;li&gt;Providing contactless payment, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we already wrote our own library for Apple Wallet in React Native because we couldn't find anything ready to use. As true open source enthusiasts, we have already shared &lt;a href="https://medium.com/@dev.family/how-to-add-a-card-to-apple-wallet-in-react-native-ae966c2e7567" rel="noopener noreferrer"&gt;this version&lt;/a&gt; with you. But now that Google Wallet is fully released, it's time to update it.&lt;/p&gt;

&lt;p&gt;Now, this library provides integration with both Apple Wallet on iOS and Google Wallet on Android. It allows you to add, remove, and check for existing passes on iOS, and add passes to Google Wallet on Android. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dev-family/react-native-wallet-manager" rel="noopener noreferrer"&gt;&lt;strong&gt;Readme&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To download the library go&lt;/strong&gt; &lt;a href="https://github.com/dev-family/react-native-wallet-manager" rel="noopener noreferrer"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You can find out more about disruptive with React Native you’ll find in &lt;a href="https://dev.family/blog/categories/mobile?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=blog-categories-mobile&amp;amp;utm_term=how-to-add-a-card-to-apple-wallet" rel="noopener noreferrer"&gt;our blog&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to build a Web App: Deploying Telegram mini-app</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 31 Oct 2024 14:45:33 +0000</pubDate>
      <link>https://dev.to/dev_family/how-to-build-a-web-app-deploying-telegram-mini-app-272e</link>
      <guid>https://dev.to/dev_family/how-to-build-a-web-app-deploying-telegram-mini-app-272e</guid>
      <description>&lt;p&gt;Hi there, it's the &lt;a href="https://dev.family/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=main&amp;amp;utm_term=how-to-build-a-web-app-part-ii-deploying-telegram-mini-app" rel="noopener noreferrer"&gt;dev.family team&lt;/a&gt; again! We're continuing our experiment with building an app in React Native that works as as a Telegram Web App. In our previous episodes, we discussed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The specifics of building a React Native web application using react-native-web and where we deviated from the documentation. You can find all the code and details of the process in &lt;a href="https://dev.family/blog/article/how-to-build-a-web-app-part-i-developing-on-react-native-web?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=how-to-build-a-web-app-part-i-developing-on-react-native-web&amp;amp;utm_term=how-to-build-a-web-app-part-ii-deploying-telegram-mini-app" rel="noopener noreferrer"&gt;the first part&lt;/a&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The reasons &lt;a href="https://dev.family/blog/article/product-launch-on-messenger-apps-telegram-web-app-opportunities-for-businesses?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=dev-family&amp;amp;utm_content=product-launch-on-messenger-apps-telegram-web-app-opportunities-for-businesses&amp;amp;utm_term=how-to-build-a-web-app-part-ii-deploying-telegram-mini-app" rel="noopener noreferrer"&gt;why companies choose to run web applications on messenger apps&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's focus on installing the web app itself within the Telegram bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web AppDeployment
&lt;/h2&gt;

&lt;p&gt;In the last part we finished the preparatory work. Now let's deploy our site.&lt;/p&gt;

&lt;p&gt;We will use Firebase to deploy the clicker. There are two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first (and easiest) is a simple command line deploy;&lt;/li&gt;
&lt;li&gt;The second (a bit more complicated) is a commit/merge/PR deploy via github actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the purposes of this article, let's look at the fastest option.&lt;/p&gt;

&lt;p&gt;Let's create a project in the Firebase Console. Follow &lt;a href="https://console.firebase.google.com/" rel="noopener noreferrer"&gt;the link&lt;/a&gt; and click on the 'Create Project' button.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fu7tu3tm2x4wquga6m1x0.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fu7tu3tm2x4wquga6m1x0.png" alt="Image description" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify the name of our project:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F65dsc35oun29c1ydi6o9.png" 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.amazonaws.com%2Fuploads%2Farticles%2F65dsc35oun29c1ydi6o9.png" alt="Image description" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, click ‘Continue’ several times, select Default Firebase Account (if you have a different one, you can select it), and click Create Project.&lt;/p&gt;

&lt;p&gt;The new project is successfully established:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fqahelbrogl9rx8qcnu5z.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fqahelbrogl9rx8qcnu5z.png" alt="Image description" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now go to the project and click the 'Add Web Application' button:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fiu0dhr8k7wh22qmh0u49.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fiu0dhr8k7wh22qmh0u49.png" alt="Image description" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, enter the name of the project:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fj1oiwmnplid5saia7tm7.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fj1oiwmnplid5saia7tm7.png" alt="Image description" width="742" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can leave the 'Set up Firebase hosting too' checkbox unchecked. Click on the 'Register application' button and you will see two options with instructions on how to install the Firebase tools in our project.&lt;/p&gt;

&lt;p&gt;We won't use the option via npm, but via the script tag, as we don't need it for the mobile application. You can choose any convenient option.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fuqo9lyju1n9urjealwbw.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fuqo9lyju1n9urjealwbw.png" alt="Image description" width="800" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This completes our work with Firebase Console, let's return to the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: It is not recommended to put all these keys directly in the html file. It is better to create an .env file and put them there.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.env&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;VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=
VITE_FIREBASE_STORAGE_BUCKET=
VITE_FIREBASE_MESSAGING_SENDER_ID=
VITE_FIREBASE_APP_ID=
VITE_FIREBASE_MEASUREMENT_ID=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that all of the keys we use start with the word ‘Vite’. We do this because we are using Vite as an assembler. And when accessing environment variables via import.meta.env, it may not recognise them without this.&lt;/p&gt;

&lt;p&gt;Next, let's edit our index.html a bit, taking into account what we've written above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.html&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;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
...
&amp;lt;script type="module"&amp;gt;
 import { initializeApp } from "https://www.gstatic.com/firebasejs/10.13.0/firebase-app.js";
 import { getAnalytics } from "https://www.gstatic.com/firebasejs/10.13.0/firebase-analytics.js";
  const firebaseConfig = {
   apiKey:import.meta.env.VITE_FIREBASE_API_KEY,
   authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
   projectId:  import.meta.env.VITE_FIREBASE_PROJECT_ID,
   storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
   messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
   appId: import.meta.env.VITE_FIREBASE_APP_ID,
   measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID,
 };


 const app = initializeApp(firebaseConfig);
 const analytics = getAnalytics(app);
&amp;lt;/script&amp;gt;
&amp;lt;script src="./index.web.js" type="module"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a terminal, go to the root of the project and type the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we go to the browser window and authorise through the Firebase console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select the highlighted item and press Space, then Enter.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F6tmoeasebvozcag85uff.png" 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.amazonaws.com%2Fuploads%2Farticles%2F6tmoeasebvozcag85uff.png" alt="Image description" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to resolve a number of configuration issues. Add the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Please select an option – here we select &lt;strong&gt;Use an existing project&lt;/strong&gt;. And from the list below – a recently created project;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What do you want to use as your public directory? – select &lt;strong&gt;dist&lt;/strong&gt; (this is where our unit will be located);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure as a single-page app (rewrite all urls to /index.html)? – &lt;strong&gt;y&lt;/strong&gt;;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up automatic builds and deploys with GitHub? (y/N) – &lt;strong&gt;N&lt;/strong&gt; (we don't need it at this stage);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;File dist/index.html already exists. Overwrite? (y/N) – &lt;strong&gt;N&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go to firebase.json and modify it a bit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;firebase.json&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;"hosting": {
   "public": "dist",
   "ignore": [
     "firebase.json",
     "**/.*",
     "**/node_modules/**",
     //past here
     "**/android/**",
     "**/ios/**"
   ],
   "rewrites": [
     {
       "source": "**",
       "destination": "/index.html"
     }
   ]
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the Android and iOS directories to ignore during deployment. Since we have a web application, we don't need to send all the files to a hosting service. Also, they're quite heavy and you won't be able to download them without some sort of subscription.&lt;/p&gt;

&lt;p&gt;So, we're nearing the finish line. There's just one more command to write.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;firebase deploy&lt;/strong&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F12ncb8hbi74q9z94l4q2.png" 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.amazonaws.com%2Fuploads%2Farticles%2F12ncb8hbi74q9z94l4q2.png" alt="Image description" width="796" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now click on the link below. Our application is already hosted!&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fjshvutt5ondi9ycg99hk.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fjshvutt5ondi9ycg99hk.png" alt="Image description" width="800" height="865"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All you have to do is deploy the app on Telegram.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing a web app in a Telegram bot
&lt;/h2&gt;

&lt;p&gt;Let's take a look at what's currently available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A working app on iOS;&lt;/li&gt;
&lt;li&gt;A working app on Android;&lt;/li&gt;
&lt;li&gt;A working web app, already hosted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With one last tap, you can add an app to the list in a messenger app. Open a bot called BotFather in Telegram and start a dialogue.&lt;/p&gt;

&lt;p&gt;Choose the option /newbot:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F0cq0qoub087bfsjvxy13.png" 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.amazonaws.com%2Fuploads%2Farticles%2F0cq0qoub087bfsjvxy13.png" alt="Image description" width="800" height="713"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give our bot a name. This will create an API key for interacting with our bot via HTTP.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fvx8chqrdoj35yasix8ux.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fvx8chqrdoj35yasix8ux.png" alt="Image description" width="800" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, write the command /mybots and choose the currently created bot. Go to &lt;strong&gt;bot settings&lt;/strong&gt;.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F3qf234z8v2bpp6jrjwdc.png" 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.amazonaws.com%2Fuploads%2Farticles%2F3qf234z8v2bpp6jrjwdc.png" alt="Image description" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose the point &lt;strong&gt;Configure Mini App&lt;/strong&gt;.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F77wsrpyaiw6n2dq7t2p8.png" 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.amazonaws.com%2Fuploads%2Farticles%2F77wsrpyaiw6n2dq7t2p8.png" alt="Image description" width="788" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may see a message saying that the Mini App is disabled for our Telegram bot. That's fine. Just click on the &lt;strong&gt;Enable Mini App&lt;/strong&gt; button.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fu1u0xuqemtl11iwo5ffc.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fu1u0xuqemtl11iwo5ffc.png" alt="Image description" width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we just pass the URL where our web application is hosted.&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fuhbmhemvdvnl7jln9etn.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fuhbmhemvdvnl7jln9etn.png" alt="Image description" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's configure the menu button. To do this, go back to the bot settings and select Configure Menu Button. Again, you may be told that the button is currently disabled and offered the option to enable it. Accept and give it a name.&lt;/p&gt;

&lt;p&gt;The time has come: let's see how our guy works. Let's go to the bot – &lt;a href="https://t.me/ReactNativeWebClickerBot" rel="noopener noreferrer"&gt;@ReactNativeWebClickerBot&lt;/a&gt; (you can rate it too, we'd appreciate it 😌). We open it up and make sure it works!&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Ffgm0ini2ix2qbx03cgz4.png" 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.amazonaws.com%2Fuploads%2Farticles%2Ffgm0ini2ix2qbx03cgz4.png" alt="Image description" width="800" height="688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All theme settings are synchronised, as is the username. If you enter the bot from the mobile app and click on a coin, you can feel how well the haptic response works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this experiment, we break down in detail how you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a web app based on a mobile app written in React Native using react-native-web;&lt;/li&gt;
&lt;li&gt;Deploy it via Firebase;&lt;/li&gt;
&lt;li&gt;Use it in a Telegram mini-app;&lt;/li&gt;
&lt;li&gt;Interoperate with the Telegram client in our shared codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The technologies described can be used not only for Telegram, but also for other platforms. So you can create cross-platform solutions that work on the same code.&lt;/p&gt;

&lt;p&gt;Why it's good:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app will work across channels and be featured in multiple stores, allowing you to reach more users;&lt;/li&gt;
&lt;li&gt;The speed of product development will increase significantly – the average time to release will be reduced by 20%, meaning a faster time to market;&lt;/li&gt;
&lt;li&gt;Most of the code base can be reused, making updates and bug fixes easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main thing is to remember the specifics of each platform and take them into account when developing.&lt;/p&gt;

&lt;p&gt;We've deliberately left some parts of the code unwritten so that you can fill them in yourself. If you like, add Telegram user validation, check if the user is present in the mobile app and set up a Firebase deployment via GitHub Actions. In short, experiment to get the best results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As usual, we leave links to the useful resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://necolas.github.io/react-native-web/docs/" rel="noopener noreferrer"&gt;React Native Web&lt;/a&gt; documentation;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://core.telegram.org/bots/webapps#hapticfeedback" rel="noopener noreferrer"&gt;Telegram mini-app&lt;/a&gt; documentation;&lt;/li&gt;
&lt;li&gt;Link to &lt;a href="https://console.firebase.google.com/?pli=1" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;All code in &lt;a href="https://github.com/dev-family/react-native-web-example" rel="noopener noreferrer"&gt;Github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://t.me/ReactNativeWebClickerBot" rel="noopener noreferrer"&gt;@ReactNativeWebClickerBot&lt;/a&gt; itself.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>What if we told you that you don't need an app or a website to sell online? Go to Messenger and launch your Telegram WebApp.</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 24 Oct 2024 16:26:56 +0000</pubDate>
      <link>https://dev.to/dev_family/what-if-we-told-you-that-you-dont-need-an-app-or-a-website-to-sell-online-go-to-messenger-and-launch-your-telegram-webapp-4m4f</link>
      <guid>https://dev.to/dev_family/what-if-we-told-you-that-you-dont-need-an-app-or-a-website-to-sell-online-go-to-messenger-and-launch-your-telegram-webapp-4m4f</guid>
      <description>&lt;p&gt;Companies are moving to web apps in messengers. And here are the reasons why you should join them: &lt;br&gt;
🟣 Increase market share by entering the channel with a constantly active audience; &lt;br&gt;
🟢 Boost sales with an easy ordering process in just a few clicks; &lt;br&gt;
⚪️ Keep users engaged by communicating with them in one channel. &lt;/p&gt;

&lt;p&gt;It only takes a few seconds for customers to order food from the restaurant, pay for services and book the time to visit your establishment in messengers like WhatsApp or WeChat. Find more ideas for web applications in &lt;a href="https://dev.family/blog/article/how-to-build-a-web-app-part-i-developing-on-react-native-web" rel="noopener noreferrer"&gt;our article&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using BLE technology when working with beacon in React Native</title>
      <dc:creator>Max Bantsevich</dc:creator>
      <pubDate>Thu, 10 Oct 2024 13:41:59 +0000</pubDate>
      <link>https://dev.to/mrbantsevich/using-ble-technology-when-working-with-beacon-in-react-native-2egk</link>
      <guid>https://dev.to/mrbantsevich/using-ble-technology-when-working-with-beacon-in-react-native-2egk</guid>
      <description>&lt;p&gt;If you decide that you want to use this solution in your project, you will need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Beacon:&lt;/strong&gt; Select a suitable BLE beacon that meets your range requirements. You can find a large number of beacons on Aliexpress, we used HOLY-IOT.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BLE-enabled smartphone or tablet:&lt;/strong&gt; A device to test and use your application that is compatible with Bluetooth Low Energy technology. For our solution, iPhone with iOS 9.0 and higher, Android with 7 and higher are suitable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Development tools&lt;/strong&gt; for your application, such as VSCode, as well as React Native and the react-native-ble-plx library.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you can start implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data collection&lt;/strong&gt;&lt;br&gt;
To collect RSSI data we will use the &lt;code&gt;react-native-ble-plx&lt;/code&gt; library. We use the startDeviceScan method. This method allows you to scan BLE devices within range and obtain information about them, including RSSI. Here's an example of how you can implement RSSI data collection for specific devices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { BleManager } from "react-native-ble-plx";

const NAME = "HOLY-IOT";

const bleManager = new BleManager();

// Function to start scanning BLE devices
function startScanning() {
  // The first parameter is the UUIDs of services (null if you want to scan all devices)
  // Second parameter - scanning options
  // The third parameter is a callback called when a device is detected
  bleManager.startDeviceScan(null, null, (error, scannedDevice) =&amp;gt; {
    if (error) {
      console.warn(error);
      return;
    }

    if (scannedDevice &amp;amp;&amp;amp; scannedDevice.name === NAME) {
      console.log(scannedDevice.name, scannedDevice.rssi); // to find the device we need
      // hereinafter we will process RSSI
    }
  });
}
// Stop scanning if necessary
function stopScanning() {
  bleManager.stopDeviceScan();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also be sure to request location permissions if you're on Android, as this is required to scan BLE devices starting with Android 6.0 (API level 23).&lt;/p&gt;

&lt;p&gt;In this example, all available BLE devices are scanned every time a device with a given UUID is detected. The console will display the device name and its RSSI.&lt;/p&gt;

&lt;p&gt;Please note that Bluetooth on iOS and Android may require permissions and privacy settings, including a request for location access and an explanation of why your app needs this permission in the &lt;code&gt;Info.plist&lt;/code&gt; (iOS) and &lt;code&gt;AndroidManifest.xml&lt;/code&gt; files (Android) respectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distance estimation based on RSSI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To calculate the distance between the BLE device and the beacon based on the RSSI value, we use this formula:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fwaje7f19ymdid0hsk9so.png" 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.amazonaws.com%2Fuploads%2Farticles%2Fwaje7f19ymdid0hsk9so.png" alt="Image description" width="701" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;d&lt;/strong&gt; — distance to the device (beacon),&lt;br&gt;
&lt;strong&gt;TX Power&lt;/strong&gt; — signal power measured at a standard distance (usually 1 meter) from the beacon,&lt;br&gt;
&lt;strong&gt;RSSI&lt;/strong&gt; — signal strength,&lt;br&gt;
&lt;strong&gt;n&lt;/strong&gt; — is the signal attenuation factor (environmental factor), reflecting the loss of the signal in the environment; typical values range from 2 to 4.&lt;/p&gt;

&lt;p&gt;This formula allows you to estimate the distance between two devices using the logarithmic relationship between the change in signal strength and distance.&lt;/p&gt;

&lt;p&gt;The value of the signal attenuation coefficient n depends on the specific environmental conditions in which the signal is transmitted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open space without obstacles:&lt;/strong&gt; An n value of about 2. This condition assumes minimal signal attenuation when there are no significant obstacles between devices and the signal can travel in a straight line.&lt;/p&gt;

&lt;p&gt;**Indoors with obstacles: **The n value can vary from 2.5 to 3.5 or even higher. Indoors, the signal can be reflected from walls, ceilings and other objects, which increases attenuation. Higher values of n are used to account for this additional attenuation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenging environments with many obstacles:&lt;/strong&gt; In environments with a high density of obstacles, such as warehouses, manufacturing facilities, or urban environments with many reflective surfaces, the n value can be set in the range of 4 to 5. These environments require a higher attenuation factor to compensate for significant signal losses.&lt;/p&gt;

&lt;p&gt;It is important to understand that determining the most appropriate value for n often requires an empirical approach. This means running tests in the target environment to measure the actual signal distribution and tailoring the attenuation factor to achieve the best accuracy in distance estimation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What will this look like in practice?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have already obtained RSSI values from scanning devices as shown in the previous example. Now let's add a function to calculate the distance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateDistance(rssi, measure = -69, multiplier = 2) {
  return Math.pow(10, (measure - rssi) / (10 * multiplier));
}

bleManager.startDeviceScan(null, null, (error, scannedDevice) =&amp;gt; {
  if (error) {
    console.warn(error);
    return;
  }
  if (scannedDevice &amp;amp;&amp;amp; scannedDevice.name === NAME) {
    const distance = calculateDistance(scannedDevice.rssi);
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Increasing measurement accuracy&lt;/p&gt;

&lt;p&gt;Factors such as physical obstructions, interference from other signal sources, and hardware differences can distort RSSI. Various filtering techniques are used to improve measurement accuracy.&lt;/p&gt;

&lt;p&gt;We will use a simple moving average method, which is used to smooth out time series data and reduce random fluctuations.&lt;/p&gt;

&lt;p&gt;To implement this technique, we will store the last few RSSI measurements for the device and calculate the average of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const rssiValues = {}; // object for storing arrays of RSSI values

function addRssiValueAndGetAverage(deviceId, newValue, maxSize = 3) {
  if (!rssiValues[deviceId]) {
    rssiValues[deviceId] = []; // Initialize the array if this is the first value
  }
  const values = rssiValues[deviceId];
  values.push(newValue); // Add a new value

  // Remove the oldest value if the maximum array size is exceeded
  if (values.length &amp;gt; maxSize) {
    values.shift();
  }

  // Calculate the average value
  const averageRssi = values.reduce((acc, value) =&amp;gt; acc + value, 0) / values.length;
  return averageRssi;
}

bleManager.startDeviceScan(null, null, (error, scannedDevice) =&amp;gt; {
  if (error) {
    console.warn(error);
    return;
  }
  if (scannedDevice &amp;amp;&amp;amp; scannedDevice.name === NAME) {
    const averageRssi = addRssiValueAndGetAverage(scannedDevice.id, scannedDevice.rssi);
    console.log(`Average RSSI value for device ${scannedDevice.name}: ${averageRssi}`);
  }
}); // Here you can use the average RSSI value to estimate the distance } });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why did we do all this?
&lt;/h2&gt;

&lt;p&gt;It is worth noting that this method allows you to achieve an approximate estimate of the distance to the beacons. Despite the introduction of algorithms to improve measurement accuracy, it must be recognized that the results obtained remain approximate. Also, a feature of this implementation is that it works only when the application is in the active state (foreground state), which imposes certain restrictions on the scope of its application.&lt;/p&gt;

&lt;p&gt;However, even in its current form, this system can find wide application in various scenarios. Examples include localization and navigation indoors, such as shopping malls, museums, warehouses, where it is important to provide users or employees with information about nearby objects and traffic routes.&lt;/p&gt;

&lt;p&gt;In the future, we plan to develop an improved version that will be able to function not only when the application is active, but also in the background state. This will expand the scope of the technology, making it suitable for real-time monitoring and tracking tasks without the need for constant user interaction with the application.&lt;/p&gt;

&lt;p&gt;The development and improvement of the tracking system using BLE and RSSI opens up new prospects for creating effective and convenient solutions in a variety of areas, from retail to food tech, providing a new level of user experience.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
