<?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: Rolan Lobo</title>
    <description>The latest articles on DEV Community by Rolan Lobo (@rolan_r_n_r).</description>
    <link>https://dev.to/rolan_r_n_r</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%2F3551696%2F5fb97d3c-ee7d-42c8-9da4-4122b6e46ab0.jpg</url>
      <title>DEV Community: Rolan Lobo</title>
      <link>https://dev.to/rolan_r_n_r</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rolan_r_n_r"/>
    <language>en</language>
    <item>
      <title>Your Backend Is Leaking Secrets (Mine Was Too)</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Fri, 17 Apr 2026 16:11:52 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/your-backend-is-leaking-secrets-mine-was-too-555m</link>
      <guid>https://dev.to/rolan_r_n_r/your-backend-is-leaking-secrets-mine-was-too-555m</guid>
      <description>&lt;p&gt;Ever had that feeling where your app &lt;em&gt;works perfectly&lt;/em&gt;… but deep down you know it's kinda unsafe?&lt;/p&gt;

&lt;p&gt;Yeah — that was me.&lt;/p&gt;

&lt;p&gt;So I went all-in on fixing some &lt;strong&gt;serious backend security flaws&lt;/strong&gt; in my project:&lt;br&gt;
👉 &lt;strong&gt;BAR (Burn After Reading)&lt;/strong&gt; — a secure file system with self-destruct capabilities.&lt;/p&gt;

&lt;p&gt;And honestly? This round of fixes made the project feel &lt;em&gt;10x more production-ready&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let me walk you through what I fixed — in a way that actually makes sense 👇&lt;/p&gt;


&lt;h2&gt;
  
  
  🚨 The Problem
&lt;/h2&gt;

&lt;p&gt;The app was functional, but under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sensitive error messages were leaking 😬&lt;/li&gt;
&lt;li&gt;Debug &lt;code&gt;print()&lt;/code&gt; statements were everywhere&lt;/li&gt;
&lt;li&gt;Logging wasn’t structured&lt;/li&gt;
&lt;li&gt;Some code paths were… let’s say “questionable choices”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing was &lt;em&gt;breaking&lt;/em&gt; — but from a security perspective?&lt;br&gt;
It needed serious tightening.&lt;/p&gt;


&lt;h2&gt;
  
  
  🛠️ What I Fixed (The Real Stuff)
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. 💀 Killing Error Leaks (Big One)
&lt;/h3&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah… that means if something fails, users might see &lt;strong&gt;internal errors, stack traces, even SMTP failures&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;security&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OPAQUE_500_DETAIL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users get a &lt;strong&gt;generic safe message&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Real errors go to logs (where they belong)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Result: &lt;strong&gt;No internal system info leaks to clients&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  2. 🧼 Cleaning Up a Dead Function Parameter
&lt;/h3&gt;

&lt;p&gt;There was this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;sanitize_error_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But… the parameter wasn’t even used properly 🤦‍♂️&lt;/p&gt;

&lt;p&gt;So I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removed the useless parameter&lt;/li&gt;
&lt;li&gt;Exported a clean constant:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;OPAQUE_500_DETAIL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Cleaner code, less confusion, fewer mistakes.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. 📧 Fixing OTP Email Leak
&lt;/h3&gt;

&lt;p&gt;This one was sneaky.&lt;/p&gt;

&lt;p&gt;If OTP sending failed, the API returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;error_msg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which could expose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SMTP issues&lt;/li&gt;
&lt;li&gt;Email service internals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&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="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;security&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OPAQUE_500_DETAIL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users see nothing sensitive&lt;/li&gt;
&lt;li&gt;Devs still get full logs&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. 🕵️ Tamper Detection Logging (Finally Useful)
&lt;/h3&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🚨 tamper detected: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tamper_exc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[SECURITY] Possible tamper detected …&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Why this matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works with logging systems&lt;/li&gt;
&lt;li&gt;Can trigger alerts&lt;/li&gt;
&lt;li&gt;Actually usable in production&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  5. ⚠️ Logger Setup Order Fix
&lt;/h3&gt;

&lt;p&gt;Yeah… this was subtle.&lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_logger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_logger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Prevents weird initialization issues and keeps things clean.&lt;/p&gt;




&lt;h3&gt;
  
  
  6. 🧯 Removing All &lt;code&gt;print()&lt;/code&gt; From Security Logic
&lt;/h3&gt;

&lt;p&gt;This was a big cleanup.&lt;/p&gt;

&lt;p&gt;Replaced things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Wrong password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;File destroyed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Brute force attempt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Why this matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;print()&lt;/code&gt; = invisible in production&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;logger&lt;/code&gt; = structured, searchable, monitorable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Verification (No Guesswork)
&lt;/h2&gt;

&lt;p&gt;I didn’t just “hope it works” — I verified everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ No &lt;code&gt;sanitize_error_message()&lt;/code&gt; calls left&lt;/li&gt;
&lt;li&gt;✅ No &lt;code&gt;detail=str(e)&lt;/code&gt; anywhere&lt;/li&gt;
&lt;li&gt;✅ No security-related &lt;code&gt;print()&lt;/code&gt; calls&lt;/li&gt;
&lt;li&gt;✅ OTP leaks completely removed&lt;/li&gt;
&lt;li&gt;✅ All files compile cleanly&lt;/li&gt;
&lt;li&gt;✅ Logging is consistent across modules&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 What I Learned
&lt;/h2&gt;

&lt;p&gt;Honestly, this round of fixes taught me something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Secure code isn’t about big features — it’s about small decisions done right.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not exposing errors&lt;/li&gt;
&lt;li&gt;Logging properly&lt;/li&gt;
&lt;li&gt;Keeping APIs predictable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the details that separate:&lt;br&gt;
👉 a “working app”&lt;br&gt;
from&lt;br&gt;
👉 a &lt;strong&gt;production-ready system&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This wasn’t a flashy update.&lt;/p&gt;

&lt;p&gt;No UI changes.&lt;br&gt;
No new features.&lt;/p&gt;

&lt;p&gt;But under the hood?&lt;/p&gt;

&lt;p&gt;👉 It made the app &lt;strong&gt;way more solid, safer, and professional&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Check Out the Project
&lt;/h2&gt;

&lt;p&gt;If you’re curious or want to explore the code:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/Mrtracker-new/BAR_RYY" rel="noopener noreferrer"&gt;https://github.com/Mrtracker-new/BAR_RYY&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  💬 If You’re Building Something…
&lt;/h2&gt;

&lt;p&gt;Take this as a reminder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don’t trust raw error messages&lt;/li&gt;
&lt;li&gt;Never leave &lt;code&gt;print()&lt;/code&gt; in security logic&lt;/li&gt;
&lt;li&gt;Logging is your best friend&lt;/li&gt;
&lt;li&gt;Small fixes = big impact&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>backend</category>
      <category>python</category>
    </item>
    <item>
      <title>🔐 AES-256 Finally Makes Sense (And It’s Way Simpler Than You Think)</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Wed, 01 Apr 2026 17:11:12 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/aes-256-finally-makes-sense-and-its-way-simpler-than-you-think-3kmc</link>
      <guid>https://dev.to/rolan_r_n_r/aes-256-finally-makes-sense-and-its-way-simpler-than-you-think-3kmc</guid>
      <description>&lt;p&gt;Let’s be honest…&lt;/p&gt;

&lt;p&gt;We’ve all heard this everywhere:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Your data is secured with AES-256 encryption”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cool… but &lt;strong&gt;what does that even mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I used to just nod like:&lt;br&gt;
“Yeah yeah… sounds secure 😌”&lt;/p&gt;

&lt;p&gt;But recently, I &lt;em&gt;actually&lt;/em&gt; understood it — and trust me, it’s not as scary as it sounds.&lt;/p&gt;

&lt;p&gt;So let me explain it to you in the simplest (and fun) way possible 👇&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 First, What is Encryption?
&lt;/h2&gt;

&lt;p&gt;Encryption is basically:&lt;/p&gt;

&lt;p&gt;👉 Turning your readable data into &lt;strong&gt;gibberish&lt;/strong&gt; so no one else can understand it.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Hello → X7#pL@9!

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only someone with the &lt;strong&gt;correct key&lt;/strong&gt; can turn it back into "Hello".&lt;/p&gt;




&lt;h2&gt;
  
  
  🔑 So What is AES?
&lt;/h2&gt;

&lt;p&gt;AES stands for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advanced Encryption Standard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s one of the most secure encryption methods used today.&lt;/p&gt;

&lt;p&gt;Used in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Banking systems 💳
&lt;/li&gt;
&lt;li&gt;WhatsApp messages 💬
&lt;/li&gt;
&lt;li&gt;Wi-Fi passwords 📶
&lt;/li&gt;
&lt;li&gt;Even governments 🏛️
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yeah… it’s &lt;em&gt;that serious.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  💪 What Does “256” Mean?
&lt;/h2&gt;

&lt;p&gt;AES comes in 3 types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AES-128
&lt;/li&gt;
&lt;li&gt;AES-192
&lt;/li&gt;
&lt;li&gt;AES-256
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 The number = &lt;strong&gt;key size (in bits)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So AES-256 = &lt;strong&gt;256-bit key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Which basically means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔐 There are 2^256 possible keys&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That number is insanely huge.&lt;/p&gt;

&lt;p&gt;Like… even if you had the fastest computer in the world,&lt;br&gt;
it would take &lt;strong&gt;billions of years&lt;/strong&gt; to brute-force it.&lt;/p&gt;


&lt;h2&gt;
  
  
  🎯 Imagine This (Simple Analogy)
&lt;/h2&gt;

&lt;p&gt;Think of AES-256 like this:&lt;/p&gt;

&lt;p&gt;You have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;super strong locker&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;256-digit password&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;And inside it → your data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now imagine someone trying to guess that password…&lt;/p&gt;

&lt;p&gt;Yeah… not happening anytime soon 😂&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚙️ How AES-256 Actually Works (Simple Version)
&lt;/h2&gt;

&lt;p&gt;Okay, no boring math — just the idea:&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Data is split into blocks
&lt;/h3&gt;

&lt;p&gt;Your data is divided into chunks (16 bytes each)&lt;/p&gt;


&lt;h3&gt;
  
  
  Step 2: Multiple rounds of scrambling (14 rounds!)
&lt;/h3&gt;

&lt;p&gt;Each round does things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mixing data&lt;/li&gt;
&lt;li&gt;Shuffling bits&lt;/li&gt;
&lt;li&gt;Substituting values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically:&lt;br&gt;
👉 It completely &lt;strong&gt;scrambles your data again and again&lt;/strong&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  Step 3: Secret key is applied
&lt;/h3&gt;

&lt;p&gt;A 256-bit key is used in every round&lt;/p&gt;

&lt;p&gt;This is what makes it secure 🔥&lt;/p&gt;


&lt;h3&gt;
  
  
  Step 4: Final Output
&lt;/h3&gt;

&lt;p&gt;You get encrypted data like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
k9@Lm#2!zPq8...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Completely unreadable.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔓 How Decryption Works
&lt;/h2&gt;

&lt;p&gt;To get the original data back:&lt;/p&gt;

&lt;p&gt;👉 You MUST have the same key&lt;/p&gt;

&lt;p&gt;Then the process runs &lt;strong&gt;in reverse&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And boom 💥&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
k9@Lm#2!zPq8... → Hello

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🚫 Why Hackers Can’t Easily Break AES-256
&lt;/h2&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Too many possible keys (2^256 🤯)&lt;/li&gt;
&lt;li&gt;Too many transformation rounds&lt;/li&gt;
&lt;li&gt;No shortcut to guess the correct key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even supercomputers struggle.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Where You See AES-256 in Real Life
&lt;/h2&gt;

&lt;p&gt;You’re already using it daily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔐 HTTPS websites (the lock icon in browser)&lt;/li&gt;
&lt;li&gt;💬 Messaging apps&lt;/li&gt;
&lt;li&gt;💾 File encryption tools&lt;/li&gt;
&lt;li&gt;☁️ Cloud storage&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧑‍💻 Why I Learned This
&lt;/h2&gt;

&lt;p&gt;While working on my project &lt;strong&gt;InvisioVault&lt;/strong&gt; (a file-hiding tool),&lt;br&gt;
I realized:&lt;/p&gt;

&lt;p&gt;👉 Hiding data is cool&lt;br&gt;&lt;br&gt;
👉 But securing it is &lt;em&gt;next level&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s when I explored AES-256.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✨ Final Thoughts
&lt;/h2&gt;

&lt;p&gt;AES-256 sounds complicated…&lt;/p&gt;

&lt;p&gt;But in reality, it’s just:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔐 A super powerful way to scramble data using a secret key&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’re a developer,&lt;br&gt;
understanding this gives you a &lt;strong&gt;huge edge&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 If You Made It This Far…
&lt;/h2&gt;

&lt;p&gt;You officially understand AES-256 better than most beginners 💯&lt;/p&gt;

&lt;p&gt;If this helped you, drop a like ❤️ or share it!&lt;/p&gt;




&lt;h2&gt;
  
  
  👋 Let’s Connect
&lt;/h2&gt;

&lt;p&gt;I’m a beginner dev building cool stuff and learning every day.&lt;/p&gt;

&lt;p&gt;More blogs coming soon 🚀&lt;/p&gt;

</description>
      <category>security</category>
      <category>cryptography</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>🧨 The Bugs That Almost Broke Sortify (And How I Crushed Them)</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Sun, 15 Feb 2026 15:03:43 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/the-bugs-that-almost-broke-sortify-and-how-i-crushed-them-h3h</link>
      <guid>https://dev.to/rolan_r_n_r/the-bugs-that-almost-broke-sortify-and-how-i-crushed-them-h3h</guid>
      <description>&lt;p&gt;Let me tell you something.&lt;/p&gt;

&lt;p&gt;Apps don’t usually break because of complex algorithms.&lt;/p&gt;

&lt;p&gt;They break because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A 0-byte file.&lt;/li&gt;
&lt;li&gt;A random binary blob pretending to be text.&lt;/li&gt;
&lt;li&gt;A filename like &lt;code&gt;report:final*version?.docx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Or an undo operation that travels back in time… badly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sortify ran into all of these.&lt;br&gt;
So I did what every developer eventually has to do:&lt;/p&gt;

&lt;p&gt;I went into &lt;strong&gt;defensive programming mode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the story of how I hardened Sortify’s invalid input handling — and made it way more stable in the process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Check it out on GitHub:&lt;/strong&gt; &lt;br&gt;
🔗 &lt;a href="https://github.com/Mrtracker-new/Sortify" rel="noopener noreferrer"&gt;Sortify — automatic file organizer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  🗂️ 1. The “Empty File” Problem
&lt;/h2&gt;

&lt;p&gt;You’d think an empty file wouldn’t be dangerous.&lt;/p&gt;

&lt;p&gt;It’s literally nothing.&lt;/p&gt;

&lt;p&gt;But that’s the problem.&lt;/p&gt;

&lt;p&gt;No content → extraction logic behaves weirdly → AI categorization becomes unreliable.&lt;/p&gt;

&lt;p&gt;So now we explicitly detect 0-byte files before doing anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_size_bytes&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="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Empty file detected (0 bytes): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What happens now?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Empty files are detected instantly&lt;/li&gt;
&lt;li&gt;✅ Logged properly&lt;/li&gt;
&lt;li&gt;✅ Categorized using filename only&lt;/li&gt;
&lt;li&gt;✅ No crashes&lt;/li&gt;
&lt;li&gt;✅ No silent weirdness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of “why did this behave strangely?”&lt;br&gt;
Now it’s “Ah, it’s empty. Makes sense.”&lt;/p&gt;

&lt;p&gt;Predictable &amp;gt; Magical.&lt;/p&gt;


&lt;h2&gt;
  
  
  💣 2. Binary Files Pretending to Be Text
&lt;/h2&gt;

&lt;p&gt;This one was sneaky.&lt;/p&gt;

&lt;p&gt;Some files looked harmless.&lt;/p&gt;

&lt;p&gt;But internally?&lt;/p&gt;

&lt;p&gt;Binary junk.&lt;/p&gt;

&lt;p&gt;And when text extraction libraries try to read binary data…&lt;/p&gt;

&lt;p&gt;You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exceptions&lt;/li&gt;
&lt;li&gt;Garbage output&lt;/li&gt;
&lt;li&gt;Or mysterious failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built a binary detector.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧠 How It Works
&lt;/h2&gt;

&lt;p&gt;We check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First 8KB of the file&lt;/li&gt;
&lt;li&gt;Presence of null bytes (&lt;code&gt;\x00&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Ratio of non-printable characters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If more than &lt;strong&gt;30% of characters are non-printable&lt;/strong&gt;, we treat it as binary.&lt;/p&gt;

&lt;p&gt;Why 30%?&lt;/p&gt;

&lt;p&gt;Because real text files don’t look like corrupted alien transmissions.&lt;/p&gt;


&lt;h3&gt;
  
  
  If file is binary:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Binary file detected, skipping content extraction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Skip text extraction&lt;/li&gt;
&lt;li&gt;✅ Fall back to filename-based categorization&lt;/li&gt;
&lt;li&gt;✅ Log everything&lt;/li&gt;
&lt;li&gt;✅ Avoid crashes completely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if the file extension lies.&lt;/p&gt;

&lt;p&gt;Doesn’t matter if it’s &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.md&lt;/code&gt;, or &lt;code&gt;.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Binary is binary.&lt;/p&gt;

&lt;p&gt;No more surprise explosions.&lt;/p&gt;


&lt;h2&gt;
  
  
  😩 3. Windows Filename Rage
&lt;/h2&gt;

&lt;p&gt;Previously, if someone tried to rename a file using invalid Windows characters…&lt;/p&gt;

&lt;p&gt;They got a boring, unhelpful error.&lt;/p&gt;

&lt;p&gt;Now?&lt;/p&gt;

&lt;p&gt;We explain exactly what Windows hates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows does not allow these characters in filenames:
  \ (backslash)  / (forward slash)  : (colon)
  * (asterisk)   ? (question mark)  " (quote)
  &amp;lt; (less than)  &amp;gt; (greater than)  | (pipe)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plus a clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please remove these characters and try again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simple change.&lt;/p&gt;

&lt;p&gt;Massive UX improvement.&lt;/p&gt;

&lt;p&gt;No more guessing what went wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  🕰️ 4. The Undo Operation That Could Have Been Dangerous
&lt;/h2&gt;

&lt;p&gt;Undo is supposed to feel magical.&lt;/p&gt;

&lt;p&gt;But under the hood, it’s risky.&lt;/p&gt;

&lt;p&gt;What if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The moved file was deleted?&lt;/li&gt;
&lt;li&gt;The original location now has a new file?&lt;/li&gt;
&lt;li&gt;Something changed between operations?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Previously, this could cause crashes or accidental overwrites.&lt;/p&gt;

&lt;p&gt;Now?&lt;/p&gt;

&lt;p&gt;We check everything.&lt;/p&gt;

&lt;p&gt;Before undoing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Does the moved file still exist?&lt;/li&gt;
&lt;li&gt;✅ Is the original location free?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If not?&lt;/p&gt;

&lt;p&gt;We stop and clearly explain why:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cannot undo: Original location is already occupied.
A file already exists at: ...
Please manually verify and move the file if needed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No corruption.&lt;br&gt;
No overwriting.&lt;br&gt;
No chaos.&lt;/p&gt;

&lt;p&gt;This one was a critical-level fix.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 Before vs After
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Empty files behaved weirdly&lt;/li&gt;
&lt;li&gt;Binary files could crash extraction&lt;/li&gt;
&lt;li&gt;Error messages were vague&lt;/li&gt;
&lt;li&gt;Undo could break in edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Empty files detected and logged&lt;/li&gt;
&lt;li&gt;Binary files safely skipped&lt;/li&gt;
&lt;li&gt;Clear, human-readable error messages&lt;/li&gt;
&lt;li&gt;Undo operations protected and safe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It feels like the app matured overnight.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 What This Really Is
&lt;/h2&gt;

&lt;p&gt;This wasn’t a “new feature” release.&lt;/p&gt;

&lt;p&gt;This was a &lt;strong&gt;stability hardening phase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The kind of work users never see.&lt;/p&gt;

&lt;p&gt;But they feel it.&lt;/p&gt;

&lt;p&gt;Because the app stops:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crashing randomly&lt;/li&gt;
&lt;li&gt;Acting unpredictably&lt;/li&gt;
&lt;li&gt;Failing silently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, it behaves like a professional desktop application.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Final Thought
&lt;/h2&gt;

&lt;p&gt;The difference between a prototype and a production-ready app?&lt;/p&gt;

&lt;p&gt;Not fancy AI.&lt;br&gt;
Not cool UI.&lt;/p&gt;

&lt;p&gt;It’s this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Handling weird, messy, real-world input gracefully.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Users will always find edge cases.&lt;/p&gt;

&lt;p&gt;Your job is to make sure they don’t break everything when they do.&lt;/p&gt;

&lt;p&gt;Sortify is now much harder to break.&lt;/p&gt;

&lt;p&gt;And honestly?&lt;/p&gt;

&lt;p&gt;That feels better than shipping a new feature. 💙&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Fixing a Frozen UI &amp; a Sneaky Scheduler Crash — A Tale of Threads, Signals, and Defensive Code 🧵🔥</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Tue, 03 Feb 2026 14:43:07 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/fixing-a-frozen-ui-a-sneaky-scheduler-crash-a-tale-of-threads-signals-and-defensive-code-35gc</link>
      <guid>https://dev.to/rolan_r_n_r/fixing-a-frozen-ui-a-sneaky-scheduler-crash-a-tale-of-threads-signals-and-defensive-code-35gc</guid>
      <description>&lt;p&gt;If your app &lt;em&gt;looks&lt;/em&gt; alive but &lt;em&gt;feels&lt;/em&gt; dead… congratulations 🎉&lt;br&gt;&lt;br&gt;
You’ve probably blocked the main thread.&lt;/p&gt;

&lt;p&gt;This post is a walkthrough of two real bugs I fixed recently:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;A UI freeze caused by blocking file I/O on the main thread&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A nasty crash where a scheduler ran before it was initialized&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both bugs were invisible during “small tests” and brutally obvious in real usage.&lt;br&gt;&lt;br&gt;
Let’s break down what went wrong, how I fixed it, and what I learned.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧊 Problem #1: The UI Freeze from Hell
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Symptoms
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clicking &lt;strong&gt;Organize Files&lt;/strong&gt; froze the entire UI&lt;/li&gt;
&lt;li&gt;Large file sets (50+ files) caused &lt;strong&gt;5+ seconds of silence&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;No progress bar movement&lt;/li&gt;
&lt;li&gt;Users thought the app had crashed (fair assumption)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Root Cause
&lt;/h3&gt;

&lt;p&gt;I was doing &lt;em&gt;exactly&lt;/em&gt; what every GUI app should &lt;strong&gt;never&lt;/strong&gt; do:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Running file operations directly on the &lt;strong&gt;main GUI thread&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here’s the original code 😬&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Preview mode - BLOCKING code
&lt;/span&gt;&lt;span class="n"&gt;temp_file_ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileOperations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Organized Files&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dry_run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;temp_file_ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_operations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# 🚨 This loop blocks the UI
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;file_path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selected_files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;category_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp_file_ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;categorize_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;temp_file_ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;temp_file_ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finalize_operations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That innocent-looking &lt;code&gt;for&lt;/code&gt; loop?&lt;br&gt;
Yeah… that was freezing &lt;em&gt;everything&lt;/em&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  ✅ The Fix: Move Work Off the Main Thread
&lt;/h2&gt;

&lt;p&gt;Instead of doing file I/O directly, I refactored preview mode to use the &lt;strong&gt;same background threading system&lt;/strong&gt; already working for real file moves.&lt;/p&gt;
&lt;h3&gt;
  
  
  New Approach (Non-Blocking)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Preview mode - NON-BLOCKING code
&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview_file_ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FileOperations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Organized Files&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dry_run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processing_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ProcessingThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selected_files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview_file_ops&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processing_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_progress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processing_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_on_preview_finished&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processing_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on_processing_error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;processing_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Why This Works
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;File processing runs in a &lt;strong&gt;background thread&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;UI stays responsive&lt;/li&gt;
&lt;li&gt;Progress bar updates in real time&lt;/li&gt;
&lt;li&gt;Errors are handled safely via signals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✨ Chef’s kiss.&lt;/p&gt;


&lt;h2&gt;
  
  
  🪄 Showing the Preview &lt;em&gt;After&lt;/em&gt; the Work Is Done
&lt;/h2&gt;

&lt;p&gt;Instead of showing the preview dialog immediately, I added a new handler that fires &lt;strong&gt;only after the background thread finishes&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_on_preview_finished&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest_dir&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;progress_bar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setVisible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview_file_ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dry_run_manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has_operations&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;dialog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PreviewDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview_file_ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dry_run_manager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;QDialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DialogCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accepted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_execute_organization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_dir&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_bar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Preview cancelled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No frozen UI&lt;/li&gt;
&lt;li&gt;No half-ready preview&lt;/li&gt;
&lt;li&gt;Clean, predictable flow&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📊 Before vs After (Quick Visual)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ Before (Blocking)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Main Thread
 └── Loop over files
     └── UI freezes 😵
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ After (Non-Blocking)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Main Thread        Background Thread
 ├── UI alive 🟢    └── File processing
 ├── Progress bar  └── Categorization
 └── Signals       └── Dry-run tracking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧨 Problem #2: The Scheduler That Crashed on Startup
&lt;/h2&gt;

&lt;p&gt;This one was sneakier.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Crash
&lt;/h3&gt;

&lt;p&gt;Sometimes the app would crash when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-sort was enabled before manual organization&lt;/li&gt;
&lt;li&gt;Scheduled jobs ran on fresh app start&lt;/li&gt;
&lt;li&gt;The app reopened with existing schedules&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Culprit
&lt;/h3&gt;

&lt;p&gt;The scheduler was created like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SortScheduler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;categorizer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;None&lt;/code&gt;?&lt;br&gt;
Yeah… &lt;code&gt;file_ops&lt;/code&gt; wasn’t initialized yet.&lt;/p&gt;

&lt;p&gt;So when the scheduler tried to move files:&lt;/p&gt;

&lt;p&gt;💥 &lt;strong&gt;NoneType crash&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🛡️ The Fix: Lazy Initialization + Defensive Guards
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Don’t Initialize Too Early
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Delay scheduler creation
&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 2: Centralize Setup with &lt;code&gt;_ensure_file_ops()&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SortScheduler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file_ops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;categorizer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file_ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file_ops&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scheduler only exists when &lt;code&gt;file_ops&lt;/code&gt; exists&lt;/li&gt;
&lt;li&gt;No duplicated setup logic&lt;/li&gt;
&lt;li&gt;No race conditions&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🧯 Step 3: Defense in Depth (Crash Prevention)
&lt;/h2&gt;

&lt;p&gt;Even with good initialization, I added &lt;strong&gt;guards&lt;/strong&gt; inside the scheduler and watcher:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file_ops&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;logging&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FileOperations not initialized&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No crashes&lt;/li&gt;
&lt;li&gt;Errors are logged&lt;/li&gt;
&lt;li&gt;App degrades gracefully instead of exploding&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Final Results
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;

&lt;p&gt;❌ Frozen UI&lt;br&gt;
❌ No progress feedback&lt;br&gt;
❌ Random crashes&lt;br&gt;
❌ Users panic&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;

&lt;p&gt;✅ Fully responsive UI&lt;br&gt;
✅ Smooth progress updates&lt;br&gt;
✅ Safe background execution&lt;br&gt;
✅ Stable scheduler &amp;amp; watcher&lt;br&gt;
✅ App feels &lt;em&gt;professional&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Testing Still Matters
&lt;/h2&gt;

&lt;p&gt;I manually tested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small file sets&lt;/li&gt;
&lt;li&gt;Large file sets&lt;/li&gt;
&lt;li&gt;Preview ON / OFF&lt;/li&gt;
&lt;li&gt;Auto-sort before manual use&lt;/li&gt;
&lt;li&gt;Scheduled jobs on restart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything behaved exactly as expected 🎉&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Never block the GUI thread&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Reuse proven threading patterns&lt;/li&gt;
&lt;li&gt;Lazy initialization beats eager crashes&lt;/li&gt;
&lt;li&gt;Defensive checks save your future self&lt;/li&gt;
&lt;li&gt;If the UI freezes, users will assume the worst&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you’re building desktop apps with Python + Qt:&lt;br&gt;
&lt;strong&gt;Threads + signals are not optional — they’re survival tools.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy coding 🧑‍💻🔥&lt;br&gt;
And may your UI never freeze again.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>productivity</category>
      <category>performance</category>
    </item>
    <item>
      <title>I Eliminated SQLite Race Conditions in a Multi-Threaded Python App 🚀</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Sun, 01 Feb 2026 14:59:13 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/i-eliminated-sqlite-race-conditions-in-a-multi-threaded-python-app-4eod</link>
      <guid>https://dev.to/rolan_r_n_r/i-eliminated-sqlite-race-conditions-in-a-multi-threaded-python-app-4eod</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Random crashes. Database corruption. “database is locked” errors.&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;That’s how my app &lt;strong&gt;Sortify&lt;/strong&gt; behaved when multiple threads hit SQLite at the same time.  &lt;/p&gt;

&lt;p&gt;This post is how I &lt;strong&gt;fixed it properly&lt;/strong&gt; — and made the database production-ready.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 The Problem: SQLite + Threads = Trouble
&lt;/h2&gt;

&lt;p&gt;SQLite is lightweight and fast — but it has a &lt;strong&gt;big footgun&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❌ &lt;strong&gt;A single database connection shared across threads is NOT safe&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my app &lt;strong&gt;Sortify&lt;/strong&gt;, multiple components were running concurrently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-sort watcher&lt;/li&gt;
&lt;li&gt;Manual file operations&lt;/li&gt;
&lt;li&gt;Scheduler tasks&lt;/li&gt;
&lt;li&gt;Background processing threads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of them were touching the &lt;strong&gt;same SQLite connection&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symptoms I Saw
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Random crashes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;database is locked&lt;/code&gt; errors&lt;/li&gt;
&lt;li&gt;Inconsistent history data&lt;/li&gt;
&lt;li&gt;Risk of database corruption&lt;/li&gt;
&lt;li&gt;App instability during concurrent operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This line was the silent killer 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check_same_thread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It &lt;em&gt;disables safety&lt;/em&gt;, but &lt;strong&gt;does not make SQLite thread-safe&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  💥 Why This Happens
&lt;/h2&gt;

&lt;p&gt;SQLite &lt;strong&gt;allows multiple connections&lt;/strong&gt;, but &lt;strong&gt;each connection must stay in one thread&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sharing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ cursors&lt;/li&gt;
&lt;li&gt;❌ connections&lt;/li&gt;
&lt;li&gt;❌ transactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;across threads causes &lt;strong&gt;race conditions&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ The Solution: Thread-Local Database Manager
&lt;/h2&gt;

&lt;p&gt;I implemented a &lt;strong&gt;proper thread-safe architecture&lt;/strong&gt; using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;threading.local()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Per-thread SQLite connections&lt;/li&gt;
&lt;li&gt;Automatic retry logic&lt;/li&gt;
&lt;li&gt;Centralized DB access layer&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Introducing &lt;code&gt;DatabaseManager&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A brand-new module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;core/database_manager.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Design Idea
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Each thread gets its own SQLite connection&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Connections are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created &lt;strong&gt;on demand&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Stored &lt;strong&gt;per thread&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Automatically reused inside that thread&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔐 Enforced Safety
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;db_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;check_same_thread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;  &lt;span class="c1"&gt;# ✅ SAFE
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a thread tries to use another thread’s connection → &lt;strong&gt;SQLite blocks it immediately&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s what we want.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Features of &lt;code&gt;DatabaseManager&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✔ Thread-Local Connection Pooling
&lt;/h3&gt;

&lt;p&gt;Each thread has &lt;strong&gt;its own isolated connection&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ✔ Automatic Retry on Locks
&lt;/h3&gt;

&lt;p&gt;Handles SQLite’s infamous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OperationalError: database is locked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with retry + backoff logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✔ Transaction Support
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;execute_transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensures &lt;strong&gt;atomic writes&lt;/strong&gt; even under load.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✔ Clean Shutdown
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;close_all_connections&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No leaked file handles. No corrupted DBs.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔁 Fixing Existing Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ Before: Shared Connection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check_same_thread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ After: Thread-Safe Manager
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.database_manager&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DatabaseManager&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db_manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DatabaseManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every database call now goes through &lt;strong&gt;one safe gateway&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧼 Removing Direct Cursor Access
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ UI Code Touching DB Directly
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history_manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETE FROM history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ Proper Encapsulation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history_manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear_operations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history_manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear_history&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more hidden race conditions.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Stress Testing the Fix
&lt;/h2&gt;

&lt;p&gt;I didn’t trust this blindly — I &lt;strong&gt;stress tested it hard&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Setup
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;5 threads&lt;/li&gt;
&lt;li&gt;50 DB operations each&lt;/li&gt;
&lt;li&gt;250 total concurrent writes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Total operations: 250
Successful: 250
Failed: 0
Database records: 250
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎉 &lt;strong&gt;Zero failures. Zero locks. Zero corruption.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Thread-Local Connections Verified
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Number of unique connections: 3
✓ Each thread has its own connection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exactly as designed.&lt;/p&gt;




&lt;h2&gt;
  
  
  📈 Impact
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before ❌
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Random crashes&lt;/li&gt;
&lt;li&gt;Locked database errors&lt;/li&gt;
&lt;li&gt;Unsafe concurrent writes&lt;/li&gt;
&lt;li&gt;App unstable under load&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After ✅
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fully thread-safe database access&lt;/li&gt;
&lt;li&gt;Stable concurrent operations&lt;/li&gt;
&lt;li&gt;No corruption risk&lt;/li&gt;
&lt;li&gt;Production-ready SQLite usage&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🗂️ Files Changed
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;core/database_manager.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;New thread-safe DB layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;core/history.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Migrated all queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ui/main_window.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removed direct DB access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tests/test_database_threading.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stress test suite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SQLite is thread-friendly, not thread-safe&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;check_same_thread=False&lt;/code&gt; is a trap&lt;/li&gt;
&lt;li&gt;One connection per thread is the correct model&lt;/li&gt;
&lt;li&gt;Centralizing DB access prevents future bugs&lt;/li&gt;
&lt;li&gt;Stress tests reveal bugs unit tests won’t&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🔗 Source Code
&lt;/h2&gt;

&lt;p&gt;📦 GitHub Repository:&lt;br&gt;
👉 &lt;a href="https://github.com/Mrtracker-new/Sortify" rel="noopener noreferrer"&gt;https://github.com/Mrtracker-new/Sortify&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🏁 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This wasn’t just a bug fix — it was a &lt;strong&gt;foundational stability upgrade&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your Python app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses SQLite&lt;/li&gt;
&lt;li&gt;Has background threads&lt;/li&gt;
&lt;li&gt;Randomly crashes under load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;This pattern will save you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>python</category>
      <category>sql</category>
      <category>programming</category>
      <category>database</category>
    </item>
    <item>
      <title>Introducing QR Code Steganography: Because Normal QR Codes Are Too Mainstream</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Sun, 25 Jan 2026 14:28:27 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/introducing-qr-code-steganography-because-normal-qr-codes-are-too-mainstream-1ipj</link>
      <guid>https://dev.to/rolan_r_n_r/introducing-qr-code-steganography-because-normal-qr-codes-are-too-mainstream-1ipj</guid>
      <description>&lt;h2&gt;
  
  
  The Problem Nobody Knew They Had
&lt;/h2&gt;

&lt;p&gt;You know what's boring? Regular QR codes. You scan them, they take you to a website. Yawn. 😴&lt;/p&gt;

&lt;p&gt;You know what's &lt;em&gt;exciting&lt;/em&gt;? QR codes that look totally normal to everyone else, but secretly contain hidden messages that only &lt;strong&gt;you&lt;/strong&gt; can read. Spy level: 100. 🕵️‍♂️&lt;/p&gt;

&lt;p&gt;So I built exactly that into InvisioVault. Because why should images have all the steganography fun?&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes This Different?
&lt;/h2&gt;

&lt;p&gt;Most QR code generators can add text. Cool. But that text is in the QR data itself - anyone with a scanner can see it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;InvisioVault's QR codes are double agents.&lt;/strong&gt; They have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📱 &lt;strong&gt;Public data&lt;/strong&gt; - What normal scanners see (your URL, contact info, whatever)&lt;/li&gt;
&lt;li&gt;🔐 &lt;strong&gt;Hidden secret&lt;/strong&gt; - Only visible when scanned with InvisioVault&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scan it with your phone? Goes to your website.&lt;br&gt;&lt;br&gt;
Scan it with InvisioVault? Reveals your secret message.&lt;/p&gt;

&lt;p&gt;Same QR code. Two completely different experiences. Magic? No. URL fragments? &lt;em&gt;Yes.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  How It Works (The Nerdy Bits)
&lt;/h2&gt;

&lt;p&gt;When you generate a QR code with InvisioVault, we encode it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://yourwebsite.com/#IVDATA:encrypted_secret_goes_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Here's the clever part:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Normal QR scanners&lt;/strong&gt; read the URL and open your browser&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browsers ignore everything after the &lt;code&gt;#&lt;/code&gt;&lt;/strong&gt; (it's a URL fragment)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your website loads perfectly&lt;/strong&gt; - no weird data, no errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;InvisioVault&lt;/strong&gt; reads the &lt;em&gt;full&lt;/em&gt; QR data including the fragment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We decrypt and display your hidden message&lt;/strong&gt; 🎉&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's like hiding a secret note inside a birthday card, except the birthday card is a QR code and the note is encrypted with AES-256. As one does.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Journey: A Tale of Trial and Error
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Attempt 1: Null Byte Separation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"Let's use &lt;code&gt;\x00&lt;/code&gt; to separate public and private data!"&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Result: Some scanners URL-encoded it. URLs looked like &lt;code&gt;website.com%00garbage&lt;/code&gt;. Fail. ❌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 2: LSB Image Steganography&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"Hide the secret in the QR code pixels!"&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Result: Camera captures recompress images. Pixel data destroyed. Hidden message? Gone. Double fail. ❌❌&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attempt 3: URL Fragments&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;"What if we just... use URL fragments?"&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Result: &lt;strong&gt;IT ACTUALLY WORKS.&lt;/strong&gt; ✅&lt;/p&gt;

&lt;p&gt;Sometimes the simple solution is the right solution. Sometimes you just need to fail twice first.&lt;/p&gt;


&lt;h2&gt;
  
  
  Live Camera Scanning 📷
&lt;/h2&gt;

&lt;p&gt;But wait, there's more! You can now scan QR codes &lt;strong&gt;directly with your webcam&lt;/strong&gt;. No screenshots, no uploads, just point and scan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The technical magic:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5-tier progressive camera fallback (works on 95%+ devices)&lt;/li&gt;
&lt;li&gt;Dual-canvas processing:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Original canvas&lt;/strong&gt;: Preserves color for extraction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced canvas&lt;/strong&gt;: 2x upscaling + grayscale + 50% contrast boost&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Adaptive scan intervals (500ms → 2000ms with exponential backoff)&lt;/li&gt;
&lt;li&gt;MD5-based request caching (60-80% cache hit rate)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Translation: It works fast, on almost any device, and doesn't murder your server. Success! 🎊&lt;/p&gt;


&lt;h2&gt;
  
  
  Show Me The Goods! 📸
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Generating a QR Code
&lt;/h3&gt;

&lt;p&gt;Here's what it looks like when you create a secret QR code:&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%2Fk1qw3nzy1nyexp2jnlre.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%2Fk1qw3nzy1nyexp2jnlre.png" alt="QR generation page" width="800" height="826"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Just a normal-looking QR code generator... or is it?&lt;/em&gt; 😏&lt;/p&gt;
&lt;h3&gt;
  
  
  Scanning &amp;amp; Extracting the Secret
&lt;/h3&gt;

&lt;p&gt;And here's what happens when you scan it with InvisioVault:&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%2F9dq3z8k2vgor4ag07whp.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%2F9dq3z8k2vgor4ag07whp.png" alt="QR code scan result" width="800" height="691"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Public data? Check. Hidden secret message? Double check. Mission accomplished!&lt;/em&gt; ✨&lt;/p&gt;


&lt;h2&gt;
  
  
  Why This Is Actually Useful
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"Okay cool, but when would I actually use this?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Glad you asked! Here are some totally-not-made-up scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Business Cards&lt;/strong&gt; 📇&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public: Your LinkedIn profile&lt;/li&gt;
&lt;li&gt;Secret: Your actual phone number (for select people who scan it right)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Event Tickets&lt;/strong&gt; 🎫&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public: Event website&lt;/li&gt;
&lt;li&gt;Secret: VIP access code or exclusive content link&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Product Packaging&lt;/strong&gt; 📦&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public: Product information&lt;/li&gt;
&lt;li&gt;Secret: Warranty details or customer support portal&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Marketing Materials&lt;/strong&gt; 📰&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public: Standard landing page&lt;/li&gt;
&lt;li&gt;Secret: Special discount code for InvisioVault users&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Just Because You Can&lt;/strong&gt; 🎉&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public: Rick Roll link&lt;/li&gt;
&lt;li&gt;Secret: Actual content you wanted to share&lt;/li&gt;
&lt;li&gt;(Okay this one might be real)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Performance Stats 📊
&lt;/h2&gt;

&lt;p&gt;Because numbers make everything more credible:&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;QR Detection Rate&lt;/td&gt;
&lt;td&gt;80%+ in good lighting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Device Compatibility&lt;/td&gt;
&lt;td&gt;95%+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend Load Reduction&lt;/td&gt;
&lt;td&gt;60-80% (thanks to caching)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Normal Scanner Compatibility&lt;/td&gt;
&lt;td&gt;100% (they just ignore the secret)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Times I Thought This Wouldn't Work&lt;/td&gt;
&lt;td&gt;47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Times I Was Wrong&lt;/td&gt;
&lt;td&gt;1 (this time it worked!)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  The Code Journey
&lt;/h2&gt;

&lt;p&gt;This feature went through more iterations than I'd like to admit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- Attempt 1: Data encoding with null bytes
&lt;/span&gt;&lt;span class="gi"&gt;+ Attempt 2: LSB pixel steganography
+ Attempt 3: URL fragment encoding ✓
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shoutout to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Segno&lt;/strong&gt; for QR generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pyzbar&lt;/strong&gt; for QR scanning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL fragments&lt;/strong&gt; for existing and being perfect for this&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coffee&lt;/strong&gt; for existing&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Head over to &lt;a href="https://github.com/Mrtracker-new/InvisioVault" rel="noopener noreferrer"&gt;InvisioVault&lt;/a&gt; and give it a spin!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a QR code with a hidden message&lt;/li&gt;
&lt;li&gt;Scan it with your phone - see the public data&lt;/li&gt;
&lt;li&gt;Scan it with InvisioVault - see the secret&lt;/li&gt;
&lt;li&gt;Feel like a spy&lt;/li&gt;
&lt;li&gt;Repeat until you've hidden secrets everywhere&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Some ideas I'm considering (read: may or may not implement):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎨 More QR customization options (logos, colors, patterns)&lt;/li&gt;
&lt;li&gt;📊 Analytics to see who scanned your QR codes&lt;/li&gt;
&lt;li&gt;🔗 QR code chaining (scan one, get led to another, treasure hunt style!)&lt;/li&gt;
&lt;li&gt;🎭 Multiple hidden messages in one QR (because why not?)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building this feature taught me several things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The simple solution is often hidden behind two complicated ones&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URL fragments are more useful than you think&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Camera APIs are surprisingly well-supported now&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LSB steganography is fragile and I should stop trying to make it work for everything&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you made it this far, congrats! You're either really interested in steganography, procrastinating on actual work, or both. Either way, thanks for reading! 🎉&lt;/p&gt;

&lt;p&gt;Now go forth and hide secrets in QR codes. The world is your oyster. Or QR code. Same thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technical Details (For the Curious)
&lt;/h2&gt;

&lt;p&gt;If you want to dive deep into how this works:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encryption:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AES-256-CBC with PBKDF2 key derivation&lt;/li&gt;
&lt;li&gt;100,000 iterations (industry standard)&lt;/li&gt;
&lt;li&gt;Random 16-byte salt and IV for each generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;QR Format:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{public_data}#IVDATA:{base64_encrypted_secret}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Camera Processing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MediaStream API for webcam access&lt;/li&gt;
&lt;li&gt;Canvas API for frame capture and enhancement&lt;/li&gt;
&lt;li&gt;Dual-canvas approach for quality preservation&lt;/li&gt;
&lt;li&gt;Real-time QR detection with adaptive intervals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance Optimizations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MD5 hashing for request deduplication&lt;/li&gt;
&lt;li&gt;In-memory caching with 1-second TTL&lt;/li&gt;
&lt;li&gt;Exponential backoff to reduce unnecessary processing&lt;/li&gt;
&lt;li&gt;Progressive camera configuration fallback&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Made with 💜 by Rolan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. - If you find any bugs, they're not bugs, they're undocumented features. But please tell me anyway.&lt;/em&gt; 😅&lt;/p&gt;




&lt;h2&gt;
  
  
  Share Your Creations!
&lt;/h2&gt;

&lt;p&gt;If you create something cool with this feature, tag me! I'd love to see what creative uses people come up with for hidden QR messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Mrtracker-new" rel="noopener noreferrer"&gt;@Mrtracker-new&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="mailto:rolanlobo901@gmail.com"&gt;rolanlobo901@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy hiding! 🎭✨&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>python</category>
      <category>react</category>
    </item>
    <item>
      <title>Stop Making Your Users Play 'Will It Fit?'</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Fri, 23 Jan 2026 16:43:07 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/stop-making-your-users-play-will-it-fit-m8c</link>
      <guid>https://dev.to/rolan_r_n_r/stop-making-your-users-play-will-it-fit-m8c</guid>
      <description>&lt;h2&gt;
  
  
  Stop Making Your Users Play 'Will It Fit?'
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;My steganography app lets users hide files inside images. Cool, right? Except users kept getting this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ Error: Image doesn't have enough capacity.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt; uploading everything. &lt;strong&gt;After&lt;/strong&gt; waiting. &lt;strong&gt;After&lt;/strong&gt; clicking the button.&lt;/p&gt;

&lt;p&gt;So they'd try a bigger image. Upload again. Click. Fail. Repeat until rage-quit. &lt;/p&gt;

&lt;p&gt;Not great for retention. 📉&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;I added a real-time capacity calculator that shows users if their file will fit &lt;strong&gt;before&lt;/strong&gt; they click anything.&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%2Fw2a4epm6s87fiu8yafph.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%2Fw2a4epm6s87fiu8yafph.png" alt="Capacity check" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's just a React component that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calculates capacity when files are selected&lt;/li&gt;
&lt;li&gt;Shows a color-coded progress bar&lt;/li&gt;
&lt;li&gt;Tells users upfront: "✅ File will fit comfortably" or "❌ Too big buddy"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Code (The Interesting Bits)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt; - Calculate how much fits in an image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@api.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/calculate-capacity&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_capacity&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RGB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total_pixels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&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="c1"&gt;# LSB stego: 3 bits per pixel / 8 = bytes
&lt;/span&gt;    &lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_pixels&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;totalCapacityBytes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;capacity&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;Frontend&lt;/strong&gt; - Debounce so we don't spam the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="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="c1"&gt;// Wait 500ms after user stops typing&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&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="nf"&gt;calculateCapacity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&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;image&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="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&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;The Pretty Part&lt;/strong&gt; - Color-coded status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;percentage&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;percentage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&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;icon&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too large!&lt;/span&gt;&lt;span class="dl"&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;percentage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;90&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;icon&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Barely fits&lt;/span&gt;&lt;span class="dl"&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;percentage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;70&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;icon&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;High capacity&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;icon&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fits comfortably&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Plot Twist
&lt;/h2&gt;

&lt;p&gt;I deployed it. Users loved it. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❌ Failed to calculate capacity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns out my 50 req/hour rate limit couldn't handle users actually &lt;em&gt;using&lt;/em&gt; the feature. Whoops.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Bumped to 100 req/hour + added debouncing = happy users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero&lt;/strong&gt; "file too large" complaints (down from many)&lt;/li&gt;
&lt;li&gt;Users understand capacity limits without reading docs&lt;/li&gt;
&lt;li&gt;App feels way more professional&lt;/li&gt;
&lt;li&gt;I learned about debouncing the hard way&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Show, don't tell&lt;/strong&gt; - Real-time feedback &amp;gt; documentation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Debounce everything&lt;/strong&gt; - Users type fast. Your API can't keep up. Plan accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Polish matters&lt;/strong&gt; - That shine animation on the progress bar? Totally unnecessary. Users love it anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Watch your rate limits&lt;/strong&gt; - Good features get used. A lot. Be ready.&lt;/p&gt;

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

&lt;p&gt;The full code is on &lt;a href="https://github.com/Mrtracker-new/InvisioVault" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Feel free to steal, improve, or roast my implementation. &lt;/p&gt;

&lt;p&gt;Sometimes the best features aren't the flashy new capabilities - they're the tiny UX tweaks that make users go "oh thank god, finally."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What small feature transformed your app's UX?&lt;/strong&gt; Drop it in the comments! 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Building steganography tools at 3 AM with too much coffee ☕&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Follow: &lt;a href="https://github.com/Mrtracker-new" rel="noopener noreferrer"&gt;@Mrtracker-new&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>ux</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Stop Lying to Your Users With Spinning Circles</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Thu, 22 Jan 2026 16:28:32 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/stop-lying-to-your-users-with-spinning-circles-16lb</link>
      <guid>https://dev.to/rolan_r_n_r/stop-lying-to-your-users-with-spinning-circles-16lb</guid>
      <description>&lt;h2&gt;
  
  
  I Gave My Loading Screens a Glow-Up (And You Can Too!) 💅
&lt;/h2&gt;

&lt;p&gt;You know that awkward moment when your app is loading and all your users see is a lonely spinning circle? Yeah, me too. So I decided to do something about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Spinners Are Liars 🤥
&lt;/h2&gt;

&lt;p&gt;Picture this: You're building a file encryption app (yes, that's what I do for fun), and your backend is sleeping on Render's free tier. When someone tries to access a file, they click the button and... nothing. Just a spinner. For 15 seconds.&lt;/p&gt;

&lt;p&gt;No feedback. No progress. Just vibes. ✨&lt;/p&gt;

&lt;p&gt;Users are left wondering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it working?&lt;/li&gt;
&lt;li&gt;Did I break it?&lt;/li&gt;
&lt;li&gt;Should I refresh?&lt;/li&gt;
&lt;li&gt;Is it time to panic yet?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spoiler: They always panic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Multi-Stage Loading Indicators 🎯
&lt;/h2&gt;

&lt;p&gt;Instead of a basic spinner that screams "I'm working, trust me bro," I built a loading component that actually &lt;strong&gt;communicates&lt;/strong&gt; with users. Here's what it does:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔵 Stage 1: Connecting
&lt;/h3&gt;

&lt;p&gt;"Waking up server..." (because yes, it's literally waking up from a nap)&lt;/p&gt;

&lt;h3&gt;
  
  
  🟣 Stage 2: Authenticating
&lt;/h3&gt;

&lt;p&gt;"Authenticating request..." (fancy words for checking if you're allowed in)&lt;/p&gt;

&lt;h3&gt;
  
  
  🟡 Stage 3: Decrypting
&lt;/h3&gt;

&lt;p&gt;"Decrypting file..." (the actual magic happens here)&lt;/p&gt;

&lt;h3&gt;
  
  
  🟢 Stage 4: Rendering
&lt;/h3&gt;

&lt;p&gt;"Rendering preview..." (almost there!)&lt;/p&gt;

&lt;p&gt;Each stage gets its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Icon&lt;/strong&gt; (Server → Shield → Lock → Eye)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Color&lt;/strong&gt; (Blue → Purple → Amber → Green)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progress percentage&lt;/strong&gt; (0% → 25% → 50% → 75% → 100%)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smooth animations&lt;/strong&gt; (because we're fancy like that)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Code: Let's Get Spicy 🌶️
&lt;/h2&gt;

&lt;p&gt;I created a reusable &lt;code&gt;LoadingStages&lt;/code&gt; component that takes the current stage and progress as props:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LoadingStages&lt;/span&gt;
  &lt;span class="na"&gt;currentStage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"connecting"&lt;/span&gt;
  &lt;span class="na"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;estimatedTime&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component cycles through stages automatically based on your app's actual loading process. No fake progress bars here! (We're honest people.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Cold Start Detection 🥶
&lt;/h3&gt;

&lt;p&gt;The best part? It detects when the server is cold-starting and shows an estimated time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responseTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&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;responseTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setEstimatedTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "~15s" appears on screen&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, users know they're in for a wait and can grab their coffee ☕&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results: Happy Users 😊
&lt;/h2&gt;

&lt;p&gt;Instead of anxious button-mashing, users now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;See exactly what's happening&lt;/strong&gt; at each stage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know how long it'll take&lt;/strong&gt; during cold starts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feel confident&lt;/strong&gt; the app is working&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't spam refresh&lt;/strong&gt; (my server thanks them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus, it looks &lt;em&gt;gorgeous&lt;/em&gt;. The glassmorphic design with color transitions makes loading actually pleasant to watch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to Try It? 🚀
&lt;/h2&gt;

&lt;p&gt;Check out the full implementation in my repo:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/Mrtracker-new/BAR_RYY" rel="noopener noreferrer"&gt;BAR_RYY&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The magic lives in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;frontend/src/components/LoadingStages.jsx&lt;/code&gt; (the star of the show)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;frontend/src/components/SharePage.jsx&lt;/code&gt; (where it's integrated)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways 💡
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Loading screens are prime real estate&lt;/strong&gt; - Use them to communicate!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Users tolerate waits better&lt;/strong&gt; when they know what's happening&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold start detection&lt;/strong&gt; turns frustration into understanding&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pretty animations&lt;/strong&gt; make everything better (scientific fact)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Thoughts 🎨
&lt;/h2&gt;

&lt;p&gt;We spend so much time optimizing for speed, but sometimes the wait is unavoidable (looking at me, free tier cold starts). When you can't eliminate the wait, make it &lt;strong&gt;informative&lt;/strong&gt; and &lt;strong&gt;beautiful&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your users will appreciate knowing that yes, the app is working, and no, they don't need to panic.&lt;/p&gt;

&lt;p&gt;Now if you'll excuse me, I'm off to give all my loading screens glow-ups. This is addicting. 💅✨&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What's the most creative loading indicator you've seen?&lt;/strong&gt; Drop it in the comments! 👇&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. - If you're building anything with file encryption, 2FA, or self-destructing links, definitely check out the repo. It's got some cool security features too!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>react</category>
      <category>ux</category>
    </item>
    <item>
      <title>How I Stopped Worrying and Learned to Love Organization</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Wed, 21 Jan 2026 15:57:03 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/how-i-stopped-worrying-and-learned-to-love-organization-18el</link>
      <guid>https://dev.to/rolan_r_n_r/how-i-stopped-worrying-and-learned-to-love-organization-18el</guid>
      <description>&lt;h2&gt;
  
  
  The Before Times (aka The Dark Ages)
&lt;/h2&gt;

&lt;p&gt;Picture this: You open your backend folder. It's like walking into a teenager's room. Files everywhere. No rhyme. No reason. Just pure, unadulterated chaos.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;database.py&lt;/code&gt; living next to &lt;code&gt;upload.py&lt;/code&gt;, hanging out with &lt;code&gt;security.py&lt;/code&gt;, while &lt;code&gt;cleanup.py&lt;/code&gt; just vibes in the corner. Everyone's at the same level, nobody has their own space, and finding anything requires either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A prayer 🙏&lt;/li&gt;
&lt;li&gt;Ctrl+P like your life depends on it&lt;/li&gt;
&lt;li&gt;Or acceptance that you'll spend 10 minutes scrolling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sound familiar? Yeah, I thought so.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Intervention
&lt;/h2&gt;

&lt;p&gt;One day, I looked at my backend folder and had an epiphany. Or maybe it was just caffeine-induced clarity. Either way, I realized something profound:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My files were adults. They deserved their own rooms.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I did what any responsible developer would do: I created folders. ACTUAL. FOLDERS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend/
├── core/           # The VIPs
├── services/       # The workers
├── storage/        # The file hoarders
└── utils/          # The helpful folks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Revolutionary? No. Overdue? Absolutely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Great Migration (aka Moving Day)
&lt;/h2&gt;

&lt;p&gt;Moving files is like playing Tetris, but with imports. You move one file and suddenly 47 things break. It's beautiful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Create folders&lt;br&gt;&lt;br&gt;
✅ Easy mode&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Move files into folders&lt;br&gt;&lt;br&gt;
✅ Still easy&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Update all the imports&lt;br&gt;&lt;br&gt;
⚠️ &lt;strong&gt;BOSS BATTLE INITIATED&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Before
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt;

&lt;span class="c1"&gt;# After
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;core.database&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt;

&lt;span class="c1"&gt;# My brain
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;please.work.i.beg.you&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Sanity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I spent quality time with find-and-replace. We bonded. We grew together. I may have shed a tear when all the imports finally worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Changed
&lt;/h2&gt;

&lt;p&gt;Here's what I inflicted upon my codebase:&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;core/&lt;/strong&gt; - The Foundation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;database.py&lt;/code&gt; - Because databases are core, obviously&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;config.py&lt;/code&gt; - All the environment variables in one place&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;auth.py&lt;/code&gt; - Security matters, folks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚙️ &lt;strong&gt;services/&lt;/strong&gt; - The Doers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;upload_service.py&lt;/code&gt; - Handles uploads&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;share_service.py&lt;/code&gt; - Handles sharing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cleanup_service.py&lt;/code&gt; - Cleans up after everyone else (the real MVP)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  💾 &lt;strong&gt;storage/&lt;/strong&gt; - The Packrats
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;file_manager.py&lt;/code&gt; - Manages files (shocking, I know)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;storage_handler.py&lt;/code&gt; - Stores things&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛠️ &lt;strong&gt;utils/&lt;/strong&gt; - The Helpers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;security.py&lt;/code&gt; - Security utilities&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;validators.py&lt;/code&gt; - Validates stuff&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;helpers.py&lt;/code&gt; - Helps with... stuff&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Fallout
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Good:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finding files is now actually possible&lt;/li&gt;
&lt;li&gt;New team members don't look at me with fear and confusion&lt;/li&gt;
&lt;li&gt;I can pretend I know what I'm doing&lt;/li&gt;
&lt;li&gt;Separation of concerns is no longer just a buzzword I throw around&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Bad:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My muscle memory is completely wrecked&lt;/li&gt;
&lt;li&gt;I still type old import paths&lt;/li&gt;
&lt;li&gt;Had to update the mental map in my brain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Ugly:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;That one time I forgot to update an import and the server crashed in production&lt;/li&gt;
&lt;li&gt;Just kidding! (Or am I? 😅)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with folders.&lt;/strong&gt; Don't be like me. Don't wait until you have 30 files in the root directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Your IDE's refactoring tools are your friends.&lt;/strong&gt; Use them. Love them. They'll save you from import hell.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test after moving EVERYTHING.&lt;/strong&gt; I mean it. Test it all. Then test it again.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It's never too late to organize.&lt;/strong&gt; Even if your codebase is a disaster, you can fix it. I believe in you.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document the structure.&lt;/strong&gt; Future you will thank present you. Past you is already disappointed, but that's okay.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Commit Message That Started It All
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;refactor: finally convinced my files to use folders like adults

- Created proper folder structure (core, services, storage, utils)
- Moved files from root to appropriate directories
- Updated all import statements
- Celebrated with coffee
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Is my backend perfect now? No.&lt;br&gt;&lt;br&gt;
Is it better? Absolutely.&lt;br&gt;&lt;br&gt;
Did I learn something? Maybe.&lt;br&gt;&lt;br&gt;
Will I do this again? Already planning the frontend refactor.&lt;/p&gt;

&lt;p&gt;Remember folks: &lt;strong&gt;Organization is not about being perfect. It's about being less chaotic than you were yesterday.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if you're sitting there with a messy backend folder, take this as your sign. Your files deserve their own rooms too.&lt;/p&gt;

&lt;p&gt;Now go forth and mkdir! 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you ever done a massive refactor? Share your horror stories in the comments! I promise mine was worse. Probably.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>coding</category>
      <category>backend</category>
    </item>
    <item>
      <title>Why Let Users Choose Between Being Nice and Being Paranoid? 🔄</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Tue, 20 Jan 2026 18:17:41 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/why-let-users-choose-between-being-nice-and-being-paranoid-5c8n</link>
      <guid>https://dev.to/rolan_r_n_r/why-let-users-choose-between-being-nice-and-being-paranoid-5c8n</guid>
      <description>&lt;h2&gt;
  
  
  The Problem: My App Had Commitment Issues 💔
&lt;/h2&gt;

&lt;p&gt;So I built this file-sharing web-app called &lt;a href="https://bar-rnr.vercel.app/" rel="noopener noreferrer"&gt;BAR Web&lt;/a&gt; that lets you send files that self-destruct after being viewed (think Mission Impossible but for PDFs). Cool, right?&lt;/p&gt;

&lt;p&gt;But here's where things got weird: I added &lt;strong&gt;two&lt;/strong&gt; features to control how page refreshes work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;View Refresh Threshold&lt;/strong&gt; - "Hey, if the same person refreshes within 5 minutes, don't count it as a new view"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-Refresh Interval&lt;/strong&gt; - "Force the page to reload every 30 seconds so the file disappears"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And like a fool, I let users enable &lt;strong&gt;both at the same time&lt;/strong&gt;. 🤦‍♂️&lt;/p&gt;

&lt;h2&gt;
  
  
  What Could Go Wrong?
&lt;/h2&gt;

&lt;p&gt;Imagine this conversation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt; "I want to be nice! Let people refresh without wasting views!"&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Also User:&lt;/strong&gt; "But also force them to reload every 30 seconds!"&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Me:&lt;/strong&gt; "...that's like wearing a belt AND suspenders, my friend."&lt;/p&gt;

&lt;p&gt;It made zero sense. If you're auto-reloading the page, why care about refresh thresholds? If you're being forgiving with refreshes, why force reloads?&lt;/p&gt;

&lt;p&gt;It was like trying to be both chill and paranoid at the same time. Pick a lane, buddy!&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution: Couples Therapy for UI Elements 💑
&lt;/h2&gt;

&lt;p&gt;I made them &lt;strong&gt;mutually exclusive&lt;/strong&gt; using radio buttons. Now users have to choose ONE:&lt;/p&gt;
&lt;h3&gt;
  
  
  Option 1: View Refresh Threshold (The Nice One)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"I trust you not to spam refresh. Take your time!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recipients who might have slow internet 📶&lt;/li&gt;
&lt;li&gt;People who need to scroll through long documents&lt;/li&gt;
&lt;li&gt;When you're feeling generous&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0 minutes (every refresh counts - default)&lt;/li&gt;
&lt;li&gt;5 minutes (recommended)&lt;/li&gt;
&lt;li&gt;Up to 1 hour (very forgiving)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
User refreshes 3 times in 4 minutes → Still counts as 1 view 🎯&lt;/p&gt;


&lt;h3&gt;
  
  
  Option 2: Auto-Refresh Interval (The Paranoid One)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"You have 30 seconds. Make them count. ⏱️"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Super sensitive stuff&lt;/li&gt;
&lt;li&gt;Time-limited access codes&lt;/li&gt;
&lt;li&gt;Maximum security theater&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Options:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10 seconds (ruthless)&lt;/li&gt;
&lt;li&gt;30 seconds (recommended)&lt;/li&gt;
&lt;li&gt;Up to 5 minutes (generous for paranoia mode)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
User opens file → Has 30 seconds to read → Page reloads → File might be gone 💨&lt;/p&gt;
&lt;h2&gt;
  
  
  The Implementation (For the Nerds) 🤓
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Frontend Magic
&lt;/h3&gt;

&lt;p&gt;I used radio buttons styled like cards (same pattern as my storage mode selector):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// When "View Refresh Threshold" is selected&lt;/span&gt;
&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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="nf"&gt;onRulesChange&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;viewRefreshMinutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// Enable this one&lt;/span&gt;
  &lt;span class="na"&gt;autoRefreshSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;          &lt;span class="c1"&gt;// Disable the other&lt;/span&gt;
&lt;span class="p"&gt;})}&lt;/span&gt;

&lt;span class="c1"&gt;// When "Auto-Refresh Interval" is selected  &lt;/span&gt;
&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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="nf"&gt;onRulesChange&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;viewRefreshMinutes&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;// Disable this one&lt;/span&gt;
  &lt;span class="na"&gt;autoRefreshSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;         &lt;span class="c1"&gt;// Enable the other&lt;/span&gt;
&lt;span class="p"&gt;})}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I show the dropdown settings &lt;strong&gt;only&lt;/strong&gt; for the selected option. One choice, one settings panel. Clean and simple.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend Wisdom
&lt;/h3&gt;

&lt;p&gt;The backend was already handling both features separately. I just had to make sure only one value is non-zero at a time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# In the database
&lt;/span&gt;&lt;span class="n"&gt;view_refresh_minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;auto_refresh_seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;# Only one should be &amp;gt; 0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fingerprinting logic checks if enough time has passed, and the auto-refresh header tells the browser when to reload. Easy peasy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned 🎓
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don't give users contradictory choices&lt;/strong&gt; - It's our job to prevent foot-shooting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI should reflect reality&lt;/strong&gt; - If two options fight each other, make them exclusive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Good UX is about constraints&lt;/strong&gt; - Sometimes the best feature is the one you don't include&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Radio buttons &amp;gt; Checkboxes&lt;/strong&gt; for mutually exclusive stuff (duh)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Result 🎉
&lt;/h2&gt;

&lt;p&gt;Now my app has a clear UI that says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Pick your personality: Nice or Paranoid. You can't be both, Karen."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Users love it. No more confusion. No more contradictory settings. Just clean, simple choices.&lt;/p&gt;

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

&lt;p&gt;The feature is live at &lt;a href="https://bar-rnr.vercel.app/" rel="noopener noreferrer"&gt;bar-rnr.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you want to see the code or contribute:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/Mrtracker-new/BAR_RYY" rel="noopener noreferrer"&gt;GitHub: BAR_RYY&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fun fact:&lt;/strong&gt; I committed this in 4 separate commits with increasingly silly commit messages. Because if you're not having fun while coding, what's the point? 😄&lt;/p&gt;

&lt;p&gt;The last commit was literally:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Docs got the memo! 📝 README and FEATURES.md now explain the new Smart Refresh Control with examples, emojis, and a healthy reminder that you can't enable both options because that'd be like wearing a belt AND suspenders 👖"&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;Have you ever built conflicting features into your app? Share your "oops" moments in the comments! 👇&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>ux</category>
    </item>
    <item>
      <title>How I Accidentally Became a Performance Guru</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Sun, 18 Jan 2026 15:51:58 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/how-i-accidentally-became-a-performance-guru-3lla</link>
      <guid>https://dev.to/rolan_r_n_r/how-i-accidentally-became-a-performance-guru-3lla</guid>
      <description>&lt;h2&gt;
  
  
  The Classic Beginner Move: Doing Everything Backwards
&lt;/h2&gt;

&lt;p&gt;You know that feeling when you're building your portfolio as a beginner and you suddenly think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“THIS is going to be legendary.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yeah. That was me.&lt;/p&gt;

&lt;p&gt;I planned everything with &lt;em&gt;extreme seriousness&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Cool animations
&lt;/li&gt;
&lt;li&gt;✅ Smooth transitions
&lt;/li&gt;
&lt;li&gt;✅ Project showcase
&lt;/li&gt;
&lt;li&gt;✅ Fancy tech stack badges
&lt;/li&gt;
&lt;li&gt;✅ Blog section
&lt;/li&gt;
&lt;li&gt;❌ Resume… eventually?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the thing about being a beginner:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You overthink the simple stuff&lt;br&gt;&lt;br&gt;
and underthink the important stuff.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I spent &lt;strong&gt;days&lt;/strong&gt; perfecting my hero section animation.&lt;/p&gt;

&lt;p&gt;But adding my actual resume to my portfolio?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Eh… I’ll do it later.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So naturally, I added my resume &lt;strong&gt;dead last&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You know —&lt;br&gt;&lt;br&gt;
&lt;strong&gt;the ONE thing employers might actually want to see&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By the time I got to it, I had already:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;implemented &lt;strong&gt;three color themes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;refactored my components &lt;strong&gt;twice&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;memorized half of the React docs&lt;/li&gt;
&lt;li&gt;emotionally bonded with my CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Classic beginner behavior. 🤦‍♂️&lt;/p&gt;


&lt;h2&gt;
  
  
  The React-PDF Rabbit Hole 🕳️🐇
&lt;/h2&gt;

&lt;p&gt;When I &lt;em&gt;finally&lt;/em&gt; decided to add my resume, I told myself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I’m a &lt;strong&gt;developer&lt;/strong&gt; now.&lt;br&gt;&lt;br&gt;
I must do this the &lt;strong&gt;developer way&lt;/strong&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I did what any self-respecting beginner does:&lt;/p&gt;

&lt;p&gt;🔍 Googled: &lt;em&gt;“How to add PDF to React website”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And there it was.&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;react-pdf&lt;/strong&gt; ✨&lt;/p&gt;

&lt;p&gt;A whole library just for PDFs?&lt;/p&gt;

&lt;p&gt;Perfect.&lt;br&gt;&lt;br&gt;
Libraries = Professional.&lt;br&gt;&lt;br&gt;
More code = Smarter developer.&lt;br&gt;&lt;br&gt;
Right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;}&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;react-pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Look at me using a library 😎&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/Rolan_Resume.pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="nx"&gt;pageNumber&lt;/span&gt;&lt;span class="o"&gt;=&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Document&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I felt unstoppable.&lt;/p&gt;

&lt;p&gt;I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installed dependencies&lt;/li&gt;
&lt;li&gt;Configured webpack&lt;/li&gt;
&lt;li&gt;read &lt;strong&gt;15 Stack Overflow answers&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Fought canvas rendering errors&lt;/li&gt;
&lt;li&gt;Questioned my life choices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was &lt;strong&gt;REAL development&lt;/strong&gt;, right?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Wake-Up Call 😱
&lt;/h2&gt;

&lt;p&gt;Then I ran &lt;strong&gt;Lighthouse&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance: 67&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;💀💀💀&lt;/p&gt;

&lt;p&gt;My beautifully crafted portfolio — the one I spent weeks polishing — was being absolutely &lt;strong&gt;murdered&lt;/strong&gt; by a PDF renderer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mobile users were probably aging in real time&lt;/li&gt;
&lt;li&gt;Resume loading slower than my motivation on Mondays&lt;/li&gt;
&lt;li&gt;And for WHAT?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The PDF:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wasn’t interactive&lt;/li&gt;
&lt;li&gt;didn’t zoom properly&lt;/li&gt;
&lt;li&gt;took forever to load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had officially used a &lt;strong&gt;sledgehammer to hang a photo frame&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The “Duh” Moment: WebP to the Rescue 🧠✨
&lt;/h2&gt;

&lt;p&gt;One day, while optimizing my project images (you know… the things I optimized &lt;em&gt;before&lt;/em&gt; my resume 🙃), I converted everything to &lt;strong&gt;WebP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;File sizes dropped like my hopes during a failed &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And suddenly…&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;It hit me.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Wait…&lt;br&gt;
Why am I rendering a PDF…&lt;br&gt;
when I could just show an image?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🤯🤯🤯&lt;/p&gt;

&lt;p&gt;Groundbreaking thinking, I know.&lt;br&gt;
Someone call the Nobel committee.&lt;/p&gt;

&lt;p&gt;So I did the most &lt;em&gt;un-developer&lt;/em&gt; thing possible:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opened my resume PDF&lt;/li&gt;
&lt;li&gt;Exported it as a high-quality image&lt;/li&gt;
&lt;li&gt;Converted it to &lt;strong&gt;WebP&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Deleted &lt;code&gt;react-pdf&lt;/code&gt; like it owed me money&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Replaced all of this complexity with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; 
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/resume-preview.webp"&lt;/span&gt; 
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Resume Preview"&lt;/span&gt;
  &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;No library.&lt;br&gt;
No config.&lt;br&gt;
No pain.&lt;br&gt;
Just ✨ a native &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag no libraries involved ✨.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Results Were… Embarrassingly Good 😐
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before (react-pdf)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;📦 Bundle size: &lt;strong&gt;+500KB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;⏱️ Load time (3G): &lt;strong&gt;3.2s&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🎨 Lighthouse score: &lt;strong&gt;67&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;😤 Stress level: &lt;strong&gt;High&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After (WebP)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;📦 File size: &lt;strong&gt;~45KB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;⏱️ Load time (3G): &lt;strong&gt;0.3s&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🎨 Lighthouse score: &lt;strong&gt;95&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;😎 Stress level: &lt;strong&gt;Chill&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I accidentally made my site &lt;strong&gt;10x faster&lt;/strong&gt; by doing the &lt;strong&gt;simplest thing possible&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Taught Me (Besides Humility)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1️⃣ Not Everything Needs a Library
&lt;/h3&gt;

&lt;p&gt;Just because a library exists doesn’t mean you need it.&lt;/p&gt;

&lt;p&gt;Sometimes the browser already does the job perfectly fine.&lt;/p&gt;

&lt;p&gt;Using a library for this felt like buying a &lt;strong&gt;smart electric can opener&lt;/strong&gt;…&lt;br&gt;
when you have hands.&lt;/p&gt;




&lt;h3&gt;
  
  
  2️⃣ WebP Is a Game Changer
&lt;/h3&gt;

&lt;p&gt;If you’re not using WebP yet… why? 😭&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;25–35% smaller than PNG/JPEG&lt;/li&gt;
&lt;li&gt;Better quality at lower sizes&lt;/li&gt;
&lt;li&gt;Supported by all modern browsers
&lt;em&gt;(sorry IE11, this party isn’t for you)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WebP is basically a &lt;strong&gt;free performance upgrade&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3️⃣ The Beginner Advantage 🧠
&lt;/h3&gt;

&lt;p&gt;As a beginner, I wasn’t emotionally attached to “the right way”.&lt;/p&gt;

&lt;p&gt;When something didn’t work well, I didn’t defend it.&lt;/p&gt;

&lt;p&gt;I just went:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This sucks.”&lt;br&gt;
&lt;em&gt;Delete.&lt;/em&gt;&lt;br&gt;
Try something simpler.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That mindset saved my performance.&lt;/p&gt;




&lt;h3&gt;
  
  
  4️⃣ Performance &amp;gt; Complexity
&lt;/h3&gt;

&lt;p&gt;No recruiter will ever say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Wow… you used react-pdf.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But they &lt;strong&gt;will notice&lt;/strong&gt; when your site loads faster than their coffee machine.&lt;/p&gt;

&lt;p&gt;Users don’t see your code.&lt;br&gt;
They &lt;strong&gt;feel&lt;/strong&gt; your performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Irony of It All 🎭
&lt;/h2&gt;

&lt;p&gt;I thought being a “real developer” meant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more libraries&lt;/li&gt;
&lt;li&gt;more configs&lt;/li&gt;
&lt;li&gt;more complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the biggest improvement to my portfolio came from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Converting a file&lt;br&gt;
and using an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes the &lt;strong&gt;best code&lt;/strong&gt;&lt;br&gt;
is the code you &lt;strong&gt;don’t write&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How You Can Do This Too (Dead Simple)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Export your resume as a high-quality image&lt;/li&gt;
&lt;li&gt;Convert it to &lt;strong&gt;WebP&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"resume-preview.webp"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Resume"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Still offer the PDF download:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/resume.pdf"&lt;/span&gt; &lt;span class="na"&gt;download&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Download PDF&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. 🎉&lt;/p&gt;

&lt;p&gt;You’ve now avoided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PDF.js headaches&lt;/li&gt;
&lt;li&gt;Webpack nightmares&lt;/li&gt;
&lt;li&gt;“canvas is not defined” errors&lt;/li&gt;
&lt;li&gt;Performance crimes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building a portfolio as a beginner is basically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;doing things backwards&lt;/li&gt;
&lt;li&gt;learning the hard way&lt;/li&gt;
&lt;li&gt;accidentally discovering best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I added my resume last.&lt;br&gt;
I over-engineered a simple problem.&lt;br&gt;
But I learned something valuable:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Simple beats fancy.&lt;br&gt;
Fast beats clever.&lt;br&gt;
Users beat libraries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If my Lighthouse score went from &lt;strong&gt;67 → 95&lt;/strong&gt; just by using WebP…&lt;/p&gt;

&lt;p&gt;Imagine what yours could be.&lt;/p&gt;

&lt;p&gt;Now if you’ll excuse me, I need to refactor something that’s working perfectly fine —&lt;br&gt;
you know, as developers do. 😅&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
Tried to be fancy with &lt;code&gt;react-pdf&lt;/code&gt;, murdered performance.&lt;br&gt;
Switched to WebP image preview, became accidentally fast.&lt;br&gt;
WebP is magic. Simple is better.&lt;/p&gt;

&lt;p&gt;Got similar over-engineering stories?&lt;br&gt;
Drop them in the comments — let’s laugh at our beginner mistakes together 👇&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. Yes, my resume is still downloadable as a PDF.&lt;br&gt;
I’m not a monster. But the preview?&lt;br&gt;
That’s pure WebP goodness.&lt;/em&gt; 😌&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>performance</category>
      <category>react</category>
    </item>
    <item>
      <title>This message will self-destruct in 5 seconds...</title>
      <dc:creator>Rolan Lobo</dc:creator>
      <pubDate>Tue, 16 Dec 2025 17:44:01 +0000</pubDate>
      <link>https://dev.to/rolan_r_n_r/this-message-will-self-destruct-in-5-seconds-505i</link>
      <guid>https://dev.to/rolan_r_n_r/this-message-will-self-destruct-in-5-seconds-505i</guid>
      <description>&lt;p&gt;You know that scene in Mission Impossible where Ethan Hunt gets his briefing and then—&lt;em&gt;poof&lt;/em&gt;—the tape/phone/hologram bursts into flames? &lt;/p&gt;

&lt;p&gt;Yeah, I wanted that. But for files. On the internet. Without the fire hazard. 🔥&lt;/p&gt;

&lt;p&gt;So, I built &lt;strong&gt;BAR-Web&lt;/strong&gt; (Burn After Reading) - a file-sharing app where your secrets actually stay secret and then disappear forever. No "oops, I can recover that from the recycle bin." No "let me just use this recovery tool." Just... &lt;strong&gt;gone&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Origin Story (aka "Why Did I Do This?")
&lt;/h2&gt;

&lt;p&gt;It started with a simple problem: I needed to share a password with someone. Email? Nah, that stays in their inbox forever. WhatsApp? Now it's on their cloud backup. Signal? Better, but still... what if they screenshot it?&lt;/p&gt;

&lt;p&gt;I wanted something that would:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;✅ Self-destruct after being read&lt;/li&gt;
&lt;li&gt;✅ Have ACTUAL security (not just vibes)&lt;/li&gt;
&lt;li&gt;✅ Give ME control over who sees what, and when&lt;/li&gt;
&lt;li&gt;✅ Make me feel like a secret agent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Spoiler: No good free options existed. So I made one. Twice. (First a desktop exe, then this web version because I got addicted to the idea.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does It Actually Do?
&lt;/h2&gt;

&lt;p&gt;Think &lt;strong&gt;Snapchat for files&lt;/strong&gt;, but with &lt;strong&gt;actual teeth&lt;/strong&gt; and &lt;strong&gt;bank-level encryption&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's the deal:&lt;/p&gt;

&lt;h3&gt;
  
  
  📤 Upload Anything
&lt;/h3&gt;

&lt;p&gt;PDFs, images, videos, your secret cookie recipe—up to 100MB. No judgment.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔒 Fort Knox Encryption
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AES-256&lt;/strong&gt; encryption (the same stuff governments use to protect classified docs). Your files are turned into digital gibberish that would take a supercomputer billions of years to crack. No pressure.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔑 Zero-Knowledge Security
&lt;/h3&gt;

&lt;p&gt;Here's the cool part: Even &lt;strong&gt;I&lt;/strong&gt; can't read your files. When you password-protect something, the encryption key is derived from your password and &lt;strong&gt;NEVER stored anywhere&lt;/strong&gt;. No password? No file. It's that simple.&lt;/p&gt;

&lt;p&gt;(This is the same tech 1Password, Bitwarden, and Signal use. If it's good enough for Edward Snowden, it's good enough for us.)&lt;/p&gt;

&lt;h3&gt;
  
  
  ⏱️ Time Bombs
&lt;/h3&gt;

&lt;p&gt;Set files to expire in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 minutes (for the truly paranoid)&lt;/li&gt;
&lt;li&gt;24 hours (for the casually paranoid)&lt;/li&gt;
&lt;li&gt;Or custom times (for the "I know what I'm doing" folks)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  👁️ View Limits
&lt;/h3&gt;

&lt;p&gt;"This file will self-destruct after 1 view."&lt;br&gt;
Or 5 views. Or 100. Your call. Once the limit hits? &lt;strong&gt;POOF.&lt;/strong&gt; File deletes itself. No takebacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Two Ways to Share
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Download a &lt;code&gt;.bar&lt;/code&gt; File&lt;/strong&gt; &lt;br&gt;
Send someone an encrypted file they can decrypt later. Good for offline sharing or when you don't trust servers (fair).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2: Magic Link&lt;/strong&gt;&lt;br&gt;
Share a link. We host the encrypted file and enforce the rules. Once it hits the view limit or expires? It's &lt;strong&gt;gone forever&lt;/strong&gt;. We even overwrite it 3 times with random data to make sure nobody's recovering it.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔔 Webhook Alerts (The Fun Part)
&lt;/h3&gt;

&lt;p&gt;Want to know when someone tries to access your file? Set up a webhook! Get a Discord or Slack notification when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Someone views your file&lt;/li&gt;
&lt;li&gt;Someone enters the wrong password&lt;/li&gt;
&lt;li&gt;Someone hits the view limit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't know about you, but getting a ping that says "⚠️ Wrong password attempt #3" is oddly satisfying.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛡️ Brute-Force Protection
&lt;/h3&gt;

&lt;p&gt;Try to guess the password? Cute. Here's what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wrong password = delays (1s, 2s, 4s, 8s...)&lt;/li&gt;
&lt;li&gt;5 wrong attempts? &lt;strong&gt;Locked out for 60 minutes.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Try to cheat by re-uploading? Nope. We track that.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hackers hate this one simple trick. (It's called "making them give up.")&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech Stack (For My Fellow Nerds 🤓)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Backend:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI&lt;/strong&gt; (because Python is still king for APIs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cryptography&lt;/strong&gt; library (the heavy lifter)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PBKDF2&lt;/strong&gt; for key derivation (100,000 iterations, because we're not amateurs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HMAC-SHA256&lt;/strong&gt; for tamper detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Frontend:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React 18&lt;/strong&gt; + &lt;strong&gt;Vite&lt;/strong&gt; (blazing fast dev experience)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; (looking good without the pain)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lucide React&lt;/strong&gt; icons (because they're clean AF)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hosting:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend on &lt;strong&gt;Vercel&lt;/strong&gt; (because it just works)&lt;/li&gt;
&lt;li&gt;Backend on &lt;strong&gt;Render Free Tier&lt;/strong&gt; (warning: it takes 50 seconds to wake up from hibernation, so be patient!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Desktop Version (Plot Twist!)
&lt;/h2&gt;

&lt;p&gt;Before I built the web version, I made a &lt;strong&gt;Windows desktop app&lt;/strong&gt; (exe) that's honestly even MORE paranoid. Same core security, but with some extra spicy features:&lt;/p&gt;

&lt;h3&gt;
  
  
  🚨 Desktop-Only Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Panic Button&lt;/strong&gt;: Someone walking up behind you? Hit the button. Your files? Gone in seconds. Three destruction levels:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Selective&lt;/em&gt;: Just clear session data&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Aggressive&lt;/em&gt;: Nuke 98%+ of BAR data&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Scorched Earth&lt;/em&gt;: Maximum destruction + anti-forensics (nuclear option)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Deadman Switch&lt;/strong&gt;: Don't log in for a week? Files auto-delete themselves. &lt;em&gt;Spooky but useful.&lt;/em&gt;
&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Hardware Binding&lt;/strong&gt;: Lock files to your specific PC. Try to copy them elsewhere? They won't decrypt.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;100% Offline&lt;/strong&gt;: No internet. No cloud. Your files NEVER leave your machine.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Security Levels&lt;/strong&gt;: Choose your paranoia level:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Standard&lt;/em&gt;: 5 wrong passwords = temp lockout&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;High&lt;/em&gt;: 4 wrong passwords = 24hr lockouts&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Maximum&lt;/em&gt;: 3 wrong passwords = &lt;strong&gt;EVERYTHING DELETED&lt;/strong&gt; ☠️&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Why did I make a web version then? Because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Not everyone wants a desktop app&lt;/li&gt;
&lt;li&gt;Sharing links is easier than sending .bar files&lt;/li&gt;
&lt;li&gt;I wanted to prove the same security works in a browser&lt;/li&gt;
&lt;li&gt;I wanted to flex my full-stack muscles 💪&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both versions use the same encryption standards (AES-256-GCM), so pick your poison!&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;🌐 Live Demo:&lt;/strong&gt; &lt;a href="https://bar-rnr.vercel.app/" rel="noopener noreferrer"&gt;https://bar-rnr.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fair warning: The backend is on a free tier that hibernates when not in use. If it's slow to load, give it ~50 seconds to wake up, stretch, and grab some coffee. After that? Lightning fast. ⚡&lt;/p&gt;

&lt;p&gt;Want to self-host? The code is on GitHub:&lt;br&gt;
&lt;strong&gt;🔗 Web Version: &lt;a href="https://github.com/Mrtracker-new/BAR_RYY" rel="noopener noreferrer"&gt;github.com/Mrtracker-new/BAR_RYY&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want the desktop app instead?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;🔗 Desktop Version (v2.0.0): &lt;a href="https://github.com/Mrtracker-new/BAR" rel="noopener noreferrer"&gt;github.com/Mrtracker-new/BAR&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The desktop version has the panic button and deadman switch—perfect for the truly paranoid! 😈&lt;/p&gt;

&lt;h2&gt;
  
  
  Things I Learned (The Hard Way)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Encryption is HARD.&lt;/strong&gt; Like, "I rewrote this 5 times" hard. Don't roll your own crypto. Use battle-tested libraries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UX matters for security tools.&lt;/strong&gt; If your security tool is annoying to use, people won't use it. Then they'll go back to emailing passwords in plaintext. 😭&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Free hosting has trade-offs.&lt;/strong&gt; The 50-second wake-up time on Render? Yeah, that's the price of free. Still worth it though!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;People LOVE the webhook notifications.&lt;/strong&gt; I thought it was a silly feature. Turns out everyone wants to know when their file gets accessed. It's like having a security camera for your data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;"Zero-knowledge" is a great pitch.&lt;/strong&gt; Telling users "I literally CAN'T read your files" is way more reassuring than "I promise I won't read your files."&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Some ideas I'm toying with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mobile app&lt;/strong&gt; (because why not go full circle?)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser extension&lt;/strong&gt; (right-click → "Share securely")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email integration&lt;/strong&gt; (auto-generate BAR links in Gmail)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiring messages&lt;/strong&gt; (not just files, but text too)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But honestly? I built this mostly because I thought it was cool. If even one person uses it to send a password securely instead of over Slack, I'll call it a win. 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Talk Section
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is this production-ready?&lt;/strong&gt; For personal use? Absolutely. For enterprise secrets? Maybe test it first. 😅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can you read my files?&lt;/strong&gt; Nope! Zero-knowledge means zero-knowledge. I don't have your password, so I can't decrypt anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if the server goes down?&lt;/strong&gt; If you used client-side mode (downloaded the .bar file), you're fine—it's on your machine. If you used server-side (link sharing), well... RIP. Back up important stuff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this actually secure?&lt;/strong&gt; I'm not a cryptographer, but I used industry-standard algorithms (AES-256, PBKDF2, HMAC-SHA256) implemented by people way smarter than me. The code is open source, so feel free to audit it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It, Break It, Tell Me About It
&lt;/h2&gt;

&lt;p&gt;Seriously, go play with it: &lt;strong&gt;&lt;a href="https://bar-rnr.vercel.app/" rel="noopener noreferrer"&gt;bar-rnr.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Upload a file, set it to self-destruct, feel like James Bond for 30 seconds. If you find bugs (or ways to break it), open an issue on GitHub. I accept PRs, feature requests, and memes.&lt;/p&gt;

&lt;p&gt;And if you're thinking "this is over-engineered for sharing cat pictures"—you're absolutely right. But wouldn't you rather share those cat pictures with &lt;strong&gt;military-grade encryption&lt;/strong&gt;? 😺🔐&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Made with ☕, 💻, and a healthy dose of paranoia.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. - Want the desktop version with the panic button? Check out &lt;a href="https://github.com/Mrtracker-new/BAR" rel="noopener noreferrer"&gt;github.com/Mrtracker-new/BAR&lt;/a&gt; for the 100% offline, extra-paranoid version! 🚨&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;strong&gt;Live Demo (Web):&lt;/strong&gt; &lt;a href="https://bar-rnr.vercel.app/" rel="noopener noreferrer"&gt;https://bar-rnr.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;strong&gt;GitHub (Web Version):&lt;/strong&gt; &lt;a href="https://github.com/Mrtracker-new/BAR_RYY" rel="noopener noreferrer"&gt;https://github.com/Mrtracker-new/BAR_RYY&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub (Desktop Version):&lt;/strong&gt; &lt;a href="https://github.com/Mrtracker-new/BAR" rel="noopener noreferrer"&gt;https://github.com/Mrtracker-new/BAR&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Questions?&lt;/strong&gt; Drop a comment below!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
