<?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: Shourya Parashar</title>
    <description>The latest articles on DEV Community by Shourya Parashar (@im-shourya).</description>
    <link>https://dev.to/im-shourya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3898002%2F6284c5d3-4556-4805-bc4e-8fc555bbaf7e.jpg</url>
      <title>DEV Community: Shourya Parashar</title>
      <link>https://dev.to/im-shourya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/im-shourya"/>
    <language>en</language>
    <item>
      <title>Building Archie: A System-Design Board That Asks Instead of Guessing</title>
      <dc:creator>Shourya Parashar</dc:creator>
      <pubDate>Wed, 28 Oct 2026 19:22:19 +0000</pubDate>
      <link>https://dev.to/im-shourya/building-archie-a-system-design-board-that-asks-instead-of-guessing-5goh</link>
      <guid>https://dev.to/im-shourya/building-archie-a-system-design-board-that-asks-instead-of-guessing-5goh</guid>
      <description>&lt;p&gt;On the first held-out eval run, Archie scored 91.2%. One of the three misses worried me more than the score: I told it to "connect the workers to the database", the board had two databases, and it quietly picked one.&lt;/p&gt;

&lt;p&gt;Nothing crashed. The diagram just became wrong, and a wrong architecture diagram looks exactly like a right one. This post is about how I built &lt;a href="https://archie-rb2x.onrender.com" rel="noopener noreferrer"&gt;Archie&lt;/a&gt;, and why the feature I care about most is the one that makes it stop and ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Archie Is
&lt;/h2&gt;

&lt;p&gt;Archie is a system-design board you talk to. You say "five replicas of the API" or "kill Redis", the diagram updates, and a simulator shows where the system saturates, which requests fail, and why. I built it for the Wispr Flow challenge at Hacker House Goa 2026, mostly by dictation, for two kinds of people: engineers sketching a design, and students practising system-design interviews.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Voice or typed commands&lt;/strong&gt; that become graph edits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A live simulator&lt;/strong&gt;: load, utilization (ρ), p50/p95/p99 latency, success rate, throughput and a monthly cost estimate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure injection&lt;/strong&gt;: "Kill Redis" drops success from 96.3% to 54.5%, and the blast radius shows which components went hot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interview mode&lt;/strong&gt;: six problems, from a URL shortener to video streaming, with an interviewer that asks about your weakest point&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Two Tiers, One Rule: Never Guess
&lt;/h2&gt;

&lt;p&gt;Every command goes through two tiers, and both follow the same rule. If a tier isn't certain, it doesn't act.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fast path&lt;/strong&gt; is a deterministic parser with an anchored grammar. It resolves names like "the db", "it" or "postgres replica one" and handles commands such as "shard Postgres into two" in the browser. It runs at a P50 of 0.006 ms over 14,000 runs. On the 92-case eval set it handles only 8 cases, but all 8 are correct. It abstains on everything else, which is the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI tier&lt;/strong&gt; gets whatever the fast path won't touch. The server sends the model a compact text form of the board, the simulator summary, the last few chat turns and the command. The model runs on a ladder of free-tier Gemini models with Groq as the fallback. It can only return one of five things: edits, a clarifying question, a confirmation request, an answer, or a no-op.&lt;/p&gt;

&lt;p&gt;The model never edits the board directly. It proposes typed operations, the code validates them, and an invalid batch gets one repair attempt before it turns into a question. Operations apply atomically, so one bad operation changes nothing, and everything can be undone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;command
  → fast path (deterministic, certain or silent)
  → AI tier (Gemini → Groq) → proposed ops
  → validate as a batch → one repair → else ask
  → apply atomically → simulator re-runs → canvas updates
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bug That Changed the Design
&lt;/h2&gt;

&lt;p&gt;The guardrails were already there when I ran the held-out test split the first time. The model still saw "the database", found two candidates, and picked one with confidence. That was 1 false action out of 34 cases.&lt;/p&gt;

&lt;p&gt;A prompt tweak would have been the quick fix. Instead I added a guard in code: when a reference matches more than one component, Archie asks "Which database?" with tappable answers. It doesn't depend on the model behaving.&lt;/p&gt;

&lt;p&gt;The second run on the held-out split scored 97.1% (33 of 34) with zero false actions. Part of that jump is run-to-run variance on free-tier models, and I've written that next to the result in the repo. The zero false actions is the number I trust, because a guard in code enforces it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simulator That Shows Its Math
&lt;/h2&gt;

&lt;p&gt;Every edit re-runs a queueing model: M/M/1 per replica at steady state, with cache-aside reads, read replicas, sharding, queues with backlog and failover, plus a 10,000-sample Monte Carlo for latency. A 100-component system simulates in 2.39 ms at P95, so the board keeps up while you talk.&lt;/p&gt;

&lt;p&gt;I didn't want the simulator to just paint a node red. The bottleneck gets a note with the arithmetic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1,500 reads/s + 5,000 writes/s on 1 shard
(capacity 10,000 reads / 4,000 writes per shard)
→ ρ = 1.40 → 28.6% of its requests dropped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those numbers are golden-tested against hand calculations. It's a teaching model, not a vendor benchmark, and the docs list every assumption.&lt;/p&gt;

&lt;p&gt;The same engine powers interview mode. The SLO checklist (success rate, read and write p99, headroom, surviving any single failure, cost) is computed by the simulator, not judged by the model. The final scorecard combines those checks with a five-part rubric where every score has to cite evidence from your board.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing It Like It Matters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;612&lt;/strong&gt; unit, property and contract tests (Vitest and fast-check)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;260&lt;/strong&gt; end-to-end tests on desktop and mobile Chromium (Playwright)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0&lt;/strong&gt; serious or critical accessibility violations across 15 states, light and dark, desktop and phone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;266.9 KB&lt;/strong&gt; of gzipped initial JS on the board route, with a budget enforced in CI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One target I haven't hit: I wanted 95% of answers to cite only the simulator's numbers. On the test split it was 2 of 3. That's next, along with a multi-turn eval category.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;p&gt;Next.js 16, React 19 and TypeScript, React Flow with ELK layout in a Web Worker, Zustand and IndexedDB for state, Hono for the API, Zod for validation, and Vitest, fast-check and Playwright for tests. It runs as a single Docker container on Render.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Took Away
&lt;/h2&gt;

&lt;p&gt;A tool that edits something people trust has to be more careful than it is clever. Archie's accuracy barely moved when I added the clarifying guard, but I stopped worrying about what it would do with an ambiguous command.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://archie-rb2x.onrender.com" rel="noopener noreferrer"&gt;archie-rb2x.onrender.com&lt;/a&gt; (free hosting, so the first load can take about a minute)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/im-shourya/Archie" rel="noopener noreferrer"&gt;github.com/im-shourya/Archie&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the 50k rps demo and try saying "shard Postgres into two".&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://shouryaparashar.in/blog/building-archie-a-system-design-board-that-asks-instead-of-guessing" rel="noopener noreferrer"&gt;shouryaparashar.in&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>typescript</category>
      <category>ai</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Building a Voice RAG System Under a 200ms Latency Budget</title>
      <dc:creator>Shourya Parashar</dc:creator>
      <pubDate>Sat, 05 Sep 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/im-shourya/building-a-voice-rag-system-under-a-200ms-latency-budget-1cap</link>
      <guid>https://dev.to/im-shourya/building-a-voice-rag-system-under-a-200ms-latency-budget-1cap</guid>
      <description>&lt;p&gt;What happens when you combine Voice &lt;strong&gt;AI + RAG + multilingual retrieval&lt;/strong&gt;, but give yourself a strict &lt;strong&gt;200ms latency budget&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;That was the challenge behind my &lt;strong&gt;HH Goa 2026 Task 2&lt;/strong&gt; project.&lt;/p&gt;

&lt;p&gt;I built a voice-driven RAG system on the &lt;strong&gt;AI4Bharat MSMARCO-XI&lt;/strong&gt; dataset, designed to retrieve relevant information, generate grounded answers, and gracefully refuse when the evidence isn't strong enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pipeline
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Voice
  ↓
Speech-to-Text
  ↓
Query Guard
  ↓
Hybrid Retrieval
  ↓
RRF + MMR
  ↓
Grounded Answer
  ↓
Verification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What made it interesting?
&lt;/h3&gt;

&lt;p&gt;Instead of relying only on vector search, I combined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dense retrieval&lt;/li&gt;
&lt;li&gt;BM25+ sparse retrieval&lt;/li&gt;
&lt;li&gt;Reciprocal Rank Fusion&lt;/li&gt;
&lt;li&gt;MMR reranking&lt;/li&gt;
&lt;li&gt;Multiple chunking strategies&lt;/li&gt;
&lt;li&gt;Retrieval confidence checks&lt;/li&gt;
&lt;li&gt;Prompt-injection protection&lt;/li&gt;
&lt;li&gt;Grounding verification&lt;/li&gt;
&lt;li&gt;Extractive fallback answers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal wasn't just to make the system answer.&lt;/p&gt;

&lt;p&gt;It was to make it &lt;strong&gt;answer only when it has enough evidence&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The part I cared about most: latency
&lt;/h3&gt;

&lt;p&gt;I instrumented every stage and benchmarked the complete pipeline.&lt;/p&gt;

&lt;p&gt;The final results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;P50&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.87 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P70&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9.62 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P100&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;40.71 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Benchmark runs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;927&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Within 200ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I also tested the actual HTTP service separately, instead of relying only on in-process benchmarks.&lt;/p&gt;

&lt;h3&gt;
  
  
  A few lessons
&lt;/h3&gt;

&lt;p&gt;The biggest takeaway wasn't a particular model or framework.&lt;/p&gt;

&lt;p&gt;It was that &lt;strong&gt;good AI systems are often about making the right engineering trade-offs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A bigger model isn't always better.&lt;/p&gt;

&lt;p&gt;More retrieval isn't always better.&lt;/p&gt;

&lt;p&gt;And sometimes the best answer is simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"I don't have enough evidence to answer that."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This project pushed me to think about RAG not just as &lt;em&gt;retrieval + generation&lt;/em&gt;, but as a complete system with &lt;strong&gt;latency, reliability, safety, and verification&lt;/strong&gt; built into the architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built with
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Python&lt;/code&gt; · &lt;code&gt;FastAPI&lt;/code&gt; · &lt;code&gt;BM25+&lt;/code&gt; · &lt;code&gt;Dense Retrieval&lt;/code&gt; · &lt;code&gt;RRF&lt;/code&gt; · &lt;code&gt;MMR&lt;/code&gt; · &lt;code&gt;Sarvam&lt;/code&gt; · &lt;code&gt;Claude&lt;/code&gt; · &lt;code&gt;Docker&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you're interested in the implementation, the complete project is here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/im-shourya/HHGOA-TASK2" rel="noopener noreferrer"&gt;https://github.com/im-shourya/HHGOA-TASK2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3y0jx1xv1pl7b6nao3yv.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3y0jx1xv1pl7b6nao3yv.png" alt=" " width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built for &lt;strong&gt;HH Goa 2026 — Shortlisting Task 2&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  AI #RAG #Python #LLM #MachineLearning #VoiceAI #InformationRetrieval
&lt;/h1&gt;

</description>
      <category>rag</category>
      <category>ai</category>
      <category>python</category>
    </item>
    <item>
      <title>KanbanFlow</title>
      <dc:creator>Shourya Parashar</dc:creator>
      <pubDate>Sat, 25 Apr 2026 20:37:33 +0000</pubDate>
      <link>https://dev.to/im-shourya/kanbanflow-3am9</link>
      <guid>https://dev.to/im-shourya/kanbanflow-3am9</guid>
      <description>&lt;p&gt;I Built a Zero-Backend Kanban Board with React + TypeScript — Here's What I Learned&lt;/p&gt;

&lt;p&gt;No server. No database. No login. Just pure React — and it actually works great.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I Built KanbanFlow&lt;/strong&gt;&lt;br&gt;
Every Kanban tool I used asked me to sign up, connect to a server, or pay for features I didn't need. I wanted something that just &lt;strong&gt;opened and worked&lt;/strong&gt; — instantly, privately, offline.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://kanbanflow.shouryaparashar.in" rel="noopener noreferrer"&gt;KanbanFlow&lt;/a&gt; — a fully-featured Kanban board that lives entirely in your browser. No account. No backend. No setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What It Does&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unlimited columns and tasks&lt;/strong&gt; — fully customizable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drag &amp;amp; drop&lt;/strong&gt; task movement across columns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Priority tagging&lt;/strong&gt; — High, Medium, Low, None&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Due dates&lt;/strong&gt; with overdue highlighting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live search&lt;/strong&gt; + priority filtering&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark / Light theme&lt;/strong&gt; toggle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-saves to localStorage&lt;/strong&gt; — data persists across sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React 18 + Vite 5 + TypeScript 5 + Tailwind CSS + React Router v6&lt;/p&gt;

&lt;p&gt;No Redux. No external state library. Just React's &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useReducer&lt;/code&gt; — keeping it lean.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Interesting Part — localStorage as a Database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most people reach for Firebase or Supabase immediately. But for a personal productivity tool, &lt;code&gt;localStorage&lt;/code&gt; is genuinely underrated.&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;// Auto-save board state on every change&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kanban-board&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;board&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="nx"&gt;board&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Load on mount&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;board&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBoard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Board&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kanban-board&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;defaultBoard&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;This pattern gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instant persistence with zero latency&lt;/li&gt;
&lt;li&gt;Works completely offline&lt;/li&gt;
&lt;li&gt;No auth, no API keys, no cost&lt;/li&gt;
&lt;li&gt;Data stays on the user's machine (privacy win)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tradeoff? No cross-device sync. For a personal board, that's totally acceptable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drag &amp;amp; Drop Without a Library&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of reaching for &lt;code&gt;react-beautiful-dnd&lt;/code&gt; or &lt;code&gt;dnd-kit&lt;/code&gt;, I implemented drag and drop using the native HTML5 Drag and Drop API — which kept the bundle size tiny.&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;const&lt;/span&gt; &lt;span class="nx"&gt;handleDragStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DragEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;taskId&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataTransfer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;taskId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;taskId&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;handleDrop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DragEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetColumnId&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;taskId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataTransfer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;taskId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;moveTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetColumnId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Project Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I kept the component tree flat and predictable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── types/kanban.ts         # All types + constants
├── components/kanban/
│   ├── TaskCard.tsx
│   ├── KanbanColumn.tsx
│   ├── TaskForm.tsx
│   ├── Header.tsx
│   └── Toolbar.tsx
└── pages/
    └── Index.tsx           # Main orchestrator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One rule I followed: &lt;strong&gt;no component does more than one thing&lt;/strong&gt;. &lt;code&gt;KanbanColumn&lt;/code&gt; renders a column. &lt;code&gt;TaskCard&lt;/code&gt; renders a card. &lt;code&gt;Index.tsx&lt;/code&gt; wires them together.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try It&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://kanbanflow.shouryaparashar.in" rel="noopener noreferrer"&gt;kanbanflow.shouryaparashar.in&lt;/a&gt; &lt;br&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/im-shourya/KanbanFlow" rel="noopener noreferrer"&gt;github.com/im-shourya/KanbanFlow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built by &lt;a href="https://shouryaparashar.in" rel="noopener noreferrer"&gt;Shourya Parashar&lt;/a&gt; — Full Stack Developer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you found this useful, drop a ⭐ on GitHub — it genuinely helps!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>buildinpublic</category>
    </item>
  </channel>
</rss>
