<?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>Forem: Niels</title>
    <description>The latest articles on Forem by Niels (@darkbranchcore).</description>
    <link>https://forem.com/darkbranchcore</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%2F3682905%2Fccceeb68-388c-4fae-b258-4d7b1513ecfb.png</url>
      <title>Forem: Niels</title>
      <link>https://forem.com/darkbranchcore</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/darkbranchcore"/>
    <language>en</language>
    <item>
      <title>I Tried to Beat the Market at 3AM… and Ended Up Debugging My Life</title>
      <dc:creator>Niels</dc:creator>
      <pubDate>Tue, 05 May 2026 15:55:17 +0000</pubDate>
      <link>https://forem.com/darkbranchcore/i-tried-to-beat-the-market-at-3am-and-ended-up-debugging-my-life-b4j</link>
      <guid>https://forem.com/darkbranchcore/i-tried-to-beat-the-market-at-3am-and-ended-up-debugging-my-life-b4j</guid>
      <description>&lt;p&gt;There’s a very specific kind of confidence that only shows up at 3AM.&lt;/p&gt;

&lt;p&gt;It’s the same confidence that makes you think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“This trade is obvious.”&lt;/li&gt;
&lt;li&gt;“Gas fees are fine.”&lt;/li&gt;
&lt;li&gt;“This smart contract definitely works.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spoiler: none of those were true.&lt;/p&gt;

&lt;p&gt;The Trade That Looked Too Easy&lt;/p&gt;

&lt;p&gt;A few months ago, I was staring at a chart like I had just unlocked the secrets of the universe.&lt;/p&gt;

&lt;p&gt;IT looked clean. Too clean.&lt;/p&gt;

&lt;p&gt;“Perfect breakout,” I said to myself — the same way developers say “&lt;em&gt;it works on my machine&lt;/em&gt;” right before production crashes.&lt;/p&gt;

&lt;p&gt;I jumped in.&lt;/p&gt;

&lt;p&gt;No risk management. No second thought. Just vibes.&lt;/p&gt;

&lt;p&gt;And within minutes, the market did what it always does to overconfident people:&lt;/p&gt;

&lt;p&gt;It humbled me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Developer Instinct Kicked In&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After the emotional damage settled, I did what every developer does when something breaks:&lt;/p&gt;

&lt;p&gt;I started debugging.&lt;/p&gt;

&lt;p&gt;Not just the trade — but the whole system behind it.&lt;/p&gt;

&lt;p&gt;Because trading, just like software engineering, isn’t about being right once.&lt;/p&gt;

&lt;p&gt;It’s about building systems that don’t collapse under pressure.&lt;/p&gt;

&lt;p&gt;From Charts to Code&lt;/p&gt;

&lt;p&gt;That’s when I started thinking beyond charts.&lt;/p&gt;

&lt;p&gt;“What if I treat trading like an engineering problem?”&lt;/p&gt;

&lt;p&gt;Instead of reacting emotionally, I began designing systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pulling market data using APIs&lt;/li&gt;
&lt;li&gt;Processing signals with Python&lt;/li&gt;
&lt;li&gt;Building backend logic with Django&lt;/li&gt;
&lt;li&gt;Creating event-driven workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because honestly, staring at charts all day is just manual labor with better branding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Real Problem: Humans&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s the uncomfortable truth:&lt;/p&gt;

&lt;p&gt;The biggest bug in any trading system isn’t the code.&lt;/p&gt;

&lt;p&gt;It’s the human.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Enter too early&lt;/li&gt;
&lt;li&gt;Exit too late&lt;/li&gt;
&lt;li&gt;Panic under volatility&lt;/li&gt;
&lt;li&gt;Overtrade out of boredom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this were a production system, we’d already be fired.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enter Blockchain: Where Mistakes Are Permanent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now add blockchain into the mix.&lt;/p&gt;

&lt;p&gt;At least in traditional systems, you can roll back.&lt;/p&gt;

&lt;p&gt;In blockchain?&lt;/p&gt;

&lt;p&gt;You deploy a broken smart contract… congratulations, it’s now immortal.&lt;/p&gt;

&lt;p&gt;I learned this the hard way while experimenting with Solidity.&lt;/p&gt;

&lt;p&gt;At some point, I thought:&lt;br&gt;
“Yeah, this contract is fine.”&lt;/p&gt;

&lt;p&gt;It wasn’t.&lt;/p&gt;

&lt;p&gt;Let’s just say — reading on-chain logs after a mistake hits differently when the transaction is already confirmed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event-Driven Thinking Changed Everything&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The real shift came when I stopped thinking in actions and started thinking in events.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I will manually place a trade”&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;“When X happens on-chain → trigger Y off-chain”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where things got interesting.&lt;/p&gt;

&lt;p&gt;Using tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web3.js / Ethers.js&lt;/li&gt;
&lt;li&gt;Event listeners for smart contracts&lt;/li&gt;
&lt;li&gt;Backend workers (Node.js / Python)&lt;/li&gt;
&lt;li&gt;Queue systems for handling load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I started building systems that react instead of panic.&lt;/p&gt;

&lt;p&gt;Because markets move fast — faster than your emotions, but not faster than well-designed architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance Matters (More Than Ego)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another lesson: performance is everything.&lt;/p&gt;

&lt;p&gt;It doesn’t matter how smart your strategy is if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your API is slow&lt;/li&gt;
&lt;li&gt;Your backend can’t scale&lt;/li&gt;
&lt;li&gt;Your event listener misses signals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At one point, my system was basically:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Works great… until it doesn’t.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Classic.&lt;/p&gt;

&lt;p&gt;So I had to think like an engineer again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Optimize requests&lt;/li&gt;
&lt;li&gt;Reduce latency&lt;/li&gt;
&lt;li&gt;Handle concurrency&lt;/li&gt;
&lt;li&gt;Prepare for unexpected load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because production doesn’t care about your intentions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trading Is Just Life in Disguise&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s where it gets philosophical.&lt;/p&gt;

&lt;p&gt;Trading, blockchain, and life… they’re all the same game.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Make decisions with incomplete information&lt;/li&gt;
&lt;li&gt;Deal with uncertainty&lt;/li&gt;
&lt;li&gt;Learn from mistakes (if you survive them)&lt;/li&gt;
&lt;li&gt;Build systems to protect yourself from yourself&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference?&lt;/p&gt;

&lt;p&gt;In trading, the feedback is immediate.&lt;/p&gt;

&lt;p&gt;In life, it takes longer — but it’s just as real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Final Realization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That 3AM trade wasn’t a failure.&lt;/p&gt;

&lt;p&gt;It was just… expensive education.&lt;/p&gt;

&lt;p&gt;It pushed me to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Think in systems, not impulses&lt;/li&gt;
&lt;li&gt;Combine engineering with decision-making&lt;/li&gt;
&lt;li&gt;Respect uncertainty instead of fighting it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now when I look at a chart, I don’t think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This is obvious.”&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;blockquote&gt;
&lt;p&gt;“What system would survive being wrong here?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Closing Thought&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re a developer getting into trading or blockchain, remember this:&lt;/p&gt;

&lt;p&gt;You don’t need better predictions.&lt;/p&gt;

&lt;p&gt;You need better systems.&lt;/p&gt;

&lt;p&gt;Because in the end:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code can fail&lt;/li&gt;
&lt;li&gt;Markets can crash&lt;/li&gt;
&lt;li&gt;Contracts can break&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But a well-designed mindset?&lt;/p&gt;

&lt;p&gt;That’s the only thing that scales.&lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>etherjs</category>
      <category>development</category>
    </item>
    <item>
      <title>Exploring the Future of Trading: Staking, Stocks, and Loans</title>
      <dc:creator>Niels</dc:creator>
      <pubDate>Sat, 18 Apr 2026 12:00:03 +0000</pubDate>
      <link>https://forem.com/tirixa-hub/exploring-the-future-of-trading-staking-stocks-and-loans-3586</link>
      <guid>https://forem.com/tirixa-hub/exploring-the-future-of-trading-staking-stocks-and-loans-3586</guid>
      <description>&lt;p&gt;The world of trading has always been a dynamic and fast-evolving domain. Whether you’re an investor looking to diversify your portfolio, a trader aiming to profit from market fluctuations, or someone seeking innovative ways to generate passive income, the landscape offers myriad opportunities. From traditional stock trading to emerging concepts like staking and decentralized finance (DeFi), the avenues to explore are broad and diverse. This article delves into key components of modern trading and offers insights into how staking, stocks, and loans intersect in today’s market.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Staking: A Passive Income Opportunity
&lt;/h2&gt;

&lt;p&gt;Staking has emerged as a powerful tool in the cryptocurrency ecosystem, allowing holders of digital assets to lock their tokens in a blockchain network to support its operations. In return, participants earn rewards, typically in the form of additional tokens. But why is this concept becoming more than just a niche activity?&lt;/p&gt;

&lt;p&gt;At its core, staking aligns the interests of token holders with the overall health and success of a blockchain network. When users stake their tokens, they help secure the network and validate transactions, enhancing the decentralization and security of the system. For those seeking passive income, staking offers an attractive alternative to traditional investment vehicles, where returns are generally tied to high-risk market movements.&lt;/p&gt;

&lt;p&gt;However, it’s important to consider that staking isn’t without risks. Depending on the blockchain, staking can require long-term commitment, and there is always the possibility of slashing—losing part of your staked tokens if you fail to comply with network rules.&lt;/p&gt;

&lt;p&gt;Despite this, staking provides an opportunity for diversification and exposure to a rapidly growing segment of the market. It is not just about making money off digital assets, but about participating in the long-term success of a decentralized ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stock Trading: The Traditional Yet Evolving Game
&lt;/h2&gt;

&lt;p&gt;While cryptocurrencies and DeFi platforms continue to capture attention, traditional stock trading remains a cornerstone of global finance. Stocks represent ownership in a company and have long been considered a primary way for individuals and institutions to invest in businesses and industries. From tech giants to emerging startups, the stock market offers a broad spectrum of opportunities to trade.&lt;/p&gt;

&lt;p&gt;However, as with any investment, stock trading involves risk. Prices fluctuate due to various factors—market sentiment, economic conditions, geopolitical events, and corporate performance. The rise of algorithmic trading and the democratization of trading platforms like Robinhood and Webull has further changed the landscape, making trading more accessible to retail investors. Today, anyone with a smartphone can buy and sell stocks, engage in fractional ownership, and utilize tools like options and margin trading.&lt;/p&gt;

&lt;p&gt;Moreover, advancements like AI-driven stock analysis and sentiment prediction tools are reshaping how traders make decisions. Algorithms now crunch vast amounts of data, providing insights that were once reserved for institutional investors. These tools can provide an edge, but they also come with the challenge of understanding the underlying algorithms and knowing when to trust the data they produce.&lt;/p&gt;

&lt;p&gt;Incorporating these AI-driven solutions into stock trading, however, requires both a keen understanding of market trends and technological proficiency. Balancing between data-driven insights and traditional market analysis is the key to navigating the complexities of stock trading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loans and Trading: A Growing Nexus
&lt;/h2&gt;

&lt;p&gt;While many associate loans with the realm of personal finance, they also play an increasingly vital role in the world of trading and investing. Margin trading, where investors borrow funds to increase their market exposure, is one example of how loans intersect with trading. This strategy amplifies potential returns but also comes with heightened risks—especially in volatile markets.&lt;/p&gt;

&lt;p&gt;In cryptocurrency markets, lending platforms have sprung up, allowing users to borrow or lend digital assets. For instance, in DeFi, platforms like Aave and Compound allow users to deposit cryptocurrencies to earn interest or borrow against their assets. In the world of stocks, margin loans are still widely used, enabling traders to borrow money from brokers to leverage their positions.&lt;/p&gt;

&lt;p&gt;However, while margin trading can enhance profits, it can also magnify losses. It’s essential to understand the implications of borrowed funds in trading and the need for strict risk management strategies. The key to using loans successfully in trading is ensuring that the potential rewards justify the risks taken and that you are well-prepared for any market downturns.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of Trading: Integration and Innovation
&lt;/h2&gt;

&lt;p&gt;As the world of finance evolves, so does the way we trade. From decentralized exchanges (DEXs) to automated trading systems, the future of trading is defined by integration and innovation. Staking, stocks, loans, and other trading mechanisms are becoming interconnected, offering a comprehensive ecosystem where digital and traditional assets coexist.&lt;/p&gt;

&lt;p&gt;The rise of blockchain technology and decentralized finance is pushing the boundaries of what is possible. Staking rewards and liquidity mining are becoming more intertwined with traditional markets, and it’s only a matter of time before we see deeper integration between these ecosystems. Trading platforms are adapting to this shift by offering more tools and assets to a broader audience, enabling both beginner and professional traders to participate in a unified marketplace.&lt;/p&gt;

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

&lt;p&gt;Trading is no longer confined to the realms of stock exchanges or crypto markets. With new innovations such as staking, margin loans, and DeFi protocols, the landscape is rapidly evolving. While there are significant opportunities to explore, understanding the risks and diversifying your strategies remains essential. Whether you’re staking digital assets for passive income, trading stocks with advanced algorithms, or using loans to leverage positions, it’s crucial to remain adaptable and informed.&lt;/p&gt;

&lt;p&gt;The future of trading isn’t about one asset class or strategy—it's about creating an ecosystem that thrives on innovation, collaboration, and a deeper understanding of the global financial markets. The next generation of traders will need to be as fluent in decentralized finance as they are in traditional investment techniques, and the best strategies will combine both to navigate this new era of financial opportunity.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>productivity</category>
      <category>architecture</category>
    </item>
    <item>
      <title>When Debugging Became Belonging: What Nearly 15 Years of Helping Developers Taught Me</title>
      <dc:creator>Niels</dc:creator>
      <pubDate>Mon, 30 Mar 2026 12:54:16 +0000</pubDate>
      <link>https://forem.com/tirixa-hub/when-debugging-became-belonging-what-nearly-15-years-of-helping-developers-taught-me-3amg</link>
      <guid>https://forem.com/tirixa-hub/when-debugging-became-belonging-what-nearly-15-years-of-helping-developers-taught-me-3amg</guid>
      <description>&lt;p&gt;The first time code made me question my place in tech, it was not elegant.&lt;/p&gt;

&lt;p&gt;It was not cinematic either, unless your favorite genre is “junior developer stares at legacy JavaScript while silently bargaining with the universe.” Mine happened on a gray Monday morning, the kind of morning where even coffee feels underqualified. I had just been given my first real bug on my first real project at a company paying me real money to write code. That should have felt empowering. Instead, it felt like being handed a fork and asked to repair a jet engine.&lt;/p&gt;

&lt;p&gt;The instruction was almost offensive in its simplicity: “Just fix this bug.”&lt;/p&gt;

&lt;p&gt;Anyone who has worked with old code knows that “just” is one of the most dangerous words in software development. I opened the file and found the usual archaeological layers of logic, half-decisions, mysterious comments, and code that looked like three different developers had fought each other and the code had won. I tried to run the app. Errors. I changed something. More errors. I changed something else. New errors, different font, same emotional damage.&lt;/p&gt;

&lt;p&gt;For a while, I did what many early-career developers do but rarely admit out loud: I mistook confusion for incompetence.&lt;/p&gt;

&lt;p&gt;I was not only debugging the application. I was debugging my confidence. I wondered whether I belonged in tech, whether the recruiter had emailed the wrong person, whether my future career path might somehow involve leaving software altogether and becoming a professional yodeler in Switzerland. It felt dramatic at the time. In hindsight, it was dramatic. But it was also real.&lt;/p&gt;

&lt;p&gt;And then I did the thing that scared me most.&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%2Fgrr5ftcnphczuu233mcs.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%2Fgrr5ftcnphczuu233mcs.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I asked for help.&lt;/p&gt;

&lt;p&gt;I still remember how big that tiny sentence felt: “I’m stuck. I don’t know what to do.”&lt;/p&gt;

&lt;p&gt;What changed me was not just that someone answered. It was how she answered. A senior engineer walked me through the logic without making me feel small. She did not treat my confusion like a personal failure. She treated it like part of the craft. She showed me where the code bent, where it broke, and where I could safely touch it without summoning six new production incidents. Less than an hour later, I fixed the bug.&lt;/p&gt;

&lt;p&gt;That should have been the victory. But it was not.&lt;/p&gt;

&lt;p&gt;The real victory was learning that asking for help was not proof that I was weak. It was proof that I was still in the fight.&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%2Fmyqbd5uw6d9og8rct0kx.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%2Fmyqbd5uw6d9og8rct0kx.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That lesson stayed with me far longer than the bug did. Since then, I have met deadlines that felt like punishment, APIs that behaved like they had a private grudge against me, and merge conflicts that probably qualify as spiritual warfare. But I have also learned that growth in this industry rarely arrives looking polished. Usually it arrives wearing panic, carrying a stack trace, and asking whether you have tried turning your assumptions off and on again.&lt;/p&gt;

&lt;p&gt;That is one reason the idea of WeCoded matters to me.&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%2Fs68qlkhqbzfxdc3bvtmj.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%2Fs68qlkhqbzfxdc3bvtmj.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Too many developers, especially those from underrepresented and marginalized genders, spend part of their careers being made to feel that uncertainty is something shameful. That not knowing is a flaw. That asking questions is a weakness. But the healthiest technical spaces I have ever seen were not the ones full of people performing brilliance. They were the ones full of people practicing generosity.&lt;/p&gt;

&lt;p&gt;The engineers who changed my life were not always the loudest people in the room. They were the ones who made room. They explained without humiliating. They corrected without performing superiority. They understood that inclusion is not a slogan you put on a company page. It is a daily engineering practice. It is visible in code reviews, in mentoring, in who gets heard, in who gets interrupted, in who feels safe saying, “I don’t understand this yet.”&lt;/p&gt;

&lt;p&gt;That word matters: yet.&lt;/p&gt;

&lt;p&gt;Because “yet” has carried a lot of developers farther than talent alone ever could.&lt;/p&gt;

&lt;p&gt;For me, that journey did not stop at surviving hard moments in code. Over time, it turned into a habit of showing up for other developers too. For nearly fifteen years, I have been active on Stack Overflow under the name Niels, where I have built a record of more than 50,000 reputation, 680 answers, and 40 questions, with strong activity around JavaScript, jQuery, MySQL, HTML, and PHP. &lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://stackoverflow.com/users/1041948/niels" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstackoverflow.com%2FContent%2FSites%2Fstackoverflow%2FImg%2Fapple-touch-icon%402.png%3Fv%3D0f0cab681579" height="360" class="m-0" width="360"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://stackoverflow.com/users/1041948/niels" rel="noopener noreferrer" class="c-link"&gt;
            User Niels - Stack Overflow
          &lt;/a&gt;
        &lt;/h2&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstackoverflow.com%2FContent%2FSites%2Fstackoverflow%2FImg%2Ffavicon.ico%3Fv%3D562fb39d93c8" width="48" height="48"&gt;
          stackoverflow.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;My profile still describes the same practical mix of technologies and the same instinct to help others that shaped me early on.&lt;/p&gt;

&lt;p&gt;And honestly, that long Stack Overflow chapter taught me something important about community: most of software is not built by isolated genius. It is built by people answering each other’s questions on ordinary weekdays.&lt;/p&gt;

&lt;p&gt;One person asks why their URL parameters are breaking. Another asks how to reset an auto-increment value in MySQL. Someone else is fighting jQuery, as humanity has done for generations. The problems are rarely glamorous, but the act itself is powerful. Every answer is a small vote for access. Every explanation says, “You do not have to stay stuck here alone.”&lt;/p&gt;

&lt;p&gt;That same spirit is exactly why I wanted my first real Dev.to post to be more than just another article sitting in a browser tab.&lt;/p&gt;

&lt;p&gt;So I built something around the reading experience itself.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/yDOffm739Ag"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The project I prepared is Always with Dev.to — Desktop Client, a cross-platform Electron desktop application designed to wrap Dev.to into a more native, focused experience. It uses vanilla JavaScript, HTML, and CSS inside Electron, with an embedded Express backend that proxies the Dev.to public API, handles authentication, and manages caching, all packaged into a single portable executable with no installation required.&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%2Fhb3f6gt6xzdhyep13e44.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%2Fhb3f6gt6xzdhyep13e44.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I love about that project is that it reflects how I now think about software: not just “Does it run?” but “Does it make the experience kinder, simpler, and more useful?”&lt;/p&gt;

&lt;p&gt;The interesting part was not only the interface. It was the engineering behind the convenience. I embedded the backend directly into the Electron main process rather than forcing a separate backend service and extra orchestration. I packaged the app as a single portable .exe while carrying the backend resources with it. I added in-memory LRU caching with TTL and pattern invalidation to avoid hammering the Dev.to API. I used retry logic with exponential backoff for transient failures, added lazy Supabase initialization for authentication, and documented lessons from painful but useful issues like response-shape mismatches, temporal dead zone crashes, and a later layered-architecture refactor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embedding a backend server inside Electron&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The challenge: Electron apps typically need a separate backend process, requiring IPC, process spawning, and port management. Instead, the Express server runs directly inside the Electron main process.&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;// frontend/main.js&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;startEmbeddedBackend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isDev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isPackaged&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isDev&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resourcesPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;envPath&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serverPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isDev&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resourcesPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;serverPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Backend server started on port 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Backend failed to start:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;whenReady&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;startEmbeddedBackend&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// server starts before window opens&lt;/span&gt;
  &lt;span class="nf"&gt;createWindow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;require(serverPath)&lt;/code&gt; loads the Express app into the same Node.js process Electron is already running. No child process, no IPC, no port negotiation. The &lt;code&gt;.env&lt;/code&gt; path switches between dev (source tree) and production (&lt;code&gt;process.resourcesPath&lt;/code&gt;) automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building a single portable .exe&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The challenge: packaging an Electron app with an embedded Express backend — including all backend &lt;code&gt;node_modules&lt;/code&gt; — into one file that runs without installation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;frontend/package.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"win"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"portable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"arch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"x64"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"icon.ico"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"signAndEditExecutable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extraResources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../backend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"backend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"filter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"**/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"!*.log"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"**/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"!node_modules/.cache"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"!**/*.map"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"!**/*.md"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"directories"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../dist"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;extraResources&lt;/code&gt; copies the entire &lt;code&gt;backend/&lt;/code&gt; folder (including its &lt;code&gt;node_modules&lt;/code&gt;) into the packaged app's &lt;code&gt;resources/&lt;/code&gt; directory. At runtime, &lt;code&gt;process.resourcesPath&lt;/code&gt; points there. The original config had &lt;code&gt;!node_modules/**&lt;/code&gt; in the filter — that excluded backend deps and broke the embedded server at runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bypassing Windows symlink restriction during build&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The challenge: &lt;code&gt;electron-builder&lt;/code&gt; downloads &lt;code&gt;winCodeSign-2.6.0.7z&lt;/code&gt; which contains macOS symlinks (&lt;code&gt;libcrypto.dylib&lt;/code&gt;, &lt;code&gt;libssl.dylib&lt;/code&gt;). Extracting it on Windows without Developer Mode fails with &lt;code&gt;Cannot create symbolic link: A required privilege is not held by the client.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// frontend/node_modules/electron-builder/node_modules/&lt;/span&gt;
&lt;span class="c1"&gt;//   app-builder-lib/out/binDownload.js  (patched)&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doGetBin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// winCodeSign archive contains macOS symlinks that fail to extract&lt;/span&gt;
  &lt;span class="c1"&gt;// on Windows without Developer Mode. Return the already-extracted&lt;/span&gt;
  &lt;span class="c1"&gt;// cache folder directly to skip the download+extract entirely.&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;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;winCodeSign&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;os&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ELECTRON_BUILDER_CACHE&lt;/span&gt;
      &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;homedir&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AppData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electron-builder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;winCodeSign&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;014093675&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;download-artifact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="nx"&gt;url&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;checksum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--sha512&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;executeAppBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This patch was applied to all three copies of &lt;code&gt;binDownload.js&lt;/code&gt; across &lt;code&gt;electron-builder&lt;/code&gt;, &lt;code&gt;dmg-builder&lt;/code&gt;, and &lt;code&gt;electron-builder-squirrel-windows&lt;/code&gt;. Combined with &lt;code&gt;"signAndEditExecutable": false&lt;/code&gt; in the build config to skip the &lt;code&gt;rcedit&lt;/code&gt; step that also triggers the same download.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In-memory LRU cache with TTL and pattern invalidation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The challenge: Dev.to API has rate limits. Every page load hitting the API directly would be slow and risk throttling. Need a fast in-process cache with automatic expiry and the ability to bust related keys when data changes.&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;// backend/server.js&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LRUCache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CACHE_MAX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_maxSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;maxSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &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;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// LRU: delete and re-insert to move to end of Map iteration order&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_maxSize&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// evict the oldest entry (first key in Map)&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;exp&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;ttl&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;invalidatePattern&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;re&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\*&lt;/span&gt;&lt;span class="sr"&gt;/g&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="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage: bust all article list caches when a reaction is posted&lt;/span&gt;
&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invalidatePattern&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;articles:*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Map&lt;/code&gt; preserves insertion order, so the first key is always the oldest — O(1) LRU eviction without a doubly-linked list. TTL is stored per-entry as an absolute expiry timestamp, checked on read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev.to API proxy with exponential back-off retry&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The challenge: network calls to Dev.to can fail transiently. Retrying immediately hammers the server. 4xx errors (bad request, unauthorized) should never be retried — only transient 5xx and network failures.&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;// backend/server.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devtoAxios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_BASE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEVTO_TIMEOUT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;API_HEADERS&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Per-request api-key injection without polluting the instance defaults&lt;/span&gt;
&lt;span class="nx"&gt;devtoAxios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cfg&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;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_apiKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_apiKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_apiKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;withRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RETRY_COUNT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RETRY_DELAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// never retry client errors — they won't succeed on retry&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;throw&lt;/span&gt; &lt;span class="nx"&gt;e&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 500ms, 1s, 2s&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;devtoGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;withRetry&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;devtoAxios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;_apiKey&lt;/code&gt; trick lets each request carry its own Dev.to API key (from the logged-in user's header) without overwriting the shared Axios instance's default headers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JWT authentication with Supabase as user store&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The challenge: the app needs user accounts (to save API keys, bookmarks, etc.) but can't bundle a database. Supabase provides a hosted Postgres. The client must initialise lazily — if env vars are missing, the app should still run for unauthenticated browsing.&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;// backend/server.js&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;_supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSupabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_supabase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_supabase&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// graceful degradation&lt;/span&gt;
  &lt;span class="nx"&gt;_supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SUPABASE_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;autoRefreshToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;persistSession&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_supabase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;authLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&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;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getSupabase&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sendUnavail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Database not configured&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sb&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id, username, email, password_hash, devto_api_key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sendError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HTTP_UNAUTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email or password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;valid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare&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;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password_hash&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sendError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HTTP_UNAUTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email or password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// fire-and-forget — don't block the login response&lt;/span&gt;
  &lt;span class="nx"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;last_login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;catch&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;return&lt;/span&gt; &lt;span class="nf"&gt;sendOk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildUserToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bcrypt.compare&lt;/code&gt; is timing-safe — it takes the same time whether the user exists or not, preventing timing-based user enumeration attacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response envelope compatibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The challenge: refactoring introduced a &lt;code&gt;{ success, data }&lt;/code&gt; wrapper around all responses. The frontend's &lt;code&gt;api.js&lt;/code&gt; does &lt;code&gt;const data = await res.json()&lt;/code&gt; and immediately uses &lt;code&gt;data&lt;/code&gt; as an array — &lt;code&gt;data.filter(...)&lt;/code&gt;, &lt;code&gt;data.map(...)&lt;/code&gt;. The wrapper broke every single page with "Unexpected response".&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;// BROKEN — frontend does data.filter(...) which fails on { success, data }&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// FIXED — return raw data, frontend gets the array directly&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Error shape stays as { error: '...' } — frontend checks data.error&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// frontend/js/api.js (unchanged — this is what it expects)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cachedFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// data is used directly as array — no .data unwrapping&lt;/span&gt;
  &lt;span class="nx"&gt;fetchCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;exp&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;ttl&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lesson: when adding a backend in front of an existing frontend, match the existing API contract exactly. Changing the response shape is a breaking change even if the status code is still 200.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ReferenceError from temporal dead zone&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`server.js`&lt;/span&gt; &lt;span class="nx"&gt;grew&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="nx"&gt;added&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;different&lt;/span&gt; &lt;span class="nx"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;`app.use(loggerHelper.logRequest)`&lt;/span&gt; &lt;span class="nx"&gt;was&lt;/span&gt; &lt;span class="nx"&gt;placed&lt;/span&gt; &lt;span class="nx"&gt;at&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;284&lt;/span&gt; &lt;span class="nx"&gt;during&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;but&lt;/span&gt; &lt;span class="s2"&gt;`const app = express()`&lt;/span&gt; &lt;span class="nx"&gt;was&lt;/span&gt; &lt;span class="nx"&gt;at&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;991&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="c1"&gt;// line 284 — CRASHES: const is not hoisted, TDZ throws ReferenceError&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loggerHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ReferenceError: Cannot access 'app' before initialization&lt;/span&gt;

&lt;span class="c1"&gt;// ... 700 lines later ...&lt;/span&gt;

&lt;span class="c1"&gt;// line 991 — app is declared here&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1mb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestLogger&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loggerHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// FIXED: moved here, after app exists&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;var&lt;/code&gt; would have hoisted and silently been &lt;code&gt;undefined&lt;/code&gt; at line 284, causing a different error (&lt;code&gt;TypeError: Cannot read properties of undefined&lt;/code&gt;). &lt;code&gt;const&lt;/code&gt; throws immediately and clearly. The fix is always to keep all &lt;code&gt;app.use()&lt;/code&gt; calls in one place, after &lt;code&gt;const app = express()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layered architecture refactor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The challenge: a single 200-line &lt;code&gt;server.js&lt;/code&gt; with routes, auth logic, caching, and HTTP client all mixed together. Adding features meant scrolling through everything. Testing any piece required the whole file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:                          After:
backend/                         backend/
  server.js  (200 lines,           config/
  everything mixed)                  app.config.js    (env vars)
                                     constants.js     (HTTP codes, keys)
                                     database.config.js (Supabase client)
                                   controllers/
                                     article.controller.js
                                     auth.controller.js
                                   services/
                                     devto-api.service.js (all API calls)
                                     auth.service.js      (register/login)
                                     cache.service.js     (TTL wrappers)
                                   middleware/
                                     auth.middleware.js
                                     error.middleware.js
                                   routes/
                                     article.routes.js
                                     auth.routes.js
                                   utils/
                                     cache.util.js
                                     http-client.util.js
                                     token.util.js
                                   server.js  (slim entry, ~40 lines)

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

&lt;/div&gt;



&lt;p&gt;Each layer has one job. Controllers handle HTTP in/out. Services contain business logic with no &lt;code&gt;req/res&lt;/code&gt; knowledge. Utils are pure functions. This means &lt;code&gt;devto-api.service.js&lt;/code&gt; can be tested without Express, and &lt;code&gt;auth.middleware.js&lt;/code&gt; can be swapped without touching routes.&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;th&gt;Usage in This Project&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;Node.js v18+&lt;/td&gt;
&lt;td&gt;Server runtime embedded inside Electron main process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desktop&lt;/td&gt;
&lt;td&gt;Electron 28&lt;/td&gt;
&lt;td&gt;Cross-platform desktop shell, window management, IPC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend Framework&lt;/td&gt;
&lt;td&gt;Express 4&lt;/td&gt;
&lt;td&gt;REST API server, middleware pipeline, route handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP Client&lt;/td&gt;
&lt;td&gt;Axios&lt;/td&gt;
&lt;td&gt;Dev.to API proxy with interceptors and retry logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;JWT (jsonwebtoken)&lt;/td&gt;
&lt;td&gt;Stateless session tokens, Bearer auth middleware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Password Security&lt;/td&gt;
&lt;td&gt;bcryptjs&lt;/td&gt;
&lt;td&gt;Salted password hashing, timing-safe comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Supabase (Postgres)&lt;/td&gt;
&lt;td&gt;Hosted user store, lazy client initialization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caching&lt;/td&gt;
&lt;td&gt;Custom LRU + TTL&lt;/td&gt;
&lt;td&gt;In-memory cache with pattern invalidation, O(1) eviction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build Tool&lt;/td&gt;
&lt;td&gt;electron-builder&lt;/td&gt;
&lt;td&gt;Portable single &lt;code&gt;.exe&lt;/code&gt; packaging, extraResources bundling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Vanilla JS / HTML / CSS&lt;/td&gt;
&lt;td&gt;No framework, direct DOM manipulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment&lt;/td&gt;
&lt;td&gt;dotenv&lt;/td&gt;
&lt;td&gt;Runtime env switching between dev and packaged paths&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Architecture Skills&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Layered architecture&lt;/td&gt;
&lt;td&gt;config / controllers / services / middleware / routes / utils separation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Embedded server pattern&lt;/td&gt;
&lt;td&gt;Express running inside Electron main process — no child process or IPC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-aside pattern&lt;/td&gt;
&lt;td&gt;Check cache → miss → fetch API → populate cache → return&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exponential back-off retry&lt;/td&gt;
&lt;td&gt;Transient failures retried with &lt;code&gt;delay * 2^attempt&lt;/code&gt;, 4xx never retried&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graceful degradation&lt;/td&gt;
&lt;td&gt;App runs without Supabase configured — auth disabled, browsing works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API contract preservation&lt;/td&gt;
&lt;td&gt;Backend response shape matched existing frontend without changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Middleware composition&lt;/td&gt;
&lt;td&gt;Auth, logging, validation, error handling as independent Express middleware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build pipeline patching&lt;/td&gt;
&lt;td&gt;Patched &lt;code&gt;binDownload.js&lt;/code&gt; in 3 locations to bypass Windows symlink restriction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Problems Solved&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Root Cause&lt;/th&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Single &lt;code&gt;.exe&lt;/code&gt; with embedded backend&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;node_modules&lt;/code&gt; excluded from &lt;code&gt;extraResources&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Removed &lt;code&gt;!node_modules/**&lt;/code&gt; filter in build config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build fails on Windows&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;winCodeSign&lt;/code&gt; archive contains macOS symlinks&lt;/td&gt;
&lt;td&gt;Patched &lt;code&gt;doGetBin()&lt;/code&gt; + &lt;code&gt;signAndEditExecutable: false&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Unexpected response" on all pages&lt;/td&gt;
&lt;td&gt;Response wrapped in &lt;code&gt;{ success, data }&lt;/code&gt; envelope&lt;/td&gt;
&lt;td&gt;Returned raw data — matched existing frontend contract&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ReferenceError: Cannot access 'app'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;app.use()&lt;/code&gt; called before &lt;code&gt;const app = express()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Moved all &lt;code&gt;app.use()&lt;/code&gt; calls after app initialization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev.to API rate limiting&lt;/td&gt;
&lt;td&gt;Every render hitting the API directly&lt;/td&gt;
&lt;td&gt;LRU cache with per-resource TTLs (1–10 min)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stale reaction counts after like&lt;/td&gt;
&lt;td&gt;Cache not invalidated on mutation&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cache.invalidatePattern('articles:*')&lt;/code&gt; on POST/DELETE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User enumeration via timing&lt;/td&gt;
&lt;td&gt;Login returning early on unknown email&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;bcrypt.compare&lt;/code&gt; always runs regardless of user existence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monolithic server hard to maintain&lt;/td&gt;
&lt;td&gt;All logic in one 200-line file&lt;/td&gt;
&lt;td&gt;Refactored into 6 layers, 20+ files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend path wrong in packaged app&lt;/td&gt;
&lt;td&gt;Dev path &lt;code&gt;../backend&lt;/code&gt; invalid after packaging&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;process.resourcesPath&lt;/code&gt; used in production, &lt;code&gt;__dirname&lt;/code&gt; in dev&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That project is technical, yes. But to me it is also personal.&lt;/p&gt;

&lt;p&gt;Because underneath all the implementation details is a very human belief: developers deserve tools that meet them with less friction, not more. We spend enough time wrestling complexity. Good software should not add ego to the burden.&lt;/p&gt;

&lt;p&gt;That is also what I think gender equity in tech should look like in practice. Not just opening the door and walking away, but designing better rooms once people get inside. Rooms where curiosity is not punished. Rooms where beginners are not treated like inconveniences. Rooms where expertise is shared in a way that multiplies confidence instead of hoarding status.&lt;/p&gt;

&lt;p&gt;I did not stay in tech because every experience was welcoming. I stayed because enough people, at crucial moments, chose to be generous.&lt;/p&gt;

&lt;p&gt;A patient senior engineer.&lt;br&gt;
A stranger answering a question online.&lt;br&gt;
A community that reminds you that even experienced developers still get stuck, still learn, still rewrite the same thing three times before pretending it was intentional.&lt;/p&gt;

&lt;p&gt;So when I think about the “echoes of experience,” I do not think only about the painful moments. I think about what answered them.&lt;/p&gt;

&lt;p&gt;Patience.&lt;br&gt;
Humor.&lt;br&gt;
Persistence.&lt;br&gt;
Community.&lt;/p&gt;

&lt;p&gt;And yes, sometimes coffee.&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%2Fdm2a54jiimlomifxuse5.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%2Fdm2a54jiimlomifxuse5.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I still have hard days. I still meet code that looks like it was written during a minor electrical storm. I still occasionally open a file and feel my soul leave my body for a second. But I no longer confuse that feeling with failure.&lt;/p&gt;

&lt;p&gt;Now I recognize it for what it usually is:&lt;/p&gt;

&lt;p&gt;the start of learning,&lt;br&gt;
the invitation to ask,&lt;br&gt;
and another chance to make this industry more human than I found it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try the project yourself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to experience Always with Dev.to — Desktop Client directly, you can check the project here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/wvalencs/devTo-electron" rel="noopener noreferrer"&gt;https://github.com/wvalencs/devTo-electron&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run locally&lt;/p&gt;

&lt;p&gt;1.Clone the repository&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/wvalencs/devTo-electron.git
&lt;span class="nb"&gt;cd &lt;/span&gt;devTo-electron
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.Install dependencies&lt;/p&gt;

&lt;p&gt;Install dependencies for both the frontend and backend parts of the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;backend
npm &lt;span class="nb"&gt;install
cd&lt;/span&gt; ../frontend
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.Start the application in development mode&lt;/p&gt;

&lt;p&gt;Run the Electron frontend, which will start the embedded backend automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;backend
npm start
&lt;span class="nb"&gt;cd &lt;/span&gt;frontend
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.Build portable executable&lt;/p&gt;

&lt;p&gt;To generate the portable desktop app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;frontend
npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the build is complete, the packaged app will be available in the dist folder.&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%2Ft3k6hor04bo7s2hyeu93.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%2Ft3k6hor04bo7s2hyeu93.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want, next I can turn this into a true Dev.to-ready version with a stronger hook, cleaner section headers, and final tags.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>wecoded</category>
      <category>dei</category>
      <category>career</category>
    </item>
  </channel>
</rss>
