<?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: Cn</title>
    <description>The latest articles on DEV Community by Cn (@cn308d66c92e2).</description>
    <link>https://dev.to/cn308d66c92e2</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4022031%2Fad680799-44e0-4e05-8f29-af4001370f84.png</url>
      <title>DEV Community: Cn</title>
      <link>https://dev.to/cn308d66c92e2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cn308d66c92e2"/>
    <language>en</language>
    <item>
      <title>The API Update That Quietly Made a Paid Product Free</title>
      <dc:creator>Cn</dc:creator>
      <pubDate>Thu, 06 Aug 2026 02:05:00 +0000</pubDate>
      <link>https://dev.to/cn308d66c92e2/the-api-update-that-quietly-made-a-paid-product-free-489i</link>
      <guid>https://dev.to/cn308d66c92e2/the-api-update-that-quietly-made-a-paid-product-free-489i</guid>
      <description>&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;A content platform I was updating had a familiar-looking editor: write your post, mark a line as "everything above this is free preview," publish. Readers see the free part; paying customers see the rest. Standard paywall pattern, nothing exotic.&lt;/p&gt;

&lt;p&gt;I needed to fix a batch of stale price references across several paid posts — pure text edits, nothing structural. Doing it by hand through the rich-text editor for a dozen posts is slow and error-prone, so I pulled each post's content through the platform's API, did the string replacement in code, and pushed the updated body back through the same API.&lt;/p&gt;

&lt;p&gt;Fast, clean, verifiable diff before and after. Or so I thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually happening
&lt;/h2&gt;

&lt;p&gt;The paywall boundary — "everything above this line is free" — isn't stored as part of the post body text. It's separate state, and the editor UI renders it as a marker positioned within the content. When I pushed a full-body replacement through the API, that marker didn't travel with it. On the next visit to the editor, the paywall boundary had silently reset to right after the first paragraph.&lt;/p&gt;

&lt;p&gt;For most of the posts, "right after the first paragraph" happened to be close enough to correct that nothing looked obviously wrong in the editor's own preview — which, critically, is rendered from the account owner's session. Owners can always see the full content, paid or not. The editor's preview will never show you what a non-paying visitor actually sees.&lt;/p&gt;

&lt;p&gt;For the posts where the intended free preview was substantial — several paragraphs of sample questions before the paywall — the reset boundary would have made almost the entire paid product readable for free the moment I hit publish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is the dangerous kind of bug
&lt;/h2&gt;

&lt;p&gt;Nothing about the update looked wrong. The text I changed was correct. The editor's own preview looked correct, because the editor's preview is authenticated as me. The only way to see the actual bug was to load the page with no session at all and see where the content actually cut off for a stranger.&lt;/p&gt;

&lt;p&gt;This is the same shape as the bundle-pricing bug I wrote about before: a piece of state that looks like it belongs to the content actually lives in a separate system, edited through a separate path, and nothing forces the two to stay in sync. Except this time the blast radius wasn't "a customer sees an outdated number" — it was "a paid product becomes free and nobody notices until revenue quietly drops."&lt;/p&gt;

&lt;h2&gt;
  
  
  How I caught it
&lt;/h2&gt;

&lt;p&gt;Same rule as always: don't trust the rendering, check the actual output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;public-post-url&amp;gt;"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"User-Agent: Mozilla/5.0"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"Question [0-9]*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A plain anonymous HTTP fetch, no login, filtered for a marker that only appears past a certain point in each post. Compare that against what should be visible for free. For three posts, content that should have cut off after item 5 was fully readable straight through to item 20.&lt;/p&gt;

&lt;p&gt;The account-owner preview inside the editor would never have shown this. It took an explicitly logged-out check to surface it — and that's the part worth internalizing: if a permission boundary exists, the only preview that actually validates it is one taken from outside that boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Once caught, fixing it was mechanical: reopen each affected post's paywall settings, drag the boundary marker back to its intended position, republish, re-verify with the same anonymous curl check. Nothing clever about the fix. The value was entirely in catching it before a reader did.&lt;/p&gt;

&lt;p&gt;Going forward, any workflow that updates paid content through an API now has a mandatory step: after publishing, re-fetch the public URL with no auth and confirm the paid section is actually gated. Not a one-time check — a step baked into the process, every time, because the failure mode is silent and the API makes it trivially repeatable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;APIs are usually the more trustworthy path — no flaky UI, no accidental clicks, a clean diff of what changed. But an API only guarantees the fields it explicitly manages. Anything the UI quietly maintains alongside the content — access boundaries, ordering, visibility flags, anything that isn't literally "the text" — can be invisible to that API and get reset the moment you bypass the UI that was implicitly protecting it.&lt;/p&gt;

&lt;p&gt;If you're editing paid or access-controlled content through anything other than the exact UI flow it was designed for, the question isn't "did my edit apply correctly." It's "what else does that UI silently manage that my edit didn't know to preserve" — and the only way to answer that is to check from outside the account that's editing it.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>webdev</category>
      <category>api</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>When a Price Change Doesn't Actually Change the Price Everywhere</title>
      <dc:creator>Cn</dc:creator>
      <pubDate>Mon, 27 Jul 2026 05:01:53 +0000</pubDate>
      <link>https://dev.to/cn308d66c92e2/when-a-price-change-doesnt-actually-change-the-price-everywhere-3h2</link>
      <guid>https://dev.to/cn308d66c92e2/when-a-price-change-doesnt-actually-change-the-price-everywhere-3h2</guid>
      <description>&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;A small content business (online courses, individually priced + bundle pricing) cut its bundle price a few weeks back. The main sales pages were updated correctly — price field, checkout, everything downstream of the "official" product record was consistent.&lt;/p&gt;

&lt;p&gt;But this business also runs a secondary content channel: dozens of SEO-oriented blog posts that link back to the main product, each with its own call-to-action line quoting the price. Standard content-marketing setup — write once, publish, let it sit and collect search traffic for months.&lt;/p&gt;

&lt;p&gt;Nobody re-checks old posts when a price changes. Why would you? The price is "the price," defined once in the product system. The blog posts just &lt;em&gt;reference&lt;/em&gt; it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually happening
&lt;/h2&gt;

&lt;p&gt;18 days after the price cut, 7 separate blog posts were still quoting the old, higher bundle price in their CTA text. Not because anyone made a mistake — the posts were correct &lt;em&gt;when they were written&lt;/em&gt;. They just never got touched again after the price changed elsewhere.&lt;/p&gt;

&lt;p&gt;This is the less dramatic sibling of the "bundle contains almost nothing" bug I wrote about last time. No broken checkout, no angry customer emails (it was a price &lt;em&gt;decrease&lt;/em&gt;, so if anything readers were mildly undersold). But it's the same underlying failure mode: &lt;strong&gt;content and pricing live in different systems, edited independently, with no mechanism forcing them to agree.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The more interesting failure mode — and the one that should actually worry you — is the reverse: a price &lt;em&gt;increase&lt;/em&gt; that old posts don't reflect. Now a reader clicks through expecting one price and sees another at checkout. That's a trust problem, not just a stale-number problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this scales badly
&lt;/h2&gt;

&lt;p&gt;One post with a wrong price is a typo. Seven posts with the same wrong price, discovered weeks later, is a pattern — and the pattern gets worse as content volume grows. Every additional blog post is another place a price can silently go stale. Nobody manually re-audits 20+ published posts every time a price changes; the audit cost grows linearly with content volume while nobody's incentive to actually do it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I found it
&lt;/h2&gt;

&lt;p&gt;Same approach as before: don't trust the rendering, diff the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"¥[0-9,]*"&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.html | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"¥300&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;¥800&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;¥1,200&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;¥2,480"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A one-line grep across every locally-saved post, filtered against the list of currently-valid prices. Anything left over is a stale number. Took under a minute to run, and immediately surfaced 7 hits across a content library that would take an hour to eyeball manually — and eyeballing is exactly the kind of check humans are bad at, because every individual post &lt;em&gt;looks&lt;/em&gt; fine in isolation. The mismatch only shows up when you compare across posts, and nobody does that by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Once flagged, the fix itself is boring — open each post's editor, swap the old price string for the current one, republish. The interesting part isn't the fix, it's that the check needs to exist &lt;em&gt;at all&lt;/em&gt;, and it needs to run every time pricing changes, not just once.&lt;/p&gt;

&lt;p&gt;If you're editing prices in one place and referencing them in another (blog posts, email templates, landing pages, changelogs — anywhere text repeats a number that lives elsewhere), that reference will drift eventually. The only question is whether you find out from a customer or from a grep.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;This is the same poka-yoke principle as last time, just applied at a different scale: the failure isn't in any single piece of content, it's in the &lt;em&gt;absence of a step&lt;/em&gt; that reconciles distributed copies of the same fact. Single source of truth is the textbook answer, but most small content operations don't have the infrastructure for that — so the practical fallback is a periodic diff: pull every place a number is repeated, compare it against the current source of truth, flag mismatches.&lt;/p&gt;

&lt;p&gt;It's not sophisticated. It just has to actually run.&lt;/p&gt;

&lt;p&gt;If you're maintaining more than a handful of content pieces that reference pricing, and haven't checked lately — it's worth five minutes with grep.&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>Poka-yoke for your online store: finding the bug that made a "bundle" contain almost nothing</title>
      <dc:creator>Cn</dc:creator>
      <pubDate>Thu, 09 Jul 2026 02:27:36 +0000</pubDate>
      <link>https://dev.to/cn308d66c92e2/poka-yoke-for-your-online-store-finding-the-bug-that-made-a-bundle-contain-almost-nothing-35fl</link>
      <guid>https://dev.to/cn308d66c92e2/poka-yoke-for-your-online-store-finding-the-bug-that-made-a-bundle-contain-almost-nothing-35fl</guid>
      <description>&lt;h2&gt;
  
  
  Poka-yoke, briefly
&lt;/h2&gt;

&lt;p&gt;Poka-yoke (ポカヨケ) is a term from Japanese manufacturing — mistake-proofing. It's not about detecting defects after the fact; it's about designing a check so an error can't slip through unnoticed in the first place. Toyota built an entire quality system around this idea: assume mistakes will happen, and put a mechanism in place that catches them automatically instead of relying on someone noticing.&lt;/p&gt;

&lt;p&gt;The same idea applies directly to content and e-commerce platforms — just applied to data instead of physical parts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Content platforms (think Substack, Gumroad, or any CMS where pricing and bundling are edited separately from the article body) let creators edit price, body text, and bundle membership independently. After enough edits — a price cut here, a bundle reshuffle there — it's easy to end up with a page that &lt;em&gt;looks&lt;/em&gt; fine but is quietly broken underneath.&lt;/p&gt;

&lt;p&gt;Two real patterns I ran into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A "bundle" product page rendered normally, but the actual bundle had lost almost all of its member items along the way.&lt;/li&gt;
&lt;li&gt;After an individual item's price was cut, the bundle's price wasn't updated — so buying the bundle ended up costing &lt;em&gt;more&lt;/em&gt; than buying the items separately, while the copy still said "bundle and save."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither of these throws an error. The rendering layer just displays whatever data exists, correct or not. There was no poka-yoke in place — nothing designed to catch the mistake automatically, so it just sat there silently costing money.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Pull the real data via the public API
&lt;/h3&gt;

&lt;p&gt;Most of these platforms expose a read API for published content. If you're logged in, you can usually just &lt;code&gt;fetch&lt;/code&gt; with &lt;code&gt;credentials: 'include'&lt;/code&gt; and reuse your browser session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://example.com/api/v3/notes/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?draft=false`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;include&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Cross-check "price mentioned in body" against "actual price"
&lt;/h3&gt;

&lt;p&gt;A simple regex over the body HTML surfaces every price string. Compare that against the real price field (or the actual bundle price) and any mismatch is a stale number left over from a previous edit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\$&lt;/span&gt;&lt;span class="sr"&gt;¥&lt;/span&gt;&lt;span class="se"&gt;][\d&lt;/span&gt;&lt;span class="sr"&gt;,&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Count actual bundle members vs. the claimed count
&lt;/h3&gt;

&lt;p&gt;Open the bundle page and count how many items are actually attached. Compare it against what the marketing copy claims ("5-piece bundle," etc.). Mismatches here are silent revenue leaks — a customer paying for a "bundle" that's mostly empty is not a good look.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Fix it via automation, not manual re-entry
&lt;/h3&gt;

&lt;p&gt;Once a mismatch is found, browser automation (Playwright, etc.) can walk through the normal edit → publish flow the same way a human would, just faster and across every affected item at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;None of this required anything sophisticated — no ML, no scraping tricks, just diffing public data against itself. The interesting part is &lt;em&gt;why&lt;/em&gt; nobody notices: creators trust the screen they're looking at. If the rendering layer never throws an error, there's no signal that anything is wrong. The only way to catch it is to stop trusting the UI and go straight to the data.&lt;/p&gt;

&lt;p&gt;That's the poka-yoke mindset applied to a digital storefront: don't wait to notice the mistake, build the check that catches it automatically. This generalizes to any platform where content, pricing, and bundling are edited independently over time — the more edit history a page has, the more likely something has quietly drifted out of sync.&lt;/p&gt;

&lt;p&gt;If you run a small store or content business and want a free pass over your own setup, feel free to reach out — happy to take a look.&lt;/p&gt;

</description>
      <category>webdevecommerceautomation</category>
    </item>
  </channel>
</rss>
