<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged web</title>
<link>https://coderlegion.com/tag/web</link>
<description>Powered by Question2Answer</description>
<item>
<title>How to Fix Core Web Vitals: LCP, CLS &amp; INP | FloxoLab</title>
<link>https://coderlegion.com/25677/how-to-fix-core-web-vitals-lcp-cls-inp-floxolab</link>
<description>
&lt;p&gt;
        Core Web Vitals are three numbers Google uses to measure how a page feels to a real person: how fast the main content loads, whether the layout jumps around while it does, and how quickly the page reacts when you tap or click. They are one part of page experience, which Google says its core ranking systems seek to reward. They do not override relevance or useful content.
      &lt;/p&gt;
      &lt;p&gt;
        This guide explains each of the three, plus the supporting numbers you will see in the same report, and then shows the real fixes that took this site's mobile Lighthouse performance score from 77 to 98. Nothing here is theory. It is the same work I run on client sites in an &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo-audit&quot;&gt;SEO audit&lt;/a&gt;.
      &lt;/p&gt;

      &lt;h2 id=&quot;what-a-good-result-looks-like&quot;&gt;What a good result looks like&lt;/h2&gt;
      &lt;p&gt;
        In the July 2026 PageSpeed Insights test shown below, this site scored 98 on mobile and 100 on desktop using the same code. The two tests look different because mobile is run on a throttled, slower simulated device, so it always has less room to work with. Mobile is often the harder target, and it deserves priority when most of your visitors use phones. Google measures mobile and desktop field data separately, so check both instead of treating one Lighthouse score as the final answer.
      &lt;/p&gt;

      &lt;div class=&quot;figure-pair&quot;&gt;
        &lt;figure class=&quot;article-figure&quot;&gt;
          &lt;img width=&quot;980&quot; height=&quot;891&quot; src=&quot;https://floxolab.com/uploads/seo/guides/how-to-fix-core-web-vitals/mobile.webp?v=20260707&quot; alt=&quot;PageSpeed Insights mobile report for this site: performance 98, LCP 1.9 seconds, CLS 0, total blocking time 40 milliseconds, all green&quot;&gt;
          &lt;figcaption&gt;Mobile: performance 98, LCP 1.9s, CLS 0, all vitals in the green.&lt;/figcaption&gt;
        &lt;/figure&gt;
        &lt;figure class=&quot;article-figure&quot;&gt;
          &lt;img width=&quot;979&quot; height=&quot;887&quot; src=&quot;https://floxolab.com/uploads/seo/guides/how-to-fix-core-web-vitals/desktop.webp?v=20260707&quot; alt=&quot;PageSpeed Insights desktop report for this site: performance 100, LCP 0.5 seconds, CLS 0, and speed index 0.4 seconds&quot;&gt;
          &lt;figcaption&gt;Desktop: performance 100, LCP 0.5s, CLS 0, speed index 0.4s.&lt;/figcaption&gt;
        &lt;/figure&gt;
      &lt;/div&gt;

      &lt;h2 id=&quot;the-three-core-web-vitals-one-at-a-time&quot;&gt;The three Core Web Vitals, one at a time&lt;/h2&gt;
      &lt;p&gt;
        Everything on the scoreboard comes down to three real-user metrics. A page passes when 75 percent of real visitors fall inside the &quot;good&quot; band for each.
      &lt;/p&gt;

      &lt;div class=&quot;article-table-wrap&quot;&gt;
        &lt;table class=&quot;article-table&quot;&gt;
          &lt;thead&gt;
            &lt;tr&gt;
              &lt;th&gt;Metric&lt;/th&gt;
              &lt;th&gt;Measures&lt;/th&gt;
              &lt;th&gt;Good&lt;/th&gt;
              &lt;th&gt;Poor&lt;/th&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
            &lt;tr&gt;
              &lt;td&gt;LCP (Largest Contentful Paint)&lt;/td&gt;
              &lt;td&gt;Loading&lt;/td&gt;
              &lt;td&gt;2.5s or less&lt;/td&gt;
              &lt;td&gt;Over 4s&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;CLS (Cumulative Layout Shift)&lt;/td&gt;
              &lt;td&gt;Visual stability&lt;/td&gt;
              &lt;td&gt;0.1 or less&lt;/td&gt;
              &lt;td&gt;Over 0.25&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;INP (Interaction to Next Paint)&lt;/td&gt;
              &lt;td&gt;Responsiveness&lt;/td&gt;
              &lt;td&gt;200ms or less&lt;/td&gt;
              &lt;td&gt;Over 500ms&lt;/td&gt;
            &lt;/tr&gt;
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/div&gt;

      &lt;h3&gt;LCP: how fast the main thing loads&lt;/h3&gt;
      &lt;p&gt;
        Largest Contentful Paint is the moment the biggest element in view finishes rendering, usually the hero image or the headline block. It is the reader's gut sense of &quot;has this page loaded yet&quot;. What drags it down is nearly always one of four things: a heavy, uncompressed hero image, a slow server or host, render-blocking CSS and JavaScript that must run before anything paints, and web fonts that arrive late.
      &lt;/p&gt;
      &lt;p&gt;
        The fixes follow the causes. Compress and serve the hero as WebP at the right size, and preload it so the browser fetches it early. Use srcset so a phone pulls a small version and a desktop a larger one, instead of shipping one heavy file to every device. That is a separate lever from preloading: preload fetches the image sooner, srcset makes sure it is the right weight, and on a slow mobile connection the srcset part is often what saves the most. Cut or defer render-blocking scripts, and self-host your fonts instead of pulling them from a third-party domain. On this site LCP is 1.9s on mobile and 0.5s on desktop, and the single biggest lever was the hero image: right format, right size per device, preloaded.
      &lt;/p&gt;

      &lt;h3&gt;CLS: whether the page holds still&lt;/h3&gt;
      &lt;p&gt;
        Cumulative Layout Shift measures how much the content jumps around as the page loads. You have felt it: you go to tap a link, an image or banner loads above it, and the whole page shoves down. The usual culprits are images and embeds with no width and height set, ad or banner slots injected after load, and fonts that swap and reflow the text.
      &lt;/p&gt;
      &lt;p&gt;
        This is the most fixable vital, and the cheapest win on the list. Put explicit width and height (or an aspect ratio) on every image and iframe so the browser reserves the space before the file arrives. Give injected elements a fixed slot. Set font-display so a font swap does not reshuffle the layout. This site sits at a CLS of 0, and it got there almost entirely by adding size attributes to images.
      &lt;/p&gt;

      &lt;h3&gt;INP: how fast the page answers you&lt;/h3&gt;
      &lt;p&gt;
        Interaction to Next Paint replaced First Input Delay in March 2024. It measures the delay between you doing something, a tap, a click, a keypress, and the page actually showing a response, taking close to the worst interaction across the whole visit. A high INP is a page that feels sluggish and unresponsive, and the cause is almost always JavaScript hogging the main thread: heavy frameworks, big third-party scripts, and long tasks that block the browser from reacting. It is also the vital the most sites fail, so it is worth the attention.
      &lt;/p&gt;
      &lt;p&gt;
        The fix is to give the main thread less to do. Defer or split heavy JavaScript, hold third-party scripts off the critical path until the user needs them, and break long tasks into smaller pieces. This site now runs without client-side behavioral analytics, which removes one common source of third-party main-thread work. On sites that need analytics or other third-party scripts, keep them off the critical path and verify that delayed loading does not break consent or measurement. In the lab result shown above, total blocking time, the lab stand-in for INP, was 40 milliseconds.
      &lt;/p&gt;

      &lt;h2 id=&quot;the-other-numbers-in-the-report&quot;&gt;The other numbers in the report&lt;/h2&gt;
      &lt;p&gt;
        The same Lighthouse report shows three more metrics. These are lab diagnostics, useful for finding problems, but they are not the vitals Google ranks on.
      &lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;First Contentful Paint (FCP).&lt;/strong&gt; When the first text or image appears. An early signal that something is happening.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Total Blocking Time (TBT).&lt;/strong&gt; How long the main thread was blocked during load. It is the lab proxy for INP, so lowering TBT usually lowers INP for real users too.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Speed Index.&lt;/strong&gt; How quickly the page visibly fills in. On this site it shows 3.5s on mobile and lands in the amber band, while every actual vital is green. That is a fair reminder that the overall score is a blend, and a single amber lab number is not worth panicking over when the real-user vitals all pass.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;h2 id=&quot;lab-data-and-field-data-are-not-the-same&quot;&gt;Lab data and field data are not the same&lt;/h2&gt;
      &lt;p&gt;
        There are two ways to measure all of this, and mixing them up causes a lot of confusion. &lt;strong&gt;Lab data&lt;/strong&gt; is a single simulated test, like the Lighthouse run in the screenshots above, on a fixed device and connection. It is repeatable and great for debugging. &lt;strong&gt;Field data&lt;/strong&gt; is what real Chrome users actually experienced over the last 28 days, and it is what Google uses for ranking. You can see your own field data in the Core Web Vitals report inside Search Console.
      &lt;/p&gt;
      &lt;p&gt;
        The practical order: use the lab test to find and fix problems fast, then watch the field data in Search Console to confirm real users feel the change. A lab score can be perfect while the field still lags, especially on a page that only just got fixed, because the field window is a rolling average. Reading that report is part of the wider habit covered in &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/how-to-read-your-monthly-seo-report&quot;&gt;how to read your monthly SEO report&lt;/a&gt;.
      &lt;/p&gt;
      &lt;p&gt;
        When performance is only one concern on a specific URL, place this diagnosis inside an &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/on-page-seo-audit-checklist&quot;&gt;on-page audit of its indexability, search task, content, links, media, and validation&lt;/a&gt;. That keeps a Lighthouse number from replacing the wider page decision.
      &lt;/p&gt;
      &lt;p&gt;
        A mobile performance score also does not prove that Googlebot and customers receive complete content, usable navigation, accessible controls, or a working form. Check those separately with the &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/mobile-seo-checklist&quot;&gt;mobile SEO checklist for rendering, content parity, and real phone tasks&lt;/a&gt;.
      &lt;/p&gt;
      &lt;p&gt;
        If the site has not launched yet, set media, script, layout-stability, and representative-template budgets in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/seo-friendly-web-design-checklist&quot;&gt;SEO-friendly web design checklist&lt;/a&gt;. Performance is cheaper to protect in the design contract than to recover after every component is approved.
      &lt;/p&gt;

      &lt;h2 id=&quot;what-actually-moved-this-site-from-77-to-98&quot;&gt;What actually moved this site from 77 to 98&lt;/h2&gt;
      &lt;p&gt;
        The jump was not one clever trick. It was a short list of unglamorous fixes, each aimed at a specific metric:
      &lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;Self-hosted the fonts.&lt;/strong&gt; Pulling fonts from a third-party domain adds a connection and a render delay. Serving them from the same domain, preloaded, cut straight into LCP.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Reduced third-party JavaScript.&lt;/strong&gt; The current site does not load client-side behavioral analytics. Removing or deferring non-essential third-party scripts reduces main-thread competition; verify consent and measurement before changing a production setup.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Responsive images in WebP.&lt;/strong&gt; Every image ships as WebP at several sizes with srcset, so a phone downloads a small file and a desktop a larger one, never the wrong one.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Width and height on everything.&lt;/strong&gt; Explicit dimensions on images and figures reserve their space, which is why CLS is 0.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;
        None of that touched the design or the content. It is exactly the kind of finite, technical work that a small site needs once, not every month, which is the point I make in &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/technical-seo-fixes-agencies-wont-touch&quot;&gt;the technical SEO fixes agencies won't touch&lt;/a&gt;.
      &lt;/p&gt;

      &lt;h2 id=&quot;a-quick-checklist&quot;&gt;A quick checklist&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li&gt;Compress the hero image, serve it as WebP, and preload it.&lt;/li&gt;
        &lt;li&gt;Set width and height on every image, iframe, and embed.&lt;/li&gt;
        &lt;li&gt;Self-host fonts and set font-display so text does not reflow.&lt;/li&gt;
        &lt;li&gt;Remove unnecessary third-party scripts and defer the ones the site genuinely needs.&lt;/li&gt;
        &lt;li&gt;Test in the lab with PageSpeed Insights, then confirm in Search Console field data.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;div class=&quot;article-callout&quot;&gt;
        &lt;p&gt;
          Core Web Vitals are one part of a technical SEO check, alongside indexing, schema, and titles. If you would rather have someone measure yours, find what is dragging them down, and hand you a prioritized fix list, that is exactly what the &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo-audit&quot;&gt;fixed-price SEO audit&lt;/a&gt; does: one report, a flat $150, no retainer, no ranking promises. If the work turns out to be ongoing, the &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/retainer&quot;&gt;monthly retainer&lt;/a&gt; picks it up from there. &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/#contact&quot;&gt;Get in touch&lt;/a&gt; to start.
        &lt;/p&gt;
      &lt;/div&gt;

      &lt;h2 id=&quot;frequently-asked-questions&quot;&gt;Frequently asked questions&lt;/h2&gt;

      &lt;h3&gt;What are Core Web Vitals?&lt;/h3&gt;
      &lt;p&gt;
        Three metrics Google uses to measure real-world page experience: Largest Contentful Paint (LCP) for loading, Cumulative Layout Shift (CLS) for visual stability, and Interaction to Next Paint (INP) for responsiveness. They come from real Chrome users and feed into ranking as a page experience signal.
      &lt;/p&gt;

      &lt;h3&gt;What is a good Core Web Vitals score?&lt;/h3&gt;
      &lt;p&gt;
        A page passes when 75 percent of real users see LCP at 2.5s or less, CLS at 0.1 or less, and INP at 200ms or less. In the Lighthouse lab test the overall score is good from 90 to 100. In the recorded July 2026 test, this site scored 98 on mobile and 100 on desktop.
      &lt;/p&gt;

      &lt;h3&gt;Why is my mobile score lower than desktop?&lt;/h3&gt;
      &lt;p&gt;
        Lighthouse tests mobile on a throttled, slower simulated device and connection, so the same page has less CPU and bandwidth to work with. Mobile is often the harder target, and it deserves priority when most of your visitors use phones. Google measures mobile and desktop field data separately, so check both instead of treating one Lighthouse score as the final answer.
      &lt;/p&gt;

      &lt;h3&gt;Do Core Web Vitals affect SEO rankings?&lt;/h3&gt;
      &lt;p&gt;
        Google says Core Web Vitals, together with other aspects of page experience, align with what its core ranking systems seek to reward. They are not a separate shortcut to higher rankings, and good scores do not override relevance or useful content.
      &lt;/p&gt;

      &lt;h2 id=&quot;sources-checked&quot;&gt;Sources checked&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href=&quot;https://web.dev/articles/vitals&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;web.dev: Web Vitals and the Core Web Vitals thresholds&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://developers.google.com/search/docs/appearance/page-experience&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Google Search Central: page experience and Core Web Vitals in ranking&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;PageSpeed Insights: the lab and field report used above&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/seo/guides/how-to-fix-core-web-vitals&quot;&gt;FloxoLab&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/25677/how-to-fix-core-web-vitals-lcp-cls-inp-floxolab</guid>
<pubDate>Fri, 16 Oct 2026 15:50:00 +0000</pubDate>
</item>
<item>
<title>I Built a Directory for People Who Still Like Clicking Around the Internet</title>
<link>https://coderlegion.com/29760/i-built-a-directory-for-people-who-still-like-clicking-around-the-internet</link>
<description>&lt;p&gt;There are two ways to use the internet.&lt;/p&gt;
&lt;p&gt;The first way is to search for one exact answer, get it, close the tab, and move on with your life.&lt;/p&gt;
&lt;p&gt;The second way is to click something interesting, then click another thing, then somehow end up looking at a website that lets you listen to radio stations around the world or watch a person point directly at your mouse cursor.&lt;/p&gt;
&lt;p&gt;I like the second version of the internet.&lt;/p&gt;
&lt;p&gt;So I built &lt;a rel=&quot;nofollow&quot; href=&quot;https://base31.org&quot;&gt;base31.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is a hand-built directory of useful tools, playful websites, public APIs, web apps, AI tools, and small projects that are worth opening in a new tab.&lt;/p&gt;
&lt;p&gt;Not because every link will change your life.&lt;/p&gt;
&lt;p&gt;Mostly because the web is more fun when it surprises you.&lt;/p&gt;
&lt;h3 id=&quot;the-internet-is-not-boring-finding-it-is-&quot;&gt;The internet is not boring. Finding it is.&lt;/h3&gt;
&lt;p&gt;There are still thousands of great websites out there.&lt;/p&gt;
&lt;p&gt;Tiny browser tools that solve one specific problem.&lt;/p&gt;
&lt;p&gt;Personal projects that are better than most huge platforms.&lt;/p&gt;
&lt;p&gt;Interactive experiments that clearly took someone way too long to make — in the best possible way.&lt;/p&gt;
&lt;p&gt;Public APIs that make you immediately want to build something.&lt;/p&gt;
&lt;p&gt;The issue is that a lot of these projects are hard to find unless someone sends you a link, you see them in a random post, or you fall into a very specific search-engine rabbit hole.&lt;/p&gt;
&lt;p&gt;That is what base31 is for.&lt;/p&gt;
&lt;p&gt;It is a place to browse things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Useful browser tools&lt;/li&gt;
&lt;li&gt;Creative web experiments&lt;/li&gt;
&lt;li&gt;Free web apps&lt;/li&gt;
&lt;li&gt;Public APIs&lt;/li&gt;
&lt;li&gt;AI tools&lt;/li&gt;
&lt;li&gt;Small independent websites&lt;/li&gt;
&lt;li&gt;Tools built and hosted under the &lt;code&gt;base31.org&lt;/code&gt; umbrella&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The directory is meant to be slower than an app store, stranger than a listicle, and more useful than a bookmark folder you will never organize.&lt;/p&gt;
&lt;h3 id=&quot;it-is-curated-not-scraped&quot;&gt;It is curated, not scraped&lt;/h3&gt;
&lt;p&gt;I did not want this to be a page filled with links that were automatically collected, barely described, and possibly dead by next week.&lt;/p&gt;
&lt;p&gt;Every site on base31 is meant to be opened, checked, described, categorized, and tagged by hand.&lt;/p&gt;
&lt;p&gt;The directory tracks useful details too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When something was added&lt;/li&gt;
&lt;li&gt;When it was last reviewed&lt;/li&gt;
&lt;li&gt;Whether a listing has not been reviewed yet&lt;/li&gt;
&lt;li&gt;Tags and categories to make browsing easier&lt;/li&gt;
&lt;li&gt;A separate space for editor’s picks&lt;/li&gt;
&lt;li&gt;A clear distinction between editorial picks and sponsored links&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last part matters to me.&lt;/p&gt;
&lt;p&gt;An editor’s pick should mean I actually think it is worth visiting. A sponsored link should be clearly labeled as sponsored. Those are different things, and the site treats them differently.&lt;/p&gt;
&lt;p&gt;No mysterious “recommended” section that turns out to be an advertisement wearing a fake mustache.&lt;/p&gt;
&lt;h3 id=&quot;there-is-a-search-bar-but-surprise-me-is-important-too&quot;&gt;There is a search bar, but “Surprise me” is important too&lt;/h3&gt;
&lt;p&gt;Search is useful when you know what you need.&lt;/p&gt;
&lt;p&gt;Maybe you need an image tool. Maybe you are looking for a free API. Maybe you need a browser app that does not require an account before it lets you click one button.&lt;/p&gt;
&lt;p&gt;base31 lets people search names, URLs, descriptions, categories, and tags. You can use searches like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;#utility
tag:no-key
#image compress
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But I also added a &lt;strong&gt;Surprise me&lt;/strong&gt; option.&lt;/p&gt;
&lt;p&gt;Because sometimes the best way to use a directory is to admit you have no idea what you are looking for.&lt;/p&gt;
&lt;p&gt;That is how you end up discovering something useful.&lt;/p&gt;
&lt;p&gt;Or something completely unnecessary that you will send to three people anyway.&lt;/p&gt;
&lt;p&gt;Both outcomes are valid.&lt;/p&gt;
&lt;h3 id=&quot;i-started-building-the-tools-too&quot;&gt;I started building the tools too&lt;/h3&gt;
&lt;p&gt;The project did not stay “just a directory” for very long.&lt;/p&gt;
&lt;p&gt;I started building small tools and giving them their own homes on subdomains.&lt;/p&gt;
&lt;p&gt;Right now, base31 includes tools for things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compressing and resizing images in the browser&lt;/li&gt;
&lt;li&gt;Removing image backgrounds without uploading files&lt;/li&gt;
&lt;li&gt;Creating QR codes&lt;/li&gt;
&lt;li&gt;Generating passwords and passphrases&lt;/li&gt;
&lt;li&gt;Opening disposable email inboxes&lt;/li&gt;
&lt;li&gt;Testing iframes&lt;/li&gt;
&lt;li&gt;Exploring GitHub repositories&lt;/li&gt;
&lt;li&gt;Creating app screenshots&lt;/li&gt;
&lt;li&gt;Staying focused with a simple deep-work timer&lt;/li&gt;
&lt;li&gt;Finding domain ideas&lt;/li&gt;
&lt;li&gt;Playing a daily word game&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each tool can live on its own subdomain, while still being part of the larger base31 project.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;imagecompressor.base31.org
backgroundremover.base31.org
githubexplorer.base31.org
screenshot.base31.org
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I like that setup because every tool can stay focused.&lt;/p&gt;
&lt;p&gt;Not every useful feature needs to be shoved into one giant dashboard with fifteen sidebars and a pop-up asking if you want to upgrade before you have even tried it.&lt;/p&gt;
&lt;p&gt;Sometimes a tool should open, do its job, and get out of the way.&lt;/p&gt;
&lt;h3 id=&quot;people-can-add-their-own-sites&quot;&gt;People can add their own sites&lt;/h3&gt;
&lt;p&gt;One feature I am especially excited about is community publishing.&lt;/p&gt;
&lt;p&gt;Visitors can upload a small static site made with HTML, CSS, and JavaScript. The site can be hosted for free, shown in the directory, and discovered by other people browsing base31.&lt;/p&gt;
&lt;p&gt;That means a project does not need to become a business to deserve a place online.&lt;/p&gt;
&lt;p&gt;You can build a one-page experiment, a tiny game, a weird visual idea, a portfolio, or a simple tool, then actually let people see it.&lt;/p&gt;
&lt;p&gt;The web needs more of that.&lt;/p&gt;
&lt;p&gt;Not every project needs investors.&lt;/p&gt;
&lt;p&gt;Not every project needs a five-year roadmap.&lt;/p&gt;
&lt;p&gt;Not every project needs to “disrupt” anything.&lt;/p&gt;
&lt;p&gt;Sometimes it just needs a URL.&lt;/p&gt;
&lt;h3 id=&quot;how-it-is-built&quot;&gt;How it is built&lt;/h3&gt;
&lt;p&gt;The main directory is built with &lt;strong&gt;Next.js&lt;/strong&gt; and TypeScript.&lt;/p&gt;
&lt;p&gt;The content is stored in editable JSON files, which makes it easier to maintain the directory without hard-coding every site into the interface. That data powers the categories, search, detail pages, editor’s picks, tags, and metadata.&lt;/p&gt;
&lt;p&gt;The project also uses a Cloudflare Worker for shared features such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;View counters and basic statistics&lt;/li&gt;
&lt;li&gt;Votes&lt;/li&gt;
&lt;li&gt;Community site publishing&lt;/li&gt;
&lt;li&gt;Email and browser-notification subscriptions&lt;/li&gt;
&lt;li&gt;A public discussion area&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The tools themselves can be plain HTML, CSS, and JavaScript projects served through their own base31 subdomains.&lt;/p&gt;
&lt;p&gt;That has been one of my favorite parts of building it.&lt;/p&gt;
&lt;p&gt;A project can be small and simple without needing a giant framework around it. If a static tool does one thing well, it can have its own small corner of the internet.&lt;/p&gt;
&lt;h3 id=&quot;section&quot;&gt;&lt;/h3&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/29760/i-built-a-directory-for-people-who-still-like-clicking-around-the-internet</guid>
<pubDate>Sun, 04 Oct 2026 21:13:03 +0000</pubDate>
</item>
<item>
<title>Anatomy of a Short Link, When People Actually Want to Click?</title>
<link>https://coderlegion.com/26675/anatomy-of-a-short-link-when-people-actually-want-to-click</link>
<description>&lt;h3 id=&quot;five-small-details-that-make-a-short-url-feel-clearer-safer-and-more-memorable&quot;&gt;Five small details that make a short url feel clearer, safer, and more memorable&lt;/h3&gt;
&lt;p&gt;A short link is not automatically a good link. Removing characters from a URL solves a length problem, but it does not answer the questions people ask before clicking: Where will this take me? Is it relevant? Can I trust it? Will I remember it later?&lt;/p&gt;
&lt;p&gt;For web developers, the best short link is a small piece of interface design. Its domain, slug, surrounding copy, visual treatment, and technical behavior work together to reduce uncertainty. Get those details right and the link feels intentional instead of anonymous. &lt;/p&gt;
&lt;p&gt;This guide explains five details that make a short link more useful across websites, email, social posts, documentation, QR codes, and messaging apps. The examples are global by design, so they also account for mobile users, multilingual audiences, and people navigating with keyboards or assistive technology.&lt;/p&gt;
&lt;h3 id=&quot;1-a-recognizable-domain-comes-first&quot;&gt;1. A recognizable domain comes first&lt;/h3&gt;
&lt;p&gt;The domain is the first identity signal a person sees. A familiar brand domain tells the reader who is responsible for the destination. An unfamiliar or randomly generated domain makes the same destination feel harder to evaluate.&lt;/p&gt;
&lt;p&gt;Compare these examples:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;https://xmpl.co/a8K2p
https://docs.example.com/api/authentication
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first is shorter, but the second gives the reader more context. It identifies the organization, the product area, and the subject of the page.&lt;/p&gt;
&lt;p&gt;A branded short link can combine the compactness of a short URL with the recognition of a known name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;https://go.example.com/api-auth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This does not prove that a destination is safe. It does, however, give people a useful signal to check. Security still depends on the actual destination, the service that manages the redirect, and the way your application handles abuse reports and compromised links.&lt;/p&gt;
&lt;h4 id=&quot;developer-checklist&quot;&gt;Developer checklist&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Use HTTPS for the short-link domain.&lt;/li&gt;
&lt;li&gt;Keep the domain easy to read aloud and type.&lt;/li&gt;
&lt;li&gt;Avoid confusing character combinations, such as lowercase &lt;code&gt;l&lt;/code&gt;, uppercase &lt;code&gt;I&lt;/code&gt;, and the number &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use a branded domain when the link represents a company, product, or community.&lt;/li&gt;
&lt;li&gt;Make the domain match the identity shown in the surrounding copy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you do not want to operate the redirect infrastructure yourself, &lt;a rel=&quot;nofollow&quot; href=&quot;https://eslotmain.xyz&quot;&gt;Eslotmain is a link-shortening platform&lt;/a&gt; that offers custom slugs and branded domains. That can help keep a short link recognizable in a campaign or product flow. Treat the domain as an identity layer, not as a substitute for security review. A detailed &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.techtips.fun/blog/build-bulk-10-url-shortner-next-js/&quot;&gt;url shortener tutorial post is available&lt;/a&gt; &lt;/p&gt;
&lt;h3 id=&quot;2-the-slug-should-explain-the-destination&quot;&gt;2. The slug should explain the destination&lt;/h3&gt;
&lt;p&gt;The slug is the part of the short URL after the domain. It is a small space, but it can carry a surprising amount of meaning.&lt;/p&gt;
&lt;p&gt;A random slug such as this is difficult to remember:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;https://go.example.com/q7N4bP
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A descriptive slug is easier to scan and repeat:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;https://go.example.com/webinar-replay
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The goal is not to put the whole page title into the URL. The goal is to provide the shortest useful description. Use lowercase letters, hyphens between words, and stable words that will still make sense after the campaign ends.&lt;/p&gt;
&lt;p&gt;Good slugs are usually:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Specific:&lt;/strong&gt; &lt;code&gt;node-logging-guide&lt;/code&gt; says more than &lt;code&gt;guide&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compact:&lt;/strong&gt; remove filler words and unnecessary dates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Readable:&lt;/strong&gt; use words instead of an opaque character string.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stable:&lt;/strong&gt; avoid changing the slug every time the page copy changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audience-aware:&lt;/strong&gt; use language your intended readers understand.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Be careful with dates, regional terms, and abbreviations. A slug such as &lt;code&gt;summer-sale-uk&lt;/code&gt; may be useful for a time-limited campaign, but &lt;code&gt;product-guide-en&lt;/code&gt; and &lt;code&gt;product-guide-fr&lt;/code&gt; are clearer when you maintain separate language destinations. For a worldwide audience, decide whether language belongs in the slug, the destination path, or the campaign system. Do not make readers guess.&lt;/p&gt;
&lt;p&gt;A descriptive slug is also helpful when someone sees a link without its surrounding page, such as in a screenshot or a copied message. It cannot reveal every redirect detail, but it gives the reader an immediate reason to understand the link.&lt;/p&gt;
&lt;h3 id=&quot;3-the-words-around-the-link-must-set-expectations&quot;&gt;3. The words around the link must set expectations&lt;/h3&gt;
&lt;p&gt;A short URL cannot do all the communication by itself. Link context tells people why the destination matters and what will happen after the click.&lt;/p&gt;
&lt;p&gt;Weak copy:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Read more: &lt;code&gt;https://go.example.com/r4T9&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Clearer copy:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Read the &lt;strong&gt;WebAuthn implementation guide&lt;/strong&gt; for a browser-ready passkey flow: &lt;code&gt;https://go.example.com/webauthn-guide&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The second version answers three questions before the click:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What is the destination?&lt;/li&gt;
&lt;li&gt;Why should I open it?&lt;/li&gt;
&lt;li&gt;What kind of content will I find?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is also an accessibility requirement, not just a conversion tactic. &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-in-context.html&quot;&gt;WCAG guidance says that a link's&lt;/a&gt; purpose should be understandable from its text or its immediately associated context. &lt;a rel=&quot;nofollow&quot; href=&quot;https://designsystem.digital.gov/components/link/&quot;&gt;The U.S. Web Design System similarly advises developers&lt;/a&gt; to use unique, meaningful link text and avoid generic phrases such as “click here” and “read more”&lt;/p&gt;
&lt;p&gt;Use the link itself as the meaningful phrase where possible:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;p&amp;gt;
  Read the
  &amp;lt;a href=&quot;https://go.example.com/webauthn-guide&quot;&amp;gt;
    WebAuthn implementation guide
  &amp;lt;/a&amp;gt;
  before adding passkey support.
&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Avoid relying on a &lt;code&gt;title&lt;/code&gt; attribute to repair vague link text. The visible words should do most of the work. If the link opens a PDF, starts a download, requires a login, or leaves your site, say so in the visible text or its nearby context.&lt;/p&gt;
&lt;p&gt;For international audiences, keep the context direct and easy to translate. Short sentences with concrete nouns are easier to understand than clever calls to action.&lt;/p&gt;
&lt;h3 id=&quot;4-visual-treatment-should-make-the-click-obvious&quot;&gt;4. Visual treatment should make the click obvious&lt;/h3&gt;
&lt;p&gt;People should not have to move a pointer around the page to discover what is clickable. A link needs a visible affordance, which is a cue that communicates how an element can be used.&lt;/p&gt;
&lt;p&gt;A dependable text-link treatment includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A consistent color that is distinct from ordinary text.&lt;/li&gt;
&lt;li&gt;An underline or another non-color cue in body copy.&lt;/li&gt;
&lt;li&gt;A visible hover state.&lt;/li&gt;
&lt;li&gt;A visible keyboard focus state.&lt;/li&gt;
&lt;li&gt;Sufficient contrast against the background.&lt;/li&gt;
&lt;li&gt;A target large enough to tap comfortably on a phone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do not style ordinary headings or noninteractive cards to look like links. That creates false signals. &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.nngroup.com/articles/clickable-elements/&quot;&gt;Nielsen Norman Group describes&lt;/a&gt; consistency, placement, color, borders, and familiar web conventions as important cues for recognizing clickable elements. Its practical lesson is simple: if a design system teaches users one visual pattern for links, use that pattern everywhere.&lt;/p&gt;
&lt;p&gt;The HTML should preserve native link behavior:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;a class=&quot;text-link&quot; href=&quot;https://go.example.com/docs&quot;&amp;gt;
  Read the developer documentation
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.text-link {
  color: #075985;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.text-link:hover,
.text-link:focus-visible {
  color: #0c4a6e;
  text-decoration-thickness: 0.14em;
}

.text-link:focus-visible {
  outline: 3px solid #f59e0b;
  outline-offset: 3px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not remove the outline without replacing it with an equally visible focus style. A keyboard user must be able to find the active link, and pressing Enter should activate it. Use a real &lt;code&gt;&amp;lt;a href=&quot;...&quot;&amp;gt;&lt;/code&gt; for navigation, not a clickable &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; that forces you to recreate browser behavior with JavaScript.&lt;/p&gt;
&lt;h3 id=&quot;5-the-redirect-should-feel-safe-and-predictable&quot;&gt;5. The redirect should feel safe and predictable&lt;/h3&gt;
&lt;p&gt;A short link is a promise: the destination should match the expectation created by the link. Broken redirects, unexpected login walls, surprise downloads, and unrelated landing pages damage trust quickly.&lt;/p&gt;
&lt;p&gt;Before publishing a short link, check the full path from click to destination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does the short URL use HTTPS?&lt;/li&gt;
&lt;li&gt;Does it redirect quickly on mobile and desktop?&lt;/li&gt;
&lt;li&gt;Does it land on the page named in the link text?&lt;/li&gt;
&lt;li&gt;Does it preserve the intended language or regional experience?&lt;/li&gt;
&lt;li&gt;Does it avoid unnecessary redirect chains?&lt;/li&gt;
&lt;li&gt;Does it remain valid after the campaign or product release changes?&lt;/li&gt;
&lt;li&gt;Can you disable or update it if the destination becomes unsafe?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Analytics can help you detect problems and improve future links, but measurement should not make the experience opaque. Explain tracking where your privacy rules require it, collect only what you need, and protect link analytics as user data.&lt;/p&gt;
&lt;p&gt;A useful short-link dashboard can show patterns such as clicks, locations, devices, and referrers. Eslotmain publicly describes these analytics as part of its platform, along with quick link creation and a free option for personal links with no credit card required. Developers can use those signals to compare distribution channels, spot a broken campaign, or learn whether a mobile audience needs a different landing page. Analytics should answer a product question, not become a reason to add needless tracking.&lt;/p&gt;
&lt;h3 id=&quot;putting-the-five-details-together&quot;&gt;Putting the five details together&lt;/h3&gt;
&lt;p&gt;Here is a practical example for a developer newsletter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;p&amp;gt;
  The new release adds passkey support. See the
  &amp;lt;a href=&quot;https://go.example.com/passkeys-node&quot;&amp;gt;
    Node.js passkey integration guide
  &amp;lt;/a&amp;gt;
  for setup steps and browser notes.
&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The link works because each part has a job:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Link detail &lt;/th&gt;&lt;th&gt;What the reader learns&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Recognizable domain &lt;/td&gt;&lt;td&gt;Who owns or manages the link&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Descriptive slug &lt;/td&gt;&lt;td&gt;The general destination topic&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Surrounding copy &lt;/td&gt;&lt;td&gt;Why the destination is relevant&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Visible link styling &lt;/td&gt;&lt;td&gt;What can be clicked or tapped&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Predictable redirect &lt;/td&gt;&lt;td&gt;What will happen after activation&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A short link does not need to be loud. It needs to be legible, specific, and consistent with the experience that follows it.&lt;/p&gt;
&lt;h3 id=&quot;a-quick-pre-publish-test-for-web-developers&quot;&gt;A quick pre-publish test for web developers&lt;/h3&gt;
&lt;p&gt;Run this five-minute review before you share a link in production:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Read it without context.&lt;/strong&gt; Can you infer the topic from the domain and slug?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read the sentence only.&lt;/strong&gt; Does the link explain its destination and purpose?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use the keyboard.&lt;/strong&gt; Can you reach the link with Tab and activate it with Enter?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test a phone.&lt;/strong&gt; Is the target easy to tap, and does the redirect load quickly?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follow the complete redirect.&lt;/strong&gt; Does the final page match the promise?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check a copied version.&lt;/strong&gt; Does the link remain understandable when pasted into a message?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review the data plan.&lt;/strong&gt; Are analytics transparent, necessary, and handled according to your privacy obligations?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;final-takeaway&quot;&gt;Final takeaway&lt;/h3&gt;
&lt;p&gt;The anatomy of a link people want to click is not complicated. Start with a recognizable domain, add a readable slug, explain the destination in nearby text, make the link visibly interactive, and keep the redirect safe and predictable.&lt;/p&gt;
&lt;p&gt;Shortening a URL is only the mechanical step. The real work is reducing doubt. When the link tells people where they are going, why it matters, and what to expect, a click becomes a reasonable decision instead of a gamble.&lt;/p&gt;
&lt;h3&gt;Frequently Asked Questions&lt;/h3&gt;
&lt;h4 id=&quot;what-makes-a-link-more-clickable-&quot;&gt;What makes a link more clickable?&lt;/h4&gt;
&lt;p&gt;A link becomes more clickable when its destination and benefit are clear before activation. Descriptive link text, a recognizable domain, a readable slug, strong visual treatment, and a reliable redirect all reduce uncertainty.&lt;/p&gt;
&lt;h4 id=&quot;should-developers-use-descriptive-link-text-instead-of-click-here-&quot;&gt;Should developers use descriptive link text instead of “click here”?&lt;/h4&gt;
&lt;p&gt;Yes. Descriptive text helps sighted readers scan the page and helps screen-reader users understand a list of links out of context. Use words that identify the destination or action, such as “download the API reference PDF” or “view the passkey guide.”&lt;/p&gt;
&lt;h4 id=&quot;are-short-links-safe-to-click-&quot;&gt;Are short links safe to click?&lt;/h4&gt;
&lt;p&gt;Short links are not automatically safe because they hide the final destination. Use HTTPS, publish links through a service with abuse controls and management tools, provide useful context, and verify unfamiliar links before opening them.&lt;/p&gt;
&lt;h4 id=&quot;do-branded-short-links-improve-trust-&quot;&gt;Do branded short links improve trust?&lt;/h4&gt;
&lt;p&gt;They can improve recognition because the visible domain is connected to a known organization or product. Branded links do not guarantee that a destination is safe, so they should be combined with secure redirects, honest link context, and regular destination checks.&lt;/p&gt;
&lt;h4 id=&quot;do-short-links-help-seo-&quot;&gt;Do short links help SEO?&lt;/h4&gt;
&lt;p&gt;A short link can improve sharing and readability, but shortening a URL alone does not guarantee higher search rankings. For SEO, focus on the final page's content, canonical setup, crawlability, internal linking, and a clear user experience.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/26675/anatomy-of-a-short-link-when-people-actually-want-to-click</guid>
<pubDate>Wed, 09 Sep 2026 22:07:23 +0000</pubDate>
</item>
<item>
<title>The Story Behind Accesstive: Web Accessibility. Done Right.</title>
<link>https://coderlegion.com/26586/the-story-behind-accesstive-web-accessibility-done-right</link>
<description>&lt;p&gt;It's more than our tagline. It's the reason Accesstive exists.&lt;br&gt;
And it's why we're telling you this before talking about our product.&lt;br&gt;
In 2025 alone, 8,667 ADA web accessibility lawsuits were filed in the United States, a 37% increase year over year. Across Europe, the European Accessibility Act (EAA) is now in force, and organizations that fail to meet accessibility requirements can face significant financial penalties and legal risk.&lt;br&gt;
Most organizations don't discover they have an accessibility problem until they receive a complaint, lose a customer, or are asked to prove compliance.&lt;br&gt;
We believe that shouldn't be the case.&lt;br&gt;
That's one of the reasons we built Accesstive and why we made our Free Accessibility Checker available to everyone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What Most Accessibility Tools Get Wrong&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Search for &quot;accessibility checker&quot; and you'll find hundreds of scanners, overlays, and widgets promising quick fixes or instant compliance.&lt;br&gt;
The reality is different.&lt;br&gt;
An automated scan can identify many accessibility issues, but it cannot evaluate everything. Likewise, a widget alone doesn't make a website compliant or accessible for every user. Accessibility requires continuous attention, thoughtful remediation, and, in many cases, human expertise.&lt;br&gt;
The challenge isn't finding another scanner.&lt;br&gt;
The challenge is knowing what matters, fixing issues correctly, tracking progress over time, and having the documentation to demonstrate the work that's been done.&lt;br&gt;
That's where many organizations struggle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why We Built Accesstive&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For more than 15 years, we've been building enterprise websites and digital experiences for organizations across industries. Throughout that journey, one challenge kept repeating itself: web accessibility.&lt;br&gt;
The problem wasn't a lack of accessibility tools. There were scanners, overlays, consultants, manual audits, and reporting tools. The real challenge was that they all worked separately. Agencies and in-house teams had to switch between multiple tools, track fixes in spreadsheets, coordinate audits, and maintain documentation on their own.&lt;br&gt;
We faced the same challenge while delivering websites for our clients.&lt;br&gt;
So we built an internal solution to simplify the process. It helped our team monitor accessibility, manage issues, track remediation, and keep everything in one workflow. It wasn't created as a product. It was built to solve a real problem we experienced every day.&lt;br&gt;
As more clients started facing the same challenges, we realized this wasn't unique to us. It was a problem shared by agencies, developers, businesses, and public sector organizations around the world.&lt;br&gt;
That's how Accesstive was born.&lt;br&gt;
We didn't build another accessibility scanner.&lt;br&gt;
We didn't build another overlay.&lt;br&gt;
We built a Continuous Accessibility Platform that helps web teams find issues, understand them, fix them, monitor progress, and document everything in one place.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;More Than a Free Accessibility Checker&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For organizations taking their first step, we created the Free Accessibility Checker.&lt;br&gt;
It goes far beyond a traditional automated scan.&lt;br&gt;
In seconds, you can scan any public website, launch a Live Audit that highlights accessibility issues directly on the webpage, review findings against relevant WCAG success criteria, explore AI-powered remediation guidance, and download a detailed accessibility report.&lt;br&gt;
The goal isn't just to generate another list of issues.&lt;br&gt;
It's to help teams understand what needs attention, why it matters, and how to move forward with confidence.&lt;br&gt;
AI When It Helps. Human Experts When It Matters.&lt;br&gt;
We believe automation should support accessibility, not replace expertise.&lt;br&gt;
That's why every organization can book a free first consultation with one of our accessibility experts.&lt;br&gt;
Whether you need help interpreting your scan results, prioritizing remediation, validating complex accessibility issues, or planning your compliance journey, our specialists are available to guide you.&lt;br&gt;
AI helps you move faster.&lt;br&gt;
Human expertise helps you make the right decisions.&lt;br&gt;
We believe organizations need both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Accessibility Is Never &quot;Done&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Websites evolve. Content changes. New features are released. Regulations continue to evolve.&lt;br&gt;
Accessibility should evolve with them.&lt;br&gt;
That's why Accesstive is built around continuous accessibility instead of one-time scans or one-off compliance projects. Our goal is to help organizations make accessibility part of their everyday web operations, not something they only think about after receiving a legal notice.&lt;br&gt;
Our mission is simple: Help every web team Find, Fix &amp;amp; Prove accessibility with confidence. &lt;br&gt;
Help agencies, developers, businesses, and public sector organizations avoid the fragmented accessibility journey we experienced for years.&lt;br&gt;
Because Web Accessibility. Done Right. isn't just our tagline.&lt;br&gt;
It's the standard we're committed to helping every web team achieve.&lt;br&gt;
Learn more about Accesstive or run a free accessibility scan at &lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://accesstive.com/free-accessibility-checker/&quot;&gt;https://accesstive.com/free-accessibility-checker/&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/26586/the-story-behind-accesstive-web-accessibility-done-right</guid>
<pubDate>Wed, 09 Sep 2026 10:00:35 +0000</pubDate>
</item>
<item>
<title># Designing a Non-Custodial Multichain Wallet Hub for a Web3 Marketplace</title>
<link>https://coderlegion.com/25601/designing-a-non-custodial-multichain-wallet-hub-for-a-web3-marketplace</link>
<description>&lt;h2 id=&quot;designing-a-non-custodial-multichain-wallet-hub-for-a-web3-marketplace&quot;&gt;Designing a Non-Custodial Multichain Wallet Hub for a Web3 Marketplace&lt;/h2&gt;
&lt;p&gt;Building a marketplace that supports cryptocurrency payments creates an architectural decision very early:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who controls the keys?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While developing the open-source MyZubster ecosystem, I decided that the Marketplace and virtual world should be able to interact with multiple blockchain networks without turning the platform into a custodian.&lt;/p&gt;
&lt;p&gt;The result is an experimental &lt;strong&gt;multichain Wallet Hub&lt;/strong&gt; designed around four external settlement rails:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ethereum (ETH)&lt;/li&gt;
&lt;li&gt;Bitcoin (BTC)&lt;/li&gt;
&lt;li&gt;Monero (XMR)&lt;/li&gt;
&lt;li&gt;Tari&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;alongside MYZ, which remains a separate internal ecosystem accounting/reward layer.&lt;/p&gt;
&lt;h3 id=&quot;the-core-rule-never-put-private-keys-in-the-application&quot;&gt;The core rule: never put private keys in the application&lt;/h3&gt;
&lt;p&gt;A web application does not need a user's seed phrase to display a receiving address.&lt;/p&gt;
&lt;p&gt;It does not need private keys to create marketplace settlement intent.&lt;/p&gt;
&lt;p&gt;And it should not automatically gain authority over someone's cryptocurrency simply because they use the Marketplace.&lt;/p&gt;
&lt;p&gt;The architecture therefore follows a simple boundary:&lt;/p&gt;
&lt;p&gt;Marketplace → Settlement Intent → Public Address → User Wallet → Blockchain&lt;/p&gt;
&lt;p&gt;The wallet owner remains responsible for signing the transaction.&lt;/p&gt;
&lt;p&gt;The blockchain remains responsible for settlement.&lt;/p&gt;
&lt;p&gt;The Marketplace coordinates the interaction.&lt;/p&gt;
&lt;h3 id=&quot;public-configuration-private-authorization&quot;&gt;Public configuration, private authorization&lt;/h3&gt;
&lt;p&gt;The frontend can receive public wallet configuration through environment variables:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-env&quot;&gt;REACT_APP_WALLET_ETH=
REACT_APP_WALLET_BTC=
REACT_APP_WALLET_XMR=
REACT_APP_WALLET_TARI=
These variables are intended for public receiving addresses only.

They must never contain:

seed phrases
private keys
extended private keys
wallet passwords
signing secrets

This distinction sounds obvious, but it becomes extremely important once a project starts supporting several blockchain networks.

Extending the Marketplace

The MyZubster Marketplace already supported multiple exchange modes and currencies.

The current work extends the settlement model with Bitcoin and Ethereum so listings can identify their intended rail.

Conceptually, a listing can look like this:

{
  &quot;title&quot;: &quot;Community gardening service&quot;,
  &quot;price&quot;: 0.0001,
  &quot;currency&quot;: &quot;BTC&quot;,
  &quot;exchangeMode&quot;: &quot;payment&quot;
}

But this object represents commercial intent, not proof of payment.

Creating the listing does not move Bitcoin.

Creating an order should not automatically move Bitcoin either.

Actual settlement happens independently.

Settlement is a state machine

One of the useful lessons from building this architecture is that application state and blockchain state should not be confused.

A transaction flow can be modeled as:

ORDER CREATED
      ↓
SETTLEMENT REQUESTED
      ↓
TRANSACTION AUTHORIZED
      ↓
TRANSACTION BROADCAST
      ↓
SEEN BY NETWORK
      ↓
CONFIRMED
      ↓
SETTLED

The Marketplace should only mark an external cryptocurrency payment as settled after obtaining appropriate evidence from the corresponding network.

This becomes particularly important in a multichain environment because confirmation semantics are not identical across Bitcoin, Ethereum, Monero and Tari.

The Wallet Hub

Inside MyZubster, the Wallet Hub acts as the interface between the Marketplace/virtual world and the supported settlement rails.

The intended architecture is:

                   MyZubster World
                         │
                         ▼
                    Marketplace
                         │
                         ▼
                    Wallet Hub
                  /      |      \
                 /       |       \
               ETH      BTC      XMR      TARI
                │        │        │         │
                ▼        ▼        ▼         ▼
             Network  Network  Network   Network

The important part is what is not inside that diagram:

private-key custody.

Different chains, different adapters

A multichain system should also avoid pretending every blockchain behaves like Ethereum.

A cleaner implementation uses network-specific adapters behind a common settlement interface.

Conceptually:

const settlementAdapters = {
  ETH: ethereumAdapter,
  BTC: bitcoinAdapter,
  XMR: moneroAdapter,
  TARI: tariAdapter
};

Each adapter can eventually implement operations such as:

getReceivingAddress()
validateAddress()
getTransactionStatus()
verifyPayment()

Signing can remain outside the Marketplace boundary.

This gives the application a common interface without erasing the differences between networks.

Bitcoin

Bitcoin integration can use an Electrum-based workflow for wallet/network interaction.

The important separation remains:

Marketplace
    ↓
public Bitcoin address
    ↓
external/user-controlled signing
    ↓
Bitcoin network
    ↓
confirmation verification

A transaction ID alone should not automatically mean &quot;paid.&quot;

Confirmation status matters.

Monero

Monero requires its own integration model.

A Monero daemon and wallet RPC can provide the infrastructure needed for verification and wallet operations without exposing sensitive wallet material to the browser.

Again, the browser should never receive:

private spend key
private view key
seed
wallet password

Only the minimum information required by the application should cross the boundary.

Ethereum and Tari

ETH and Tari are exposed through the same Wallet Hub abstraction, while their network-specific adapters can evolve independently.

This is useful because the UI doesn't need to understand every protocol detail.

It only needs to understand something like:

asset
network
public destination
amount
transaction reference
status
confirmations/evidence

The backend adapter handles the chain-specific interpretation.

Security before convenience

It is tempting to build a &quot;Pay&quot; button that owns everything:

click
→ sign
→ send
→ confirm

That is convenient, but it dramatically changes the threat model if the server or frontend controls the keys.

For MyZubster, the safer initial architecture is deliberately less magical:

✓ public receiving addresses
✓ user-controlled authorization
✓ network-specific verification
✓ explicit settlement state
✓ separation of internal and external assets

✗ seed storage in frontend
✗ private keys in Git
✗ automatic custody
✗ assuming an order equals payment
✗ assuming a broadcast transaction equals confirmed settlement
Connecting the Marketplace to the virtual world

This work becomes more interesting because MyZubster isn't only a conventional marketplace.

The ecosystem is also experimenting with an interactive digital world containing community spaces, characters, chat, missions and other modules.

The longer-term architecture becomes:

Identity
   │
   ├── Community
   │
   ├── Missions
   │
   ├── Marketplace
   │       │
   │       └── Wallet Hub
   │              ├── ETH
   │              ├── BTC
   │              ├── XMR
   │              └── TARI
   │
   └── MyZubster World

That creates the possibility of virtual-world interactions that lead to real settlement rails while maintaining a clear security boundary.

Open-source implementation

The Wallet Hub work is being developed publicly in the MyZubster repository.

The current implementation is tracked in:

PR #811 — Connect metaverse market to multichain wallet hub

At this stage, it should be treated as active development rather than a claim of a production-ready financial system.

CI, security testing, deployment configuration and transaction-verification workflows are all part of moving from architecture to production.

What comes next

The next steps are particularly interesting from an engineering perspective:

complete CI and security validation;
finish deployment configuration for each public wallet rail;
implement network-specific transaction verification;
connect marketplace orders to settlement evidence;
define confirmation policies per network;
improve auditability without exposing sensitive wallet information;
keep internal MYZ accounting clearly separated from external cryptocurrency settlement.

The bigger lesson is simple:

Multichain doesn't have to mean multi-custodial.

A marketplace can coordinate several blockchain networks while keeping transaction authorization where it belongs:

with the wallet owner.

MyZubster is an open-source project under active development.

GitHub:
https://github.com/MyZubster-Ecosystem/myzubster

Wallet Hub implementation:
https://github.com/MyZubster-Ecosystem/myzubster/pull/811
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25601/designing-a-non-custodial-multichain-wallet-hub-for-a-web3-marketplace</guid>
<pubDate>Fri, 28 Aug 2026 07:40:06 +0000</pubDate>
</item>
<item>
<title>Understanding the OWASP Top 10 with Real-World Examples</title>
<link>https://coderlegion.com/24255/understanding-the-owasp-top-10-with-real-world-examples</link>
<description>&lt;h2 id=&quot;understanding-the-owasp-top-10-with-real-world-examples&quot;&gt;Understanding the OWASP Top 10 with Real-World Examples&lt;/h2&gt;
&lt;p&gt;Web applications have become the backbone of modern businesses, handling everything from online payments and customer accounts to healthcare records and enterprise data. As applications grow more complex, they also become attractive targets for attackers looking to exploit security weaknesses. This is why developers need to understand the most common application security risks before deploying software to production.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;OWASP Top 10&lt;/strong&gt; is one of the most widely recognized resources for application security, highlighting the most critical risks affecting web applications. Many development teams also rely on independent security experts such as &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://7asecurity.com/&quot;&gt;7Asecurity&lt;/a&gt;&lt;/strong&gt; to validate their applications through penetration testing and security assessments, helping identify vulnerabilities that automated tools alone may miss. Understanding these risks is the first step toward building more secure software.&lt;/p&gt;
&lt;h3 id=&quot;what-is-the-owasp-top-10-&quot;&gt;What Is the OWASP Top 10?&lt;/h3&gt;
&lt;p&gt;The OWASP Top 10 is a regularly updated awareness document published by the Open Worldwide Application Security Project (OWASP). Rather than listing every possible vulnerability, it focuses on the categories that present the greatest risk to organizations based on real-world attack data and industry research.&lt;/p&gt;
&lt;p&gt;Developers can use it as a practical checklist during application design, development, testing, and maintenance. This becomes particularly important as applications increasingly rely on APIs, cloud services, automation, and AI-driven components. For additional context on how modern AI applications operate behind the scenes, &lt;a rel=&quot;nofollow&quot; href=&quot;https://techgues.net/what-happens-behind-the-scenes-of-an-ai-powered-application/&quot;&gt;understanding what happens behind the scenes of an AI-powered application&lt;/a&gt; can help illustrate the range of components and interactions that developers need to consider when assessing application security.&lt;/p&gt;
&lt;h3 id=&quot;1-broken-access-control&quot;&gt;1. Broken Access Control&lt;/h3&gt;
&lt;p&gt;Access control determines what users are allowed to do within an application. When implemented incorrectly, attackers may gain access to resources or administrative functions they should never see.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
A user changes the ID in a URL from:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/orders/125
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/orders/126
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and successfully views another customer's order because authorization checks are missing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify authorization on the server side.&lt;/li&gt;
&lt;li&gt;Apply the principle of least privilege.&lt;/li&gt;
&lt;li&gt;Test access control for every endpoint.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-cryptographic-failures&quot;&gt;2. Cryptographic Failures&lt;/h3&gt;
&lt;p&gt;Sensitive information such as passwords, payment details, and personal records must be protected both during storage and transmission.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
A website stores passwords using outdated hashing algorithms or saves them in plain text. If the database is compromised, attackers immediately gain access to user credentials.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use strong password hashing algorithms like Argon2 or bcrypt.&lt;/li&gt;
&lt;li&gt;Enforce HTTPS everywhere.&lt;/li&gt;
&lt;li&gt;Encrypt sensitive information at rest.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-injection&quot;&gt;3. Injection&lt;/h3&gt;
&lt;p&gt;Injection vulnerabilities occur when untrusted user input is interpreted as commands by a database or operating system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A login form builds this SQL query:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM users WHERE username='admin' AND password='password';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If user input isn't validated, an attacker may inject SQL commands to bypass authentication.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use parameterized queries.&lt;/li&gt;
&lt;li&gt;Validate user input.&lt;/li&gt;
&lt;li&gt;Avoid building SQL statements through string concatenation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-insecure-design&quot;&gt;4. Insecure Design&lt;/h3&gt;
&lt;p&gt;Even well-written code can become vulnerable if the application's architecture doesn't consider security from the beginning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An online banking application allows unlimited password reset attempts without additional verification, making account takeover significantly easier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Perform threat modeling during design.&lt;/li&gt;
&lt;li&gt;Define security requirements early.&lt;/li&gt;
&lt;li&gt;Build security into the development lifecycle.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;5-security-misconfiguration&quot;&gt;5. Security Misconfiguration&lt;/h3&gt;
&lt;p&gt;Default settings, unnecessary services, and poor server configurations create opportunities for attackers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A cloud storage bucket is accidentally configured for public access, exposing confidential company files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove unused features.&lt;/li&gt;
&lt;li&gt;Disable default accounts.&lt;/li&gt;
&lt;li&gt;Review configurations regularly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-vulnerable-and-outdated-components&quot;&gt;6. Vulnerable and Outdated Components&lt;/h3&gt;
&lt;p&gt;Applications often depend on open-source libraries and frameworks. Older versions may contain publicly known vulnerabilities.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A web application continues using a framework version with a publicly disclosed remote code execution vulnerability long after a security update has been released.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maintain an inventory of dependencies.&lt;/li&gt;
&lt;li&gt;Update libraries regularly.&lt;/li&gt;
&lt;li&gt;Monitor security advisories.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;7-identification-and-authentication-failures&quot;&gt;7. Identification and Authentication Failures&lt;/h3&gt;
&lt;p&gt;Weak authentication allows attackers to compromise user accounts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An application permits unlimited login attempts without rate limiting, enabling brute-force password attacks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable multi-factor authentication.&lt;/li&gt;
&lt;li&gt;Implement account lockout policies.&lt;/li&gt;
&lt;li&gt;Enforce strong password requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;8-software-and-data-integrity-failures&quot;&gt;8. Software and Data Integrity Failures&lt;/h3&gt;
&lt;p&gt;Applications should verify that software updates, packages, and data originate from trusted sources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A CI/CD pipeline automatically installs packages without validating their integrity, allowing compromised dependencies to enter production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify package signatures.&lt;/li&gt;
&lt;li&gt;Protect build pipelines.&lt;/li&gt;
&lt;li&gt;Review third-party dependencies carefully.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;9-security-logging-and-monitoring-failures&quot;&gt;9. Security Logging and Monitoring Failures&lt;/h3&gt;
&lt;p&gt;Without effective logging, organizations may remain unaware of an attack until significant damage has occurred.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Multiple failed login attempts occur over several days, but no alerts are generated because authentication events aren't monitored.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log security-relevant events.&lt;/li&gt;
&lt;li&gt;Monitor logs continuously.&lt;/li&gt;
&lt;li&gt;Configure alerts for suspicious behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;10-server-side-request-forgery-ssrf-&quot;&gt;10. Server-Side Request Forgery (SSRF)&lt;/h3&gt;
&lt;p&gt;SSRF vulnerabilities allow attackers to trick servers into making requests to internal or external resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A file import feature accepts user-provided URLs without validation. An attacker supplies an internal address, enabling access to resources that shouldn't be publicly reachable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prevention&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Validate all URLs.&lt;/li&gt;
&lt;li&gt;Restrict outbound connections.&lt;/li&gt;
&lt;li&gt;Implement allowlists for approved destinations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;The OWASP Top 10 is more than a list of vulnerabilities—it's a practical guide for building secure applications. By understanding these risks and incorporating security throughout the software development lifecycle, developers can significantly reduce the likelihood of successful attacks.&lt;/p&gt;
&lt;p&gt;Security should not be viewed as a final testing phase. Instead, it should be integrated into planning, development, testing, deployment, and ongoing maintenance. Teams that continuously review their applications, update dependencies, validate user input, and perform regular security assessments are better prepared to defend against today's evolving threat landscape.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24255/understanding-the-owasp-top-10-with-real-world-examples</guid>
<pubDate>Fri, 07 Aug 2026 12:20:33 +0000</pubDate>
</item>
<item>
<title>Kamal vs Kubernetes: An Honest Comparison for Teams Who Don’t Need 1,000 Services</title>
<link>https://coderlegion.com/23250/kamal-vs-kubernetes-an-honest-comparison-for-teams-who-dont-need-1-000-services</link>
<description>
&lt;a href=&quot;https://alexandre-vazquez.com/kamal-vs-kubernetes/&quot; title=&quot;Kamal vs Kubernetes: An Honest Comparison for Teams Who Don&amp;rsquo;t Need 1,000 Services&quot; rel=&quot;nofollow&quot;&gt;&lt;img width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://mlk5tkvgfeoa.i.optimole.com/cb:s8WW.68/w:1536/h:1024/q:mauto/f:best/https://alexandre-vazquez.com/wp-content/uploads/2026/07/kamal.avif&quot; class=&quot;webfeedsFeaturedVisual wp-post-image&quot; alt=&quot;Kamal vs Kubernetes: An Honest Comparison for Teams Who Don't Need 1,000 Services&quot; style=&quot;display: block; margin: auto; margin-bottom: 5px;max-width: 100%;&quot; title=&quot;Kamal vs Kubernetes: An Honest Comparison for Teams Who Don't Need 1,000 Services 4&quot;&gt;&lt;/a&gt;
&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;The framing problem&lt;/h2&gt;



&lt;p&gt;Most &amp;ldquo;Kamal vs Kubernetes&amp;rdquo; articles are written by people who just discovered Kamal and are excited about it. They frame it as a simpler alternative that embarrasses Kubernetes. That framing is wrong and it will lead you to the wrong decision.&lt;/p&gt;



&lt;p&gt;Kamal is not better than Kubernetes. Kubernetes is not overkill for everyone. They solve different problems at different scales, and picking the wrong one for your context is expensive either way.&lt;/p&gt;



&lt;p&gt;This article gives you the honest version: what each tool actually is, where each one breaks, and the specific signals that should push you in one direction or the other.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;What Kamal actually is&lt;/h2&gt;



&lt;p&gt;Kamal (formerly MRSK) is a deployment tool built by 37signals. It deploys Docker containers to servers via SSH, uses kamal-proxy as its default reverse proxy, and handles rolling deploys with zero downtime. That is the entire feature set.&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;kamal deploy&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;It connects to your servers over SSH, pulls the new image, starts the new container, waits for it to be healthy, then moves traffic through kamal-proxy and stops the old one. Traefik is still possible, but in Kamal 2 it sits in front of kamal-proxy as an optional accessory rather than being the standard path.&lt;/p&gt;



&lt;p&gt;There is no control plane. No etcd. No API server. No scheduler. No concept of desired state reconciliation. Docker or systemd can restart a crashed container if you configure the right restart policy, but Kamal itself does not reschedule workloads to another node or provide cluster-level self-healing.&lt;/p&gt;



&lt;p&gt;Kamal is a deployment tool. Kubernetes is an orchestration platform. These are not the same category.&lt;/p&gt;



&lt;p&gt;That is the key distinction from tools like Nomad. I covered that angle in &lt;a rel=&quot;nofollow&quot; href=&quot;https://alexandre-vazquez.com/nomad-vs-kubernetes/&quot;&gt;Nomad vs Kubernetes&lt;/a&gt;, as part of the same &amp;ldquo;lighter alternatives to Kubernetes&amp;rdquo; discussion. Nomad is a scheduler/orchestrator. Kamal is a deployment tool that leaves scheduling and node-level recovery mostly outside its scope.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;What Kubernetes actually is&lt;/h2&gt;



&lt;p&gt;Kubernetes is a distributed system that continuously reconciles actual state against desired state. You declare what you want &amp;mdash; N replicas of container X, with these resource limits, this health check, this rollout strategy &amp;mdash; and the control plane makes it happen and keeps it that way.&lt;/p&gt;



&lt;p&gt;When a node fails, your pods are rescheduled. When a container crashes, it is restarted. When you push a new image, the rollout respects your &lt;code&gt;maxUnavailable&lt;/code&gt; and &lt;code&gt;maxSurge&lt;/code&gt; settings. When traffic spikes, HPA can add replicas.&lt;/p&gt;



&lt;p&gt;This machinery is powerful. It is also genuinely complex to operate.&lt;/p&gt;



&lt;p&gt;A minimal production-grade Kubernetes cluster involves: a multi-node control plane for HA, a CNI plugin, an ingress controller (or Gateway API), cert-manager for TLS, a CSI driver for storage, a metrics server for HPA, RBAC policies, network policies, pod disruption budgets, and some form of secret management. Getting all of this right takes time and ongoing maintenance.&lt;/p&gt;



&lt;p&gt;The question is whether the problems Kubernetes solves are problems you actually have.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;The minimum config tells the story&lt;/h2&gt;



&lt;p&gt;Here is the same tiny web service expressed in both worlds. The exact fields vary by app, registry, ingress setup, and Kubernetes distribution, but the shape is representative.&lt;/p&gt;



&lt;p&gt;&amp;lt;table&amp;gt;   &amp;lt;thead&amp;gt;     &amp;lt;tr&amp;gt;       &amp;lt;th&amp;gt;Kamal &amp;lt;code&amp;gt;deploy.yml&amp;lt;/code&amp;gt;&amp;lt;/th&amp;gt;       &amp;lt;th&amp;gt;Kubernetes &amp;lt;code&amp;gt;Deployment&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;Service&amp;lt;/code&amp;gt;&amp;lt;/th&amp;gt;     &amp;lt;/tr&amp;gt;   &amp;lt;/thead&amp;gt;   &amp;lt;tbody&amp;gt;     &amp;lt;tr&amp;gt;       &amp;lt;td&amp;gt; &amp;lt;pre&amp;gt;&amp;lt;code class=&amp;rdquo;language-yaml&amp;rdquo;&amp;gt;service: web image: ghcr.io/acme/web&lt;/p&gt;



&lt;p&gt;servers:   web:     hosts:       &amp;ndash; 203.0.113.10&lt;/p&gt;



&lt;p&gt;proxy:   ssl: true   host: app.example.com   app_port: 3000&lt;/p&gt;



&lt;p&gt;registry:   username: acme   password:     &amp;ndash; KAMAL_REGISTRY_PASSWORD&lt;/p&gt;



&lt;p&gt;env:   secret:     &amp;ndash; DATABASE_URL&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;       &amp;lt;/td&amp;gt;       &amp;lt;td&amp;gt; &amp;lt;pre&amp;gt;&amp;lt;code class=&amp;rdquo;language-yaml&amp;rdquo;&amp;gt;apiVersion: apps/v1 kind: Deployment metadata:   name: web spec:   replicas: 2   selector:     matchLabels:       app: web   template:     metadata:       labels:         app: web     spec:       containers:         &amp;ndash; name: web           image: ghcr.io/acme/web           ports:             &amp;ndash; containerPort: 3000           envFrom:             &amp;ndash; secretRef:                 name: web-secrets &amp;mdash; apiVersion: v1 kind: Service metadata:   name: web spec:   selector:     app: web   ports:     &amp;ndash; port: 80       targetPort: 3000&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;       &amp;lt;/td&amp;gt;     &amp;lt;/tr&amp;gt;   &amp;lt;/tbody&amp;gt; &amp;lt;/table&amp;gt;&lt;/p&gt;



&lt;p&gt;The Kubernetes example is still incomplete for internet traffic and TLS: you would normally add an Ingress or HTTPRoute, cert-manager, DNS, and secret provisioning. Kamal&amp;rsquo;s example is closer to &amp;ldquo;deploy this app to these servers.&amp;rdquo; Kubernetes is closer to &amp;ldquo;declare this workload inside a platform that already exists.&amp;rdquo;&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;The 37signals case&lt;/h2&gt;



&lt;p&gt;37signals (the company behind Basecamp and Hey) moved off cloud Kubernetes to bare-metal servers running Kamal in 2022-2023. Their own Ops team wrote about the &lt;a href=&quot;https://dev.37signals.com/bringing-our-apps-back-home/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;&amp;ldquo;de-cloud and de-k8s&amp;rdquo;&lt;/a&gt; move. The story got a lot of attention.&lt;/p&gt;



&lt;p&gt;What the hot takes missed: 37signals is not a startup. They have a dedicated ops team. They own and operate hardware. Their workload is well-understood and stable: a small number of mature applications serving a large, established user base.&lt;/p&gt;



&lt;p&gt;Their decision was rational for their context. Kubernetes was costing them in cloud spend and operational complexity for problems their workload does not have. Moving to Kamal on owned hardware made economic and operational sense for them.&lt;/p&gt;



&lt;p&gt;It does not follow that Kamal is the right choice for your early-stage startup, your company that runs on AWS because your team does not want to manage hardware, or your platform that needs to scale from 0 to 10x on short notice.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Where Kamal breaks&lt;/h2&gt;



&lt;p&gt;&lt;strong&gt;No cluster-level self-healing.&lt;/strong&gt; If your container crashes, Docker or systemd can restart it with the right policy, but Kamal has no involvement. If your server fails, Kamal will not reschedule that workload elsewhere; your service is down until you intervene or until you have set up something else to handle it.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;No built-in auto-scaling.&lt;/strong&gt; Kamal has no equivalent of HPA or KEDA. If your traffic spikes, you add servers manually or script something yourself.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;No multi-AZ HA by default.&lt;/strong&gt; You can deploy to multiple servers across regions, but the coordination is yours to manage. There is no concept of spreading replicas across availability zones automatically.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Rolling deploys are basic.&lt;/strong&gt; Kamal&amp;rsquo;s zero-downtime deploy is good for single-server or simple multi-server setups. It is not a substitute for Kubernetes rolling update with fine-grained health check integration across a fleet.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Secret management is manual.&lt;/strong&gt; Kamal reads secrets from &lt;code&gt;.kamal/secrets&lt;/code&gt; and has &lt;code&gt;kamal secrets&lt;/code&gt; helpers for fetching and extracting values from password managers and cloud secret stores, but there is no Kubernetes-style projected secret lifecycle. Rotation and policy remain yours to manage.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;No workload isolation.&lt;/strong&gt; Everything on the same server shares the same kernel, same resources. Resource limits are Docker-level, not enforced by an orchestration layer with quotas and namespaces.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Where Kubernetes breaks&lt;/h2&gt;



&lt;p&gt;&lt;strong&gt;The complexity tax is real.&lt;/strong&gt; Running Kubernetes yourself &amp;mdash; not a managed service, but actual cluster operation &amp;mdash; requires dedicated expertise. A team without a platform engineer will spend significant time debugging networking issues, understanding why pods are Pending, or figuring out why cert-manager is not issuing certificates.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Managed K8s is not free.&lt;/strong&gt; EKS charges for the cluster control plane, with standard support priced around $0.10/hour per cluster; GKE and AKS have their own pricing rules and credits. In all cases, you still pay for nodes, load balancers, and persistent volumes. For a small application, this cost can exceed what bare-metal hosting would cost.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;The YAML surface area scales with complexity.&lt;/strong&gt; A simple web app on Kubernetes requires a Deployment, a Service, an Ingress (or HTTPRoute), a Certificate, potentially a HorizontalPodAutoscaler, a PodDisruptionBudget, and NetworkPolicies. That is a lot of infrastructure for a CRUD app.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Debugging is harder.&lt;/strong&gt; Distributed systems are harder to debug than single-server setups. &lt;code&gt;kubectl exec&lt;/code&gt; and &lt;code&gt;kubectl logs&lt;/code&gt; are good tools but diagnosing why traffic is not reaching your pod &amp;mdash; DNS, CNI, network policy, service selector, readiness probe &amp;mdash; requires Kubernetes-specific knowledge that takes time to build.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;The honest decision framework&lt;/h2&gt;



&lt;p&gt;Ask yourself these questions in order:&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;1. Do you have more than one team working on independent services with different scaling needs?&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;If yes: Kubernetes starts making sense. The isolation and per-service resource management are worth the overhead.&lt;/p&gt;



&lt;p&gt;If no: Kamal is probably sufficient.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;2. Do you need to survive individual server failures automatically, without manual intervention?&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;If yes: You need either Kubernetes with proper HA setup, or a managed container platform whose recovery and placement model fits your app. Cloud Run, Fly.io, Render, and Railway all help here, but their HA boundaries differ. Kamal alone does not give you this.&lt;/p&gt;



&lt;p&gt;If no: A Docker or systemd restart policy covers the common crash case.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;3. Does your traffic profile require automatic scaling?&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;If yes: Kubernetes with HPA or KEDA, or a managed platform with the scaling behavior you actually need. Cloud Run scales request-driven services to and from zero; Fly.io supports autostart/autostop and machine scaling; Render and Railway support scaling, but with provider-specific limits and billing. Kamal has no answer here without custom tooling.&lt;/p&gt;



&lt;p&gt;If no: Fixed capacity is fine. Kamal works.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;4. Do you have a platform team, or is &amp;ldquo;ops&amp;rdquo; a shared responsibility among product engineers?&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;If platform team exists: Kubernetes operational overhead is distributed and manageable.&lt;/p&gt;



&lt;p&gt;If ops is everyone&amp;rsquo;s side job: Kamal&amp;rsquo;s simplicity is a genuine advantage. Less to go wrong, less to learn, faster to debug.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;5. Are you on cloud infrastructure you do not own, and cloud costs matter?&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;If yes: Run the numbers on managed K8s vs a few VPS instances. For small workloads, VPS + Kamal is significantly cheaper.&lt;/p&gt;



&lt;p&gt;If no: You have hardware already. Kamal is almost certainly the right choice.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Side-by-side&lt;/h2&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Kamal&lt;/th&gt;&lt;th&gt;Managed container platforms&lt;/th&gt;&lt;th&gt;Kubernetes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Kamal on VPS/bare metal&lt;/td&gt;&lt;td&gt;Cloud Run, Fly.io, Render, Railway&lt;/td&gt;&lt;td&gt;EKS, GKE, AKS, self-managed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Deployment model&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;SSH + Docker&lt;/td&gt;&lt;td&gt;Platform API / Git deploy / container deploy&lt;/td&gt;&lt;td&gt;API-driven, reconciliation loop&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Self-healing&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Docker/systemd restart policy only&lt;/td&gt;&lt;td&gt;Platform-managed restart and placement&lt;/td&gt;&lt;td&gt;Pod rescheduling, node failure recovery&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Auto-scaling&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Manual&lt;/td&gt;&lt;td&gt;Provider-specific; not all scale the same way&lt;/td&gt;&lt;td&gt;HPA, VPA, KEDA&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;HA&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Manual (multiple servers)&lt;/td&gt;&lt;td&gt;Provider-managed, with platform limits&lt;/td&gt;&lt;td&gt;Available with a well-configured multi-node control plane (not free)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TLS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;kamal-proxy with automatic HTTPS; Traefik optional&lt;/td&gt;&lt;td&gt;Usually built in&lt;/td&gt;&lt;td&gt;cert-manager + ingress controller&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Secret management&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;.kamal/secrets&lt;/code&gt; + helper commands&lt;/td&gt;&lt;td&gt;Platform secrets&lt;/td&gt;&lt;td&gt;Secrets API, external-secrets, Vault&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Observability&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Standard Docker logging&lt;/td&gt;&lt;td&gt;Provider logs/metrics, export varies&lt;/td&gt;&lt;td&gt;Rich ecosystem (Prometheus, OTel, etc.)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Rollout control&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Basic rolling deploy&lt;/td&gt;&lt;td&gt;Simple rollouts, provider-specific&lt;/td&gt;&lt;td&gt;Fine-grained (maxUnavailable, canary, etc.)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Learning curve&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;Low to medium&lt;/td&gt;&lt;td&gt;High&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Ops overhead&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;Medium to high&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Right scale&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;1-20 services, stable load&lt;/td&gt;&lt;td&gt;Small to medium teams that want managed recovery/scaling&lt;/td&gt;&lt;td&gt;10+ services, variable load, or regulated&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;What the threshold actually looks like&lt;/h2&gt;



&lt;p&gt;Kamal is the right default if you are:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;

&lt;li&gt;A team of 2&amp;ndash;10 engineers shipping a web application&lt;/li&gt;


&lt;li&gt;Running stable, predictable workloads&lt;/li&gt;


&lt;li&gt;On a budget where managed K8s costs matter&lt;/li&gt;


&lt;li&gt;Without a dedicated platform engineer&lt;/li&gt;

&lt;/ul&gt;



&lt;p&gt;Kubernetes is the right choice when:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;

&lt;li&gt;You have 10+ services with independent deployment cycles&lt;/li&gt;


&lt;li&gt;You need multi-zone HA and automatic failover&lt;/li&gt;


&lt;li&gt;Traffic is variable enough that &lt;a rel=&quot;nofollow&quot; href=&quot;https://alexandre-vazquez.com/cluster-autoscaler-vs-karpenter/&quot;&gt;auto-scaling saves real money or prevents real incidents&lt;/a&gt;&lt;/li&gt;


&lt;li&gt;You have a platform team that can absorb the operational complexity&lt;/li&gt;


&lt;li&gt;You are in a regulated environment that benefits from K8s&amp;rsquo;s audit trails and RBAC&lt;/li&gt;

&lt;/ul&gt;



&lt;p&gt;There is a middle tier worth mentioning: &lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://alexandre-vazquez.com/eks-auto-mode/&quot;&gt;managed container platforms&lt;/a&gt;&lt;/strong&gt; like Fly.io, Railway, Render, and Google Cloud Run. These give you some of Kubernetes&amp;rsquo;s operational benefits with closer to Kamal&amp;rsquo;s operational simplicity, but the details matter: HA, auto-scaling, scale-to-zero, regions, and billing differ by provider. For teams that need more than Kamal but do not want to operate K8s, this tier is often the right answer and gets underrepresented in the debate.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;The real lesson from 37signals&lt;/h2&gt;



&lt;p&gt;The story is not &amp;ldquo;Kamal beat Kubernetes.&amp;rdquo; The story is: &lt;strong&gt;match your infrastructure to your actual operational profile, not to what is fashionable or what scales to Google&amp;rsquo;s size.&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;37signals evaluated what problems they actually had and picked the tool that solved those problems at the lowest operational cost. That is the right framework.&lt;/p&gt;



&lt;p&gt;For most teams reading this, Kubernetes is probably the right answer eventually &amp;mdash; when your system&amp;rsquo;s complexity justifies it. The mistake is adopting it before you are there, burning engineering time on infrastructure problems instead of product problems.&lt;/p&gt;



&lt;p&gt;Kamal is a good tool for a specific stage and scale. Use it until you outgrow it. When you outgrow it, you will know &amp;mdash; because the things Kubernetes solves will be actual problems you have, not hypothetical ones.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;What to do next&lt;/h2&gt;



&lt;p&gt;Before you choose, write down your actual requirements in one page: number of services, expected traffic variance, failure tolerance, who owns ops, whether you own hardware, and what compliance needs are real today. Then run a small proof of concept with the simplest tool that satisfies those requirements. If Kamal plus Docker restart policies covers the failure modes you actually accept, start there. If you need automatic placement, autoscaling, and multi-zone recovery now, compare managed container platforms first, then Kubernetes.&lt;/p&gt;



&lt;hr class=&quot;wp-block-separator has-alpha-channel-opacity&quot;&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;FAQ&lt;/h2&gt;



&lt;p&gt;&lt;strong&gt;Can Kamal and Kubernetes coexist?&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Yes. Some teams use Kamal for simple auxiliary services (internal tools, cron jobs, simple APIs) while running their core platform on Kubernetes. The tools are not mutually exclusive.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Is Kamal production-ready?&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Yes. 37signals runs Basecamp and Hey on it. It handles zero-downtime deploys, TLS, and multi-server deployments reliably. The limitation is not reliability &amp;mdash; it is feature scope.&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/23250/kamal-vs-kubernetes-an-honest-comparison-for-teams-who-dont-need-1-000-services</guid>
<pubDate>Fri, 24 Jul 2026 10:00:00 +0000</pubDate>
</item>
<item>
<title>Two projects, one motivation</title>
<link>https://coderlegion.com/22405/two-projects-one-motivation</link>
<description>&lt;p&gt;Recently, I built two projects, just because I wanted to give people the info they need: news.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://splot.dev/dinkus/&quot;&gt;Dinkus&lt;/a&gt; was the first one. It is a MacOS RSS feed aggregator, and it gives updates—not only for news—but also for other website updates. It is particularly interesting because it appears on the system tray—which I thought was quite unique, until I figured out there were many other instances of this.&lt;/p&gt;
&lt;p&gt;Unsatisfied, I came up with &lt;a rel=&quot;nofollow&quot; href=&quot;https://gazette.pythonanywhere.com/&quot;&gt;The Olden Gazette&lt;/a&gt;, a novel news aggregator that pulls from BBC RSS, the NewsData API, and many other sources. It provides weather, breaking news, articles and the date. It is all black-and-white, and it is vintage, which is the point. Less screamy, loud and cramped, more real news.&lt;/p&gt;
&lt;p&gt;These two projects taught me how to better use many frameworks, especially &lt;a rel=&quot;nofollow&quot; href=&quot;https://rumps.readthedocs.io/en/latest/&quot;&gt;Rumps&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://flask.palletsprojects.com/en/stable/&quot;&gt;Flask&lt;/a&gt;, and they really improved my coding style: in The Olden Gazette, I began splitting the project into files, which I didn't really do previously. This may seem silly, because no one &lt;em&gt;doesn't&lt;/em&gt; split the code, but I learned this. Late.&lt;/p&gt;
&lt;p&gt;That's really it... I hope these tools are nice little gems.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22405/two-projects-one-motivation</guid>
<pubDate>Sun, 12 Jul 2026 22:22:00 +0000</pubDate>
</item>
<item>
<title>Does Web Hosting Affect Website Speed and Google Rankings</title>
<link>https://coderlegion.com/21883/does-web-hosting-affect-website-speed-and-google-rankings</link>
<description>&lt;p&gt;You keep working on your SEO. Better content. Better keywords. More backlinks. Still, your website’s ranking feels stuck. It could be that the issue isn’t your SEO strategy. It could be your hosting.&lt;/p&gt;
&lt;p&gt;A slow server affects everything from how fast your pages load to how smoothly users interact with your website and how efficiently Google can crawl it.  When your site is slow, both visitors and search engines notice it quickly.&lt;/p&gt;
&lt;p&gt;That’s why two sites with the same content can have very different rankings. One is quick and dependable. The other is slow and inconsistent.&lt;/p&gt;
&lt;p&gt;Content is no longer the only thing in modern SEO. Performance matters too.&lt;/p&gt;
&lt;p&gt;SEO Can Bring Visitors. Hosting Decides Whether They Stay.&lt;br&gt;
You can invest heavily in content, backlinks, and technical SEO, but if your website feels slow the moment someone lands on it, maintaining strong rankings becomes much harder. &lt;/p&gt;
&lt;p&gt;Google measures that experience. And users notice it even quicker.&lt;/p&gt;
&lt;p&gt;In this guide, we’ll study the impact of web hosting on website speed and Google rankings, and how the right infrastructure can actually be a game-changer for SEO.&lt;/p&gt;
&lt;p&gt;How Web Hosting Directly Controls Your Website Speed&lt;br&gt;
At the backend level, your hosting setup determines how quickly your website responds when someone tries to access it. Before images, scripts, or content can load, the server must respond. &lt;/p&gt;
&lt;p&gt;That first server response is called Time to First Byte (TTFB), and it acts like the starting signal for your entire website experience. If the server responds slowly, everything that follows feels slower, too. &lt;/p&gt;
&lt;p&gt;When server response time is slow:&lt;/p&gt;
&lt;p&gt;pages begin loading later&lt;br&gt;
Visitors wait longer to interact&lt;br&gt;
Core Web Vitals become unstable&lt;br&gt;
Users leave before the experience feels smooth&lt;br&gt;
Put simply, if your server is slow, your entire website feels slow.&lt;/p&gt;
&lt;p&gt;The 3 Core Hosting Factors That Impact Speed&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Storage type&lt;br&gt;
NVMe storage is much faster than SSDs or HDDs, resulting in faster data access and lower server latency.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resource allocation&lt;br&gt;
On shared web hosting, CPU and RAM are divided across multiple sites. This often leads to slowdowns during traffic spikes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server location&lt;br&gt;
The farther your server is from your users, the higher the latency. Hosting closer to your audience improves load time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What Are Core Web Vitals and Why Does Hosting Determine Them&lt;br&gt;
Google uses Core Web Vitals to measure how real users experience your website. And your hosting plays a direct role in all three.&lt;/p&gt;
&lt;p&gt;Core Web Vitals Explained&lt;br&gt;
LCP (Largest Contentful Paint)&lt;br&gt;
Measures how fast your main content loads.&lt;br&gt;
If your server is slow, LCP quickly crosses the 2.5-second limit, which hurts rankings.&lt;/p&gt;
&lt;p&gt;INP (Interaction to Next Paint)&lt;br&gt;
Measures how quickly your site responds to user actions.&lt;br&gt;
Overloaded or underpowered servers delay clicks, taps, and interactions.&lt;/p&gt;
&lt;p&gt;CLS (Cumulative Layout Shift)&lt;br&gt;
Measures visual stability while the page loads.&lt;br&gt;
Unstable server delivery can cause elements to shift, creating a poor user experience.&lt;/p&gt;
&lt;p&gt;Why Hosting Matters for Core Web Vitals&lt;br&gt;
Slow server response increases LCP&lt;br&gt;
Limited resources delay interactivity&lt;br&gt;
Inconsistent performance affects layout stability&lt;br&gt;
Sites that consistently pass Core Web Vitals benchmarks tend to rank higher and attract more organic traffic.&lt;/p&gt;
&lt;p&gt;In simple terms, users do not care about your server. They care about how fast your site feels. And that experience is heavily shaped by your hosting.&lt;/p&gt;
&lt;p&gt;Most Websites Do Not Have an SEO Problem&lt;br&gt;
They have a performance issue.&lt;/p&gt;
&lt;p&gt;There are many sites with excellent content, strong backlinks, and proper optimization, but over time, rankings become unstable.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;p&gt;The website’s server is not capable.&lt;br&gt;
When the host slows down, everything slows down&lt;br&gt;
Pages take longer to load&lt;br&gt;
interactions feel delayed&lt;br&gt;
Core Web Vitals become inconsistent&lt;br&gt;
Users leave faster&lt;br&gt;
Google notices these signals. And visitors notice it even more quickly.&lt;br&gt;
A faster website feels trustworthy and professional. A slow one creates frustration before the content even gets a chance.&lt;/p&gt;
&lt;p&gt;This is why sites that rank well in competitive searches today typically have infrastructure designed to be fast and consistent, rather than relying on overloaded, low-cost hosting.&lt;/p&gt;
&lt;p&gt;Fast Websites Usually Win More Than Just Rankings&lt;br&gt;
A faster website not only improves SEO.&lt;/p&gt;
&lt;p&gt;It also improves:&lt;/p&gt;
&lt;p&gt;user trust&lt;br&gt;
engagement&lt;br&gt;
conversion rates&lt;br&gt;
session duration&lt;br&gt;
overall browsing experience&lt;br&gt;
People naturally spend more time on websites that feel smooth and responsive. Search engines track those behaviour signals closely.&lt;/p&gt;
&lt;p&gt;How Cheap Shared Hosting Hurts Your Rankings&lt;br&gt;
Shared hosting may look affordable, but it often comes at the cost of performance.&lt;/p&gt;
&lt;p&gt;Your website shares server resources with many other websites. If one of those websites suddenly uses too many resources, your website can slow down too. &lt;/p&gt;
&lt;p&gt;Even if your traffic is stable, your server response time can spike without warning.&lt;/p&gt;
&lt;p&gt;Why This Becomes an SEO Problem&lt;br&gt;
Google evaluates performance over 28 days&lt;br&gt;
Occasional slowdowns can push your Core Web Vitals into the Poor range&lt;br&gt;
Lower performance scores can lead to weaker rankings&lt;br&gt;
On paper, cheap hosting looks like a smart way to save money. In reality, it often becomes the hidden reason behind slow growth, poor rankings, and lost traffic. What you save in cost, you usually pay back in performance.&lt;/p&gt;
&lt;p&gt;How to Check If Hosting Is Slowing Down SEO&lt;br&gt;
You don’t need advanced technical skills to spot hosting issues. A few quick checks can reveal whether your server is holding back rankings.&lt;/p&gt;
&lt;p&gt;Step 1: Test Speed with Google PageSpeed Insights&lt;br&gt;
Focus on these key metrics:&lt;/p&gt;
&lt;p&gt;LCP above 2.5 seconds means slow page loading&lt;br&gt;
TTFB above 600ms means a server performance issue&lt;br&gt;
If both are high, your hosting is likely the bottleneck.&lt;/p&gt;
&lt;p&gt;Step 2: Check Core Web Vitals in Google Search Console&lt;br&gt;
Review real user data over time&lt;br&gt;
Pages marked Poor are already underperforming&lt;br&gt;
Consistent issues here can impact rankings&lt;br&gt;
Step 3: Run a Waterfall Test (GTmetrix)&lt;br&gt;
Look at the first request (server response time)&lt;br&gt;
A long initial response indicates a backend delay&lt;br&gt;
If the first bar is slow, hosting is the problem&lt;br&gt;
What It Means&lt;br&gt;
If your TTFB stays consistently high, no amount of frontend optimization will fully fix it.&lt;/p&gt;
&lt;p&gt;In most cases, upgrading your hosting delivers the fastest and most noticeable SEO improvement.&lt;/p&gt;
&lt;p&gt;Does Upgrading Hosting Actually Improve Rankings&lt;br&gt;
Yes, and the impact is measurable.&lt;/p&gt;
&lt;p&gt;When you move from shared hosting to a high-performance setup, improvements happen at the server level first and then reflect in your rankings.&lt;/p&gt;
&lt;p&gt;What Improves After Upgrading&lt;br&gt;
Server response time drops&lt;br&gt;
LCP (loading speed) improves&lt;br&gt;
Core Web Vitals move into the Good range&lt;br&gt;
Search engines track these improvements over time, typically across a 28-day data cycle.&lt;/p&gt;
&lt;p&gt;Websites that move from Poor to Good performance often see ranking gains, especially in competitive niches where speed becomes a deciding factor.&lt;/p&gt;
&lt;p&gt;Will Migration Affect Your Rankings&lt;br&gt;
A properly handled migration does not harm your rankings.&lt;/p&gt;
&lt;p&gt;To ensure a smooth transition:&lt;/p&gt;
&lt;p&gt;Lower DNS TTL before migration&lt;br&gt;
Avoid downtime during the switch&lt;br&gt;
Resubmit your sitemap after moving&lt;br&gt;
When You’ll See Results&lt;br&gt;
Most websites start seeing measurable improvements within 30 to 45 days, once performance data is updated.&lt;/p&gt;
&lt;p&gt;In simple terms, better hosting improves performance, and better performance can lead to better visibility.&lt;/p&gt;
&lt;p&gt;What to Look for in Hosting That Supports SEO Performance&lt;br&gt;
Not all hosting environments are built for speed. The right infrastructure directly impacts your rankings.&lt;/p&gt;
&lt;p&gt;Key Features That Matter&lt;br&gt;
NVMe storage&lt;br&gt;
Faster data access reduces server delay and improves response time&lt;/p&gt;
&lt;p&gt;Modern web servers (LiteSpeed or Nginx)&lt;br&gt;
Handle traffic efficiently and improve caching performance&lt;/p&gt;
&lt;p&gt;Server location close to your audience&lt;br&gt;
Reduces latency and improves real-world load speed&lt;/p&gt;
&lt;p&gt;Dedicated resources (CPU and RAM)&lt;br&gt;
Prevents slowdowns during traffic spikes&lt;/p&gt;
&lt;p&gt;Built-in CDN integration&lt;br&gt;
Delivers content faster from locations closest to your users&lt;/p&gt;
&lt;p&gt;Reliable uptime and stable server performance&lt;br&gt;
Helps search engines crawl and index your website more efficiently &lt;/p&gt;
&lt;p&gt;Choosing the right hosting setup is often the difference between a site that loads and a site that competes.&lt;/p&gt;
&lt;p&gt;This is where most websites hit a ceiling. Not because of content, but because of infrastructure limitations.&lt;/p&gt;
&lt;p&gt;Why BigCloudy Is Built for Performance-Focused Websites&lt;br&gt;
Good hosting is not just about keeping a website online anymore. It directly affects how fast your pages load, how stable your site feels during traffic spikes, and how efficiently search engines can crawl your content.&lt;/p&gt;
&lt;p&gt;BigCloudy is designed around performance infrastructure rather than simply offering server space. The focus is on delivering consistent speed, stable uptime, and lower server response times that support better user experience and stronger Core Web Vitals performance.&lt;/p&gt;
&lt;p&gt;Key performance advantages include:&lt;/p&gt;
&lt;p&gt;NVMe storage for faster data access and reduced server delay&lt;br&gt;
Optimized server stack designed for stable performance under load&lt;br&gt;
Multiple data center locations to reduce latency for global audiences&lt;br&gt;
Built-in CDN integration for faster content delivery worldwide&lt;br&gt;
Reliable uptime infrastructure that helps maintain crawlability and SEO stability&lt;br&gt;
The real advantage is consistency.&lt;/p&gt;
&lt;p&gt;Because in modern SEO, consistency matters just as much as speed. Websites that remain fast, stable, and responsive over time usually perform better in search than websites with inconsistent performance.&lt;/p&gt;
&lt;p&gt;Final Thoughts&lt;br&gt;
Many websites have poor rankings not because their content is bad, but because their infrastructure does not consistently deliver a quick, stable experience.&lt;/p&gt;
&lt;p&gt;Modern SEO is not only about keywords and backlinks. The performance of your website is now a direct factor in how your users interact with your content and how your site is evaluated by search engines over time.&lt;/p&gt;
&lt;p&gt;A faster hosting environment improves more than speed. It enhances the user experience, stability, crawlability, and reliability of the website.&lt;/p&gt;
&lt;p&gt;That’s why choosing the right &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.bigcloudy.com/seo-vps-hosting&quot;&gt;SEO VPS hosting&lt;/a&gt; is no longer just a technical decision. It directly affects your website speed, search visibility, and ability to rank competitively.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21883/does-web-hosting-affect-website-speed-and-google-rankings</guid>
<pubDate>Sat, 04 Jul 2026 06:34:41 +0000</pubDate>
</item>
<item>
<title>How to Hire a Website Developer in 2026: Complete Guide</title>
<link>https://coderlegion.com/21101/how-to-hire-a-website-developer-in-2026-complete-guide</link>
<description>
&lt;h1&gt;How to Hire a Website Developer in 2026: A Complete Guide From the Other Side of the Table&lt;/h1&gt;
&lt;p class=&quot;post-byline&quot;&gt;
    &lt;span&gt; Hiring Guide&lt;/span&gt; &amp;middot;     Updated June 2026     &amp;middot; 12 min read    &amp;middot; by Jacob Campbell
&lt;/p&gt;

&lt;p class=&quot;article-intro&quot;&gt;&lt;/p&gt;&lt;p&gt;I'm Jacob Campbell, and I've been the developer on the other side of this conversation hundreds of times. I've also cleaned up after plenty of bad hires &amp;mdash; sites the owner couldn't edit, &quot;custom&quot; builds that were locked themes, projects where the client didn't even own their own domain. So this guide is written from inside the process: where to actually find a reliable developer, the precise questions that separate professionals from order-takers, the contract terms that protect you, the red flags worth walking away from, and what hiring really costs in 2026. The goal is simple &amp;mdash; to help you hire once and hire well, whether that's a freelancer, an agency, or a specialist like me.&lt;/p&gt;

&lt;h2&gt;Quick answers&lt;/h2&gt;
&lt;div class=&quot;post-stats&quot;&gt;
        &lt;div class=&quot;post-stat&quot;&gt;&lt;div class=&quot;v&quot;&gt;24 hrs&lt;/div&gt;&lt;div class=&quot;l&quot;&gt;Quote turnaround&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;post-stat&quot;&gt;&lt;div class=&quot;v&quot;&gt;~30 days&lt;/div&gt;&lt;div class=&quot;l&quot;&gt;Typical build time&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;post-stat&quot;&gt;&lt;div class=&quot;v&quot;&gt;100%&lt;/div&gt;&lt;div class=&quot;l&quot;&gt;Code ownership&lt;/div&gt;&lt;/div&gt;
        &lt;div class=&quot;post-stat&quot;&gt;&lt;div class=&quot;v&quot;&gt;5.0&amp;#9733;&lt;/div&gt;&lt;div class=&quot;l&quot;&gt;Verified client rating&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Where to actually find a reliable developer&lt;/h2&gt;
&lt;p&gt;You can hire through specialist studios, vetted freelance marketplaces (Upwork, Toptal), referrals, or by contacting a web design agency directly. In my experience the most reliable outcomes come from direct hires and specialists, because you work with the person who actually writes your code &amp;mdash; not a sales rep who hands the work to an offshore ticket queue you never see. Wherever you look, screen for three things before anything else: &lt;strong&gt;verified reviews&lt;/strong&gt;, a &lt;strong&gt;real portfolio you can load and inspect&lt;/strong&gt;, and &lt;strong&gt;clear flat-fee pricing&lt;/strong&gt;. A portfolio you can run through PageSpeed Insights yourself tells you more than any sales pitch.&lt;/p&gt;&lt;h2&gt;The questions that separate pros from order-takers&lt;/h2&gt;
&lt;p&gt;Ask every candidate, and get the answers in writing: &lt;em&gt;Do I own the code, content, and domain outright? What Lighthouse performance score do you guarantee? Is this a flat fee, or are there monthly costs? Who handles SEO, JSON-LD schema, and Core Web Vitals? What is the timeline, and how do revisions work? What happens if I want to move hosts later?&lt;/em&gt; A professional answers all of these without hesitation. An order-taker gets vague exactly where the money and the risk live &amp;mdash; ownership and recurring fees.&lt;/p&gt;&lt;h2&gt;Contract terms that protect you&lt;/h2&gt;
&lt;p&gt;Three clauses matter more than the rest. First, an explicit &lt;strong&gt;IP-transfer / code-ownership clause&lt;/strong&gt; stating the finished code and assets are yours on final payment. Second, &lt;strong&gt;account ownership&lt;/strong&gt; &amp;mdash; your domain, hosting, and analytics should be registered in your name, not the developer's. Third, a defined &lt;strong&gt;scope and revision count&lt;/strong&gt; so &quot;one more change&quot; doesn't become an open-ended bill. I put all three in plain language in every engagement, because the disputes I've seen others have almost always trace back to one of them being left unwritten.&lt;/p&gt;&lt;h2&gt;Red flags worth walking away from&lt;/h2&gt;
&lt;p&gt;Be cautious of anyone who: locks you into a proprietary platform you can't export, charges vague &quot;ongoing&quot; fees with no itemisation, can't show real performance scores on their own live work, has no verifiable reviews, or only communicates through a call centre. One more I've learned to flag: a developer who won't let you keep your own domain and hosting logins. That's not a convenience &amp;mdash; it's leverage over you, and a reputable developer never needs it.&lt;/p&gt;&lt;h2&gt;What it actually costs to hire in 2026&lt;/h2&gt;
&lt;p&gt;Hiring for a professional business website typically runs &lt;strong&gt;$1,500&amp;ndash;$10,000 as a one-time project&lt;/strong&gt;, consistent with Clutch survey data putting the median small-business spend near $5,000; hourly rates vary widely by region and seniority. A flat-fee specialist removes the estimating risk entirely: I build a business website for $1,750, ecommerce for $5,600, and SaaS from $10,000 &amp;mdash; no monthly fees, full code ownership. (See my full &lt;a href=&quot;/blog/how-much-does-a-custom-website-cost&quot;&gt;cost breakdown&lt;/a&gt; for what drives the number.)&lt;/p&gt;&lt;h2&gt;Freelancer vs agency vs specialist&lt;/h2&gt;
&lt;p&gt;A freelancer can be affordable, but availability and continuity vary. A large agency offers scale and redundancy, usually at higher cost and with less direct contact with the person doing the work. A focused specialist gives you expert, hands-on delivery with a single accountable point of contact &amp;mdash; typically the best balance of quality, speed, and value for a small or growing business. There's no universally &quot;right&quot; answer; the right one depends on your budget, timeline, and how much direct access to the builder you want.&lt;/p&gt;&lt;h2&gt;Sources &amp;amp; further reading&lt;/h2&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://clutch.co/web-developers/resources/small-business-websites-2024&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Clutch &amp;mdash; Small Business Website Survey (cost benchmarks)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Google PageSpeed Insights &amp;mdash; verify any developer's live work yourself&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Pricing, turnaround, and ownership terms reflect my own current BuiltToWinWeb engagement standards as of June 2026.&lt;/p&gt;
&lt;h2&gt;Work with an expert&lt;/h2&gt;
&lt;div class=&quot;post-related&quot;&gt;
        &lt;a href=&quot;/web-design-agency/&quot;&gt;
        &lt;div class=&quot;t&quot;&gt;Work with a web design agency&lt;/div&gt;
        &lt;div class=&quot;d&quot;&gt;A professional, reliable team for your full website project.&lt;/div&gt;
    &lt;/a&gt;
        &lt;a href=&quot;/custom-web-application/&quot;&gt;
        &lt;div class=&quot;t&quot;&gt;Hire for a custom web app&lt;/div&gt;
        &lt;div class=&quot;d&quot;&gt;Expert developers for database-driven applications and SaaS.&lt;/div&gt;
    &lt;/a&gt;
        &lt;a href=&quot;/free-quote/&quot;&gt;
        &lt;div class=&quot;t&quot;&gt;Get a free project quote&lt;/div&gt;
        &lt;div class=&quot;d&quot;&gt;Tell us your goals and get a flat-fee estimate within 24 hours.&lt;/div&gt;
    &lt;/a&gt;
    &lt;/div&gt;

&lt;h2&gt;Frequently asked questions&lt;/h2&gt;
&lt;h3&gt;How do I hire a good website developer?&lt;/h3&gt;
&lt;p&gt;Screen for verified reviews, a real portfolio you can load and test, flat-fee pricing, and a guaranteed Lighthouse score. Confirm in writing that you own the code, content, and domain, ask who handles SEO and Core Web Vitals, and choose someone who communicates directly.&lt;/p&gt;
&lt;h3&gt;How much does it cost to hire a website developer?&lt;/h3&gt;
&lt;p&gt;A professional website typically costs $1,500&amp;ndash;$10,000 as a one-time project in 2026, with the median small-business spend near $5,000 per Clutch. BuiltToWinWeb offers flat fees of $1,750 for business sites, $5,600 for ecommerce, and from $10,000 for SaaS, with no monthly costs.&lt;/p&gt;
&lt;h3&gt;Should I hire a freelancer or an agency?&lt;/h3&gt;
&lt;p&gt;A freelancer can be affordable but availability varies; an agency offers scale at higher cost and less direct contact. A specialist gives you expert, hands-on work with one accountable contact, which is often the best value for small businesses.&lt;/p&gt;
&lt;h3&gt;What questions should I ask a web developer before hiring?&lt;/h3&gt;
&lt;p&gt;Ask whether you own the code, content, and domain, what Lighthouse score is guaranteed, whether pricing is a flat fee, who handles SEO and Core Web Vitals, what the timeline and revision process are, and what happens if you change hosts.&lt;/p&gt;
&lt;h3&gt;What are red flags when hiring a developer?&lt;/h3&gt;
&lt;p&gt;Watch for platform lock-in you can't export, vague ongoing fees, no verifiable reviews, no guaranteed performance scores, call-centre-only communication, and any refusal to let you keep your own domain and hosting logins.&lt;/p&gt;
&lt;h3&gt;What contract terms protect me when hiring a developer?&lt;/h3&gt;
&lt;p&gt;Insist on an explicit code/IP-ownership clause that transfers the finished work to you on final payment, account ownership of your domain and hosting in your name, and a defined scope with a set revision count so changes don't become open-ended.&lt;/p&gt;

&lt;div class=&quot;post-cta&quot;&gt;
    &lt;h2&gt;Hire a developer who guarantees results&lt;/h2&gt;
    &lt;p&gt;Work directly with an expert developer &amp;mdash; flat-fee pricing, a 100 Lighthouse guarantee, and full code ownership.&lt;/p&gt;
    &lt;a class=&quot;btn&quot; href=&quot;/free-quote/&quot;&gt;Get my free quote&lt;/a&gt;
&lt;/div&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/21101/how-to-hire-a-website-developer-in-2026-complete-guide</guid>
<pubDate>Tue, 30 Jun 2026 07:45:45 +0000</pubDate>
</item>
<item>
<title>iTop VPN Premium Review (2026): My Honest Experience as a Developer &amp; Daily User</title>
<link>https://coderlegion.com/16777/itop-vpn-premium-review-2026-my-honest-experience-as-a-developer-daily-user</link>
<description>&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://bit.ly/4tcKKAj&quot;&gt;iTop VPN Premium&lt;/a&gt; is a beginner-friendly VPN service designed for secure browsing, streaming access, and privacy protection. It offers fast servers, dedicated streaming optimization, and a simple interface, making it a solid option for users who want affordable VPN protection without technical complexity.&lt;/p&gt;
&lt;h2 id=&quot;why-you-can-trust-this-review&quot;&gt;Why You Can Trust This Review&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=13902717829806804760&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I’ve personally used &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.beingoptimist.com/reviews/vpn/itop-vpn-premium-review/&quot;&gt;iTop VPN Premium&lt;/a&gt; both as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A developer handling websites and online tools&lt;/li&gt;
&lt;li&gt;A daily internet user focused on privacy and secure browsing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I tested it for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secure public Wi-Fi usage&lt;/li&gt;
&lt;li&gt;Accessing geo-restricted content&lt;/li&gt;
&lt;li&gt;Website testing across regions&lt;/li&gt;
&lt;li&gt;Private browsing while managing blogs and client work&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This review is based on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My real hands-on usage&lt;/li&gt;
&lt;li&gt;Official iTop VPN features&lt;/li&gt;
&lt;li&gt;Honest pros and limitations&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-is-itop-vpn-premium-&quot;&gt;What is iTop VPN Premium?&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.beingoptimist.com/itop-vpn-review/&quot;&gt;iTop VPN&lt;/a&gt; Premium is a virtual private network (VPN) service that helps protect your online privacy by encrypting your internet connection.&lt;/p&gt;
&lt;p&gt;It allows you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hide your IP address&lt;/li&gt;
&lt;li&gt;Access region-restricted content&lt;/li&gt;
&lt;li&gt;Secure browsing on public networks&lt;/li&gt;
&lt;li&gt;Improve privacy while working remotely&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unlike many free VPNs, Premium gives better:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Speed&lt;/li&gt;
&lt;li&gt;Server access&lt;/li&gt;
&lt;li&gt;Stability&lt;/li&gt;
&lt;li&gt;Streaming performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My Personal Experience Using iTop VPN Premium&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=11765067109689946996&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I mainly used iTop VPN for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secure access while traveling&lt;/li&gt;
&lt;li&gt;Testing websites from different locations&lt;/li&gt;
&lt;li&gt;Watching geo-restricted content&lt;/li&gt;
&lt;li&gt;Protecting login sessions on public networks&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-worked-really-well&quot;&gt;What Worked Really Well&lt;/h2&gt;
&lt;h3 id=&quot;fast-connection-speeds&quot;&gt;Fast Connection Speeds&lt;/h3&gt;
&lt;p&gt;The connection was stable for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Browsing&lt;/li&gt;
&lt;li&gt;YouTube streaming&lt;/li&gt;
&lt;li&gt;Uploading content&lt;/li&gt;
&lt;li&gt;WordPress dashboard access&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;easy-to-use-interface&quot;&gt;Easy to Use Interface&lt;/h3&gt;
&lt;p&gt;Even for beginners, setup was simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One-click connect&lt;/li&gt;
&lt;li&gt;Clear server categories&lt;/li&gt;
&lt;li&gt;Dedicated streaming options&lt;/li&gt;
&lt;li&gt;Reliable for Basic Privacy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For daily browsing and normal work, it handled:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Public Wi-Fi security&lt;/li&gt;
&lt;li&gt;IP masking&lt;/li&gt;
&lt;li&gt;Private sessions smoothly&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;should-you-buy-itop-vpn-premium-smart-cta-&quot;&gt;Should You Buy iTop VPN Premium? (Smart CTA)&lt;/h2&gt;
&lt;p&gt;If you want an affordable VPN for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secure browsing&lt;/li&gt;
&lt;li&gt;Streaming&lt;/li&gt;
&lt;li&gt;Website testing&lt;/li&gt;
&lt;li&gt;Remote work privacy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://bit.ly/4tcKKAj&quot;&gt;Check iTop VPN Premium here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tip: Premium plans unlock much better speed than the free version.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;key-features-of-itop-vpn-premium&quot;&gt;Key Features of iTop VPN Premium&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=6948184160257706094&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;dedicated-streaming-servers&quot;&gt;Dedicated Streaming Servers&lt;/h3&gt;
&lt;p&gt;Helpful for accessing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Netflix&lt;/li&gt;
&lt;li&gt;YouTube&lt;/li&gt;
&lt;li&gt;Region-based platforms&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;military-grade-encryption&quot;&gt;Military-Grade Encryption&lt;/h3&gt;
&lt;p&gt;Improves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data protection&lt;/li&gt;
&lt;li&gt;Secure browsing&lt;/li&gt;
&lt;li&gt;Public Wi-Fi safety&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;large-server-network&quot;&gt;Large Server Network&lt;/h3&gt;
&lt;p&gt;Access multiple locations for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Privacy&lt;/li&gt;
&lt;li&gt;International browsing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;kill-switch-support&quot;&gt;Kill Switch Support&lt;/h3&gt;
&lt;p&gt;Protects your privacy if VPN disconnects unexpectedly.&lt;/p&gt;
&lt;h3 id=&quot;pricing-overview&quot;&gt;Pricing Overview&lt;/h3&gt;
&lt;p&gt;Premium pricing usually depends on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monthly plans&lt;/li&gt;
&lt;li&gt;Annual subscriptions&lt;/li&gt;
&lt;li&gt;Discount offers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Longer plans often provide the best value.&lt;/p&gt;
&lt;p&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://bit.ly/4tcKKAj&quot;&gt;Check latest Premium pricing here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;pros-and-cons&quot;&gt;Pros and  Cons&lt;/h3&gt;
&lt;h3 id=&quot;-pros&quot;&gt;✅ Pros&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Beginner-friendly UI&lt;/li&gt;
&lt;li&gt;Good speed for daily use&lt;/li&gt;
&lt;li&gt;Dedicated streaming support&lt;/li&gt;
&lt;li&gt;Affordable compared to many competitors&lt;/li&gt;
&lt;li&gt;Strong enough for regular privacy needs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;-cons&quot;&gt;❌ Cons&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Advanced users may want more customization&lt;/li&gt;
&lt;li&gt;Some servers can be slower during peak hours&lt;/li&gt;
&lt;li&gt;Free version is limited compared to Premium&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;performance-amp-real-use-case&quot;&gt;Performance &amp;amp; Real Use Case&lt;/h2&gt;
&lt;p&gt;From my experience:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Browsing felt smooth&lt;/li&gt;
&lt;li&gt;Streaming worked reliably&lt;/li&gt;
&lt;li&gt;WordPress management stayed stable&lt;/li&gt;
&lt;li&gt;Region testing for websites was helpful&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Speed Connecting to VPN:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=17412731362554339571&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This makes it useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bloggers&lt;/li&gt;
&lt;li&gt;Freelancers&lt;/li&gt;
&lt;li&gt;Remote workers&lt;/li&gt;
&lt;li&gt;General users needing privacy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Speed after Connecting VPN:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=10778470584981570642&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;who-should-use-itop-vpn-premium-&quot;&gt;Who Should Use iTop VPN Premium?&lt;/h3&gt;
&lt;p&gt;Best for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Beginner VPN users&lt;/li&gt;
&lt;li&gt;Bloggers &amp;amp; freelancers&lt;/li&gt;
&lt;li&gt;Streamers&lt;/li&gt;
&lt;li&gt;Travelers&lt;/li&gt;
&lt;li&gt;People using public Wi-Fi often&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not ideal for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Heavy enterprise-level security users&lt;/li&gt;
&lt;li&gt;Advanced networking professionals needing deep controls&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-it-compares-to-other-vpns&quot;&gt;How It Compares to Other VPNs&lt;/h2&gt;
&lt;p&gt;Compared to bigger names like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NordVPN&lt;/li&gt;
&lt;li&gt;ExpressVPN&lt;/li&gt;
&lt;li&gt;Surfshark&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;iTop VPN is more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Budget-friendly&lt;/li&gt;
&lt;li&gt;Beginner-focused&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While premium competitors may offer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stronger advanced security tools&lt;/li&gt;
&lt;li&gt;Larger premium infrastructure&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;faqs&quot;&gt;FAQs&lt;/h2&gt;
&lt;h3 id=&quot;is-itop-vpn-premium-worth-it-&quot;&gt;Is iTop VPN Premium worth it?&lt;/h3&gt;
&lt;p&gt;Yes, especially for users who want simple, affordable privacy protection without complicated setup.&lt;/p&gt;
&lt;h3 id=&quot;is-itop-vpn-good-for-streaming-&quot;&gt;Is iTop VPN good for streaming?&lt;/h3&gt;
&lt;p&gt;Yes, Premium includes optimized servers for smoother streaming access.&lt;/p&gt;
&lt;h3 id=&quot;is-the-free-version-enough-&quot;&gt;Is the free version enough?&lt;/h3&gt;
&lt;p&gt;For basic testing, yes. But for real speed and stability, Premium is much better.&lt;/p&gt;
&lt;h3 id=&quot;is-itop-vpn-safe-&quot;&gt;Is iTop VPN safe?&lt;/h3&gt;
&lt;p&gt;For general privacy use, yes. It offers encrypted browsing and kill switch protection.&lt;/p&gt;
&lt;h2 id=&quot;final-verdict&quot;&gt;Final Verdict&lt;/h2&gt;
&lt;p&gt;iTop VPN Premium is a strong option for users who want easy, affordable VPN protection without technical complexity.&lt;/p&gt;
&lt;p&gt;It works especially well for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bloggers&lt;/li&gt;
&lt;li&gt;Travelers&lt;/li&gt;
&lt;li&gt;Freelancers&lt;/li&gt;
&lt;li&gt;Daily privacy-conscious users&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your goal is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Privacy&lt;/li&gt;
&lt;li&gt;Secure browsing&lt;/li&gt;
&lt;li&gt;Streaming access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;…it’s definitely worth considering.&lt;/p&gt;
&lt;p&gt;If you want a simple VPN that works well without overpaying:&lt;/p&gt;
&lt;p&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://bit.ly/4tcKKAj&quot;&gt;Check iTop VPN Premium plans here&lt;/a&gt;.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/16777/itop-vpn-premium-review-2026-my-honest-experience-as-a-developer-daily-user</guid>
<pubDate>Tue, 05 May 2026 17:45:34 +0000</pubDate>
</item>
<item>
<title>I'm a designer, not a developer. Here's how I prepared my PHP blog for AI agents.</title>
<link>https://coderlegion.com/15339/im-a-designer-not-a-developer-heres-how-i-prepared-my-php-blog-for-ai-agents</link>
<description>&lt;p&gt;I need to be upfront about something: I'm not a developer. I'm a UX/UI designer with over 10 years in banking and fintech. I built my blog with PHP and Claude as my coding partner. Every technical decision was a conversation with an AI, not a Stack Overflow deep dive.&lt;/p&gt;
&lt;p&gt;So when Cloudflare released a tool that tests how ready your site is for AI agents, I was curious but skeptical. How hard could this be for someone who learned PHP three months ago?&lt;/p&gt;
&lt;p&gt;Turns out, not hard at all. My blog scored 50/100, and it took less than an hour.&lt;/p&gt;
&lt;h2 id=&quot;what-ai-agents-actually-need-from-your-site&quot;&gt;What AI agents actually need from your site&lt;/h2&gt;
&lt;p&gt;Forget the technical jargon for a second. AI agents are like new visitors who can't see your design. They don't care about your beautiful layout or your carefully chosen typography. They want your content, clean and structured.&lt;/p&gt;
&lt;p&gt;Most websites give them a mess. Navigation bars, cookie banners, JavaScript bundles, social media widgets. The agent has to dig through all that noise to find the actual article. It's like handing someone a book wrapped in newspaper.&lt;/p&gt;
&lt;p&gt;The four things I implemented basically unwrap the newspaper:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;A file that says &quot;here's who I am&quot;&lt;/strong&gt;  llms.txt. A simple Markdown file at my domain root. It tells AI models: I'm a designer writing about AI tools, here are my best articles, here are my free tools. Five minutes to write. I even built a free generator so you don't have to write it from scratch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One line in robots.txt&lt;/strong&gt; It tells AI crawlers: cite me, but don't train on my content. Thirty seconds to add.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A clean version for agents&lt;/strong&gt; When an AI agent asks for my page, my server sends back plain Markdown instead of HTML. No navigation, no scripts, just the article. Twenty minutes to set up with Claude's help.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A list of my tools&lt;/strong&gt; A JSON file that tells agents what they can do on my site. Five minutes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;why-i-skipped-the-other-6-standards&quot;&gt;Why I skipped the other 6 standards&lt;/h2&gt;
&lt;p&gt;The test checks 10 things. Six of them are for platforms like Stripe or Salesforce things with APIs, user accounts, and authentication flows. My blog has none of that. Implementing OAuth on a blog with no login would be absurd.&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot;&gt;What I learned&lt;/h2&gt;
&lt;p&gt;The most interesting part wasn't the implementation. It was the realization that preparing your site for AI agents is similar to good UX design. You're making content accessible to a different type of user one that processes information differently than humans.&lt;/p&gt;
&lt;p&gt;As a designer, that clicked immediately. We don't design the same interface for mobile and desktop. Why would we serve the same messy HTML to a human browser and an AI agent?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For anyone in the community with a personal blog or portfolio: have you thought about how AI agents see your site? I'm curious if others have tried the test and what they found.&lt;/strong&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15339/im-a-designer-not-a-developer-heres-how-i-prepared-my-php-blog-for-ai-agents</guid>
<pubDate>Mon, 20 Apr 2026 21:09:36 +0000</pubDate>
</item>
<item>
<title>One Button Too Many</title>
<link>https://coderlegion.com/13476/one-button-too-many</link>
<description>&lt;h3 id=&quot;why-we-removed-sign-in-with-x-&quot;&gt;Why We Removed “Sign in with X”&lt;/h3&gt;
&lt;p&gt;We had five OAuth login options on our sign in page.&lt;/p&gt;
&lt;p&gt;Google. GitHub. LinkedIn. X. Facebook.&lt;/p&gt;
&lt;p&gt;It looked complete. It felt right. More options, more flexibility.&lt;/p&gt;
&lt;p&gt;Then one night around 11pm, we were staring at logs trying to figure out why our X integration kept connecting the wrong account.&lt;/p&gt;
&lt;p&gt;That is when things got interesting.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-we-build&quot;&gt;What We Build&lt;/h3&gt;
&lt;p&gt;We are building Made4Founders, a business platform for startup founders.&lt;/p&gt;
&lt;p&gt;One of the features is social posting. You connect your X account, write a post in the dashboard, and it publishes for you.&lt;/p&gt;
&lt;p&gt;Simple idea. Should be straightforward.&lt;/p&gt;
&lt;p&gt;We also let users sign in with X.&lt;/p&gt;
&lt;p&gt;At the time, it felt obvious. If we support X, we should support logging in with it too.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-went-wrong&quot;&gt;What Went Wrong&lt;/h3&gt;
&lt;p&gt;Here is the problem.&lt;/p&gt;
&lt;p&gt;A user signs in using their personal X account. That is the account already active in their browser.&lt;/p&gt;
&lt;p&gt;Later, they go to connect their company account for posting.&lt;/p&gt;
&lt;p&gt;But X does not give you an account picker. It does not ask which account you want. It just grabs whatever session is active.&lt;/p&gt;
&lt;p&gt;So it silently reconnects the personal account.&lt;/p&gt;
&lt;p&gt;The user thinks they connected their business account. They write a company update, hit post, and it goes to their personal feed.&lt;/p&gt;
&lt;p&gt;Not ideal.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-fixes-that-did-not-work&quot;&gt;The “Fixes” That Did Not Work&lt;/h3&gt;
&lt;p&gt;We tried to patch it.&lt;/p&gt;
&lt;p&gt;We added a hint telling users to switch accounts on X first.&lt;/p&gt;
&lt;p&gt;It did not help.&lt;/p&gt;
&lt;p&gt;Even after switching inside X, OAuth still defaulted to the primary session.&lt;/p&gt;
&lt;p&gt;The only workaround was telling users to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open an incognito window  &lt;/li&gt;
&lt;li&gt;Log into their business account only  &lt;/li&gt;
&lt;li&gt;Come back and connect  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We actually wrote that into a tooltip.&lt;/p&gt;
&lt;p&gt;Then we looked at it and realized how ridiculous that was.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-question-we-should-have-asked-earlier&quot;&gt;The Question We Should Have Asked Earlier&lt;/h3&gt;
&lt;p&gt;We stopped debugging and checked our data.&lt;/p&gt;
&lt;p&gt;How many users had actually signed up using “Sign in with X”?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Zero.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not low. Zero.&lt;/p&gt;
&lt;p&gt;Every user used Google or email. A few used GitHub or LinkedIn.&lt;/p&gt;
&lt;p&gt;Nobody used X.&lt;/p&gt;
&lt;p&gt;So we had been maintaining:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OAuth flows  &lt;/li&gt;
&lt;li&gt;Token refresh logic  &lt;/li&gt;
&lt;li&gt;API credentials  &lt;/li&gt;
&lt;li&gt;Debugging time  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a feature nobody used.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-fix-took-10-minutes&quot;&gt;The Fix Took 10 Minutes&lt;/h3&gt;
&lt;p&gt;We deleted the button.&lt;/p&gt;
&lt;p&gt;Removed the frontend component. Cleaned up the API call.&lt;/p&gt;
&lt;p&gt;About 20 to 30 lines of code.&lt;/p&gt;
&lt;p&gt;Then we separated our X apps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One app for login (now disabled)  &lt;/li&gt;
&lt;li&gt;One app for posting  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Same pattern we already used for LinkedIn.&lt;/p&gt;
&lt;p&gt;Immediately, everything worked.&lt;/p&gt;
&lt;p&gt;Four login options. No conflicts. Posting works as expected.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-we-actually-learned&quot;&gt;What We Actually Learned&lt;/h3&gt;
&lt;p&gt;This was not really about X.&lt;/p&gt;
&lt;p&gt;It was about a common engineering habit.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Adding things because we can, not because they are needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each OAuth provider feels cheap to add.&lt;/p&gt;
&lt;p&gt;Just another button. Another callback. Another env variable.&lt;/p&gt;
&lt;p&gt;But they are not free.&lt;/p&gt;
&lt;p&gt;Each one adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Token flows that can break  &lt;/li&gt;
&lt;li&gt;Credentials that expire  &lt;/li&gt;
&lt;li&gt;APIs that change  &lt;/li&gt;
&lt;li&gt;Edge cases you do not control  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And sometimes, they conflict with other features.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-real-cost-of-just-one-more-option-&quot;&gt;The Real Cost of “Just One More Option”&lt;/h3&gt;
&lt;p&gt;We spent hours debugging X.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Token issues  &lt;/li&gt;
&lt;li&gt;Session conflicts  &lt;/li&gt;
&lt;li&gt;API limitations  &lt;/li&gt;
&lt;li&gt;OAuth redirect loops  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;X has also become harder to work with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pay per use pricing  &lt;/li&gt;
&lt;li&gt;Limited free tier  &lt;/li&gt;
&lt;li&gt;Hidden requirements in the developer console  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of that for a login button nobody clicked.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-broader-point&quot;&gt;The Broader Point&lt;/h3&gt;
&lt;p&gt;Every feature has a maintenance cost.&lt;/p&gt;
&lt;p&gt;Not just code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debugging time  &lt;/li&gt;
&lt;li&gt;Support tickets  &lt;/li&gt;
&lt;li&gt;Mental overhead  &lt;/li&gt;
&lt;li&gt;Edge cases  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OAuth is especially messy.&lt;/p&gt;
&lt;p&gt;Every provider behaves differently:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google gives an account picker  &lt;/li&gt;
&lt;li&gt;LinkedIn requires separate apps  &lt;/li&gt;
&lt;li&gt;Facebook has business requirements  &lt;/li&gt;
&lt;li&gt;X uses whatever session is active  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is no standard. Only variations.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;our-rule-now&quot;&gt;Our Rule Now&lt;/h3&gt;
&lt;p&gt;Before adding a login option, we ask one question:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Would our target user actually sign up this way?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For founders using a business tool:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google and email cover almost everything  &lt;/li&gt;
&lt;li&gt;GitHub works for technical users  &lt;/li&gt;
&lt;li&gt;LinkedIn makes sense  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;X and Facebook do not.&lt;/p&gt;
&lt;p&gt;If the answer is no, we do not add it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;if-you-are-building-something-similar&quot;&gt;If You Are Building Something Similar&lt;/h3&gt;
&lt;p&gt;A few things we learned the hard way.&lt;/p&gt;
&lt;h4 id=&quot;1-do-not-mix-login-and-integration-oauth&quot;&gt;1. Do not mix login and integration OAuth&lt;/h4&gt;
&lt;p&gt;Session conflicts are real and you cannot control them.&lt;/p&gt;
&lt;h4 id=&quot;2-separate-your-developer-apps&quot;&gt;2. Separate your developer apps&lt;/h4&gt;
&lt;p&gt;Authentication and integrations should not share the same setup.&lt;/p&gt;
&lt;h4 id=&quot;3-test-with-multiple-accounts&quot;&gt;3. Test with multiple accounts&lt;/h4&gt;
&lt;p&gt;Most bugs only appear in real world usage patterns.&lt;/p&gt;
&lt;h4 id=&quot;4-remove-what-is-not-earning-its-place&quot;&gt;4. Remove what is not earning its place&lt;/h4&gt;
&lt;p&gt;It feels wrong, but it is often the right move.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-result&quot;&gt;The Result&lt;/h3&gt;
&lt;p&gt;Four login buttons.&lt;/p&gt;
&lt;p&gt;No conflicts.&lt;/p&gt;
&lt;p&gt;No late night debugging sessions over something nobody uses.&lt;/p&gt;
&lt;p&gt;Sometimes the best feature you can ship is a deletion.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;closing&quot;&gt;Closing&lt;/h3&gt;
&lt;p&gt;We are building Made4Founders.&lt;/p&gt;
&lt;p&gt;One dashboard to replace a stack of disconnected tools for startup founders.&lt;/p&gt;
&lt;p&gt;If you are building in this space, you already know how messy it gets.&lt;/p&gt;
&lt;p&gt;We are trying to make it simpler.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/13476/one-button-too-many</guid>
<pubDate>Wed, 25 Mar 2026 10:32:44 +0000</pubDate>
</item>
<item>
<title>A Complete Guide to Angular Component Testing with Cypress</title>
<link>https://coderlegion.com/13405/a-complete-guide-to-angular-component-testing-with-cypress</link>
<description>&lt;p&gt;Angular's latest versions have introduced exciting features like signals, computed, and enhanced reactivity. Paired with Cypress Component Testing, developers now have a powerful toolkit to write fast, realistic, and robust tests. This post dives deep into Angular component testing using Cypress, including how to test components that use signals, observables, and mock services with confidence.&lt;/p&gt;
&lt;h4 id=&quot;-why-cypress-for-angular-component-testing-&quot;&gt;✨ Why Cypress for Angular Component Testing?&lt;/h4&gt;
&lt;p&gt;Cypress isn't just for end-to-end tests. With Cypress Component Testing, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Render Angular components in isolation&lt;/li&gt;
&lt;li&gt;Interact with them as a user would&lt;/li&gt;
&lt;li&gt;Spy on inputs/outputs&lt;/li&gt;
&lt;li&gt;Work seamlessly with Angular DI, modules, and modern features like signals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; Setting Up Cypress Component Testing&lt;br&gt;
Install Cypress and initialize component testing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install cypress @cypress/angular --save-dev
npx cypress open --component
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Follow the UI wizard to configure your Angular workspace. It will auto-generate a Cypress configuration compatible with Angular.&lt;/p&gt;
&lt;h4 id=&quot;-example-component-with-signals-amp-outputs&quot;&gt;️ Example Component with Signals &amp;amp; Outputs&lt;/h4&gt;
&lt;p&gt;Let's test a simple &lt;code&gt;CounterComponent&lt;/code&gt; that demonstrates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Input binding&lt;/li&gt;
&lt;li&gt;Output emission&lt;/li&gt;
&lt;li&gt;Signals and computed values&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// counter.component.ts
import { Component, Input, Output, EventEmitter, signal, computed } from '@angular/core';

@Component({
  selector: 'app-counter',
  template: `
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;{{ title }}&amp;lt;/h2&amp;gt;
      &amp;lt;p&amp;gt;Count: {{ count() }}&amp;lt;/p&amp;gt;
      &amp;lt;button (click)=&quot;increment()&quot;&amp;gt;Increment&amp;lt;/button&amp;gt;
      &amp;lt;button (click)=&quot;reset()&quot;&amp;gt;Reset&amp;lt;/button&amp;gt;
      &amp;lt;p&amp;gt;Double: {{ doubleCount() }}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  `
})
export class CounterComponent {
  @Input() title = 'Default Counter';
  @Output() onReset = new EventEmitter&amp;lt;void&amp;gt;();

  private _count = signal(0);
  count = this._count.asReadonly();
  doubleCount = computed(() =&amp;gt; this._count() * 2);

  increment() {
    this._count.set(this._count() + 1);
  }

  reset() {
    this._count.set(0);
    this.onReset.emit();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;basic-cypress-tests&quot;&gt;Basic Cypress Tests&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;✅ Rendering with Default and Custom Inputs&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// counter.component.cy.ts
import { mount } from 'cypress/angular';
import { CounterComponent } from './counter.component';

describe('CounterComponent', () =&amp;gt; {
  it('renders with default title', () =&amp;gt; {
    mount(CounterComponent);
    cy.contains('Default Counter');
    cy.contains('Count: 0');
  });

  it('accepts custom title', () =&amp;gt; {
    mount(CounterComponent, {
      componentProperties: { title: 'Custom Counter' }
    });
    cy.contains('Custom Counter');
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;-testing-signals-and-computed-values&quot;&gt;⚖️ Testing Signals and Computed Values&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;it('increments count and updates double', () =&amp;gt; {
  mount(CounterComponent);
  cy.get('button').contains('Increment').click().click();
  cy.contains('Count: 2');
  cy.contains('Double: 4');
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;spying-on-output-events&quot;&gt;Spying on Output Events&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;it('emits reset event', () =&amp;gt; {
  const resetSpy = cy.spy().as('resetSpy');

  mount(CounterComponent, {
    componentProperties: {
      onReset: { emit: resetSpy } as any
    }
  });

  cy.get('button').contains('Reset').click();
  cy.get('@resetSpy').should('have.been.calledOnce');
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;testing-with-observables&quot;&gt;Testing with Observables&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// message.component.ts
@Component({
  selector: 'app-message',
  template: `&amp;lt;p *ngIf=&quot;message&quot;&amp;gt;{{ message }}&amp;lt;/p&amp;gt;`
})
export class MessageComponent {
  private _message = signal('');
  message = this._message.asReadonly();

  @Input()
  set messageInput$(value: Observable&amp;lt;string&amp;gt;) {
    value.subscribe(msg =&amp;gt; this._message.set(msg));
  }
}
it('renders observable message', () =&amp;gt; {
  const message$ = of('Hello from Observable!');
  mount(MessageComponent, {
    componentProperties: { messageInput$: message$ }
  });
  cy.contains('Hello from Observable!');
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;advanced-mocking-techniques&quot;&gt;Advanced Mocking Techniques&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;⚙️ Injecting Angular Services&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class MockLoggerService {
  log = cy.stub().as('logStub');
}

mount(MyComponent, {
  providers: [
    { provide: LoggerService, useClass: MockLoggerService }
  ]
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;mocking-http-calls-with-httpclienttestingmodule&quot;&gt;Mocking HTTP Calls with HttpClientTestingModule&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

beforeEach(() =&amp;gt; {
  cy.intercept('GET', '/api/data', { fixture: 'data.json' });
});

mount(MyHttpComponent, {
  imports: [HttpClientTestingModule]
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;stubbing-child-components&quot;&gt;Stubbing Child Components&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;@Component({
  selector: 'app-child',
  template: '' // stubbed template
})
class StubChildComponent {}

mount(ParentComponent, {
  declarations: [StubChildComponent]
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Cypress Component Testing is a game-changer for Angular developers. By combining the real browser testing experience with Angular’s new reactivity features like signals and computed, we can create robust, testable, and modern UIs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mount Angular components with Cypress easily&lt;/li&gt;
&lt;li&gt;Test signals, computed, observables&lt;/li&gt;
&lt;li&gt;Use spies and stubs for robust unit isolation&lt;/li&gt;
&lt;li&gt;Mock services and HTTP with Angular-friendly tooling&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/13405/a-complete-guide-to-angular-component-testing-with-cypress</guid>
<pubDate>Tue, 24 Mar 2026 01:37:36 +0000</pubDate>
</item>
<item>
<title>DataVyn Labs × Ollama Agents multi-model AI chat workspace</title>
<link>https://coderlegion.com/13238/datavyn-labs-ollama-agents-multi-model-ai-chat-workspace</link>
<description>&lt;p&gt;We built a clean, minimal AI chat interface powered by &lt;strong&gt;Ollama Cloud Models&lt;/strong&gt;, designed as a fast workspace for trying multiple frontier LLMs in one place.&lt;/p&gt;
&lt;p&gt;You only need a single Ollama Cloud API key to chat with 19+ top models—no separate OpenAI/Gemini keys, no billing setup, or no credit card needed.&lt;/p&gt;
&lt;p&gt;This project is developed by &lt;strong&gt;DataVyn Labs&lt;/strong&gt; (&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/DataVyn-labs&quot;&gt;https://github.com/DataVyn-labs&lt;/a&gt;)&lt;/p&gt;
&lt;h3 id=&quot;what-it-does&quot;&gt;What it does&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Talk to 19+ Ollama cloud models (OpenAI, DeepSeek, Qwen, Gemini, Mistral, Kimi, GLM, MiniMax, and more) from a single UI.&lt;/li&gt;
&lt;li&gt;Upload &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.pdf&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.py&lt;/code&gt;, &lt;code&gt;.csv&lt;/code&gt; and send the content to the model.&lt;/li&gt;
&lt;li&gt;Voice input via mic with automatic transcription.&lt;/li&gt;
&lt;li&gt;Secure API key handling (session-only, never saved to disk).&lt;/li&gt;
&lt;li&gt;Dark, Claude-style interface built entirely with Streamlit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;deployed-app&quot;&gt;deployed app&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;App: &lt;a rel=&quot;nofollow&quot; href=&quot;https://datavyn-labs-x-ollama-agents.streamlit.app/&quot;&gt;https://datavyn-labs-x-ollama-agents.streamlit.app/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;github repo - &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/anshk1234/DataVyn-Labs-X-Ollama-agents&quot;&gt;anshk1234/DataVyn-Labs-X-Ollama-agents&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You just need an Ollama Cloud API key (Settings → API Keys on ollama.com) and you’re ready to go.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/13238/datavyn-labs-ollama-agents-multi-model-ai-chat-workspace</guid>
<pubDate>Fri, 20 Mar 2026 04:31:59 +0000</pubDate>
</item>
<item>
<title>The True Face of Referential Equality and Optimizations in React</title>
<link>https://coderlegion.com/12445/the-true-face-of-referential-equality-and-optimizations-in-react</link>
<description>&lt;p&gt;When performance issues arise in React applications, &lt;code&gt;React.memo&lt;/code&gt;, &lt;code&gt;useMemo&lt;/code&gt;, and &lt;code&gt;useCallback&lt;/code&gt; are usually the first things that come to mind. In practice, however, adding these tools often merely complicates the code without delivering the expected performance boost.&lt;/p&gt;
&lt;p&gt;The underlying reason isn't that React is inadequate, but rather a fundamental misunderstanding of &lt;strong&gt;referential equality&lt;/strong&gt; within React's render model and how these optimization tools actually work.&lt;/p&gt;
&lt;h3 id=&quot;react-s-decision-mechanism-value-vs-reference&quot;&gt;React's Decision Mechanism: Value vs. Reference&lt;/h3&gt;
&lt;p&gt;When deciding whether to re-render a component, React doesn't check the contents of the data (structural equality). Instead, it checks if the data points to the same location in memory (referential equality). It uses a shallow comparison similar to JavaScript's &lt;code&gt;Object.is()&lt;/code&gt; method.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const a = { value: 1 };
const b = { value: 1 };

console.log(a === b); // false

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, even though objects &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; have identical content, they point to different memory locations. Therefore, React considers them &lt;strong&gt;completely different&lt;/strong&gt; values. This becomes critical especially when objects, arrays, and functions are passed as props to child components.&lt;/p&gt;
&lt;h3 id=&quot;the-shallow-comparison-preference&quot;&gt;The Shallow Comparison Preference&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;React.memo&lt;/code&gt;, &lt;code&gt;PureComponent&lt;/code&gt;, and Hook dependency arrays intentionally perform a shallow comparison. If React were to deeply compare every property within objects during every render, the performance cost would be significantly higher.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const Child = React.memo(({ options }) =&amp;gt; {
  /* ... */
});

const Parent = () =&amp;gt; {
  // A new 'options' object is created in memory during every render.
  const options = { pageSize: 20 };

  return &amp;lt;Child options={options} /&amp;gt;;
};

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, every time the &lt;code&gt;Parent&lt;/code&gt; component renders, a new &lt;code&gt;options&lt;/code&gt; object is created in memory. Even though the &lt;code&gt;Child&lt;/code&gt; component is wrapped in &lt;code&gt;React.memo&lt;/code&gt;, the optimization cannot kick in because the reference of the &lt;code&gt;options&lt;/code&gt; prop has changed, causing the &lt;code&gt;Child&lt;/code&gt; to re-render unnecessarily.&lt;/p&gt;
&lt;h3 id=&quot;impact-on-the-reconciliation-process&quot;&gt;Impact on the Reconciliation Process&lt;/h3&gt;
&lt;p&gt;In React, rendering does not mean directly updating the DOM. During the render phase, React generates a new component tree (Fiber tree) and compares it with the previous one (Reconciliation).&lt;/p&gt;
&lt;p&gt;If a component's state or prop references have changed, React re-renders that component and its entire subtree. Even if there are no actual changes to the DOM, constantly changing references force React to perform this comparison repeatedly, wasting CPU cycles.&lt;/p&gt;
&lt;h3 id=&quot;why-usememo-and-usecallback-fall-short&quot;&gt;Why useMemo and useCallback Fall Short&lt;/h3&gt;
&lt;p&gt;These two Hooks are designed to keep references stable (memoization), but when implemented incorrectly, they only add overhead to the application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Limits of useMemo:&lt;/strong&gt; &lt;code&gt;useMemo&lt;/code&gt; is used to cache expensive calculations or keep references stable. However, if a value in the dependency array changes its reference on every render, the calculation inside &lt;code&gt;useMemo&lt;/code&gt; will re-run every time. In this case, not only does the optimization fail, but React is also burdened with the extra work of tracking these dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Role of useCallback:&lt;/strong&gt; &lt;code&gt;useCallback&lt;/code&gt; caches function definitions. But if a function depends on a frequently updated state (e.g., state changing on every keystroke in a text input), this function will be recreated with every keystroke. Passing this function as a prop to child components will cause them to continuously re-render as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;every-render-creates-its-own-scope-closures-&quot;&gt;Every Render Creates Its Own Scope (Closures)&lt;/h3&gt;
&lt;p&gt;In React, every render creates its own lexical scope. This means that during each render, a &quot;snapshot&quot; of the current state and prop values is taken.&lt;/p&gt;
&lt;p&gt;Functions within a component capture the values belonging to that specific render. When the state updates, the component re-renders, a new snapshot is taken, and naturally, brand-new functions working with these new values are created in memory. This is React's expected behavior.&lt;/p&gt;
&lt;h3 id=&quot;architectural-solutions-over-forced-optimization&quot;&gt;Architectural Solutions Over Forced Optimization&lt;/h3&gt;
&lt;p&gt;Instead of trying to forcefully stabilize references using &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt;, rethinking the component architecture is often a more permanent and cleaner solution.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Moving State Down:&lt;/strong&gt; If a piece of state only affects a specific child component, move that state directly into the child rather than keeping it in the parent. This prevents the parent from rendering unnecessarily.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lifting Content Up (Children Prop):&lt;/strong&gt; By passing expensive components to a parent via the &lt;code&gt;children&lt;/code&gt; prop, you can ensure that the child components are unaffected when the parent's state changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using Primitive Values:&lt;/strong&gt; Instead of passing an entire object to child components as a prop, pass only the necessary primitive values like &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, or &lt;code&gt;boolean&lt;/code&gt;. Primitives are always compared by value, not by reference.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;React.memo&lt;/code&gt;, &lt;code&gt;useMemo&lt;/code&gt;, and &lt;code&gt;useCallback&lt;/code&gt; are not magic wands. These tools only provide benefits in applications where the architecture and data flow are properly structured. If you are experiencing performance issues, rather than immediately reaching for these Hooks, it is much better to ask architectural questions like, &quot;Where should this component's state live?&quot; or &quot;Do I really need to pass this prop?&quot;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/12445/the-true-face-of-referential-equality-and-optimizations-in-react</guid>
<pubDate>Fri, 06 Mar 2026 20:36:54 +0000</pubDate>
</item>
<item>
<title>Innovative Projects for Python Developers</title>
<link>https://coderlegion.com/11992/innovative-projects-for-python-developers</link>
<description>&lt;p&gt;As a Python developer, staying relevant and improving your skills is vital. Here are some innovative project ideas that cater to various experience levels and can help you tackle real-world challenges.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Personal Finance Tracker&lt;/strong&gt;&lt;br&gt;
Develop an application that allows users to track expenses, income, and savings goals. Integrating data visualization libraries such as Matplotlib or Plotly can make representation of financial data intuitive and engaging. Consider adding features like budgeting alerts or trend analysis to enrich user experience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chatbot with NLP&lt;/strong&gt;&lt;br&gt;
Create a chatbot that utilizes Natural Language Processing (NLP) to provide customer support or assist with common queries. Use libraries like NLTK or SpaCy to parse and understand user input. You can enhance it by integrating it with messaging platforms like Slack or Telegram.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Web Scraping Tool&lt;/strong&gt;&lt;br&gt;
Build a tool that extracts timely information from websites like news sources or e-commerce platforms. This project can sharpen your skills in data retrieval and manipulation using libraries like BeautifulSoup and Requests. Make sure to respect website scraping policies (robots.txt) while developing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Machine Learning for Image Classification&lt;/strong&gt;&lt;br&gt;
Leverage frameworks like TensorFlow or PyTorch to build a model that classifies images. This could range from identifying dog breeds in photos to distinguishing between various plant species. Experiment with different algorithms and datasets to deepen your understanding.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Recipe Recommendation System&lt;/strong&gt;&lt;br&gt;
Create an application that provides users with meal suggestions based on available ingredients. Use Python's data handling capabilities alongside web APIs like Spoonacular for fetching recipes, allowing your app to be both functional and user-friendly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Serverless Web Application&lt;/strong&gt;&lt;br&gt;
Explore serverless architecture by building a web application using AWS Lambda and API Gateway. This project will help you grasp the concepts of cloud computing and scalability without the hassle of managing servers directly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Blog Platform with Markdown Support&lt;/strong&gt;&lt;br&gt;
Develop a full-stack blog platform that uses Python Flask or Django for backend and a JavaScript framework for the frontend. Incorporating Markdown for blog posts enables users to format their articles easily, which could enhance the overall publishing experience.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each project not only strengthens your coding skills but also adds impressive projects to your portfolio. Mix and match these ideas or combine aspects from different ones to create a unique implementation tailored to your interests. Remember to keep testing and iterating as feedback can lead to enhancements that may not have been initially considered.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/11992/innovative-projects-for-python-developers</guid>
<pubDate>Sat, 21 Feb 2026 10:58:20 +0000</pubDate>
</item>
<item>
<title>A Dive Into Programmimg Paradigms(Object-Oriented Programming)</title>
<link>https://coderlegion.com/10574/a-dive-into-programmimg-paradigms-object-oriented-programming</link>
<description>&lt;p&gt;&lt;strong&gt;INTRODUCTION&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;Now Adays, we have different sorts of people some are orderly, others are lackadaisical, a handful are hardworking, and a few are reserved.&lt;/p&gt;
&lt;p&gt; What am i trying to say?, because we have so many people with different characters, these people will also have their different approaches to evaluating things. &lt;em&gt;Take for example!.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;• Orderly People - always plan their things out&lt;br&gt;
• Lackadaisical People - are laid back&lt;br&gt;
• Hardwojung People - always persevere&lt;br&gt;
• Reserved People - are always withdrawn.&lt;/p&gt;
&lt;p&gt;Notice the trend, the same way attitudes vary among people, also applies to the logic behind the variety of programming techniques out there.&lt;/p&gt;
&lt;p&gt;What is a programming paradigm? - A programming paradigm is a fundamental style of programming that deals with the creation of software, based on some basic principles.&lt;br&gt;
These principles all have their different ways or styles of operation.&lt;/p&gt;
&lt;p&gt;They include &lt;br&gt;
● OOP(Object oriented Programming) - a paradigm where everything operates based on objects (related entities) and their classes(group)&lt;/p&gt;
&lt;p&gt;● Event Driven Programming - a paradigm where the users interaction with an applications events are all that matters, e.g first event tapped - first to be called.&lt;/p&gt;
&lt;p&gt;● Imperative Programming - a programming paradigm based on a commanding style - this follows an exact way a program is written without any modifications.&lt;/p&gt;
&lt;p&gt;There are still many more paradigms including &lt;br&gt;
● Functional Programming &lt;br&gt;
● Aspect Oriented Programming e.t.c.&lt;br&gt;
and so on, but today we'd be majoring on OOP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OOP(Object oriented Programmimg) -&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just like i said earlier like many other paradigms, OOP also has it's style of software creation. It's is one of the most widely used programming paradigms, being supported by many modern programming languages including - Python, Javascript, Java and Golang(Go).&lt;/p&gt;
&lt;p&gt;When we say a program was written with the OOP style - it literally means the entirety of the program was broken down into simpler units of relation called classes and objects, and literally everything is an object e.g &lt;em&gt;can be assigned to a variable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Classes - these are a collection of related fields of a particular entity that help group relations together.&lt;/p&gt;
&lt;p&gt;Objects - these are units or rather blueprints of classes, they help break down the different possible types of a class.&lt;/p&gt;
&lt;p&gt;E.g A Car class will have many attributes(fields) including Name, Brand, Production Year, Price, Color and so on. And the objects of the car class,  will help break down the different possible car types e.g&lt;/p&gt;
&lt;p&gt;Car1 - Name(Sports Car), Brand(Lamborghini), Production Year(2012), Price($400,000), Color(Red).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CODE IMPLEMENTATION&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;Let's say you are a car dealer, and you need to develop an application that displays the different qualities of your car to buyers, when the buyer clicks on the car - it displays the qualities, OOP will be a great fit for this job. &lt;/p&gt;
&lt;p&gt;In the Example below we'd be using the Python programming language to implement this task, as its syntax is subtle.&lt;/p&gt;
&lt;p&gt;Car Dealership &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;These are the parts, the car dealership deals with, Car - (Brand, Color, Publication, Price)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So we have 4 cars currently at the dealership.&lt;br&gt;
To implement, we go as follows.&lt;/p&gt;
&lt;p&gt;1 Class Cars:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   def __init__(self, brand, color, publication, price):
       self.brand = brand 
       self.color = Color
       self.publication = publication
       self.price = price 

    def onclick_show_details(self):
       print(&quot;The car you clicked is a {}, it is color {}. It was produced in{}, and its price is {}&quot;).format(self.brand, self.color, self.publication, self.price)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;this-instantiates-the-class-to-create-objects&quot;&gt;This instantiates the class to create objects&lt;/h2&gt;
&lt;p&gt;car1 = Cars(&quot;Lamborghini&quot;, &quot;red&quot;, &quot;2012&quot;, 300000)&lt;br&gt;
car2 = Cars(&quot;Toyota&quot;, &quot;blue&quot;, &quot;2008&quot;, 250000)&lt;br&gt;
car3 = Cars(&quot;Honda&quot;, &quot;white&quot;, &quot;2017&quot;, &quot;150000)&lt;br&gt;
car4 = Cars(&quot;Nissan&quot;, &quot;green&quot;, &quot;2013&quot;, &quot;100000)&lt;/p&gt;
&lt;h2 id=&quot;this-performs-actions-on-the-objects-by-invoking-object-methods&quot;&gt;This performs actions on the objects by invoking object methods&lt;/h2&gt;
&lt;p&gt;Car1_details = car1.onclick_show_details()&lt;br&gt;
print(Car1_details) &lt;/p&gt;
&lt;h2 id=&quot;the-car-you-clicked-is-a-lamborghini-it-is-color-red-it-was-produced-in-2012-and-its-price-is-300000-&quot;&gt;The car you clicked is a Lamborghini, it is color red, it was produced in 2012 and its price is 300000.&lt;/h2&gt;
&lt;p&gt;CONCLUSION - There are still many more concepts on OOP including characteristics of OOP e.g, Abstraction, Polymorphism, Encapsulation and Inheritance, but we'd talk about that in another article.&lt;/p&gt;
&lt;p&gt;OOP is a really used programming paradigm now adays, so it will be great to learn and grasp it's concept.&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/10574/a-dive-into-programmimg-paradigms-object-oriented-programming</guid>
<pubDate>Tue, 27 Jan 2026 14:18:40 +0000</pubDate>
</item>
<item>
<title>Why Building Projects Beats Just Watching Tutorials</title>
<link>https://coderlegion.com/8459/why-building-projects-beats-just-watching-tutorials</link>
<description>&lt;p&gt;When I started learning AI and Machine Learning, I thought watching tutorials was enough. Models, algorithms, code examples — everything looked clear while watching. But the moment I tried to build something on my own, reality hit.&lt;/p&gt;
&lt;p&gt;❌ The Tutorial Comfort Zone&lt;/p&gt;
&lt;p&gt;Tutorials made everything feel easy:&lt;/p&gt;
&lt;p&gt;Clean datasets&lt;/p&gt;
&lt;p&gt;Pre-written logic&lt;/p&gt;
&lt;p&gt;Perfect outputs&lt;/p&gt;
&lt;p&gt;But once the video ended, I realized I didn’t truly understand how things worked. &lt;/p&gt;
&lt;p&gt; What Changed: Building Real Projects&lt;/p&gt;
&lt;p&gt;Things changed when I started building my own AI &amp;amp; ML projects — even small ones.&lt;/p&gt;
&lt;p&gt;I faced:&lt;/p&gt;
&lt;p&gt;Dataset issues&lt;/p&gt;
&lt;p&gt;Model giving wrong predictions&lt;/p&gt;
&lt;p&gt;Errors I had never seen before&lt;/p&gt;
&lt;p&gt;Performance problems&lt;/p&gt;
&lt;p&gt;At first, it was frustrating. But slowly, I learned:&lt;/p&gt;
&lt;p&gt;How to debug ML code&lt;/p&gt;
&lt;p&gt;Why preprocessing matters&lt;/p&gt;
&lt;p&gt;How model choice affects results&lt;/p&gt;
&lt;p&gt;How AI systems behave in real-world scenarios&lt;/p&gt;
&lt;p&gt;That struggle taught me more than any tutorial ever could.&lt;/p&gt;
&lt;p&gt; Learning by Doing (My Approach)&lt;/p&gt;
&lt;p&gt;This is the method that worked best for me:&lt;/p&gt;
&lt;p&gt;Learn the basic concept&lt;/p&gt;
&lt;p&gt;Build a simple AI/ML project&lt;/p&gt;
&lt;p&gt;Break it by experimenting&lt;/p&gt;
&lt;p&gt;Improve accuracy or features&lt;/p&gt;
&lt;p&gt;Repeat with a new idea&lt;/p&gt;
&lt;p&gt;Each project improved my confidence and understanding.&lt;/p&gt;
&lt;p&gt; Final Thought&lt;/p&gt;
&lt;p&gt;AI and ML are not learned by just watching — they are learned by building, failing, and fixing.&lt;/p&gt;
&lt;p&gt;If you’re learning AI or ML, don’t wait to be perfect.&lt;br&gt;
Start small, build projects, and let mistakes teach you.&lt;/p&gt;
&lt;p&gt;Build → Fail → Learn → Improve &lt;/p&gt;
&lt;p&gt;Happy Coding &lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/8459/why-building-projects-beats-just-watching-tutorials</guid>
<pubDate>Sun, 14 Dec 2025 16:37:38 +0000</pubDate>
</item>
<item>
<title>API UP — an API as a Service</title>
<link>https://coderlegion.com/8143/api-up-an-api-as-a-service</link>
<description>&lt;p&gt;Hey everyone!&lt;br&gt;
API UP has just been launched, a SaaS platform that lets you create fully functional APIs&lt;br&gt;
without setting up servers, databases, Docker, Kubernetes, etc.&lt;/p&gt;
&lt;div&gt;
  
  &lt;div class=&quot;sl-embed&quot; style=&quot;position:relative;padding-bottom:calc(57.42% + 25px);width:100%;height:0;transform:scale(1)&quot;&gt;
    &lt;iframe class=&quot;sl-demo&quot; src=&quot;https://app.storylane.io/demo/x4k1nquynhhb?embed=inline&quot; name=&quot;sl-embed&quot; allowfullscreen=&quot;allowfullscreen&quot; style=&quot;position:absolute;top:0;left:0;width:100%!important;height:100%!important;border:1px solid rgba(63,95,172,0.35);box-shadow: 0px 0px 18px rgba(26, 19, 72, 0.15);border-radius:10px;box-sizing:border-box;&quot;&gt;&lt;/iframe&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;It’s not a no-code toy — it generates a real async Python backend (compiled to C), with:&lt;br&gt;
• new Python 3.14+ web framework compiled in C&lt;br&gt;
• automatic CRUD/search&lt;br&gt;
• built-in authorization (endpoint/collection/document/field level)&lt;br&gt;
• embedded background tasks&lt;br&gt;
• multi-tenant and multi-version deployment&lt;br&gt;
• multi-database&lt;br&gt;
• built-in test tools&lt;br&gt;
• an admin UI for operations/product teams&lt;br&gt;
• CLI tools&lt;br&gt;
• mobile/web SDKs&lt;br&gt;
• high-performance defaults (async, optimized queries)&lt;br&gt;
• AI integration: describe the API and a version of it start running in minutes&lt;/p&gt;
&lt;p&gt;You can create an API, deploy it, and start calling it from your frontend or mobile app in minutes.&lt;/p&gt;
&lt;p&gt;You can test the UI and play with the system here:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://apiup.ai&quot;&gt;https://apiup.ai&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Documentation:&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.apiup.ai&quot;&gt;https://docs.apiup.ai&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Would love feedback — especially from backend and SaaS folks.&lt;/p&gt;
</description>
<category>APIs &amp; SDKs</category>
<guid isPermaLink="true">https://coderlegion.com/8143/api-up-an-api-as-a-service</guid>
<pubDate>Wed, 03 Dec 2025 20:31:57 +0000</pubDate>
</item>
<item>
<title>Ai Tool Synth Website Project</title>
<link>https://coderlegion.com/8068/ai-tool-synth-website-project</link>
<description>&lt;p&gt; Discover AI Tool Synth — Your Gateway to the Best AI Tools&lt;/p&gt;
&lt;p&gt;Hey everyone!&lt;br&gt;
I’d like to introduce AI Tool Synth, a platform I’ve built to help creators, developers, and businesses easily discover and compare the latest AI tools.&lt;/p&gt;
&lt;p&gt;We offer:&lt;/p&gt;
&lt;p&gt;✅ Curated AI tool lists across categories like productivity, image generation, audio, coding, marketing, and more&lt;br&gt;
✅ Clear descriptions, pricing info, and direct access links&lt;br&gt;
✅ Daily updates — new tools are added regularly&lt;br&gt;
✅ Affiliate-supported recommendations (no extra cost to users)&lt;br&gt;
✅ A clean, simple, and fast browsing experience&lt;/p&gt;
&lt;p&gt;If you're looking for new AI tools to speed up your workflow, generate content, or boost your business, this platform will save you a ton of time.&lt;/p&gt;
&lt;p&gt; Check it out here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.aitoolsynth.com&quot;&gt;https://www.aitoolsynth.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Would love to hear your feedback!&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/8068/ai-tool-synth-website-project</guid>
<pubDate>Tue, 02 Dec 2025 13:46:21 +0000</pubDate>
</item>
<item>
<title>A Scalable and Type-Safe i18n Solution for Modern Web Applications</title>
<link>https://coderlegion.com/5237/a-scalable-and-type-safe-i18n-solution-for-modern-web-applications</link>
<description>&lt;p&gt;Building a robust internationalization (i18n) system is challenging. Many developers start with a simple, monolithic translation file, but this quickly leads to performance issues and maintenance nightmares as the project grows. A better approach is to combine the efficiency of &lt;strong&gt;lazy-loading&lt;/strong&gt; with a well-structured &lt;strong&gt;custom function&lt;/strong&gt; to create a solution that is both performant and easy to manage, regardless of the framework you're using.&lt;/p&gt;
&lt;p&gt;This article outlines a hybrid i18n strategy that handles dynamic translation loading, ensuring your application remains fast, organized, and type-safe.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;methodologies-for-internationalization&quot;&gt;&lt;strong&gt;Methodologies for Internationalization&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The choice of internationalization (i18n) method depends on your project's size and complexity. Here are three common approaches, along with a detailed explanation of their trade-offs.&lt;/p&gt;
&lt;h5 id=&quot;1-the-monolithic-method-small-projects-&quot;&gt;1. The Monolithic Method (Small Projects)&lt;/h5&gt;
&lt;p&gt;This is the simplest approach. All translations for all languages are stored in a single, large JSON file.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How it works&lt;/strong&gt;: You import a single file at the start of your app. The file is structured with language keys at the top level.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Easy to set up and great for small projects or single-language apps. All translations are immediately available.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons&lt;/strong&gt;: Not scalable. The file becomes too large, increasing initial load time and making it difficult for multiple developers to work on translations simultaneously without frequent merge conflicts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;2-the-language-based-method-medium-projects-&quot;&gt;2. The Language-Based Method (Medium Projects)&lt;/h5&gt;
&lt;p&gt;This method separates translations by language, so you have one file per language.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How it works&lt;/strong&gt;: Your application loads a single language file based on the user's locale. This is often done at the router level or in a central store.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Reduces the initial bundle size compared to the monolithic method, as the user only downloads one language. Better for version control and collaboration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cons&lt;/strong&gt;: Still inefficient for very large applications. Every user downloads the entire language file, even if they only visit a few pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;3-the-hybrid-method-large-projects-&quot;&gt;3. The Hybrid Method (Large Projects)&lt;/h5&gt;
&lt;p&gt;This is the pattern we'll focus on. It combines the benefits of the other two methods by using a &lt;strong&gt;custom function&lt;/strong&gt; (known as a &lt;strong&gt;composable&lt;/strong&gt; in Vue.js or a &lt;strong&gt;custom hook&lt;/strong&gt; in React).&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;why-the-hybrid-method-is-superior&quot;&gt;&lt;strong&gt;Why the Hybrid Method Is Superior&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The hybrid method solves the core problems of the monolithic and language-based approaches by addressing performance and maintainability.&lt;/p&gt;
&lt;h4 id=&quot;performance-the-problem-of-initial-load&quot;&gt;&lt;strong&gt;Performance: The Problem of Initial Load&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;In a large application with hundreds of pages and components, a monolithic or language-based translation file can grow to several megabytes. When a user first visits your website, they have to download this entire file before they can see any text. This is a massive waste of bandwidth and time, especially on mobile networks, and it directly impacts your &lt;strong&gt;Core Web Vitals&lt;/strong&gt; scores.&lt;/p&gt;
&lt;p&gt;The hybrid method avoids this by only loading the translations required for the current page. The common translations, which are essential everywhere, are a small fraction of the total. The rest are dynamically imported only when needed, significantly reducing the initial bundle size and improving perceived load time.&lt;/p&gt;
&lt;h4 id=&quot;maintainability-the-problem-of-monoliths&quot;&gt;&lt;strong&gt;Maintainability: The Problem of Monoliths&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Imagine a team of ten developers working on a large application. If every developer needs to add new translations to a single &lt;code&gt;en.json&lt;/code&gt; file, they will constantly run into &lt;strong&gt;merge conflicts&lt;/strong&gt;. These conflicts are a huge drain on productivity and can introduce bugs when translation keys are accidentally overwritten.&lt;/p&gt;
&lt;p&gt;By organizing translations by feature (e.g., &lt;code&gt;home.json&lt;/code&gt;, &lt;code&gt;products.json&lt;/code&gt;), each developer can work on their feature's translation file without affecting others. This dramatically improves collaboration and makes the entire translation process more manageable.&lt;/p&gt;
&lt;h4 id=&quot;the-advantage-of-a-global-common-json&quot;&gt;&lt;strong&gt;The Advantage of a Global &lt;code&gt;common.json&lt;/code&gt;&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;common.json&lt;/code&gt; file serves as a single source of truth for all frequently used strings across your entire application. This offers two key benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Centralization&lt;/strong&gt;: It ensures consistency for common phrases like &quot;Submit,&quot; &quot;Cancel,&quot; or &quot;Search.&quot; You only have to translate these once, which reduces effort and prevents human error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Immediate Availability&lt;/strong&gt;: Since it's preloaded, any part of your application can instantly access these translations without waiting for a dynamic import.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;the-core-function-a-custom-composable&quot;&gt;&lt;strong&gt;The Core Function: A Custom Composable&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;The power of this solution lies in a custom function that handles all the heavy lifting. This self-contained function provides a clean API for requesting translations for a specific feature. It performs these key functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Loading&lt;/strong&gt;: When called with a namespace (e.g., &lt;code&gt;'home'&lt;/code&gt;), it automatically imports the corresponding translation file for the current language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Built-in Caching&lt;/strong&gt;: It uses a &lt;code&gt;Map&lt;/code&gt; to cache promises, preventing redundant network requests if the same namespace is requested multiple times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reactive State Management&lt;/strong&gt;: It exposes an &lt;code&gt;isReady&lt;/code&gt; flag, a reactive state that indicates when the translations have finished loading. This allows your component to show a loading state before rendering, preventing translation keys from appearing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Global Integration&lt;/strong&gt;: After a translation file is loaded, the function merges it into the global i18n instance. This ensures any component can access the new translations using the standard &lt;code&gt;t()&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This custom function keeps your components clean and focused on their core logic, abstracting away all the complex i18n management.&lt;/p&gt;
&lt;p&gt;A significant advantage is how this pattern works with child components. Once a parent component (like a page or a large section) loads a namespace, all of its children will have automatic access to those translations. A child component only needs to use the composable if it is being used in a different context or needs to load a new namespace not provided by its parent. This avoids redundant calls and keeps your application efficient.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;example-final-code-in-vue-js&quot;&gt;&lt;strong&gt;Example: Final Code in Vue.js&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Here’s how this pattern looks in a real-world Vue.js application.&lt;/p&gt;
&lt;h5 id=&quot;initial-setup-main-ts-and-i18n-ts-&quot;&gt;&lt;strong&gt;Initial Setup (&lt;code&gt;main.ts&lt;/code&gt; and &lt;code&gt;i18n.ts&lt;/code&gt;)&lt;/strong&gt;&lt;/h5&gt;
&lt;p&gt;First, you need to set up the global i18n instance. This is done by creating an i18n file and then registering it as a middleware in your main application file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/i18n.ts&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { createI18n } from 'vue-i18n';
import commonTranslations from './locales/common.json';

const i18n = createI18n({
    locale: 'en',
    fallbackLocale: 'en',
    messages: {
        en: {
            common: commonTranslations.en
        },
        fr: {
            common: commonTranslations.fr
        },
    },
    legacy: false,
});

export default i18n;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/main.ts&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import { createApp } from 'vue';
import App from './App.vue';
import i18n from './i18n';

const app = createApp(App);
app.use(i18n); // Register the i18n instance as a middleware
app.mount('#app');
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;the-self-contained-composable-usei18nnamespace-ts-&quot;&gt;&lt;strong&gt;The Self-Contained Composable (&lt;code&gt;useI18nNamespace.ts&lt;/code&gt;)&lt;/strong&gt;&lt;/h5&gt;
&lt;p&gt;This composable handles everything internally, from loading the namespace to managing its ready state.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// src/composables/useI18nNamespace.ts
import { ref, watchEffect } from 'vue';
import { useI18n } from 'vue-i18n';
import i18n from '@/i18n';
import type { I18nNamespace } from '@/types/namespaces';

const loadingPromises = new Map&amp;lt;I18nNamespace, Promise&amp;lt;void&amp;gt;&amp;gt;();

export function useI18nNamespace(namespace: I18nNamespace) {
    const { t, locale } = useI18n({ useScope: 'global' });
    const isReady = ref(false);

    const load = async (ns: I18nNamespace) =&amp;gt; {
        isReady.value = false;
        const currentLocale = locale.value;
        
        if (i18n.global.getLocaleMessage(currentLocale)?.[ns]) {
            isReady.value = true;
            return;
        }

        if (loadingPromises.has(ns)) {
            await loadingPromises.get(ns);
            isReady.value = true;
            return;
        }
        
        const promise = (async () =&amp;gt; {
            try {
                const importedMessages = await import(`@/locales/${currentLocale}/${ns}.json`);
                i18n.global.mergeLocaleMessage(currentLocale, {
                    [ns]: importedMessages.default,
                });
            } catch (error) {
                console.error(`Failed to load namespace &quot;${ns}&quot;:`, error);
            }
        })();
        
        loadingPromises.set(ns, promise);
        await promise;
        isReady.value = true;
    };

    watchEffect(() =&amp;gt; {
        load(namespace);
    });

    return { t, isReady };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;namespaces&quot;&gt;&lt;strong&gt;Namespaces&lt;/strong&gt;&lt;/h5&gt;
&lt;p&gt;Your translation files are now organized by language and namespace. A crucial part of this setup is defining a type for your namespaces.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/types/namespaces.ts&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// You must manually update this type with new namespaces
export type I18nNamespace = 'common' | 'home' | 'about' | 'products' | 'cart';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/locales/common.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;en&quot;: {
    &quot;submit&quot;: &quot;Submit&quot;,
    &quot;cancel&quot;: &quot;Cancel&quot;
  },
  &quot;fr&quot;: {
    &quot;submit&quot;: &quot;Soumettre&quot;,
    &quot;cancel&quot;: &quot;Annuler&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/locales/en/home.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;pageTitle&quot;: &quot;Welcome to our Home Page&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/locales/fr/home.json&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;pageTitle&quot;: &quot;Bienvenue sur notre page d'accueil&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;component-usage-homepage-vue-&quot;&gt;&lt;strong&gt;Component Usage (&lt;code&gt;HomePage.vue&lt;/code&gt;)&lt;/strong&gt;&lt;/h5&gt;
&lt;p&gt;The component is simple and declarative. It just uses the &lt;code&gt;isReady&lt;/code&gt; state to manage the UI.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;lt;template&amp;gt;
  &amp;lt;div v-if=&quot;!isReady&quot;&amp;gt;
    &amp;lt;p&amp;gt;Loading translations...&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div v-else&amp;gt;
    &amp;lt;h1&amp;gt;{{ t('home.pageTitle') }}&amp;lt;/h1&amp;gt;
    &amp;lt;button&amp;gt;{{ t('common.submit') }}&amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { useI18nNamespace } from '@/composables/useI18nNamespace';

const { t, isReady } = useI18nNamespace('home');
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;where-to-use-this-approach&quot;&gt;&lt;strong&gt;Where to Use This Approach&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;This solution is ideal for any modern web application that is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Large and growing&lt;/strong&gt;: As your application's features and supported languages increase, this architecture will save you from performance bottlenecks and organizational chaos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance-critical&lt;/strong&gt;: E-commerce sites, content management systems, or any application where a fast initial page load is a priority will benefit immensely from lazy-loading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Developed by a team&lt;/strong&gt;: This structure prevents frequent merge conflicts and makes it easier to onboard new developers, as the translation files are logically organized alongside the features they belong to.&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/5237/a-scalable-and-type-safe-i18n-solution-for-modern-web-applications</guid>
<pubDate>Mon, 08 Sep 2025 19:46:29 +0000</pubDate>
</item>
<item>
<title>Using Firebase and Stripe for Modern Web Applications</title>
<link>https://coderlegion.com/4804/using-firebase-and-stripe-for-modern-web-applications</link>
<description>&lt;p&gt;Using Firebase and Stripe for Modern Web Applications&lt;/p&gt;
&lt;p&gt;Building secure, scalable, and efficient applications often requires integrating authentication, databases, and payment systems. Two popular tools that developers rely on are &lt;a rel=&quot;nofollow&quot; href=&quot;https://firebase.google.com/&quot;&gt;Firebase&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://stripe.com/&quot;&gt;Stripe&lt;/a&gt;. Together, they provide a seamless backend + payment infrastructure that accelerates development without heavy server management.&lt;/p&gt;
&lt;p&gt;In this tutorial, we’ll walk through how to integrate Firebase and Stripe in your project, with best practices for performance, serverless deployment, and real-world scenarios.&lt;/p&gt;
&lt;h3 id=&quot;why-use-firebase-stripe-&quot;&gt;Why Use Firebase + Stripe?&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Firebase handles:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Authentication (Google, GitHub, Email, Phone, etc.)&lt;/li&gt;
&lt;li&gt;Realtime database &amp;amp; Firestore&lt;/li&gt;
&lt;li&gt;Hosting &amp;amp; serverless functions&lt;/li&gt;
&lt;li&gt;Notifications and cloud messaging&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2.&lt;strong&gt;Stripe provides&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secure and compliant payments&lt;/li&gt;
&lt;li&gt;Subscriptions and billing&lt;/li&gt;
&lt;li&gt;Global payment methods&lt;/li&gt;
&lt;li&gt;Scalable APIs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When combined, Firebase + Stripe lets you build production-ready SaaS, e-commerce, or subscription apps with minimal backend code.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-firebase&quot;&gt;Setting Up Firebase&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Go to the &lt;a rel=&quot;nofollow&quot; href=&quot;https://console.firebase.google.com/&quot;&gt;Firebase Console&lt;/a&gt; and create a new project&lt;/li&gt;
&lt;li&gt;Add Firebase Authentication → enable Email/Password or OAuth&lt;br&gt;
providers.&lt;/li&gt;
&lt;li&gt;Set up Cloud Firestore for storing user data and transactions.&lt;/li&gt;
&lt;li&gt;Deploy backend logic using Firebase Cloud Functions (powered by&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/serverless-framework&quot;&gt;serverless framework&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;setting-up-stripe&quot;&gt;Setting Up Stripe&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create a free account on &lt;a rel=&quot;nofollow&quot; href=&quot;https://stripe.com/&quot;&gt;Stripe&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;From the dashboard, copy your API keys.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the Stripe SDK:&lt;/p&gt;
&lt;p&gt;npm install stripe firebase-admin firebase-functions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a test product or subscription plan in your Stripe Dashboard.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;integrating-firebase-cloud-functions-with-stripe&quot;&gt;Integrating Firebase Cloud Functions with Stripe&lt;/h3&gt;
&lt;p&gt;Example function for creating a checkout session:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const functions = require(&quot;firebase-functions&quot;);
const stripe = require(&quot;stripe&quot;)(process.env.STRIPE_SECRET_KEY);

exports.createCheckoutSession = functions.https.onCall(async (data, context) =&amp;gt; {
  const session = await stripe.checkout.sessions.create({
    payment_method_types: [&quot;card&quot;],
    line_items: [
      {
        price: data.priceId,
        quantity: 1,
      },
    ],
    mode: &quot;subscription&quot;,
    success_url: &quot;https://yourapp.com/success&quot;,
    cancel_url: &quot;https://yourapp.com/cancel&quot;,
  });
  return { id: session.id };
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function can be called from your frontend using Firebase SDK.&lt;/p&gt;
&lt;h3 id=&quot;best-practices-for-performance-amp-security&quot;&gt;Best Practices for Performance &amp;amp; Security&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use a &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/bastion-server&quot;&gt;bastion server&lt;/a&gt; or secure environment for sensitive API&lt;br&gt;
operations.&lt;/li&gt;
&lt;li&gt;Deploy in &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/serverless-containers&quot;&gt;serverless containers&lt;/a&gt; for scalability.&lt;/li&gt;
&lt;li&gt;Ensure PCI compliance via Stripe’s hosted checkout.&lt;/li&gt;
&lt;li&gt;Use Firebase Authentication to link payments with user accounts.&lt;/li&gt;
&lt;li&gt;Optimize billing operations with &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/server-optimization&quot;&gt;server optimization&lt;/a&gt; techniques.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;advanced-use-cases&quot;&gt;Advanced Use Cases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SaaS Apps → Manage &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/serverless-ml&quot;&gt;serverless ML&lt;/a&gt; workflows, bill users per usage.&lt;/li&gt;
&lt;li&gt;Gaming Platforms → Use &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/lambda-gpus&quot;&gt;lambda GPUs&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/serverless-gpu&quot;&gt;serverless GPU&lt;/a&gt; for compute&lt;br&gt;
while charging via Stripe.&lt;/li&gt;
&lt;li&gt;Virtual Desktops → Combine with &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/non-persistent-vdi&quot;&gt;non-persistent VDI&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/aws-appstream-vs-workspaces&quot;&gt;AWS AppStream&lt;br&gt;
vs Workspaces&lt;/a&gt; billing.&lt;/li&gt;
&lt;li&gt;Hybrid Architectures → Deploy with &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/on-premises-server&quot;&gt;on premises servers&lt;/a&gt; + Firebase&lt;br&gt;
Cloud Functions.&lt;/li&gt;
&lt;li&gt;Frontend Hosting → Integrate with &lt;a rel=&quot;nofollow&quot; href=&quot;https://serverlesssavants.org/vercel-serverless&quot;&gt;Vercel Serverless&lt;/a&gt; or similar&lt;br&gt;
providers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;conclusion-1&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;By combining Firebase and Stripe, you eliminate the need for managing on prem servers, payment gateways, or complex authentication stacks. This integration is ideal for startups, SaaS projects, and enterprise systems looking for top-rated serverless hosting for frontend developers.&lt;/p&gt;
</description>
<category>Getting Started</category>
<guid isPermaLink="true">https://coderlegion.com/4804/using-firebase-and-stripe-for-modern-web-applications</guid>
<pubDate>Mon, 18 Aug 2025 20:25:55 +0000</pubDate>
</item>
<item>
<title>Ethereum Basics: From Wallets to Smart Contracts</title>
<link>https://coderlegion.com/3852/ethereum-basics-from-wallets-to-smart-contracts</link>
<description>&lt;h3 id=&quot;opening-the-door-wallets-amp-addresses&quot;&gt;Opening the Door: Wallets &amp;amp; Addresses&lt;/h3&gt;
&lt;p&gt;A wallet isn’t just where you “keep your crypto”—it’s your digital identity on Ethereum.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Public Address&lt;/strong&gt; = like your email (where people send you ETH)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Private Key&lt;/strong&gt; = your super-secret password to approve transactions&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;With great private keys comes great responsibility.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Keep your private key off screenshots, sticky notes, or the back of your hand. Seriously.&lt;/p&gt;
&lt;h4 id=&quot;sending-eth-how-transactions-work&quot;&gt;Sending ETH: How Transactions Work&lt;/h4&gt;
&lt;p&gt;Think of a transaction like mailing a check:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You write the address + amount&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You sign it with your private key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You pay a gas fee (like postage)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ethereum confirms and records it forever&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once it's in, it’s in. Ethereum doesn’t do &lt;strong&gt;“undo.”&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&quot;diving-into-smart-contracts&quot;&gt;Diving Into Smart Contracts&lt;/h4&gt;
&lt;p&gt;A &lt;strong&gt;smart contract&lt;/strong&gt; is like a vending machine that runs on code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You send ETH → The machine checks the rules → It delivers the snack (or doesn’t)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These contracts automate everything from NFTs to DeFi lending to on-chain games—no humans in between.&lt;/p&gt;
&lt;h4 id=&quot;-the-tools-you-need&quot;&gt;⚙️ The Tools You Need&lt;/h4&gt;
&lt;p&gt;Your Ethereum toolbox :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://metamask.io/&quot;&gt;MetaMask&lt;/a&gt; – Your wallet and dApp gateway&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://remix-project.org/?lang=en&quot;&gt;Remix IDE&lt;/a&gt; – Try writing your first contract in the browser&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://archive.trufflesuite.com/&quot;&gt;Truffle&lt;/a&gt; / &lt;a rel=&quot;nofollow&quot; href=&quot;https://hardhat.org/&quot;&gt;Hardhat&lt;/a&gt; – Full toolkits for bigger dApps&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These help you write, test, and deploy Solidity code like a pro.&lt;/p&gt;
&lt;h3 id=&quot;so-you-met-a-fox-and-accidentally-discovered-the-world-computer&quot;&gt;So You Met a Fox… and Accidentally Discovered the World Computer&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/felikgt5koyi9vskgio6.png&quot; alt=&quot;Metamask&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;At first, it looked like just another crypto wallet... until I realized I had downloaded a portal to a decentralized world computer.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;-ethereum-is-more-than-a-coin-it-s-a-world-computer&quot;&gt;♦ Ethereum Is More Than a Coin — It’s a World Computer&lt;/h4&gt;
&lt;p&gt;Ethereum runs on something called the Ethereum Virtual Machine (EVM) — a fancy way of saying:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Everyone runs the same code, and everyone agrees on the result.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Every Ethereum node is like a tiny brain in a big robot. Together, they make Ethereum a global, unstoppable, tamper-proof machine.&lt;/p&gt;
&lt;p&gt;You’ve heard of the cloud? Ethereum is the thunderstorm. ⚡&lt;/p&gt;
&lt;h4 id=&quot;eoas-vs-contracts-who-runs-the-show-&quot;&gt;EOAs vs. Contracts — Who Runs the Show?&lt;/h4&gt;
&lt;p&gt;You (and MetaMask) are using an Externally Owned Account (EOA):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Has a private key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can send transactions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can own and control smart contracts&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But the smart contracts themselves? They’re contract accounts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;No private key&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can receive ETH&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React only when triggered&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can think of EOAs as players and contracts as automated chessboards that move when touched.&lt;/p&gt;
&lt;h4 id=&quot;your-first-contract-the-testnet-faucet&quot;&gt;Your First Contract: The Testnet Faucet&lt;/h4&gt;
&lt;p&gt;Let’s make it rain (test ETH)!&lt;/p&gt;
&lt;p&gt;Here’s a super simple (but very insecure) smart contract:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;function withdraw(uint amount) public {
  require(amount &amp;lt;= 0.1 ether);
  msg.sender.transfer(amount);
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This lets anyone request up to 0.1 ether. It’s like asking a magical bank to give you some coins—if the rules allow.&lt;/p&gt;
&lt;p&gt;Step-by-step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Paste this into Remix IDE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compile it with the Solidity compiler&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploy it with MetaMask on the Ropsten testnet&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send some ETH to the contract&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Call withdraw(100000000000000000) and voilà! ETH sent!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Congratulations—you just made money move with code.&lt;/p&gt;
&lt;h4 id=&quot;what-you-really-did&quot;&gt;What You Really Did&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Created a wallet&lt;/li&gt;
&lt;li&gt;Funded it with test ETH&lt;/li&gt;
&lt;li&gt;Wrote a contract&lt;/li&gt;
&lt;li&gt;Deployed it on the testnet&lt;/li&gt;
&lt;li&gt;Interacted with Ethereum like a dev&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;final-thoughts-1&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;You didn’t just install a wallet. You just shook hands with the future of the internet.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ethereum lets you go beyond holding coins—it lets you build logic, automation, and applications around value itself.&lt;/p&gt;
&lt;p&gt;Welcome to Web3. This is just the beginning.&lt;/p&gt;
</description>
<category>Blockchain</category>
<guid isPermaLink="true">https://coderlegion.com/3852/ethereum-basics-from-wallets-to-smart-contracts</guid>
<pubDate>Wed, 09 Jul 2025 13:50:42 +0000</pubDate>
</item>
<item>
<title>From Basics to Best Practices: Why Angular Developers Should Adopt GraphQL</title>
<link>https://coderlegion.com/3372/from-basics-to-best-practices-why-angular-developers-should-adopt-graphql</link>
<description>&lt;hr&gt;
&lt;p&gt;As Angular developers, we’re used to structured development, powerful CLI tools, and TypeScript's safety. But when it comes to APIs, most of us still work with REST. While REST has served us well, &lt;strong&gt;GraphQL&lt;/strong&gt; offers a modern, more flexible alternative—especially when building &lt;strong&gt;dynamic, scalable Angular applications&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In this blog, we’ll explore why GraphQL fits naturally into Angular projects, how to get started, and what best practices to follow.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-should-angular-developers-care-about-graphql-&quot;&gt;Why Should Angular Developers Care About GraphQL?&lt;/h3&gt;
&lt;h4 id=&quot;1-strong-typing-typescript-s-best-friend&quot;&gt;1. Strong Typing = TypeScript's Best Friend&lt;/h4&gt;
&lt;p&gt;GraphQL uses a &lt;strong&gt;strongly-typed schema&lt;/strong&gt;, which integrates perfectly with Angular's TypeScript-first ecosystem. With tools like &lt;a rel=&quot;nofollow&quot; href=&quot;https://the-guild.dev/graphql/codegen&quot;&gt;GraphQL Code Generator&lt;/a&gt;, you can auto-generate TypeScript types for your queries, reducing errors and boosting DX (developer experience).&lt;/p&gt;
&lt;h4 id=&quot;2-single-endpoint-precise-queries&quot;&gt;2. Single Endpoint, Precise Queries&lt;/h4&gt;
&lt;p&gt;Instead of juggling multiple REST endpoints, GraphQL uses &lt;strong&gt;one endpoint&lt;/strong&gt; and lets clients ask for exactly what they need. This avoids over-fetching/under-fetching and speeds up UI development in Angular components.&lt;/p&gt;
&lt;h4 id=&quot;3-better-for-complex-uis&quot;&gt;3. Better for Complex UIs&lt;/h4&gt;
&lt;p&gt;GraphQL’s nested queries let you fetch related data in one go—ideal for component-driven UIs in Angular, where you need parent and child data together.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;setting-up-graphql-in-an-angular-project&quot;&gt;Setting Up GraphQL in an Angular Project&lt;/h3&gt;
&lt;h4 id=&quot;step-1-install-apollo-client&quot;&gt;Step 1: Install Apollo Client&lt;/h4&gt;
&lt;p&gt;Use &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.apollographql.com/docs/angular/&quot;&gt;Apollo Angular&lt;/a&gt; to integrate GraphQL easily.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ng add apollo-angular
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the CLI command doesn’t work, install manually:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install @apollo/client graphql apollo-angular
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;step-2-configure-apollo-client&quot;&gt;Step 2: Configure Apollo Client&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// app.module.ts
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular';
import { HttpLink } from 'apollo-angular/http';
import { InMemoryCache } from '@apollo/client/core';

@NgModule({
  imports: [HttpClientModule, ApolloModule],
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: (httpLink: HttpLink) =&amp;gt; ({
        cache: new InMemoryCache(),
        link: httpLink.create({ uri: 'https://your-graphql-api.com/graphql' }),
      }),
      deps: [HttpLink],
    },
  ],
})
export class AppModule {}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;step-3-create-a-query-in-your-component&quot;&gt;Step 3: Create a Query in Your Component&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// app.component.ts
import { Component } from '@angular/core';
import { Apollo, gql } from 'apollo-angular';

const GET_USERS = gql`
  query {
    users {
      id
      name
      email
    }
  }
`;

@Component({
  selector: 'app-root',
  template: `
    &amp;lt;h1&amp;gt;Users&amp;lt;/h1&amp;gt;
    &amp;lt;ul *ngIf=&quot;users&quot;&amp;gt;
      &amp;lt;li *ngFor=&quot;let user of users&quot;&amp;gt;{{ user.name }} ({{ user.email }})&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  `,
})
export class AppComponent {
  users: any[] = [];

  constructor(private apollo: Apollo) {
    this.apollo.watchQuery({ query: GET_USERS }).valueChanges.subscribe((result: any) =&amp;gt; {
      this.users = result?.data?.users || [];
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;bonus-auto-generate-types&quot;&gt;Bonus: Auto-Generate Types&lt;/h3&gt;
&lt;p&gt;Install GraphQL Code Generator:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install @graphql-codegen/cli
npx graphql-codegen init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tool reads your schema and queries, and auto-generates TypeScript interfaces, query functions, and hooks for Angular.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;best-practices-for-angular-graphql&quot;&gt;Best Practices for Angular + GraphQL&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Practice                     &lt;/th&gt;&lt;th&gt;Why it matters&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;✅ Use GraphQL Codegen        &lt;/td&gt;&lt;td&gt;Ensures strict type safety and DX&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;✅ Use Apollo Caching         &lt;/td&gt;&lt;td&gt;Boosts performance with normalized caching&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;✅ Separate Queries/Mutations &lt;/td&gt;&lt;td&gt;Keep queries in &lt;code&gt;.graphql.ts&lt;/code&gt; or &lt;code&gt;.gql&lt;/code&gt; files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;✅ Use Fragments              &lt;/td&gt;&lt;td&gt;Reuse common fields between components&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;✅ Use Interceptors           &lt;/td&gt;&lt;td&gt;Add auth tokens dynamically&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;✅ Paginate Large Lists       &lt;/td&gt;&lt;td&gt;Avoid loading unnecessary data&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;angular-amp-graphql-auth-tip&quot;&gt;Angular &amp;amp; GraphQL Auth Tip&lt;/h3&gt;
&lt;p&gt;To attach auth tokens to GraphQL requests, use an &lt;code&gt;ApolloLink&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { setContext } from '@apollo/client/link/context';

const authLink = setContext((_, { headers }) =&amp;gt; {
  const token = localStorage.getItem('token');
  return {
    headers: {
      ...headers,
      Authorization: token ? `Bearer ${token}` : '',
    },
  };
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then combine &lt;code&gt;authLink&lt;/code&gt; with &lt;code&gt;httpLink&lt;/code&gt; using &lt;code&gt;from&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;link: from([authLink, httpLink.create({ uri: '...' })])
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;summary-why-angular-devs-should-adopt-graphql&quot;&gt;Summary: Why Angular Devs Should Adopt GraphQL&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Benefit                  &lt;/th&gt;&lt;th&gt;Impact&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Typed queries            &lt;/td&gt;&lt;td&gt;TypeScript-friendly development&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Declarative data loading &lt;/td&gt;&lt;td&gt;Cleaner, more readable components&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Schema introspection     &lt;/td&gt;&lt;td&gt;Better tooling and autocompletion&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Single endpoint          &lt;/td&gt;&lt;td&gt;Less REST boilerplate, more flexibility&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ecosystem support        &lt;/td&gt;&lt;td&gt;Apollo, Codegen, DevTools, Angular CLI&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;useful-resources&quot;&gt;Useful Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.apollographql.com/docs/angular/&quot;&gt;Apollo Angular Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://the-guild.dev/graphql/codegen&quot;&gt;GraphQL Code Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.graphqlbin.com/&quot;&gt;GraphQL Playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://graphql.org/learn/best-practices/&quot;&gt;GraphQL Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Ready to ditch the REST and supercharge your Angular app?&lt;/strong&gt; GraphQL isn't just a trend—it's a robust tool for building modern, efficient frontends. And in Angular’s TypeScript-powered world, it's a perfect match.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/3372/from-basics-to-best-practices-why-angular-developers-should-adopt-graphql</guid>
<pubDate>Fri, 20 Jun 2025 03:04:20 +0000</pubDate>
</item>
<item>
<title>Learnings from using Sitecore ADM</title>
<link>https://coderlegion.com/1677/learnings-from-using-sitecore-adm</link>
<description>&lt;p&gt;If you worked with a Sitecore XP website that has been live for a long time, I am sure you are familiar with the xDB cleanup requirements. I usually recommend to agree xDB data retention and set up the clean up process from day 1, but it is not always possible. Some websites were developed on an older version of Sitecore that did not have the built-in functionality for data removal, or the volume of xDB data was underestimated, or maybe tracking was enabled later down the line without considering data retention.&lt;/p&gt;
&lt;p&gt;This is a common issue and the exact reason why &lt;a rel=&quot;nofollow&quot; href=&quot;https://support.sitecore.com/kb?id=kb_article_view&amp;amp;sysparm_article=KB0232559&quot;&gt;Sitecore Analytics Database Manager (ADM) module&lt;/a&gt; exists. It allows viewing xDB records statistics and removing collection data (raw analytical data collected by Sitecore XP) via Sitecore UI while keeping the data integrity.&lt;/p&gt;
&lt;p&gt;However, when I tried to use ADM for the first time on Sitecore 9 and Sitecore 10 websites, I faced a few challenges, particularly when dealing with large volumes of old data. In this article, we’ll explore these challenges and look at optimisation strategies for efficient data cleanup.&lt;/p&gt;
&lt;h3 id=&quot;how-sitecore-adm-works&quot;&gt;How Sitecore ADM works&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=2867444197937350587&quot; alt=&quot;High-level overview of Sitecore ADM contact processing&quot;&gt;&lt;/p&gt;
&lt;p&gt;One thing that is critical to understand is that any ADM cleanup process consists of two key phases: task generation and task processing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Task generation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;During this phase, the module retrieves all contacts from the xDB regardless of the date range specified by the user. It begins processing the most recent contacts first and systematically works backward through the database. The module reads additional data associated with each contact, such as interactions and facets, to determine whether a record meets the deletion criteria. If a contact qualifies for deletion, its ID is stored in the [Tasks] table of the [ADM.Tasks] database for later task processing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Task processing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the second phase, the module processes the tasks generated in the previous step, deleting all records marked for removal.&lt;/p&gt;
&lt;p&gt;While this approach seems robust at first, it comes with a few significant limitations, particularly around the performance and scalability of the task generation phase.&lt;/p&gt;
&lt;h3 id=&quot;challenges&quot;&gt;Challenges&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. Inefficient SQL queries&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One of the main challenges is the way how the ADM module works with xDB Shard databases. Instead of relying on SQL indexes to efficiently filter contacts by date, the module retrieves all contacts and iterates through them, starting with the most recent. This results in slower data retrieval times, especially when working with large datasets spanning several years.&lt;/p&gt;
&lt;p&gt;For instance, even if you specify a short date range in 2022, the module will still need to process and check all contacts, including those from 2023-2024. This significantly increases the load on the shard databases, leading to higher data input/output operations and longer processing times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Threading and timeout issues&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By default, the ADM module operates with 4 threads and processes 1,000 contacts per batch. While these settings may be sufficient for smaller databases, you may want to tweak these settings if you have a larger database.&lt;/p&gt;
&lt;p&gt;The module’s batching system divides work between threads at the start of the process, meaning that if there is an SQL timeout in one of the threads, the entire thread will be aborted and the cleanup of this batch will not be completed. Therefore, the same process will have to be restarted from scratch to pick up remaining DB records. This can be frustrating, particularly when processing large datasets that take several hours to be processed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Single task limit&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another challenge is that only one cleanup process can run at a time. Attempting to create a new task while another is running will terminate the existing process, which makes it critical to monitor and manage the process carefully.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Limited pause functionality&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The task generation phase cannot be paused, it is supported only for task processing. There was an idea to run the cleanup in batches outside of business hours for one of the websites with a lot of xDB data to remove, but it was impossible to do run task generation in batches because it cannot be paused and it had to be done in one go.&lt;/p&gt;
&lt;h3 id=&quot;optimisation-tactics&quot;&gt;Optimisation tactics&lt;/h3&gt;
&lt;p&gt;Here are some tricks that helped me to reduce processing times and achieve the best performance for the cleanup in the past:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Read documentation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I know this sounds obvious, but if you plan to use ADM and have not looked at the documentation that comes with it, do it now! It is quite technical and can answer many questions you already have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Upscale to Premium tier&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If your server or database resources are under strain, especially Shards and ProcessingPools databases, you can try temporarily upscaling them for the cleanup. Premium Azure SKUs are optimised for high data I/O, which is critical when working with the ADM intensive data processing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Adjust performance settings&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There is some flexibility in tweaking the performance of the ADM module. You can increase multiple NumberOfThreads, RetrieveDataBatchSize and NumberOfConnectionRetries settings in the ADM configuration files (see section &quot;6. Performance Tuning&quot; in the ADM module documentation). This helps speed up task generation and processing but should be balanced against server and database available resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Measure and plan accordingly&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although tempting, splitting the cleanup process into smaller date ranges may not necessarily improve performance. The ADM module will still read all contacts every time, so this strategy may not be the most efficient for some cases. Instead, allow the process to finish at least one time and monitor its completion, note the time taken to better estimate and plan additional runs.&lt;/p&gt;
&lt;p&gt;Also, if you plan to perform the cleanup in multiple runs, start with the recent date ranges because they will be accessed first during the task generation phase.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Consider direct SQL queries&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you have an older version of Sitecore, or if you struggle to run ADM process on your xDB Shards even after tweaking performance settings, an alternative approach could be used - running direct SQL queries to clean up data (you can find a few useful scripts here). However, this method requires understanding of SQL scripts and xDB tables structure, so do this only if you have backed up your Shard DBs and you are confident in your skills.&lt;/p&gt;
&lt;p&gt;Sitecore xDB cleanup is not always simple and the ADM module can be useful tool for managing and cleaning up contact and interaction data. I hope this article helped you to understand how the module works, its limitations and tactics for optimising its performance.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Author: Anna Bastron, Sitecore MVP&lt;/em&gt;&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/1677/learnings-from-using-sitecore-adm</guid>
<pubDate>Thu, 27 Mar 2025 10:10:17 +0000</pubDate>
</item>
<item>
<title>Solved: blocked a frame with origin &quot;null&quot; from accessing a cross-origin frame</title>
<link>https://coderlegion.com/1476/solved-blocked-a-frame-with-origin-null-from-accessing-a-cross-origin-frame</link>
<description>&lt;h2 id=&quot;the-blocked-a-frame-with-origin-null-from-accessing-a-cross-origin-frame-error-and-how-to-resolve-it&quot;&gt;The 'Blocked a frame with origin &quot;null&quot; from accessing a cross-origin frame' Error and How to Resolve It&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;&quot;Blocked a frame with origin 'null' from accessing a cross-origin frame&quot;&lt;/strong&gt; error occurs due to &lt;strong&gt;cross-origin restrictions&lt;/strong&gt;. This issue typically arises when your browser tries to access content from a different origin (domain) or when you're running a local HTML file directly from your file system. Let's walk through the potential solutions to resolve this error.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;table-of-contents-&quot;&gt;&lt;strong&gt;Table of Contents:&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;What is the &quot;Blocked a frame with origin 'null' from accessing a cross-origin frame&quot; error?&lt;/li&gt;
&lt;li&gt;Why does the &quot;Blocked a frame with origin 'null' from accessing a cross-origin frame&quot; error occur?&lt;/li&gt;
&lt;li&gt;How to resolve this error:&lt;ol&gt;
&lt;li&gt;Use a local web server&lt;/li&gt;
&lt;li&gt;Disable cross-origin security in the browser (Not Recommended for production)&lt;/li&gt;
&lt;li&gt;Use extensions like XAMPP or Live Server&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;window.postMessage()&lt;/code&gt; method for cross-origin communication&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-is-the-blocked-a-frame-with-origin-null-from-accessing-a-cross-origin-frame-error-&quot;&gt;&lt;strong&gt;What is the &quot;Blocked a frame with origin 'null' from accessing a cross-origin frame&quot; Error?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;This error is a security feature in modern browsers like Google Chrome that prevents one document (or frame) from accessing another document that originates from a different domain, protocol, or port. If you see this error, it means the browser is blocking content for security reasons to prevent cross-site scripting (XSS) attacks.&lt;/p&gt;
&lt;h2 id=&quot;why-does-the-blocked-a-frame-with-origin-null-from-accessing-a-cross-origin-frame-error-occur-&quot;&gt;&lt;strong&gt;Why Does the &quot;Blocked a frame with origin 'null' from accessing a cross-origin frame&quot; Error Occur?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;This issue typically occurs when you're trying to display content from one website within an iframe or frame on another website, but the two domains are not the same. This is referred to as a &lt;strong&gt;cross-origin request&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you open a local HTML file directly in the browser (without a web server), the origin is often considered &quot;null,&quot; which causes the error. Browsers impose these restrictions for security purposes to prevent malicious access to data across domains.&lt;/p&gt;
&lt;p&gt;The error message usually looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DOMException: Blocked a frame with origin &quot;null&quot; from accessing a cross-origin frame.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;how-to-resolve-the-blocked-a-frame-with-origin-null-from-accessing-a-cross-origin-frame-error&quot;&gt;&lt;strong&gt;How to Resolve the &quot;Blocked a frame with origin 'null' from accessing a cross-origin frame&quot; Error&lt;/strong&gt;&lt;/h2&gt;
&lt;h3 id=&quot;solution-1-use-a-local-web-server&quot;&gt;&lt;strong&gt;Solution 1: Use a Local Web Server&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Running your webpage on a &lt;strong&gt;local web server&lt;/strong&gt; solves this issue by setting up a proper origin. You can do this easily by using tools like XAMPP, Python's built-in HTTP server, or any other local server setup.&lt;/p&gt;
&lt;p&gt;For example, if you're using &lt;strong&gt;Python&lt;/strong&gt;, you can run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```bash
python -m http.server 8000
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will serve your files at &lt;code&gt;http://localhost:8000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, you can set up a server using &lt;strong&gt;XAMPP&lt;/strong&gt; by moving your files to the &lt;code&gt;htdocs&lt;/code&gt; folder and starting the Apache server.&lt;/p&gt;
&lt;h3 id=&quot;solution-2-disable-cross-origin-security-in-the-browser-not-recommended-for-production-&quot;&gt;&lt;strong&gt;Solution 2: Disable Cross-Origin Security in the Browser (Not Recommended for Production)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Some developers attempt to bypass this error by disabling cross-origin security or the &lt;strong&gt;same-origin policy&lt;/strong&gt; in their browsers. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Disabling cross-origin security is extremely risky and should never be done in a production environment. This action makes your browser vulnerable to various security issues, such as cross-site scripting (XSS) attacks. It should only be used for local development and testing purposes.&lt;/p&gt;
&lt;p&gt;To disable cross-origin security in Chrome, you can launch it with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```bash
chrome.exe --disable-web-security --user-data-dir=&quot;C:\chrome_dev&quot;
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, this method is only for development and should be avoided in production environments.&lt;/p&gt;
&lt;h3 id=&quot;solution-3-use-extensions-like-xampp-or-live-server&quot;&gt;&lt;strong&gt;Solution 3: Use Extensions Like XAMPP or Live Server&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;You can use local server extensions, such as &lt;strong&gt;XAMPP&lt;/strong&gt; or &lt;strong&gt;Live Server&lt;/strong&gt;, which allow you to serve your files from a local server environment.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;XAMPP&lt;/strong&gt;: Install XAMPP and place your files in the &lt;code&gt;htdocs&lt;/code&gt; directory. Then start the Apache server and visit &lt;code&gt;http://localhost/yourfile.html&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Live Server&lt;/strong&gt;: If you're using &lt;strong&gt;Visual Studio Code (VS Code)&lt;/strong&gt;, the Live Server extension can quickly launch a local server with one click. It also provides auto-refresh and debugging features for smoother development.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;solution-4-use-the-window-postmessage-method-for-cross-origin-communication&quot;&gt;&lt;strong&gt;Solution 4: Use the &lt;code&gt;window.postMessage()&lt;/code&gt; Method for Cross-Origin Communication&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The best and most secure way to enable cross-origin communication between documents (or iframes) is by using the &lt;code&gt;window.postMessage()&lt;/code&gt; method. This allows you to send messages between windows or frames even if they come from different origins.&lt;/p&gt;
&lt;p&gt;Here’s an example of how to use &lt;code&gt;postMessage&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```javascript
// Sender (parent window)
window.postMessage('Hello from parent!', '*');

// Receiver (iframe)
window.addEventListener('message', function(event) {
    if (event.origin !== 'http://example.com') {
        return; // Ignore messages from unknown origins
    }
    console.log('Message received:', event.data);
});
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using &lt;code&gt;postMessage()&lt;/code&gt;, you can safely communicate across origins without violating the browser’s same-origin policy.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;conclusion-2&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While disabling cross-origin security might seem like a quick fix, it is &lt;strong&gt;highly discouraged&lt;/strong&gt; for any production-level work due to the significant security risks it introduces. The best practice is to serve your files through a &lt;strong&gt;local web server&lt;/strong&gt; or to use &lt;strong&gt;&lt;code&gt;window.postMessage()&lt;/code&gt;&lt;/strong&gt; for secure communication between frames or windows from different origins.&lt;/p&gt;
&lt;p&gt;Always be cautious when working with cross-origin content. Only disable security settings for local development, and make sure to follow best practices to ensure the security of your application.&lt;/p&gt;
</description>
<category>JavaScript</category>
<guid isPermaLink="true">https://coderlegion.com/1476/solved-blocked-a-frame-with-origin-null-from-accessing-a-cross-origin-frame</guid>
<pubDate>Fri, 14 Mar 2025 21:09:12 +0000</pubDate>
</item>
<item>
<title>Understanding JWT: From Basics to Advanced Security</title>
<link>https://coderlegion.com/1280/understanding-jwt-from-basics-to-advanced-security</link>
<description>
&lt;h2 id=&quot;introduction-the-evolution-of-web-authentication&quot;&gt;Introduction: The Evolution of Web Authentication&lt;/h2&gt;&lt;img src=&quot;https://images.unsplash.com/photo-1666969295767-4db7ff1f8fec?crop=entropy&amp;amp;cs=tinysrgb&amp;amp;fit=max&amp;amp;fm=jpg&amp;amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDYwfHxUb2tlbnxlbnwwfHx8fDE3NDAwODM4MDN8MA&amp;amp;ixlib=rb-4.0.3&amp;amp;q=80&amp;amp;w=2000&quot; alt=&quot;Understanding JWT: From Basics to Advanced Security&quot;&gt;&lt;p&gt;Early days of the web, authentication was relatively simple - users would log in, and servers would store their session information. However, as applications grew more complex and moved toward distributed systems and microservices, this traditional approach faced scalability challenges. JSON Web Tokens (JWTs), a revolutionary solution that changed how we handle authentication and authorization in modern web applications.&lt;/p&gt;&lt;p&gt;JWTs represent a paradigm shift in web security. Instead of the server keeping track of who's logged in, it issues a secure, self-contained token that holds all necessary information about the user. Think of it like a digital passport - once issued by a trusted authority, it can be verified anywhere without needing to check back with the issuing country. This approach has become increasingly important in our interconnected world of cloud services, mobile applications, and API-driven architectures.&lt;/p&gt;&lt;h2 id=&quot;part-1-jwt-fundamentals&quot;&gt;Part 1: JWT Fundamentals&lt;/h2&gt;&lt;h3 id=&quot;what-is-a-jwt&quot;&gt;What is a JWT?&lt;/h3&gt;&lt;p&gt;A JSON Web Token is a compact, self-contained way to securely transmit information between parties as a JSON object. Think of it as a digital passport that proves your identity and permissions in the web world. Each JWT contains three essential parts:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Header: The metadata section that describes the token's type and the signing algorithm used&lt;/li&gt;&lt;li&gt;Payload: The actual data (called &quot;claims&quot;) about the user and additional metadata&lt;/li&gt;&lt;li&gt;Signature: A verification seal that ensures the token hasn't been tampered with&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;When these three parts are combined, you get something that looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;the-anatomy-of-a-jwt-understanding-the-structure&quot;&gt;The Anatomy of a JWT: Understanding the Structure&lt;/h3&gt;&lt;p&gt;Before diving into how JWTs work, let's examine their structure in detail. A JWT consists of three distinct parts, each encoded in Base64URL format and separated by dots:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;1-header-the-metadata&quot;&gt;1. Header (The Metadata)&lt;/h3&gt;&lt;p&gt;The header contains information about how the token itself is constructed. It typically includes:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;alg&quot;: &quot;HS256&quot;,    // The algorithm used for signing
  &quot;typ&quot;: &quot;JWT&quot;       // The type of token
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-payload-the-claims&quot;&gt;2. Payload (The Claims)&lt;/h3&gt;&lt;p&gt;The payload carries the actual information about the user and token metadata. It contains claims, which are statements about an entity (typically the user) and additional metadata. &lt;/p&gt;&lt;p&gt;There are three types of claims:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Public Claims&lt;/strong&gt;: Custom claims registered in the IANA JSON Web Token Registry&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Private Claims&lt;/strong&gt;: Custom claims created for sharing information between parties&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Registered Claims&lt;/strong&gt;: Predefined claims like:&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;iss&quot;: &quot;auth.service.com&quot;,  // Issuer
  &quot;sub&quot;: &quot;user123&quot;,           // Subject
  &quot;exp&quot;: 1516239022,         // Expiration Time
  &quot;iat&quot;: 1516232822          // Issued At
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-signature-the-verification-seal&quot;&gt;3. Signature (The Verification Seal)&lt;/h3&gt;&lt;p&gt;The signature is created by taking the encoded header, encoded payload, and a secret key, then applying the algorithm specified in the header. For example, with HMAC SHA256:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;HMACSHA256(
  base64UrlEncode(header) + &quot;.&quot; +
  base64UrlEncode(payload),
  secret
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This signature ensures that the token hasn't been modified in transit and verifies its authenticity.&lt;/p&gt;&lt;h3 id=&quot;how-does-jwt-work-in-practice&quot;&gt;How Does JWT Work in Practice?&lt;/h3&gt;&lt;p&gt;The journey of a JWT follows a simple flow:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: When you log in successfully, the server creates a JWT containing information about your identity and permissions&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Token Storage&lt;/strong&gt;: Your application receives and stores this token&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Authorization&lt;/strong&gt;: For subsequent requests, your application includes this token in the header&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Verification&lt;/strong&gt;: The server checks the token's signature and grants access if it's valid&lt;/li&gt;&lt;/ol&gt;&lt;figure class=&quot;kg-card kg-image-card&quot;&gt;&lt;img src=&quot;https://guptadeepak.com/content/images/2025/02/JWT-Flow-deepak-gupta.png&quot; class=&quot;kg-image&quot; alt=&quot;Understanding JWT: From Basics to Advanced Security&quot; width=&quot;1760&quot; height=&quot;1948&quot; sizes=&quot;(min-width: 720px) 720px&quot;&gt;&lt;/figure&gt;&lt;p&gt;This process eliminates the need for the server to store session information, making JWTs perfect for modern, scalable applications.&lt;/p&gt;&lt;h2 id=&quot;part-2-the-security-challenge&quot;&gt;Part 2: The Security Challenge&lt;/h2&gt;&lt;h3 id=&quot;common-jwt-vulnerabilities&quot;&gt;Common JWT Vulnerabilities&lt;/h3&gt;&lt;p&gt;While JWTs are powerful, they're not immune to security issues. Here are the key vulnerabilities to watch out for:&lt;/p&gt;&lt;h4 id=&quot;signature-verification-flaws&quot;&gt;Signature Verification Flaws&lt;/h4&gt;&lt;p&gt;The signature is like a tamper-evident seal on a package. If the verification process is flawed or the secret key is weak, attackers can modify the token's contents without detection. This is particularly dangerous because it could allow unauthorized access to protected resources.&lt;/p&gt;&lt;h4 id=&quot;algorithm-confusion-attacks&quot;&gt;Algorithm Confusion Attacks&lt;/h4&gt;&lt;p&gt;JWTs support multiple signing algorithms, including a dangerous &quot;none&quot; algorithm. If your server isn't configured properly, an attacker might trick it into accepting an unsigned token, effectively bypassing security checks altogether.&lt;/p&gt;&lt;h4 id=&quot;client-side-storage-risks&quot;&gt;Client-Side Storage Risks&lt;/h4&gt;&lt;p&gt;Many applications store JWTs in browser storage (localStorage or sessionStorage), making them vulnerable to Cross-Site Scripting (XSS) attacks. Think of this like keeping your house key in an obvious place - if someone gains access to your browser's JavaScript environment, they could steal your token.&lt;/p&gt;&lt;h4 id=&quot;the-revocation-challenge&quot;&gt;The Revocation Challenge&lt;/h4&gt;&lt;p&gt;Unlike traditional session tokens, JWTs don't have a built-in way to be invalidated before they expire. This means if a token is compromised, it remains valid until its expiration time, potentially giving attackers a window of opportunity.&lt;/p&gt;&lt;h2 id=&quot;part-3-building-a-secure-jwt-implementation&quot;&gt;Part 3: Building a Secure JWT Implementation&lt;/h2&gt;&lt;h3 id=&quot;essential-security-practices&quot;&gt;Essential Security Practices&lt;/h3&gt;&lt;p&gt;Let's explore how to implement JWTs securely:&lt;/p&gt;&lt;h4 id=&quot;1-secure-communication&quot;&gt;1. Secure Communication&lt;/h4&gt;&lt;p&gt;Always transmit JWTs over HTTPS. This encrypts the token during transmission, preventing eavesdropping attacks. It's like sending sensitive documents through a secure courier service instead of regular mail.&lt;/p&gt;&lt;h4 id=&quot;2-smart-token-storage&quot;&gt;2. Smart Token Storage&lt;/h4&gt;&lt;p&gt;Instead of using browser storage, use HttpOnly cookies with the Secure flag enabled. This approach prevents JavaScript access to the token while ensuring it's only transmitted over secure connections. The cookie settings might look like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;Set-Cookie: access_token=&amp;lt;token&amp;gt;;
            HttpOnly;
            Secure;
            SameSite=Strict;
            Path=/api
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;3-token-lifecycle-management&quot;&gt;3. Token Lifecycle Management&lt;/h4&gt;&lt;p&gt;Implement a robust token lifecycle strategy:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Set short expiration times for access tokens (15-30 minutes)&lt;/li&gt;&lt;li&gt;Use refresh tokens for obtaining new access tokens&lt;/li&gt;&lt;li&gt;Maintain a token blacklist for revoked tokens&lt;/li&gt;&lt;li&gt;Implement token rotation to regularly replace active tokens&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;4-payload-security&quot;&gt;4. Payload Security&lt;/h4&gt;&lt;p&gt;Be mindful of what you include in your token payload:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Never store sensitive data like passwords or credit card numbers&lt;/li&gt;&lt;li&gt;Minimize the payload size to reduce overhead&lt;/li&gt;&lt;li&gt;Consider encrypting certain claims if they contain sensitive information&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;advanced-security-measures&quot;&gt;Advanced Security Measures&lt;/h3&gt;&lt;p&gt;Going beyond the basics:&lt;/p&gt;&lt;h4 id=&quot;1-fingerprinting&quot;&gt;1. Fingerprinting&lt;/h4&gt;&lt;p&gt;Include device or context information in the token to detect potential token theft:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  &quot;sub&quot;: &quot;1234567890&quot;,
  &quot;fingerprint&quot;: &quot;device_id|user_agent|ip_hash&quot;,
  &quot;exp&quot;: 1516239022
}
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;2-audience-validation&quot;&gt;2. Audience Validation&lt;/h4&gt;&lt;p&gt;Specify and validate the intended recipient of the token to prevent token reuse across different services:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  &quot;aud&quot;: &quot;&lt;a href=&quot;https://api.myservice.com&quot; rel=&quot;nofollow&quot;&gt;https://api.myservice.com&lt;/a&gt;&quot;,
  &quot;sub&quot;: &quot;1234567890&quot;,
  &quot;exp&quot;: 1516239022
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;part-4-the-future-of-jwt-security&quot;&gt;Part 4: The Future of JWT Security&lt;/h2&gt;&lt;h3 id=&quot;emerging-security-enhancements&quot;&gt;Emerging Security Enhancements&lt;/h3&gt;&lt;p&gt;The security landscape is constantly evolving, and JWT security is no exception. Here are some promising developments:&lt;/p&gt;&lt;h4 id=&quot;1-quantum-resistant-algorithms&quot;&gt;1. Quantum-Resistant Algorithms&lt;/h4&gt;&lt;p&gt;As quantum computing advances, new signing algorithms resistant to quantum attacks are being developed. These will ensure JWTs remain secure even in a post-quantum world.&lt;/p&gt;&lt;h4 id=&quot;2-dynamic-validation&quot;&gt;2. Dynamic Validation&lt;/h4&gt;&lt;p&gt;Future implementations might include real-time validation systems that can instantly revoke tokens based on security events or user behavior changes.&lt;/p&gt;&lt;h4 id=&quot;3-enhanced-standards&quot;&gt;3. Enhanced Standards&lt;/h4&gt;&lt;p&gt;The JWT standard continues to evolve with new security features and best practices. Stay updated with the latest JWT specifications and security recommendations from the IETF.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;JWTs represent a powerful solution for modern web authentication and authorization, but their security requires careful consideration and implementation. By understanding both the fundamentals and security challenges, and by implementing robust security measures, you can harness the benefits of JWTs while maintaining strong security.&lt;/p&gt;&lt;p&gt;Learn on JWT, OAuth, OIDC, and SAML: &lt;a rel=&quot;nofollow&quot; href=&quot;https://guptadeepak.com/demystifying-jwt-oauth-oidc-and-saml-a-technical-guide/&quot;&gt;https://guptadeepak.com/demystifying-jwt-oauth-oidc-and-saml-a-technical-guide/&lt;/a&gt;&lt;/p&gt;&lt;hr&gt;&lt;h3 id=&quot;quick-reference-jwt-security-checklist&quot;&gt;Quick Reference: JWT Security Checklist&lt;/h3&gt;&lt;p&gt;&amp;#10003; Use strong, unique signing keys&lt;br&gt;&amp;#10003; Implement proper algorithm validation&lt;br&gt;&amp;#10003; Store tokens securely (HttpOnly cookies)&lt;br&gt;&amp;#10003; Set appropriate token expiration&lt;br&gt;&amp;#10003; Implement token rotation&lt;br&gt;&amp;#10003; Validate token claims thoroughly&lt;br&gt;&amp;#10003; Monitor for security updates&lt;br&gt;&amp;#10003; Use HTTPS exclusively&lt;br&gt;&amp;#10003; Implement proper error handling&lt;br&gt;&amp;#10003; Regular security audits&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/1280/understanding-jwt-from-basics-to-advanced-security</guid>
<pubDate>Fri, 28 Feb 2025 19:34:07 +0000</pubDate>
</item>
</channel>
</rss>