<?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: Pyae Phyo Maung</title>
    <description>The latest articles on DEV Community by Pyae Phyo Maung (@pyaephyomaungdev).</description>
    <link>https://dev.to/pyaephyomaungdev</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%2F4119617%2F161c9a01-5952-4200-a5bf-a10b69c75e30.jpg</url>
      <title>DEV Community: Pyae Phyo Maung</title>
      <link>https://dev.to/pyaephyomaungdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pyaephyomaungdev"/>
    <language>en</language>
    <item>
      <title>Building a Zero-Backend P2P Live Collaboration System in React with Yjs and WebRTC</title>
      <dc:creator>Pyae Phyo Maung</dc:creator>
      <pubDate>Sat, 19 Sep 2026 11:28:27 +0000</pubDate>
      <link>https://dev.to/pyaephyomaungdev/building-a-zero-backend-p2p-live-collaboration-system-in-react-with-yjs-and-webrtc-3ijb</link>
      <guid>https://dev.to/pyaephyomaungdev/building-a-zero-backend-p2p-live-collaboration-system-in-react-with-yjs-and-webrtc-3ijb</guid>
      <description>&lt;p&gt;If you spin up an authoritative WebSocket server for a collaborative spreadsheet, two problems hit you immediately:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Infrastructure Tax:&lt;/strong&gt; You are now paying for idle socket connections, Redis pub/sub adapters, and persistent database sync pipelines for users who might just leave a tab open in the background.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Data Liability:&lt;/strong&gt; Translation catalogs regularly contain confidential unreleased feature keys, internal system copy, and proprietary strings. The moment those strings transit an unencrypted central server, you inherit compliance and breach blast-radius liabilities.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For &lt;a href="https://github.com/pyaephyomaungdev/json-link" rel="noopener noreferrer"&gt;JSON Link&lt;/a&gt;, I wanted zero backend hosting costs and absolute data sovereignty. &lt;/p&gt;

&lt;p&gt;Here is how the browser-native peer-to-peer collaboration engine is engineered using &lt;strong&gt;Yjs CRDTs&lt;/strong&gt;, &lt;strong&gt;WebRTC DataChannels&lt;/strong&gt;, and &lt;strong&gt;Web Crypto (AES-GCM-256)&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  The State Topology: Serverless Mesh
&lt;/h3&gt;

&lt;p&gt;Traditional collaborative apps route every mutation through a central coordinator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser A  ──[WebSocket]──&amp;gt;  [Central Node + Redis/DB]  ──[WebSocket]──&amp;gt;  Browser B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of managing server state, JSON Link runs a direct peer-to-peer data mesh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser A  &amp;lt;══════ WebRTC DataChannel (Direct P2P) ══════&amp;gt;  Browser B
                     │                                │
                     └─── [Ephemeral Signaling Nodes] ───┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Signaling is strictly for discovery:&lt;/strong&gt; Public STUN and WebSocket signaling servers only broker the initial SDP offer/answer handshake and ICE candidates. No document payload is ever stored on signaling nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct browser transport:&lt;/strong&gt; Once ICE negotiation completes, peers stream raw delta updates over SCTP-based WebRTC DataChannels. Latency drops to direct network ping (&amp;lt;20ms on LAN/regional connections).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic CRDT convergence:&lt;/strong&gt; Concurrent keystrokes on the same table cell resolve automatically using &lt;strong&gt;Yjs state vectors and Lamport timestamps&lt;/strong&gt;. There is no "last-write-wins" database overwrite.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Zero-Knowledge Signaling: Client-Side PBKDF2 + AES-GCM
&lt;/h3&gt;

&lt;p&gt;Because public WebRTC signaling nodes can inspect transit packets during connection setup, room updates must be encrypted before leaving the browser.&lt;/p&gt;

&lt;p&gt;When a room password or PIN is configured, the browser derives an &lt;strong&gt;AES-GCM 256-bit&lt;/strong&gt; encryption key using &lt;strong&gt;PBKDF2-SHA256&lt;/strong&gt; with 100,000 iterations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deriveRoomKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;roomSalt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CryptoKey&lt;/span&gt;&lt;span class="o"&gt;&amp;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;enc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&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;keyMaterial&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;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;raw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;enc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PBKDF2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;deriveKey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deriveKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PBKDF2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;enc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;roomSalt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;keyMaterial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;encrypt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decrypt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every Yjs document delta is encrypted client-side with a unique 12-byte initialization vector (&lt;code&gt;IV&lt;/code&gt;) before transmission. Even if an intermediary intercepts the signaling room traffic, all payloads remain opaque ciphertext.&lt;/p&gt;




&lt;h3&gt;
  
  
  Integrating Yjs into a Reactive Spreadsheet Grid
&lt;/h3&gt;

&lt;p&gt;Binding CRDT updates to a React spreadsheet without triggering render thrashing requires separating the document state from ephemeral collaboration presence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Y&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebrtcProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;y-webrtc&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;ydoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Doc&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;yTranslations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ydoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;translations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Establish encrypted P2P mesh across fallback signaling clusters&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebrtcProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json-link-room-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ydoc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;signaling&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://y-webrtc.fly.dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://y-webrtc-signaling.fly.dev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;roomPin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Native PBKDF2-SHA256 derivation under the hood&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Synchronize CRDT changes into the table model&lt;/span&gt;
&lt;span class="nx"&gt;yTranslations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setGridData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yTranslations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toJSON&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Ephemeral awareness (multiplayer cursors &amp;amp; focused cells)&lt;/span&gt;
&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;awareness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalStateField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alex-42&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#10b981&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;clientX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;clientY&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;activeCell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth.login.title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&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;h3&gt;
  
  
  Where P2P Sucks (And How to Mitigate It)
&lt;/h3&gt;

&lt;p&gt;Full-mesh WebRTC is not magic; it comes with real-world engineering constraints:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The $O(N^2)$ Bandwidth Limit:&lt;/strong&gt;
In a full mesh, every peer connects to every other peer. For 3–6 collaborators working on a localization file, overhead is negligible (a few KB/s). Beyond 10–12 peers, upstream bandwidth multiplies rapidly. For JSON Link's target use-case (small product pods localizing software), full mesh is the sweet spot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NAT / Corporate Firewall Traversal:&lt;/strong&gt;
Strict symmetric NATs block direct peer-to-peer hole-punching. We bundle public STUN endpoints (&lt;code&gt;stun:stun.l.google.com:19302&lt;/code&gt;) for standard NAT mapping, with self-hostable signaling flags for teams behind strict corporate firewalls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline Resilience &amp;amp; AST Protection:&lt;/strong&gt;
When a peer disconnects, their edits persist locally via the File System Access API (direct two-way disk synchronization with &lt;code&gt;locales/*.json&lt;/code&gt;). On reconnect, Yjs automatically replays missing updates. To prevent non-technical contributors from accidentally breaking translation variables, an AST tokenizer locks ICU MessageFormat (&lt;code&gt;{count, plural, ...}&lt;/code&gt;), Mustache, and Printf placeholders into immutable chips during live editing.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Code &amp;amp; Architecture
&lt;/h3&gt;

&lt;p&gt;JSON Link is MIT licensed and runs 100% in the browser with no backend dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live App:&lt;/strong&gt; &lt;a href="https://json-link.pages.dev" rel="noopener noreferrer"&gt;https://json-link.pages.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source Code:&lt;/strong&gt; &lt;a href="https://github.com/pyaephyomaungdev/json-link" rel="noopener noreferrer"&gt;https://github.com/pyaephyomaungdev/json-link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Suite:&lt;/strong&gt; 463 automated tests across 60 test suites (Vitest + React Testing Library)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>webrtc</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Hidden Failure Modes in Localization Infrastructure (And Why We Architected a Local-First Solution)</title>
      <dc:creator>Pyae Phyo Maung</dc:creator>
      <pubDate>Sat, 12 Sep 2026 14:55:42 +0000</pubDate>
      <link>https://dev.to/pyaephyomaungdev/the-hidden-failure-modes-in-localization-infrastructure-and-why-we-architected-a-local-first-2m5b</link>
      <guid>https://dev.to/pyaephyomaungdev/the-hidden-failure-modes-in-localization-infrastructure-and-why-we-architected-a-local-first-2m5b</guid>
      <description>&lt;p&gt;In scaling cross-platform codebases across Flutter, React, iOS, and Android, localization (i18n) is frequently treated as an operational afterthought. Engineering teams default to Google Sheets, manual CSV exports, or enterprise cloud translation SaaS.&lt;/p&gt;

&lt;p&gt;From a systems engineering perspective, this workflow introduces significant production vulnerabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Syntax Corruption &amp;amp; Runtime Exceptions:&lt;/strong&gt; Non-technical translators or generalist AI models routinely corrupt or delete interpolation tokens (&lt;code&gt;{username}&lt;/code&gt;, &lt;code&gt;%1$s&lt;/code&gt;, &lt;code&gt;{{count}}&lt;/code&gt;). When compiled into production builds, missing arguments trigger uncaught exceptions and mobile app crashes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository Drift &amp;amp; Multi-Format Hell:&lt;/strong&gt; Mobile and web codebases consume fundamentally different formats: Flutter requires ARB (&lt;code&gt;app_en.arb&lt;/code&gt;) with &lt;code&gt;@key&lt;/code&gt; metadata; iOS requires &lt;code&gt;.strings&lt;/code&gt;; Android requires XML resources (&lt;code&gt;strings.xml&lt;/code&gt;); modern frontend stacks require TypeScript-typed JSON. Manual conversion leads to untracked key mismatches and broken CI pipelines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Residency &amp;amp; Credential Exposure:&lt;/strong&gt; Uploading proprietary product copy and unreleased feature strings to third-party translation clouds creates compliance friction and attack surface. Furthermore, managing third-party AI keys on shared backend servers introduces avoidable operational risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve this friction at the architectural level, we designed and open-sourced &lt;strong&gt;JSON Link&lt;/strong&gt; — a zero-backend, local-first localization workstation.&lt;/p&gt;




&lt;h3&gt;
  
  
  Architectural Design Decisions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Deterministic AST Token Isolation
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ICU / Mustache / Printf Scanner -&amp;gt; Recursive-descent AST parser -&amp;gt; Locked visual tags

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

&lt;/div&gt;



&lt;p&gt;Translation cells isolate parameter placeholders so translators cannot accidentally alter them. The engine validates variable parity across source and target strings in real time.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Local-First Direct Disk Sync
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser Memory -&amp;gt; Native File System Access API -&amp;gt; Atomic disk writes

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

&lt;/div&gt;



&lt;p&gt;Instead of forcing developers to download and unpack ZIP files, JSON Link binds directly to local project directories (e.g., &lt;code&gt;src/locales&lt;/code&gt; or &lt;code&gt;assets/l10n&lt;/code&gt;). A single click updates all language files simultaneously on disk.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Client-Side Cryptographic Isolation (BYOK OpenRouter)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API Credentials -&amp;gt; AES-GCM 256-bit encryption (Web Crypto API + PBKDF2) -&amp;gt; Client-side persistence

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

&lt;/div&gt;



&lt;p&gt;Zero intermediary servers exist between the browser and OpenRouter. Keys and translation payloads never transit an intermediary cloud proxy.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Zero-Knowledge Workspace Sharing &amp;amp; Team Handoff (.jsonlink)
&lt;/h4&gt;

&lt;p&gt;Collaborating across distributed teams usually requires setting up accounts or uploading data to shared cloud databases. We avoided that entirely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Storage Instant URL Sharing (&lt;code&gt;#share=...&lt;/code&gt;):&lt;/strong&gt; Compresses entire multi-language workspace payloads in-browser using DEFLATE (&lt;code&gt;pako&lt;/code&gt;) and packs them directly into the URL hash fragment. Plaintext data never transits or resides on any backend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-Side AES-GCM 256-bit Password Encryption:&lt;/strong&gt; Optional password protection available for both Instant URLs and standalone &lt;code&gt;.jsonlink&lt;/code&gt; project files. Key derivation utilizes PBKDF2 with SHA-256 (100,000 iterations, 16-byte random salt, and 12-byte initialization vector).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full Encryption Parity Across the App:&lt;/strong&gt; Integrated across all touchpoints including &lt;code&gt;ShareModal&lt;/code&gt; (Team Handoff), &lt;code&gt;SaveProjectModal&lt;/code&gt; (&lt;code&gt;File -&amp;gt; Save Project&lt;/code&gt;), and &lt;code&gt;ExitConfirmDialog&lt;/code&gt; (&lt;code&gt;Home&lt;/code&gt; save guard).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Decryption Dialog:&lt;/strong&gt; Visiting an encrypted share URL or uploading a password-protected &lt;code&gt;.jsonlink&lt;/code&gt; file triggers the &lt;code&gt;UnlockShareDialog&lt;/code&gt;. Cryptographic authentication tag verification detects incorrect passwords or tampered ciphertext with immediate feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5. Southeast Asian Font Encoding Engine
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rabbit Algorithm Heuristics -&amp;gt; Syllable / consonant reordering -&amp;gt; Lossless Zawgyi &amp;lt;-&amp;gt; Unicode conversion

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

&lt;/div&gt;



&lt;p&gt;Prevents font rendering corruption on legacy Android forks and ensures strict compliance with standard Myanmar Unicode.&lt;/p&gt;

&lt;h4&gt;
  
  
  6. stdio JSON-RPC 2.0 Model Context Protocol (MCP) Server
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Claude&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Desktop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Cursor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stdio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JSON-RPC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Automated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;linting,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;parsing,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bundle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;compilation&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;Enables autonomous AI coding agents to inspect, validate, and compile localization bundles directly within developer IDE environments.&lt;/p&gt;




&lt;h3&gt;
  
  
  Verification &amp;amp; Reliability Baseline
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;308 Automated Tests across 42 Test Suites&lt;/strong&gt; executed via Vitest and enforced on every pull request via GitHub Actions CI (204 core library tests + 104 UI integration tests).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100% Offline Capability:&lt;/strong&gt; Packaged with a Service Worker and Web App Manifest as a standalone installable desktop PWA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source:&lt;/strong&gt; Licensed under MIT with zero telemetry and zero tracking scripts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your team is managing multi-platform localization, review the architecture and codebase here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/pyaephyomaungdev/json-link" rel="noopener noreferrer"&gt;https://github.com/pyaephyomaungdev/json-link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://json-link.pages.dev" rel="noopener noreferrer"&gt;https://json-link.pages.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
