<?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: Akash Pattnaik</title>
    <description>The latest articles on DEV Community by Akash Pattnaik (@akashpattnaik).</description>
    <link>https://dev.to/akashpattnaik</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%2F781387%2F71cf0c9e-e250-4deb-937a-4aafc6f31b53.png</url>
      <title>DEV Community: Akash Pattnaik</title>
      <link>https://dev.to/akashpattnaik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akashpattnaik"/>
    <language>en</language>
    <item>
      <title>From 5 Seconds to 50ms: How I Stopped Nuking My Database Every Time I Deleted an Order</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Sat, 13 Jun 2026 08:54:04 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/from-5-seconds-to-50ms-how-i-stopped-nuking-my-database-every-time-i-deleted-an-order-30l0</link>
      <guid>https://dev.to/akashpattnaik/from-5-seconds-to-50ms-how-i-stopped-nuking-my-database-every-time-i-deleted-an-order-30l0</guid>
      <description>&lt;h2&gt;
  
  
  My Dessert Shop Dashboard Was Choking on Its Own Data — Here's the Architecture That Fixed It
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Next.js App Router · Supabase · PostgreSQL performance · Incremental rollup tables&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scene: A Dashboard Loading Like It's On Dial-Up
&lt;/h2&gt;

&lt;p&gt;Picture this: your admin dashboard is open. You want to check last week's sales. You click the date range.&lt;/p&gt;

&lt;p&gt;Nothing.&lt;/p&gt;

&lt;p&gt;Then a spinner. A long, existential spinner.&lt;/p&gt;

&lt;p&gt;Five seconds later — &lt;em&gt;if you're lucky&lt;/em&gt; — the numbers appear. Meanwhile, your database connection pool is gasping for air, your serverless function has basically taken a lunch break, and somewhere a Postgres row lock is just vibing, holding everything hostage.&lt;/p&gt;

&lt;p&gt;That was the state of the analytics dashboard I built for a retail franchise kiosk system on &lt;strong&gt;Next.js App Router + Supabase&lt;/strong&gt;. High-volume orders, complex JSON-stored item data, coupons, loyalty coins, packaging options — and every time the admin so much as &lt;em&gt;glanced&lt;/em&gt; at the dashboard, the server started sweating.&lt;/p&gt;

&lt;p&gt;Let me walk you through the disaster, the misguided fix I shipped anyway, and the architecture that actually solved it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Root Cause: Your Raw Table Is Not a Reporting Table
&lt;/h2&gt;

&lt;p&gt;The first version of the analytics page was beautifully naive. Admin requests "last 30 days of revenue"? Sure — let's just:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fetch every order&lt;/strong&gt; in that date range from the &lt;code&gt;orders&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parse the JSONB column&lt;/strong&gt; &lt;code&gt;selected_items&lt;/code&gt; (nested arrays of items, quantities, toppings) for each row, in-memory, in a Next.js serverless function&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribute order-level discounts proportionally&lt;/strong&gt; across individual line items in real time (flat Rs. 50 off? Cool, now figure out what fraction of that hits each item after excluding toppings and packaging fees)&lt;/li&gt;
&lt;li&gt;Aggregate everything into totals&lt;/li&gt;
&lt;li&gt;Pray&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The complexity here is genuinely O(N_orders). Thousands of orders → thousands of JSON parses → proportional discount math → exhausted connection pool → timeout → 😵&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE: Every Dashboard Request

Admin requests 30-day report
         │
         ▼
┌─────────────────────────────────┐
│  Next.js Serverless Function    │
│                                 │
│  SELECT * FROM orders           │
│  WHERE created_at &amp;gt; 30 days ago │  ← Full table scan
│                                 │
│  for each order:                │
│    parse JSONB selected_items   │  ← Memory intensive
│    distribute discount          │  ← CPU intensive
│    aggregate metrics            │
└──────────────┬──────────────────┘
               │  2.5s – 5s
               ▼
         Dashboard UI
         (eventually)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under peak traffic, it was worse. Multiple admins → multiple concurrent full-table aggregation jobs → DB connection pool exhausted → cascade of timeouts. The dashboard became a slot machine where the prize was "maybe you get data."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Nuclear Rebuild: My First (Very Bad) Fix
&lt;/h2&gt;

&lt;p&gt;Here's the part where I should have thought harder but instead shipped a &lt;code&gt;/api/admin/rebuild-stats&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;The logic: whenever something changes — an order deleted, a coupon adjusted — just &lt;strong&gt;rebuild all the aggregate stats from scratch&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The process was essentially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch &lt;em&gt;all&lt;/em&gt; historical paid orders in batches of 1,000&lt;/li&gt;
&lt;li&gt;Recalculate daily stats, hourly stats, product sales, user lifetime metrics — all in-memory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TRUNCATE&lt;/code&gt; the aggregate tables&lt;/li&gt;
&lt;li&gt;Re-insert everything from scratch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This worked. For about two weeks, until the order count hit tens of thousands. Then &lt;strong&gt;a single admin deleting one duplicate order&lt;/strong&gt; would trigger a multi-minute full rebuild, lock the DB, and make the dashboard completely unresponsive.&lt;/p&gt;

&lt;p&gt;I had essentially built a manual &lt;code&gt;VACUUM&lt;/code&gt; that punished me for routine housekeeping.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The Nuclear Rebuild (❌ Don't Do This)

Admin deletes 1 order
         │
         ▼
POST /api/admin/rebuild-stats
         │
         ▼
┌─────────────────────────────────┐
│  Fetch ALL orders in batches    │  ← O(N) reads
│  of 1,000                       │
│                                 │
│  Recalculate EVERYTHING:        │
│  - daily_stats                  │
│  - hourly_orders                │  ← Minutes of work
│  - product_sales                │
│  - user_stats                   │
│                                 │
│  TRUNCATE aggregate tables      │  ← Row locks everywhere
│  Re-insert entire dataset       │
└─────────────────────────────────┘
         │
         ▼
  Dashboard unusable during rebuild
  (scales linearly with order count 🪦)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix was worse than the disease. Time to actually solve this properly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Epiphany: Pre-Aggregate at Write Time, Not Read Time
&lt;/h2&gt;

&lt;p&gt;The insight that changed everything is deceptively simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The best time to compute aggregates is when the data is created — not when someone asks for it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of running expensive aggregations on every dashboard read, maintain a set of &lt;strong&gt;flat rollup tables&lt;/strong&gt; that mirror your aggregated state. Every write (order created, order deleted, order modified) updates these rollup tables &lt;strong&gt;incrementally&lt;/strong&gt; and &lt;strong&gt;atomically&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Dashboard reads become trivial index scans on tiny tables. Writes stay O(1) regardless of historical data size.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Rollup Schema
&lt;/h3&gt;

&lt;p&gt;Four lightweight tables cover the entire analytics surface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Daily-level counters for date-range reports&lt;/span&gt;
&lt;span class="n"&gt;daily_stats&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="n"&gt;total_orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_revenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;packaging_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;packed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discount_total&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- Hourly breakdown for kitchen load planning&lt;/span&gt;
&lt;span class="n"&gt;hourly_orders&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="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;revenue&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- Per-product sales performance&lt;/span&gt;
&lt;span class="n"&gt;product_sales&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="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantity_sold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;revenue&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- Customer lifetime value tracking&lt;/span&gt;
&lt;span class="n"&gt;user_stats&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_spent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_visit&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No joins. No JSON parsing. No discount math. Just numbers, already computed, waiting in indexed rows.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture Shift
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;AFTER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dashboard&lt;/span&gt; &lt;span class="k"&gt;Reads&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;New&lt;/span&gt; &lt;span class="n"&gt;Architecture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;Admin&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;day&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;
         &lt;span class="err"&gt;│&lt;/span&gt;
         &lt;span class="err"&gt;▼&lt;/span&gt;
&lt;span class="err"&gt;┌─────────────────────────────────┐&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_revenue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;     &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;daily_stats&lt;/span&gt;               &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;     &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="k"&gt;Index&lt;/span&gt; &lt;span class="n"&gt;scan&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;N_days&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;                                 &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;             &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;         &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quantity_sold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;product_sales&lt;/span&gt;             &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;     &lt;span class="err"&gt;│&lt;/span&gt;
&lt;span class="err"&gt;└──────────────┬──────────────────┘&lt;/span&gt;
               &lt;span class="err"&gt;│&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;
               &lt;span class="err"&gt;▼&lt;/span&gt;
         &lt;span class="n"&gt;Dashboard&lt;/span&gt; &lt;span class="n"&gt;UI&lt;/span&gt; &lt;span class="err"&gt;✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                    BEFORE vs. AFTER                         │
├─────────────────────┬───────────────────────────────────────┤
│ Metric              │ Before          │ After               │
├─────────────────────┼─────────────────┼─────────────────────┤
│ Dashboard load time │ 2.5s – 5s       │ &amp;lt; 100ms             │
│ Query complexity    │ O(N_orders)     │ O(N_days)           │
│ Order delete cost   │ O(N) full scan  │ O(1) decrement      │
│ DB connection load  │ Pool exhaustion │ Minimal             │
│ Serverless timeouts │ Frequent        │ Eliminated          │
└─────────────────────┴─────────────────┴─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;50× faster dashboard reads. Zero rebuild jobs. Database stability restored.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Implementation: Incremental Reversals on Delete
&lt;/h2&gt;

&lt;p&gt;The magic is in how writes interact with the rollups. Let's look at the delete path — the one that previously triggered the nuclear rebuild.&lt;/p&gt;

&lt;p&gt;When an admin deletes an order, the endpoint (&lt;code&gt;app/api/admin/orders/delete/route.ts&lt;/code&gt;) now does something surgical instead of catastrophic:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Load the order's metadata &lt;em&gt;before&lt;/em&gt; deleting it to calculate its exact net contributions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Atomically decrement every affected rollup row.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Delete the raw order.&lt;/p&gt;

&lt;p&gt;Here's the actual code for reverting daily stats and product sales:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Fetch the daily rollup row for this order's date&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;existingDaily&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;daily_stats&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="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&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="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dateStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingDaily&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingDaily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total_orders&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&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;updatedRevenue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingDaily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total_revenue&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;netRevenue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedCount&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;updatedRevenue&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Clean up days that now have no data (keeps the table lean)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;daily_stats&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dateStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;daily_stats&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;total_orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updatedCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;total_revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updatedRevenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;packaging_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;existingDaily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;packaging_count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderToDel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opted_for_packaging&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;packed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingDaily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;packed&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;finalPackedCount&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;discount_total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingDaily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;discount_total&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;discountAmount&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dateStr&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;// 2. Revert product-level sales — one UPDATE per line item&lt;/span&gt;
&lt;span class="k"&gt;for &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;item&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;adjustedItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemRevenue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemTotal&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemDiscount&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&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;itemPackaging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;isFallbackPackaging&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;packaged&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;totalItemRevenueWithPackaging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;itemRevenue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;itemPackaging&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;existingSale&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product_sales&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="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&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="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dateStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingSale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedQty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingSale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity_sold&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quantity&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;updatedRevenue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;existingSale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revenue&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;totalItemRevenueWithPackaging&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedQty&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;updatedRevenue&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product_sales&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingSale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product_sales&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;quantity_sold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updatedQty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;revenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;updatedRevenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;existingSale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what's &lt;em&gt;not&lt;/em&gt; happening here: no fetching of thousands of orders, no TRUNCATE, no full recalculation. Just a handful of targeted &lt;code&gt;UPDATE&lt;/code&gt; statements touching exactly the rows that need to change.&lt;/p&gt;

&lt;p&gt;The same pattern applies to every other rollup: hourly stats get a decrement on the specific &lt;code&gt;(date, hour)&lt;/code&gt; row. Product sales get decremented per line item. User lifetime stats (&lt;code&gt;total_orders&lt;/code&gt;, &lt;code&gt;total_spent&lt;/code&gt;) get decremented, with a secondary query to reset &lt;code&gt;last_visit&lt;/code&gt; to their &lt;em&gt;next&lt;/em&gt; most recent order if this was their latest transaction. Even the loyalty coin ledger gets a compensatory &lt;code&gt;admin_adjust&lt;/code&gt; event inserted — no rebuild, just a corrective entry.&lt;/p&gt;

&lt;p&gt;Every operation is &lt;strong&gt;O(1) relative to historical data size.&lt;/strong&gt; It doesn't matter if you have 100 orders or 100,000 orders. Deleting one still touches the same number of rollup rows.&lt;/p&gt;




&lt;h2&gt;
  
  
  One Important Caveat: Keep the Raw Table for Granular Queries
&lt;/h2&gt;

&lt;p&gt;The rollup tables handle aggregated analytics efficiently, but they don't replace raw data entirely. &lt;strong&gt;Dynamic scanning on the &lt;code&gt;orders&lt;/code&gt; table is still permitted&lt;/strong&gt; — but only for narrow, highly-indexed single-day views where you need granular data: custom topping breakdowns, cash vs. UPI payment splits, per-transaction audit trails.&lt;/p&gt;

&lt;p&gt;The rule of thumb: &lt;strong&gt;aggregate reads go to rollups, granular inspection goes to the raw table with tight date constraints and proper indexes.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways for Dashboard Builders
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Your &lt;code&gt;orders&lt;/code&gt; table is a ledger, not a reporting table.&lt;/strong&gt;&lt;br&gt;
Don't run analytics queries on it directly. Maintain separate, pre-aggregated rollup tables optimized purely for reads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Materialized views are great — until you need incremental updates.&lt;/strong&gt;&lt;br&gt;
PostgreSQL's &lt;code&gt;MATERIALIZED VIEW&lt;/code&gt; requires a full refresh (&lt;code&gt;REFRESH MATERIALIZED VIEW&lt;/code&gt;) which has similar scalability problems to the nuclear rebuild under heavy write load. Custom rollup tables with incremental math give you more surgical control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Move complexity to write time, not read time.&lt;/strong&gt;&lt;br&gt;
Admins reading a dashboard vastly outnumber the frequency of order mutations. A slightly more complex write path (a few extra UPDATE statements on delete) pays for itself thousands of times over in fast reads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. &lt;code&gt;Math.max(0, ...)&lt;/code&gt; is your guard rail.&lt;/strong&gt;&lt;br&gt;
When doing decremental math on rollup counters, always clamp to zero. Out-of-order event processing or edge cases can produce negative counters, which will corrupt your data silently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Clean up empty rollup rows.&lt;/strong&gt;&lt;br&gt;
When a decrement produces a row where every counter is zero, delete it. This keeps your rollup tables lean and your index scans fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. The nuclear rebuild is a trap.&lt;/strong&gt;&lt;br&gt;
A full-rebuild endpoint feels like a safe escape hatch. It's actually a time bomb — completely benign at 500 rows, catastrophic at 50,000. Design the incremental path from day one.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack, For Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js 14 App Router (Server Actions + Route Handlers)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL via &lt;a href="https://supabase.com" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollup updates:&lt;/strong&gt; Supabase JS client with targeted &lt;code&gt;update()&lt;/code&gt; calls inside the relevant API route handlers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pattern:&lt;/strong&gt; Event-driven incremental rollups at write time&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Building something similar? Hit a different wall with PostgreSQL performance or Supabase at scale? Drop it in the comments — genuinely curious what patterns others are using for dashboard analytics on high-write systems.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>postgres</category>
      <category>supabase</category>
      <category>performance</category>
    </item>
    <item>
      <title>How I Built a Custom WhatsApp Cloud Partner App to Slash Marketing Costs</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Thu, 04 Jun 2026 07:49:23 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/how-i-built-a-custom-whatsapp-cloud-partner-app-to-slash-marketing-costs-4aa1</link>
      <guid>https://dev.to/akashpattnaik/how-i-built-a-custom-whatsapp-cloud-partner-app-to-slash-marketing-costs-4aa1</guid>
      <description>&lt;p&gt;Heya all 👋 I am the CTO at a dessert chain startup. We use WhatsApp marketing messages regularly to push content. In India, the cost per marketing message is 0.86 INR.&lt;br&gt;&lt;br&gt;
Till last month, we were using authkey.io. While reliable, the costs were starting to stack up as we scaled.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is authkey.io?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Authkey.io is a cloud-based CPaaS (Communication Platform as a Service) that provides APIs for businesses to automate and manage customer communications across multiple channels. It allows developers and companies to integrate messaging and identity verification into their apps, websites, or software, often using a "pay-as-you-go" pricing model.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Problem: Fixed Costs for Failed Deliveries
&lt;/h2&gt;

&lt;p&gt;Since we are a startup, cost matters to us! I started noticing something—WhatsApp doesn’t actually charge for all messages, only for messages that are delivered. However, third-party providers often charge a flat rate (like 0.95 INR) per message sent, regardless of status. On our scale of 2,000 users with a 50% failure rate, we were paying significantly more than necessary.&lt;br&gt;&lt;br&gt;
I realized I could save 60-70% of our marketing costs by building our own system directly on the WhatsApp Cloud API.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Authkey.io (Third-Party)&lt;/th&gt;
&lt;th&gt;Custom Cloud API (WhatsApp Cost)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost per Message&lt;/td&gt;
&lt;td&gt;0.95 INR (per message &lt;em&gt;sent&lt;/em&gt;)&lt;/td&gt;
&lt;td&gt;0.86 INR (per message &lt;em&gt;delivered&lt;/em&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Messages Sent&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Messages Delivered&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Cost Calculation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2,000 sent * 0.95 INR&lt;/td&gt;
&lt;td&gt;1,000 delivered * 0.86 INR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;1,900 INR&lt;/strong&gt; 😭&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;860 INR&lt;/strong&gt; 😃&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Architecture: Supabase, Next.js, and QStash
&lt;/h2&gt;

&lt;p&gt;I built a customized solution using Supabase and a Next.js app deployed on Vercel. Leveraging serverless architecture was great, but I quickly hit the 5-minute execution limit on Vercel when broadcasting to thousands of users.&lt;br&gt;&lt;br&gt;
To solve this, I used QStash’s message queues. Instead of one long request, I send a single request to QStash to split numbers into batches of 20. QStash then triggers 100 separate requests to my Vercel deployment, each taking about 50-60 seconds. This ensured no messages were missed due to timeouts.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is QStash?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;QStash is a serverless messaging and scheduling solution designed specifically for HTTP and serverless environments. Created by Upstash, it functions as a middleman (message broker) that takes HTTP requests and forwards them to your target API endpoints. Instead of calling an endpoint directly, you send the request to QStash, which then handles the heavy lifting of background tasks and API integrations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Optimizing Webhooks with Next.js 15+ &lt;code&gt;after()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Using a Meta webhook route, I receive status updates and incoming messages. Initially, I used a "Fire-And-Forget" architecture, but Vercel containers would sometimes close before processing finished. I transitioned to the new &lt;code&gt;after()&lt;/code&gt; API in Next.js 15, which allows work to continue after the response is sent. This magically slashed response times and improved reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect with me 🙍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mail&lt;/strong&gt; - &lt;code&gt;akashpattnaik.github@gamil.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Github&lt;/strong&gt; - &lt;a href="https://github.com/iAkashPattnaik" rel="noopener noreferrer"&gt;&lt;code&gt;iAkashPattnaik&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linkedin&lt;/strong&gt; - &lt;a href="https://www.linkedin.com/in/iakashpattnaik" rel="noopener noreferrer"&gt;&lt;code&gt;iAkashPattnaik&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>devops</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I got tired of Googling Docker commands, so I built an interactive cheatsheet</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Sun, 29 Mar 2026 15:17:29 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/i-got-tired-of-googling-docker-commands-so-i-built-an-interactive-cheatsheet-cgb</link>
      <guid>https://dev.to/akashpattnaik/i-got-tired-of-googling-docker-commands-so-i-built-an-interactive-cheatsheet-cgb</guid>
      <description>&lt;p&gt;Let me paint you a picture.&lt;/p&gt;

&lt;p&gt;It's late. You're writing a Dockerfile. You're &lt;em&gt;in the zone&lt;/em&gt; — the kind of focus where you're actually moving fast and everything is clicking. You type &lt;code&gt;HEALTHCHECK&lt;/code&gt; and your fingers pause.&lt;/p&gt;

&lt;p&gt;Is it &lt;code&gt;--interval&lt;/code&gt; or &lt;code&gt;--period&lt;/code&gt;? And what's the timeout default again? Is there a &lt;code&gt;--start-period&lt;/code&gt; flag or did you make that up?&lt;/p&gt;

&lt;p&gt;You open a new tab.&lt;/p&gt;

&lt;p&gt;You type "dockerfile healthcheck options" into Google.&lt;/p&gt;

&lt;p&gt;The first result is a Stack Overflow answer from 2017. The accepted answer is wrong. The second answer is right but references a flag that was renamed. You scroll past three more answers, open the official Docker docs, find the right section, get your answer, close five tabs, and try to remember where the hell you were.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three minutes gone. Flow state: destroyed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've been doing this for years. And I finally got annoyed enough to do something about it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/iAkashPattnaik/docker_hub" rel="noopener noreferrer"&gt;&lt;strong&gt;Docker Hub&lt;/strong&gt;&lt;/a&gt; is a free, open-source interactive cheatsheet for all 18 Dockerfile instructions. It lives in your browser, works offline, needs no login, and exists for one reason: so you never have to leave your editor to look up a Docker command again.&lt;/p&gt;

&lt;p&gt;Here's the layout — three panels, all visible at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┬──────────────────────────┬──────────────┐
│  Cheatsheet  │   Interactive Dockerfile  │  Deep Dive   │
│   + search   │    (hover any keyword)    │  Reference   │
└──────────────┴──────────────────────────┴──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Left panel — the cheatsheet
&lt;/h3&gt;

&lt;p&gt;All 18 instructions, grouped by category, with a real-time search bar and category filter pills. Hover any instruction card and you get an instant tooltip summary. Click it and the right panel updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Center panel — the interesting part
&lt;/h3&gt;

&lt;p&gt;This is what I actually wanted to exist. It's a realistic, multi-stage Node.js production Dockerfile rendered with &lt;strong&gt;token-level syntax highlighting&lt;/strong&gt;. Every instruction keyword — &lt;code&gt;FROM&lt;/code&gt;, &lt;code&gt;RUN&lt;/code&gt;, &lt;code&gt;COPY&lt;/code&gt;, &lt;code&gt;HEALTHCHECK&lt;/code&gt;, all of them — is a hoverable, clickable span.&lt;/p&gt;

&lt;p&gt;Hover &lt;code&gt;HEALTHCHECK&lt;/code&gt; and you get a popover right there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What it does&lt;/li&gt;
&lt;li&gt;All its options (&lt;code&gt;--interval&lt;/code&gt;, &lt;code&gt;--timeout&lt;/code&gt;, &lt;code&gt;--start-period&lt;/code&gt;, &lt;code&gt;--retries&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A live code example&lt;/li&gt;
&lt;li&gt;A link to the full reference&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No new tab. No context switch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Right panel — the full reference
&lt;/h3&gt;

&lt;p&gt;Click any keyword and the right panel shows you everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full description in readable prose&lt;/li&gt;
&lt;li&gt;All syntax variants&lt;/li&gt;
&lt;li&gt;A parameter table (type, required, default, and a &lt;strong&gt;BuildKit&lt;/strong&gt; badge for flags that need it)&lt;/li&gt;
&lt;li&gt;Multiple copy-ready code examples&lt;/li&gt;
&lt;li&gt;A layer info strip (creates a layer? persists in image? runtime override flag?)&lt;/li&gt;
&lt;li&gt;Related instructions you can jump to directly&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The tech (keeping it boring on purpose)
&lt;/h2&gt;

&lt;p&gt;This is a Next.js app with Tailwind CSS. That's basically it.&lt;/p&gt;

&lt;p&gt;There's no backend. No database. No external API calls. The entire knowledge base is a single well-structured &lt;code&gt;DATA.json&lt;/code&gt; file that gets imported at build time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/data.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../DATA.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getInstructionById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Instruction&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;searchInstructions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Instruction&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The center panel's syntax highlighting is a custom tokenizer — not Prism, not Shiki, not any heavy library. Just a function that splits each Dockerfile line into typed tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TokenType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyword&lt;/span&gt;&lt;span class="dl"&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;flag&lt;/span&gt;&lt;span class="dl"&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;string&lt;/span&gt;&lt;span class="dl"&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;comment&lt;/span&gt;&lt;span class="dl"&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;path&lt;/span&gt;&lt;span class="dl"&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;plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Token&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TokenType&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;instructionId&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;  &lt;span class="c1"&gt;// links keywords to DATA.json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tokenizeLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#&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="k"&gt;return&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="s1"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&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;line&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// first word = keyword if it matches a known instruction&lt;/span&gt;
  &lt;span class="c1"&gt;// --word = flag&lt;/span&gt;
  &lt;span class="c1"&gt;// /word or ./word = path&lt;/span&gt;
  &lt;span class="c1"&gt;// "word" = string&lt;/span&gt;
  &lt;span class="c1"&gt;// everything else = plain&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, fast, zero dependencies. Perfect for what we need.&lt;/p&gt;




&lt;h2&gt;
  
  
  The DATA.json schema — the real project
&lt;/h2&gt;

&lt;p&gt;I want to talk about this because it's where most of the work actually went.&lt;/p&gt;

&lt;p&gt;Each instruction in the JSON has a full semantic schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthcheck"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HEALTHCHECK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Defines a command to test container health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Full prose description..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deprecated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"syntax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"HEALTHCHECK [OPTIONS] CMD &amp;lt;command&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"HEALTHCHECK NONE"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"layer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"createsLayer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"persistsInImage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"overridableAtRuntime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"runtimeFlag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--health-cmd, --health-interval"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--interval"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"30s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"buildkitOnly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Time between health checks"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"examples"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthcheck-http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTTP endpoint check"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Check a health endpoint with curl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 &lt;/span&gt;&lt;span class="se"&gt;\\\n&lt;/span&gt;&lt;span class="s2"&gt;    CMD curl -f http://localhost:8080/health || exit 1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"relatedInstructions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ENTRYPOINT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EXPOSE"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"monitoring"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"check"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"liveness"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"runtime"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This schema is the reason the whole app is easy to contribute to. If you find a wrong example, a missing parameter, or a flag I forgot — you literally just edit the JSON and open a PR. You don't need to understand Next.js, React, or anything about the app. Just find the instruction, fix the data, ship it.&lt;/p&gt;

&lt;p&gt;That was an intentional design decision. I wanted the knowledge base to be community-maintained without requiring any contributors to touch application code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Things I learned building this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Token-level interactivity is a surprisingly underused pattern.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most syntax highlighters treat code as display-only. Making each token interactive — hoverable, clickable, state-driving — forced me to think about the rendering differently. Instead of a &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; tag, each line is an array of &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements with event handlers. Feels obvious in retrospect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A JSON schema is a product decision, not a technical one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I spent more time thinking about the shape of &lt;code&gt;DATA.json&lt;/code&gt; than I did writing component code. Getting the schema right — deciding what fields an &lt;code&gt;Example&lt;/code&gt; needs, how parameters should be typed, how to represent the CMD+ENTRYPOINT interaction matrix — was the hard part. The React components were almost mechanical after that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Tooltip positioning is an unsolved problem and I respect Floating UI more now.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My first tooltip implementation overflowed the viewport constantly. The second one flickered. The third one used &lt;code&gt;getBoundingClientRect()&lt;/code&gt; + a viewport-edge detection check and finally worked. I should've just used Floating UI from the start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. "No backend" is a feature, not a constraint.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every time I was tempted to add a server route ("for search", "for analytics", "for saving custom Dockerfiles"), I asked myself: can this be done in the client with the static data? The answer was always yes. Keeping it fully static means it deploys anywhere, works offline, and has zero ongoing infrastructure cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;A few things I want to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Dockerfile input&lt;/strong&gt; — paste your own Dockerfile and get it syntax-highlighted interactively with the same hover system&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose reference&lt;/strong&gt; — same format, for &lt;code&gt;docker-compose.yml&lt;/code&gt; keys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BuildKit toggle&lt;/strong&gt; — hide/show BuildKit-only parameters to reduce noise for people on older Docker versions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Print export&lt;/strong&gt; — a single-page PDF cheatsheet you can pin above your monitor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of those sound interesting to you, contributions are very welcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it / contribute
&lt;/h2&gt;

&lt;p&gt;🐳 &lt;strong&gt;Live site&lt;/strong&gt;: &lt;a href="https://docker-hub.vercel.app/" rel="noopener noreferrer"&gt;dockerhub&lt;/a&gt;&lt;br&gt;
📦 &lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/iakashpattnaik/docker_hub" rel="noopener noreferrer"&gt;github.com/iakashpattnaik/docker_hub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fastest way to contribute is to open &lt;code&gt;DATA.json&lt;/code&gt;, find an instruction you know well, and improve its description, examples, or tags. That alone is enormously valuable.&lt;/p&gt;

&lt;p&gt;If you find a bug, spot a wrong parameter, or think an instruction needs a better example — please open an issue or just send a PR directly. The bar is intentionally low.&lt;/p&gt;




&lt;p&gt;And if this saves you even one "dockerfile COPY --chown syntax" Google search — that's the whole point.&lt;/p&gt;

&lt;p&gt;Happy shipping. 🚀&lt;/p&gt;

</description>
      <category>docker</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>devtools</category>
    </item>
    <item>
      <title>For all vibe coders wanting to build apps - I strongly advise you read this once before you go on to chose a random framework!!</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Tue, 13 Jan 2026 13:18:08 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/for-all-vibe-coders-wanting-to-build-apps-i-strongly-advise-you-read-this-once-before-you-go-on-2o14</link>
      <guid>https://dev.to/akashpattnaik/for-all-vibe-coders-wanting-to-build-apps-i-strongly-advise-you-read-this-once-before-you-go-on-2o14</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/akashpattnaik/why-flutter-beats-react-native--516g" class="crayons-story__hidden-navigation-link"&gt;Why Flutter beats React Native ?&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/akashpattnaik" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F781387%2F71cf0c9e-e250-4deb-937a-4aafc6f31b53.png" alt="akashpattnaik profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/akashpattnaik" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Akash Pattnaik
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Akash Pattnaik
                
              
              &lt;div id="story-author-preview-content-2044683" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/akashpattnaik" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F781387%2F71cf0c9e-e250-4deb-937a-4aafc6f31b53.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Akash Pattnaik&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/akashpattnaik/why-flutter-beats-react-native--516g" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jan 13&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/akashpattnaik/why-flutter-beats-react-native--516g" id="article-link-2044683"&gt;
          Why Flutter beats React Native ?
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/flutter"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;flutter&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/beginners"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;beginners&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/reactnative"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;reactnative&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/akashpattnaik/why-flutter-beats-react-native--516g#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;




</description>
      <category>flutter</category>
      <category>beginners</category>
      <category>programming</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Why Flutter beats React Native ?</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Tue, 13 Jan 2026 13:17:07 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/why-flutter-beats-react-native--516g</link>
      <guid>https://dev.to/akashpattnaik/why-flutter-beats-react-native--516g</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;🚀 Performance
&lt;/li&gt;
&lt;li&gt;🎨 Consistent UI Across Platforms
&lt;/li&gt;
&lt;li&gt;⚡ Hot Reload
&lt;/li&gt;
&lt;li&gt;🛠️ Rich Widget Library
&lt;/li&gt;
&lt;li&gt;📱 Native Feel Without the Hassle
&lt;/li&gt;
&lt;/ol&gt;




&lt;blockquote&gt;
&lt;p&gt;When it comes to choosing a framework for cross-platform mobile development, both &lt;strong&gt;Flutter&lt;/strong&gt; and &lt;strong&gt;React Native&lt;/strong&gt; are strong contestants. However, Flutter has some distinct advantages that make it a compelling choice over React Native.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Performance 🚀
&lt;/h2&gt;

&lt;p&gt;Flutter delivers superior performance because it compiles directly to &lt;strong&gt;native machine code&lt;/strong&gt;. This eliminates the need for a JavaScript bridge, which React Native relies on. As a result, Flutter apps feel snappier and more responsive, particularly when handling complex UI and animations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistent UI Across Platforms 🎨
&lt;/h2&gt;

&lt;p&gt;Flutter uses a single &lt;strong&gt;codebase&lt;/strong&gt; to create a consistent user experience on both Android and iOS. Since it draws its own widgets, the app looks the same across different platforms. React Native, on the other hand, uses native components, which can lead to slight differences in the UI across devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hot Reload ⚡
&lt;/h2&gt;

&lt;p&gt;Although both frameworks offer &lt;strong&gt;Hot Reload&lt;/strong&gt;, Flutter’s implementation is faster and more reliable. Changes made to the app’s code can be seen almost instantly without needing a full app restart, speeding up development significantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rich Widget Library 🛠️
&lt;/h2&gt;

&lt;p&gt;Flutter provides an extensive collection of &lt;strong&gt;customizable widgets&lt;/strong&gt;, offering more out-of-the-box functionality compared to React Native. With Flutter, developers can easily create visually appealing apps without depending heavily on third-party libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native Feel Without the Hassle 📱
&lt;/h2&gt;

&lt;p&gt;Flutter's widgets replicate native UI elements closely, giving apps a &lt;strong&gt;native-like feel&lt;/strong&gt; while allowing developers to customize the design easily. React Native sometimes requires additional work to bridge the gap between custom designs and native components.&lt;/p&gt;

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

&lt;p&gt;In summary, &lt;strong&gt;Flutter&lt;/strong&gt; stands out with its performance, consistency, rich UI tools, and a faster development process, making it the go-to choice for developers looking for a modern and efficient cross-platform solution.'&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect with me 🙍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mail&lt;/strong&gt; - &lt;code&gt;akashpattnaik.github@gamil.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Github&lt;/strong&gt; - &lt;a href="https://github.com/iAkashPattnaik" rel="noopener noreferrer"&gt;&lt;code&gt;iAkashPattnaik&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linkedin&lt;/strong&gt; - &lt;a href="https://www.linkedin.com/in/iakashpattnaik" rel="noopener noreferrer"&gt;&lt;code&gt;iAkashPattnaik&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>beginners</category>
      <category>programming</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>10 Secret Tips That Make You Better at DSA</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Mon, 12 Jan 2026 17:22:07 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/10-secret-tips-that-make-you-better-at-dsa-4and</link>
      <guid>https://dev.to/akashpattnaik/10-secret-tips-that-make-you-better-at-dsa-4and</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Data Structures and Algorithms (DSA) often feel overwhelming at first. With so many concepts, patterns, and problem types, it’s easy to feel stuck or slow. But here’s the good news: becoming good at DSA is less about talent and more about strategy. The right habits, mindset, and techniques can dramatically speed up your progress. In this article, you’ll discover &lt;strong&gt;10 secret tips that can make you significantly better at DSA&lt;/strong&gt;, even if you’re starting from scratch.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Table of Contents 💻&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Master the Basics Before Chasing Advanced Topics&lt;/li&gt;
&lt;li&gt;Think in Patterns, Not Problems&lt;/li&gt;
&lt;li&gt;Always Dry Run Your Code&lt;/li&gt;
&lt;li&gt;Learn Time and Space Complexity Visually&lt;/li&gt;
&lt;li&gt;Write Code on Paper (Yes, Really!)&lt;/li&gt;
&lt;li&gt;Solve Fewer Problems, but Solve Them Deeply&lt;/li&gt;
&lt;li&gt;Revisit Old Problems Regularly&lt;/li&gt;
&lt;li&gt;Explain Your Solution Out Loud&lt;/li&gt;
&lt;li&gt;Learn When &lt;em&gt;Not&lt;/em&gt; to Use a Data Structure&lt;/li&gt;
&lt;li&gt;Build Consistency, Not Motivation&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;1. Master the Basics Before Chasing Advanced Topics&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Many learners rush into advanced topics like dynamic programming or graphs without fully understanding arrays, strings, and linked lists. This creates weak foundations. Spend time mastering basics like loops, recursion, and simple data structures. Strong fundamentals make complex topics feel easier and more logical.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;2. Think in Patterns, Not Problems&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Most DSA problems are variations of a few core patterns such as sliding window, two pointers, recursion, backtracking, or divide and conquer. Instead of memorizing solutions, train your brain to recognize these patterns. Once you spot the pattern, the solution becomes much clearer.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;3. Always Dry Run Your Code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before jumping into coding, dry run the logic step by step with a small example. This helps you catch edge cases, logical errors, and unnecessary steps early. Dry running also improves your problem-solving clarity and reduces debugging time.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;4. Learn Time and Space Complexity Visually&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Big-O notation can feel abstract. Instead of memorizing formulas, visualize how your algorithm grows with input size. Ask questions like: &lt;em&gt;How many loops are running?&lt;/em&gt; or &lt;em&gt;Is extra memory being used?&lt;/em&gt; This approach makes complexity analysis intuitive rather than confusing.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;5. Write Code on Paper (Yes, Really!)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Writing code on paper forces you to slow down and think clearly. It improves logical flow and prepares you for interviews where you may not have an editor or auto-complete. This habit strengthens your confidence and precision.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;6. Solve Fewer Problems, but Solve Them Deeply&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Solving 100 problems poorly is less effective than solving 30 problems deeply. For every problem you solve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand why the solution works&lt;/li&gt;
&lt;li&gt;Explore alternative approaches&lt;/li&gt;
&lt;li&gt;Analyze time and space complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depth beats quantity in DSA learning.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;7. Revisit Old Problems Regularly&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Re-solving old problems after a few weeks is incredibly powerful. You’ll notice improved speed, better logic, and cleaner code. This reinforces long-term memory and helps patterns stick naturally.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;8. Explain Your Solution Out Loud&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you can explain your solution clearly, you truly understand it. Try teaching the solution to a friend, or even to yourself. This technique exposes gaps in understanding and improves interview communication skills.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;9. Learn When &lt;em&gt;Not&lt;/em&gt; to Use a Data Structure&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Many beginners overuse complex data structures when simpler ones work better. Always ask: &lt;em&gt;Is this the simplest solution?&lt;/em&gt; Choosing the right (or minimal) data structure often leads to cleaner and faster code.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;10. Build Consistency, Not Motivation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Motivation comes and goes, but consistency builds skill. Even 30 minutes of daily DSA practice is better than long, irregular sessions. Create a routine and stick to it. Progress will follow naturally.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Becoming better at DSA isn’t about shortcuts—it’s about smart learning. Apply these 10 secret tips consistently, and you’ll notice improved problem-solving speed, better confidence, and stronger fundamentals. Remember, every expert was once a beginner who didn’t give up.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>programming</category>
      <category>beginners</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>End of ElephantSQL 😔</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Wed, 03 Apr 2024 19:52:13 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/end-of-elephantsql-2gdo</link>
      <guid>https://dev.to/akashpattnaik/end-of-elephantsql-2gdo</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.elephantsql.com/" rel="noopener noreferrer"&gt;ElephantSQL&lt;/a&gt;&lt;/strong&gt; started back in 2013 and it was one of the first services to offer &lt;code&gt;postgreSQL&lt;/code&gt; at such low rates as a service.&lt;/p&gt;

&lt;p&gt;I personally have been using it since last 4-5 years and my favorite part was the &lt;strong&gt;browser SQL executer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately 😟, just moments ago I received a mail saying that they are ending their services from &lt;strong&gt;January 27, 2025&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%2F1erfkvsvpoxe1vxwb4ys.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%2F1erfkvsvpoxe1vxwb4ys.png" alt="Image" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;This marks a end to an era!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No doubt &lt;strong&gt;ElephantSQL&lt;/strong&gt; was one of the best postgreSQL service providers out their for small projects. &lt;/p&gt;

&lt;p&gt;I had build over 20 small projects using ElephantSQL. All of them had over &lt;strong&gt;1K+ users&lt;/strong&gt;. Their free plan was, in my personal opinion, the best postgreSQL service a beginner might ever get!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Comment if you have ever used &lt;strong&gt;ElephantSQL&lt;/strong&gt; and what are you going to use from now one?!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>news</category>
      <category>programming</category>
      <category>database</category>
      <category>discuss</category>
    </item>
    <item>
      <title>File API</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Thu, 21 Mar 2024 17:04:48 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/browser-apis-explained-in-1-byte-222h</link>
      <guid>https://dev.to/akashpattnaik/browser-apis-explained-in-1-byte-222h</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for DEV Challenge v24.03.20, One Byte Explainer: Browser API or Feature.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;File&lt;/code&gt; API
&lt;/h2&gt;

&lt;p&gt;The File API allows web applications to interact with files on the user's device. It enables reading file content, accessing metadata, and handling file uploads, enhancing user experience with file management in web applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Code (Not a part of explanation)
&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;// Reading file content using File API&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;fileInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&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="nx"&gt;event&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="c1"&gt;// Get the selected file&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Create a FileReader object&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Define what to do when file is loaded&lt;/span&gt;
  &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="c1"&gt;// Retrieve the file content&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File content:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// Read the file as text&lt;/span&gt;
  &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readAsText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&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;



</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>DOM API</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Thu, 21 Mar 2024 17:03:46 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/browser-apis-explained-in-1-byte-24o1</link>
      <guid>https://dev.to/akashpattnaik/browser-apis-explained-in-1-byte-24o1</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for DEV Challenge v24.03.20, One Byte Explainer: Browser API or Feature.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;DOM&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The Document Object Model (&lt;strong&gt;DOM&lt;/strong&gt;) represents webpage structure in a &lt;code&gt;tree-like&lt;/code&gt; format. It allows scripts to dynamically access, update, and modify webpage content and styles, enabling interactive web development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Code (Not a part of explanation)
&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;// Accessing and updating DOM elements&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;heading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Selecting an element&lt;/span&gt;
&lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New Heading&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Updating its text content&lt;/span&gt;
&lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Changing its style&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Appending it to the document&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>fetch API</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Thu, 21 Mar 2024 17:01:55 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/browser-apis-explained-in-1-byte-nno</link>
      <guid>https://dev.to/akashpattnaik/browser-apis-explained-in-1-byte-nno</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for DEV Challenge v24.03.20, One Byte Explainer: Browser API or Feature.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;fetch&lt;/code&gt; API
&lt;/h2&gt;

&lt;p&gt;The Fetch API in browsers is for making &lt;strong&gt;HTTP&lt;/strong&gt; requests. It's promise-based and cleaner than &lt;strong&gt;XMLHttpRequest&lt;/strong&gt;. You can use &lt;code&gt;fetch()&lt;/code&gt; with a URL and options to get data. Returns a promise with a Response object. Extract data with methods like &lt;code&gt;.json()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Code (Not a part of explanation)
&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;// Fetching data from a URL&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/data&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if response is successful&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network response was not ok&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;// Extract JSON data from response&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Work with the retrieved data&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle any errors that occur during the fetch operation&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fetch error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;



</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The new BottomBar in Flutter</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Sun, 17 Mar 2024 13:50:55 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/the-new-bottombar-in-flutter-ifm</link>
      <guid>https://dev.to/akashpattnaik/the-new-bottombar-in-flutter-ifm</guid>
      <description>&lt;p&gt;Hello fam 👋!&lt;/p&gt;

&lt;p&gt;This tutorial shows the new BottomBar implementation in flutter. (It's official).&lt;/p&gt;

&lt;p&gt;This is a new Material UI 3 implementation and is recommended to have only &lt;strong&gt;3&lt;/strong&gt; childs (&lt;code&gt;NavigationDestination&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For further lookup you can &lt;a href="https://api.flutter.dev/flutter/material/NavigationBar-class.html" rel="noopener noreferrer"&gt;see here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's a sample code that I used...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppHomePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AppHomePage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppHomePage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_AppHomePageState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_AppHomePageState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppHomePage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="c1"&gt;// Here&lt;/span&gt;
      &lt;span class="nl"&gt;bottomNavigationBar:&lt;/span&gt; &lt;span class="n"&gt;NavigationBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;overlayColor:&lt;/span&gt; &lt;span class="n"&gt;MaterialStateProperty&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;selectedIndex:&lt;/span&gt; &lt;span class="n"&gt;_selectedIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;onDestinationSelected:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="n"&gt;_selectedIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&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;// indicatorColor: Colors.pink,&lt;/span&gt;
          &lt;span class="nl"&gt;destinations:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;NavigationDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CupertinoIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;home&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;selectedIcon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CupertinoIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;house_fill&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;label:&lt;/span&gt; &lt;span class="s"&gt;'Home'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;NavigationDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;explore_outlined&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;selectedIcon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;explore_rounded&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;label:&lt;/span&gt; &lt;span class="s"&gt;'Explore'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;NavigationDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CupertinoIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bookmark&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;selectedIcon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CupertinoIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bookmark_solid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;label:&lt;/span&gt; &lt;span class="s"&gt;'Saved'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;NavigationDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CupertinoIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;person&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;selectedIcon:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CupertinoIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;person_fill&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="nl"&gt;label:&lt;/span&gt; &lt;span class="s"&gt;'Account'&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="p"&gt;),&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>flutter</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The PlayStore Killer</title>
      <dc:creator>Akash Pattnaik</dc:creator>
      <pubDate>Tue, 27 Feb 2024 18:29:08 +0000</pubDate>
      <link>https://dev.to/akashpattnaik/the-playstore-killer-2fcp</link>
      <guid>https://dev.to/akashpattnaik/the-playstore-killer-2fcp</guid>
      <description>&lt;p&gt;It's 2024, and &lt;a href="https://play.google.com/store" rel="noopener noreferrer"&gt;PlayStore&lt;/a&gt; is dominating the space in androids.&lt;/p&gt;

&lt;p&gt;Towards the mid-end of 2023, &lt;a href="https://www.phonepe.com/" rel="noopener noreferrer"&gt;PhonePe&lt;/a&gt; announced their own AppStore for &lt;strong&gt;India&lt;/strong&gt; called &lt;strong&gt;&lt;a href="https://www.indusappstore.com/" rel="noopener noreferrer"&gt;Indus AppStore&lt;/a&gt;&lt;/strong&gt; to compete against Playstore. &lt;strong&gt;Feb 21st&lt;/strong&gt; is the date it's going to be released.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features 🚀
&lt;/h2&gt;

&lt;p&gt;This new &lt;strong&gt;AppStore&lt;/strong&gt; comes with various new features and here are a few to list -&amp;gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for 13 India regional Languages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No fee&lt;/strong&gt; for developers to list their apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI integrated&lt;/strong&gt;, you just need to enter your app details in &lt;strong&gt;english&lt;/strong&gt; and they auto generate the same for the other 13 regional languages.&lt;/li&gt;
&lt;li&gt;Ease of WebUI.&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%2Fqzrtlt820511annajs6v.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%2Fqzrtlt820511annajs6v.png" alt="Indus UI" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is something I created as my first app to be listed on &lt;strong&gt;Indus&lt;/strong&gt;. I invite you all too, to shift from playstore and get started with &lt;strong&gt;Indus&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>productivity</category>
      <category>news</category>
    </item>
  </channel>
</rss>
