<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>darkstarDEV.us Notes</title>
    <link>https://darkstardev.us/notes/</link>
    <atom:link href="https://darkstardev.us/notes/feed.xml" rel="self" type="application/rss+xml"/>
    <description>Write-ups of side projects, homelab experiments and what I learned building them.</description>
    <language>en-us</language>
    <lastBuildDate>Thu, 29 Oct 2026 00:00:00 GMT</lastBuildDate>
    <item>
      <title>From Docker web app to native iOS app</title>
      <link>https://darkstardev.us/notes/web-app-to-ios-app/</link>
      <guid isPermaLink="true">https://darkstardev.us/notes/web-app-to-ios-app/</guid>
      <pubDate>Thu, 29 Oct 2026 00:00:00 GMT</pubDate>
      <category>SwiftUI</category>
      <category>StarChores</category>
      <description>Why I replaced a chore web app that worked fine with a SwiftUI app that runs offline and syncs through iCloud.</description>
      <content:encoded><![CDATA[<ul><li>Where Chore Calendar was: a Node web app in Docker on the home network.</li><li>Why move: one app to maintain, works away from home Wi-Fi, any number of kids.</li><li>Choosing iCloud sync, since everyone in the family is on iPhone or iPad.</li><li>What I learned going from JavaScript to Swift and SwiftUI.</li><li>Keeping the web app close to feature parity in the meantime.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>How Chore Calendar syncs every phone in about a second</title>
      <link>https://darkstardev.us/notes/chore-calendar-live-sync/</link>
      <guid isPermaLink="true">https://darkstardev.us/notes/chore-calendar-live-sync/</guid>
      <pubDate>Thu, 29 Oct 2026 00:00:00 GMT</pubDate>
      <category>Web</category>
      <category>Node.js</category>
      <category>Homelab</category>
      <description>No accounts, no polling, no WebSockets. Each phone keeps one plain HTTP stream open, and the server pushes the chore list down it whenever anything changes.</description>
      <content:encoded><![CDATA[<p>Chore Calendar runs in a small Docker container on the home Wi-Fi. Every phone in the house opens the same page, and when someone checks off a chore, every other phone shows it within about a second. Nobody signs in.</p>
<p>I expected that to need WebSockets. It didn't: browsers already have a built-in way to hold a connection open and receive updates, called Server-Sent Events.</p>
<h2 id="one-stream-per-phone">One stream per phone</h2>
<p>When a phone loads the page, it opens a request the server never finishes. The server sends the current state right away, keeps the response in a set of listeners, and writes to every listener whenever something changes.</p>
<figure class="code"><figcaption><span>server.js</span><button type="button" class="code-copy">Copy</button></figcaption><pre data-lang="js"><code>// each phone keeps this stream open for live updates
function stream(req, res) {
  res.writeHead(200, { &quot;Content-Type&quot;: &quot;text/event-stream&quot; });
  res.write(`event: state\ndata: ${JSON.stringify(publicState())}\n\n`);
  listeners.add(res);
  req.on(&quot;close&quot;, () =&gt; listeners.delete(res));
}</code></pre></figure>
<h2 id="why-not-websockets">Why not WebSockets?</h2>
<p>The phones only need to hear about changes; checking something off goes up as a normal request. Server-Sent Events are one-way, run over plain HTTP, and reconnect on their own when a phone wakes up.</p>
<h2 id="what-carried-over-to-starchores">What carried over to StarChores</h2>
<p>The native app syncs through iCloud instead, but the idea stayed the same: one source of truth, and every device listens.</p>]]></content:encoded>
    </item>
    <item>
      <title>Self-hosting the StarChores site</title>
      <link>https://darkstardev.us/notes/self-hosting-starchores-site/</link>
      <guid isPermaLink="true">https://darkstardev.us/notes/self-hosting-starchores-site/</guid>
      <pubDate>Thu, 29 Oct 2026 00:00:00 GMT</pubDate>
      <category>Homelab</category>
      <category>Web</category>
      <description>Support pages, a contact form that sends through Microsoft 365, and analytics with no cookie banner, all in Docker at home.</description>
      <content:encoded><![CDATA[<ul><li>I choose darkstardev.us for a domain so I could have other projects under the same name, and branch off if I needed to.</li><li>The landing, privacy and support pages, in their own Docker container.</li><li>A self-hosted contact form that emails support through Microsoft 365, instead of a form service.</li><li>Umami for visitor stats without cookies.</li><li>I use Zoraxy for proxing the different services and websites.  This gives me flexiblity for running new services and not relying on a 3rd party service.</li></ul>]]></content:encoded>
    </item>
  </channel>
</rss>
