<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: dqj</title>
    <description>The latest articles on DEV Community by dqj (@dqj1998).</description>
    <link>https://dev.to/dqj1998</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3699688%2F0672afbc-fb16-4578-b8ff-d16dc237c174.png</url>
      <title>DEV Community: dqj</title>
      <link>https://dev.to/dqj1998</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dqj1998"/>
    <language>en</language>
    <item>
      <title>Running a high-end bakery in the age of industrialized code</title>
      <dc:creator>dqj</dc:creator>
      <pubDate>Wed, 28 Jan 2026 14:16:03 +0000</pubDate>
      <link>https://dev.to/dqj1998/running-a-high-end-bakery-in-the-age-of-industrialized-code-5c9l</link>
      <guid>https://dev.to/dqj1998/running-a-high-end-bakery-in-the-age-of-industrialized-code-5c9l</guid>
      <description>&lt;p&gt;When considering productivity, this analogy always comes to mind:&lt;br&gt;
&lt;strong&gt;High-end bakeries vs. industrial bread factories.&lt;/strong&gt;&lt;br&gt;
High-end bakeries produce bread of superior quality. They are meticulous, skillfully crafted, expensive—and serve a relatively small customer base.&lt;br&gt;
Factory bread, on the other hand, mass-produces "good enough" bread.&lt;/p&gt;

&lt;p&gt;As artificial intelligence begins to generate massive amounts of production code in an industrialized manner, I can't help but wonder if the software industry is heading in a similar direction.&lt;/p&gt;

&lt;p&gt;When AI can generate code that passes most code reviews in seconds, and most users won't even notice the difference, what does it mean that we spend ten times as much time writing elegant code?&lt;/p&gt;

&lt;p&gt;Software engineers may be in a worse position than high-end bakeries. &lt;br&gt;
&lt;strong&gt;Will anyone pay ten times more for your software simply because they appreciate its beautiful code?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I genuinely want to understand in what areas human effort can still create significant value, and in what areas might this effort quietly lose its due reward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/antcell/in-the-era-of-industrialized-code-are-you-still-planning-to-run-a-high-end-bakery-e3a777e20d0b" rel="noopener noreferrer"&gt;The full story on Medium&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>vibecoding</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Regression Bug Was the Most Important Result</title>
      <dc:creator>dqj</dc:creator>
      <pubDate>Tue, 13 Jan 2026 09:55:20 +0000</pubDate>
      <link>https://dev.to/dqj1998/the-regression-bug-was-the-most-important-result-1ki4</link>
      <guid>https://dev.to/dqj1998/the-regression-bug-was-the-most-important-result-1ki4</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Feature Wasn’t the Point&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two AI systems successfully implemented the requested UI feature.&lt;/p&gt;

&lt;p&gt;That part wasn’t interesting.&lt;/p&gt;

&lt;p&gt;What mattered was what broke outside the requested scope.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faaozvlnxztssewfk5ayy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faaozvlnxztssewfk5ayy.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Regression&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After the change:&lt;/p&gt;

&lt;p&gt;Select text in the editor&lt;/p&gt;

&lt;p&gt;Trigger the “Replace with” contextual action&lt;/p&gt;

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

&lt;p&gt;No error.&lt;br&gt;
No exception.&lt;br&gt;
Just silent failure.&lt;/p&gt;

&lt;p&gt;This is the most dangerous class of bug in production software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Happens with AI-Generated Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From an engineering perspective, this failure is predictable:&lt;/p&gt;

&lt;p&gt;The prompt emphasized new functionality&lt;/p&gt;

&lt;p&gt;Existing behavior was implicit, not asserted&lt;/p&gt;

&lt;p&gt;No test explicitly protected that interaction&lt;/p&gt;

&lt;p&gt;AI systems optimize for local correctness,&lt;br&gt;
not global behavioral invariants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where the Implementations Differed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A closer look at the code revealed meaningful trade-offs:&lt;/p&gt;

&lt;p&gt;One approach prioritized UX richness and localization&lt;/p&gt;

&lt;p&gt;The other emphasized modular helpers, safer selectors, and test coverage&lt;/p&gt;

&lt;p&gt;A concrete example:&lt;/p&gt;

&lt;p&gt;encodeURIComponent(...) vs CSS.escape(...)&lt;/p&gt;

&lt;p&gt;Both work, but only one is designed for DOM and selector safety.&lt;/p&gt;

&lt;p&gt;These choices matter months later, not minutes after generation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Unit Tests Made the Difference&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only one implementation introduced unit tests covering:&lt;/p&gt;

&lt;p&gt;State migration&lt;/p&gt;

&lt;p&gt;Regex escaping&lt;/p&gt;

&lt;p&gt;Replacement logic edge cases&lt;/p&gt;

&lt;p&gt;Those tests didn’t just validate correctness —&lt;br&gt;
they made the regression visible.&lt;/p&gt;

&lt;p&gt;Without them, the bug would likely ship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you evaluate AI coding tools in real projects, ask:&lt;/p&gt;

&lt;p&gt;What existing behavior is protected?&lt;/p&gt;

&lt;p&gt;What assumptions remain implicit?&lt;/p&gt;

&lt;p&gt;What breaks quietly?&lt;/p&gt;

&lt;p&gt;Demos won’t answer those questions.&lt;br&gt;
Production code will.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Final Thought&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most valuable result wasn’t the feature.&lt;/p&gt;

&lt;p&gt;It was identifying where AI coding systems still fail like junior engineers —&lt;br&gt;
and where they don’t.&lt;/p&gt;

&lt;p&gt;That distinction is what matters in real-world software.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>testing</category>
      <category>codequality</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Why WebAuthn Feels Easy — Until You Try to Ship It</title>
      <dc:creator>dqj</dc:creator>
      <pubDate>Thu, 08 Jan 2026 13:14:04 +0000</pubDate>
      <link>https://dev.to/dqj1998/why-webauthn-feels-easy-until-you-try-to-ship-it-5bi3</link>
      <guid>https://dev.to/dqj1998/why-webauthn-feels-easy-until-you-try-to-ship-it-5bi3</guid>
      <description>&lt;p&gt;&lt;em&gt;Every WebAuthn demo works. Production is where things quietly fall apart.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;WebAuthn demos are dangerously convincing.&lt;/p&gt;

&lt;p&gt;You follow a tutorial, register a passkey, authenticate successfully, and everything feels… solved.&lt;br&gt;&lt;br&gt;
No passwords. No OTPs. No friction.&lt;/p&gt;

&lt;p&gt;Then you ship it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Users authenticate when they shouldn’t&lt;/li&gt;
&lt;li&gt;Counters behave strangely&lt;/li&gt;
&lt;li&gt;Different browsers disagree&lt;/li&gt;
&lt;li&gt;Enterprise customers ask questions your demo never prepared you for&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gap — between &lt;em&gt;“it works”&lt;/em&gt; and &lt;em&gt;“it survives production”&lt;/em&gt; — is where most WebAuthn implementations fail.&lt;/p&gt;

&lt;p&gt;After watching teams repeat the same mistakes for years, &lt;strong&gt;three gaps show up again and again&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Gap #1: Demo-Grade Database Access
&lt;/h2&gt;

&lt;p&gt;Most WebAuthn demos include some version of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`SELECT * FROM users WHERE username = '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works in development.&lt;br&gt;&lt;br&gt;
It works in testing.&lt;br&gt;&lt;br&gt;
It even works in staging.&lt;/p&gt;

&lt;p&gt;Until a real username contains a quote — or someone decides to try &lt;code&gt;' OR '1'='1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This isn’t a WebAuthn problem.&lt;br&gt;&lt;br&gt;
It’s a &lt;em&gt;production engineering&lt;/em&gt; problem that demos ignore.&lt;/p&gt;

&lt;p&gt;Production systems parameterize everything, including dynamic &lt;code&gt;IN&lt;/code&gt; clauses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildInClause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(NULL)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;placeholders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference isn’t elegance — it’s &lt;strong&gt;survivability&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gap #2: “One-Call” Verification Illusions
&lt;/h2&gt;

&lt;p&gt;Demo verification often looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fido2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean. Minimal. Completely insufficient.&lt;/p&gt;

&lt;p&gt;In production, this single call hides multiple attack surfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replay attacks&lt;/li&gt;
&lt;li&gt;Counter rollback (cloned authenticators)&lt;/li&gt;
&lt;li&gt;Origin spoofing&lt;/li&gt;
&lt;li&gt;Challenge reuse across sessions&lt;/li&gt;
&lt;li&gt;Native app origin edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real verification logic validates &lt;em&gt;every layer&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;prevCounter&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;counterSupported&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter rollback detected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;expectedOrigin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;origin mismatch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Counters, origins, encoding, challenge binding, RP ID — none of these are optional in production.&lt;/p&gt;

&lt;p&gt;If you skip one, authentication still “works” — until it doesn’t.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gap #3: The Myth of “Single-Domain” WebAuthn
&lt;/h2&gt;

&lt;p&gt;Demos assume:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One RP ID&lt;/li&gt;
&lt;li&gt;One domain&lt;/li&gt;
&lt;li&gt;One policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Production environments don’t.&lt;/p&gt;

&lt;p&gt;Real systems need to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple subdomains&lt;/li&gt;
&lt;li&gt;Wildcard RP IDs&lt;/li&gt;
&lt;li&gt;Enterprise authenticator allowlists (AAGUID-based)&lt;/li&gt;
&lt;li&gt;Device limits per user&lt;/li&gt;
&lt;li&gt;Per-tenant timeouts&lt;/li&gt;
&lt;li&gt;Device binding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configuration stops being a constant and becomes &lt;em&gt;data&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"device_limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"registration_session_timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;999&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn’t complexity for complexity’s sake.&lt;br&gt;&lt;br&gt;
It’s the minimum required to support real organizations.&lt;/p&gt;




&lt;h2&gt;
  
  
  What “Production-Ready” Actually Means
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Demo Reality&lt;/th&gt;
&lt;th&gt;Production Reality&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;String queries&lt;/td&gt;
&lt;td&gt;Parameterized everywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verification&lt;/td&gt;
&lt;td&gt;Single function&lt;/td&gt;
&lt;td&gt;Multi-layer validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domains&lt;/td&gt;
&lt;td&gt;localhost&lt;/td&gt;
&lt;td&gt;Wildcards &amp;amp; subdomains&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Counters&lt;/td&gt;
&lt;td&gt;Ignored&lt;/td&gt;
&lt;td&gt;Rollback detection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy&lt;/td&gt;
&lt;td&gt;Hardcoded&lt;/td&gt;
&lt;td&gt;Per-tenant configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of these failures are obvious in demos.&lt;br&gt;&lt;br&gt;
All of them show up &lt;strong&gt;after users trust your system&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hard Truth About WebAuthn
&lt;/h2&gt;

&lt;p&gt;WebAuthn is easy to &lt;em&gt;demonstrate&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
It is hard to &lt;em&gt;operate safely&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The problem isn’t the standard — it’s the illusion that a passing demo equals a shippable system.&lt;/p&gt;

&lt;p&gt;If you’re planning to deploy passkeys beyond a prototype, &lt;strong&gt;treat demos as educational tools, not architectural references&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because in authentication, failure rarely looks like an error.&lt;br&gt;&lt;br&gt;
It looks like success — for the wrong user.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;I work on WebAuthn systems that need to survive real-world traffic, browsers, and enterprise constraints.&lt;br&gt;&lt;br&gt;
Most of the lessons above came from fixing things that “worked fine” — until they didn’t.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webauthn</category>
      <category>security</category>
      <category>authentication</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
