<?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: georgevillalobos</title>
    <description>The latest articles on DEV Community by georgevillalobos (@pvgproduction).</description>
    <link>https://dev.to/pvgproduction</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%2F4043094%2Fcab2d551-f3a8-4abf-8c13-b89d85c14b12.jpg</url>
      <title>DEV Community: georgevillalobos</title>
      <link>https://dev.to/pvgproduction</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pvgproduction"/>
    <language>en</language>
    <item>
      <title>I shipped my local Python app to the app stores as a PWA — here's the whole path</title>
      <dc:creator>georgevillalobos</dc:creator>
      <pubDate>Thu, 23 Jul 2026 05:55:50 +0000</pubDate>
      <link>https://dev.to/pvgproduction/i-shipped-my-local-python-app-to-the-app-stores-as-a-pwa-heres-the-whole-path-27n9</link>
      <guid>https://dev.to/pvgproduction/i-shipped-my-local-python-app-to-the-app-stores-as-a-pwa-heres-the-whole-path-27n9</guid>
      <description>&lt;p&gt;A couple of months ago, I had a Python script that ran on my desk. Today the same project is an installable app on the Microsoft Store — with Google Play and iOS on the way — and it never got a native rewrite or a cloud host for the front-end.&lt;/p&gt;

&lt;p&gt;I learned how to do this from scattered blog posts, docs, and forum answers, and I hit a pile of small traps that cost hours each. So I wrote down the whole path and open-sourced it. This is the short version of the story; the &lt;a href="https://github.com/georgevillalobos/ship-pwa-to-stores" rel="noopener noreferrer"&gt;full step-by-step guide is on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I was starting with
&lt;/h2&gt;

&lt;p&gt;My project is a personal research dashboard for public prediction markets — it watches which proven traders are moving, cross-checks that against bookmaker odds and news, and grades every one of its own calls against reality. (It's a &lt;strong&gt;research tool&lt;/strong&gt; — it places no bets and holds no money. Nothing here is financial advice.)&lt;/p&gt;

&lt;p&gt;The important part for this post: it was a plain Python backend rendering an HTML page, running on my home PC. Great on my desk. Invisible everywhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one idea that unlocked it
&lt;/h2&gt;

&lt;p&gt;Your web app + a &lt;strong&gt;web manifest&lt;/strong&gt; + a &lt;strong&gt;service worker&lt;/strong&gt; = a &lt;strong&gt;PWA&lt;/strong&gt; (Progressive Web App). A PWA is installable on every platform. And a free tool called &lt;a href="https://www.pwabuilder.com/" rel="noopener noreferrer"&gt;PWABuilder&lt;/a&gt; packages that same PWA into native store bundles:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Store&lt;/th&gt;
&lt;th&gt;Bundle&lt;/th&gt;
&lt;th&gt;Difficulty&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Store&lt;/td&gt;
&lt;td&gt;MSIX&lt;/td&gt;
&lt;td&gt;⭐ easiest&lt;/td&gt;
&lt;td&gt;Free (individual fee waived)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Play&lt;/td&gt;
&lt;td&gt;Android &lt;code&gt;.aab&lt;/code&gt; (TWA)&lt;/td&gt;
&lt;td&gt;⭐⭐&lt;/td&gt;
&lt;td&gt;$25 once + hoops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iOS App Store&lt;/td&gt;
&lt;td&gt;Xcode project&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;$99/yr + a Mac&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The part that surprised me most: &lt;strong&gt;you don't need a web host.&lt;/strong&gt; A local app can be given a stable public HTTPS address with a free &lt;strong&gt;named Cloudflare Tunnel&lt;/strong&gt;. That URL is what the stores point at.&lt;/p&gt;

&lt;p&gt;Recommended order: &lt;strong&gt;PWA → Microsoft Store → Google Play → iOS.&lt;/strong&gt; Ship the free, easy one first for the morale win.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gotchas that actually cost me time
&lt;/h2&gt;

&lt;p&gt;These are the ones I wish someone had put in bold:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Service workers only register over HTTPS or &lt;code&gt;localhost&lt;/code&gt;.&lt;/strong&gt; Testing over a plain &lt;code&gt;http://&amp;lt;LAN-IP&amp;gt;&lt;/code&gt; address silently skips them and you'll think it's broken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A 404 on &lt;code&gt;sw.js&lt;/code&gt; breaks everything downstream — and the app still &lt;em&gt;looks&lt;/em&gt; fine.&lt;/strong&gt; If your server uses an allow-list, it has to actually serve &lt;code&gt;sw.js&lt;/code&gt;, your icons, the manifest, &lt;em&gt;and&lt;/em&gt; &lt;code&gt;/.well-known/assetlinks.json&lt;/code&gt; at those exact paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The store app must load with no login.&lt;/strong&gt; A store app opens for strangers, so your public view can't require a secret key. Keep any private/owner view behind auth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google re-signs your Android bundle.&lt;/strong&gt; So the fingerprint that goes in &lt;code&gt;assetlinks.json&lt;/code&gt; is &lt;em&gt;Google's&lt;/em&gt; app-signing SHA-256 (from Play Console), &lt;strong&gt;not&lt;/strong&gt; the upload key PWABuilder hands you. This one silently breaks deep-link verification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package IDs are permanent&lt;/strong&gt; on both stores. Decide before your first upload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Back up your Android signing keystore + passwords.&lt;/strong&gt; Lose them and you can never update the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I shared, and what I kept
&lt;/h2&gt;

&lt;p&gt;Here's a line I think more solo builders should draw deliberately: I shared the &lt;strong&gt;mechanics&lt;/strong&gt;, not the &lt;strong&gt;edge&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public:&lt;/strong&gt; the PWA-to-stores guide, and a clean &lt;a href="https://github.com/georgevillalobos/prediction-agent-skeleton" rel="noopener noreferrer"&gt;reference skeleton&lt;/a&gt; showing how a self-grading research agent fits together — the loop, the grading/trust-ranking system, and how I route news through an LLM into a probability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private:&lt;/strong&gt; the actual scoring math, the prompts, the wallet lists — the stuff that makes it &lt;em&gt;good&lt;/em&gt;. Every one of those spots in the open-source skeleton is a labeled &lt;code&gt;&amp;gt;&amp;gt;&amp;gt; PLACEHOLDER&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sharing the frame costs you nothing and helps a lot of people. The recipe stays yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to do the same
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📖 The full playbook, with every gotcha marked: &lt;strong&gt;&lt;a href="https://github.com/georgevillalobos/ship-pwa-to-stores" rel="noopener noreferrer"&gt;ship-pwa-to-stores&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🧩 The research-agent reference skeleton: &lt;strong&gt;&lt;a href="https://github.com/georgevillalobos/prediction-agent-skeleton" rel="noopener noreferrer"&gt;prediction-agent-skeleton&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🎯 The project itself, and how it was built: &lt;strong&gt;&lt;a href="https://georgevillalobos.github.io/prediction-command-center/" rel="noopener noreferrer"&gt;project page&lt;/a&gt;&lt;/strong&gt; · &lt;a href="https://app.pvgproduction.com" rel="noopener noreferrer"&gt;live app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built this solo, part-time, under the name &lt;strong&gt;PVG Production&lt;/strong&gt;. If any of it saves you a few hours, that's the whole point — and if you find the next gotcha, open a PR.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Research tool only — not financial advice. Everything it produces is evidence to weigh, and every decision stays with a human.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>python</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
