<?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: Ketut Dana</title>
    <description>The latest articles on DEV Community by Ketut Dana (@ketutdana).</description>
    <link>https://dev.to/ketutdana</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%2F483655%2Fbaf23e70-d511-42d5-acd7-ee4b94ae0625.jpg</url>
      <title>DEV Community: Ketut Dana</title>
      <link>https://dev.to/ketutdana</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ketutdana"/>
    <language>en</language>
    <item>
      <title>hello, I make this new tools call envGo, please check and review at https://envgo.dev</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Fri, 02 Oct 2026 00:43:32 +0000</pubDate>
      <link>https://dev.to/ketutdana/hello-i-make-this-new-tools-call-envgo-please-check-and-review-at-httpsenvgodev-iln</link>
      <guid>https://dev.to/ketutdana/hello-i-make-this-new-tools-call-envgo-please-check-and-review-at-httpsenvgodev-iln</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://envgo.dev/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fenvgo.dev%2Fog-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://envgo.dev/" rel="noopener noreferrer" class="c-link"&gt;
            envGo — Keep .env values out of the browser | envGo
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Zero-dependency Go binary that serves your static HTML and injects .env secrets server-side. No Node, no build — secrets never reach the browser. MIT, no telemetry.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fenvgo.dev%2Ffavicon.svg" width="32" height="32"&gt;
          envgo.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>envGo &gt;&gt; https://envgo.dev</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Wed, 30 Sep 2026 13:55:47 +0000</pubDate>
      <link>https://dev.to/ketutdana/envgo-httpsenvgodev-10i8</link>
      <guid>https://dev.to/ketutdana/envgo-httpsenvgodev-10i8</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://envgo.dev/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fenvgo.dev%2Fog-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://envgo.dev/" rel="noopener noreferrer" class="c-link"&gt;
            envGo — Keep .env values out of the browser | envGo
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Zero-dependency Go binary that serves your static HTML and injects .env secrets server-side. No Node, no build — secrets never reach the browser. MIT, no telemetry.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fenvgo.dev%2Ffavicon.svg" width="32" height="32"&gt;
          envgo.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>envgo: a dependency-free .env runtime for static sites — browser hot reload over SSE, envgo cache clear, and self-updates, no Node.js 
 needed. Give it a try 🚀 https://envgo.dev</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Sat, 26 Sep 2026 06:29:36 +0000</pubDate>
      <link>https://dev.to/ketutdana/envgo-a-dependency-free-env-runtime-for-static-sites-browser-hot-reload-over-sse-envgo-cache-44el</link>
      <guid>https://dev.to/ketutdana/envgo-a-dependency-free-env-runtime-for-static-sites-browser-hot-reload-over-sse-envgo-cache-44el</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://envgo.dev/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fenvgo.dev%2Fog-image.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://envgo.dev/" rel="noopener noreferrer" class="c-link"&gt;
            envGo — Keep .env values out of the browser | envGo
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Zero-dependency Go binary that serves your static HTML and injects .env secrets server-side. No Node, no build — secrets never reach the browser. MIT, no telemetry.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fenvgo.dev%2Ffavicon.svg" width="32" height="32"&gt;
          envgo.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>envgo.dev</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Thu, 24 Sep 2026 07:43:20 +0000</pubDate>
      <link>https://dev.to/ketutdana/envgodev-3k5j</link>
      <guid>https://dev.to/ketutdana/envgodev-3k5j</guid>
      <description>&lt;p&gt;Hey Dev.to community! I built envGo—a lightweight, zero-dependency Go binary (2–8 MB) that serves your static site and injects .env secrets safely on the server-side, keeping API keys completely invisible to browser DevTools and the Network tab without needing a Node.js runtime. It features hot reload, a built-in proxy/gateway, zero telemetry, and an MIT license. I would love for you to try it out, break it, and share your review or feedback on the codebase. You can check it out at &lt;a href="https://envgo.dev" rel="noopener noreferrer"&gt;https://envgo.dev&lt;/a&gt; and grab the source on GitHub!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Niche Collector — Collection Tracker + Price Intelligence</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Tue, 22 Sep 2026 05:05:36 +0000</pubDate>
      <link>https://dev.to/ketutdana/niche-collector-collection-tracker-price-intelligence-444d</link>
      <guid>https://dev.to/ketutdana/niche-collector-collection-tracker-price-intelligence-444d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Sanity Challenge — Path 2: Vibe-code something strange&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Portfolio tracker for niche hobbies (Hot Wheels, Gunpla, Mechanical Keyboards) that proves why structured content beats keyword search. Every valuation is a GROQ aggregation, outlier-aware.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔗 Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Demo:&lt;/strong&gt; &lt;a href="https://sanity-challenge.vercel.app" rel="noopener noreferrer"&gt;https://sanity-challenge.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collection Demo (GROQ live):&lt;/strong&gt; &lt;a href="https://sanity-challenge.vercel.app/collection" rel="noopener noreferrer"&gt;https://sanity-challenge.vercel.app/collection&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanity Studio (public, no login):&lt;/strong&gt; &lt;a href="https://sanity-challenge.vercel.app/studio" rel="noopener noreferrer"&gt;https://sanity-challenge.vercel.app/studio&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub (MIT):&lt;/strong&gt; &lt;a href="https://github.com/dnysaz/niche-collector" rel="noopener noreferrer"&gt;https://github.com/dnysaz/niche-collector&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanity Project ID:&lt;/strong&gt; &lt;code&gt;71m89sy5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt; — &lt;a href="https://71m89sy5.apicdn.sanity.io/v2024-01-01/data/query/production?query=*%5B_type==%22collectibleItem%22%5D" rel="noopener noreferrer"&gt;https://71m89sy5.apicdn.sanity.io/v2024-01-01/data/query/production?query=*[_type=="collectibleItem"]&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organization ID:&lt;/strong&gt; &lt;code&gt;os9xuj7u1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Submission tag: &lt;code&gt;#sanitychallenge&lt;/code&gt;&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Niche Collector&lt;/strong&gt; is a collection portfolio for hobbyists who track value — not just items. Think Hot Wheels Treasure Hunts, Gunpla kits, custom keyboards. The app stores your purchase price vs current market, pulls priceHistory from Tokopedia/Shopee listings, and auto-calculates gain/loss. The trick: a scam &lt;code&gt;Rp 5,000,000&lt;/code&gt; listing is flagged &lt;code&gt;isOutlier=true&lt;/code&gt; and excluded from the median — so your portfolio stays honest.&lt;/p&gt;

&lt;p&gt;It’s deliberately boring in the best way: no AI chat, just structured data doing work keyword search can’t.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this only works with structured content:&lt;/strong&gt; Try answering “total market vs total purchase for owned grails” with full-text search. You can’t. You need &lt;code&gt;math::sum(*[_type=="collectibleItem" &amp;amp;&amp;amp; status=="owned"].currentValue)&lt;/code&gt; and a filtered &lt;code&gt;priceHistory&lt;/code&gt; join on &lt;code&gt;item._ref&lt;/code&gt;. That’s 100% schema-dependent.&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo — What to Click
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;/&lt;/strong&gt; — landing explains schema + shows GROQ example&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/collection&lt;/strong&gt; — live portfolio:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TOTAL MARKET Rp 3,900,000&lt;/code&gt; vs &lt;code&gt;TOTAL PURCHASE Rp 2,900,000&lt;/code&gt; → &lt;code&gt;+Rp 1,000,000 (34%)&lt;/code&gt; (computed via GROQ, not client JS)&lt;/li&gt;
&lt;li&gt;Cards: Hot Wheels Camaro STH (+733%), Nu Gundam (+31%), Keychron Q1 (-14%) with trend &lt;code&gt;Tokopedia → Shopee&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Outlier filtered: Camaro has 3 history docs, but only 2 shown — the 5M scam is excluded&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/studio&lt;/strong&gt; — Sanity Studio (embedded NextStudio, &lt;code&gt;basePath: '/studio'&lt;/code&gt;, Vision enabled). Try Vision:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   *[_type=="priceHistory" &amp;amp;&amp;amp; isOutlier != true] | order(recordedAt desc){price, source, "item": item-&amp;gt;title}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SEO goodies:&lt;/strong&gt; &lt;code&gt;/opengraph-image&lt;/code&gt; (1200×630 edge), &lt;code&gt;/icon.svg&lt;/code&gt;, &lt;code&gt;/sitemap.xml&lt;/code&gt;, &lt;code&gt;/robots.txt&lt;/code&gt;, JSON-LD &lt;code&gt;WebApplication&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If &lt;code&gt;NEXT_PUBLIC_SANITY_PROJECT_ID&lt;/code&gt; is missing, &lt;code&gt;/collection&lt;/code&gt; falls back to mock — but on Vercel it’s live against &lt;code&gt;71m89sy5/production&lt;/code&gt; (14 seeded docs).&lt;/p&gt;




&lt;h2&gt;
  
  
  Schema — Thoughtfulness Behind It
&lt;/h2&gt;

&lt;p&gt;5 types in &lt;code&gt;sanity/schemaTypes/&lt;/code&gt; — designed for portfolio math, not just CMS text:&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="c1"&gt;// sanity/schemaTypes/index.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schemaTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hobbyCategory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;collectibleItem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;priceHistory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wishlist&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Why it exists&lt;/th&gt;
&lt;th&gt;Key fields&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;hobbyCategory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Taxonomy + scraping hints&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;title&lt;/code&gt;, &lt;code&gt;slug&lt;/code&gt;, &lt;code&gt;icon&lt;/code&gt; (🏎️🤖⌨️), &lt;code&gt;marketplaceKeywords&lt;/code&gt; for future scraper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;collectibleItem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Core asset&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;title&lt;/code&gt;, &lt;code&gt;slug&lt;/code&gt;, &lt;code&gt;category(ref)&lt;/code&gt;, &lt;code&gt;brand&lt;/code&gt;, &lt;code&gt;year&lt;/code&gt;, &lt;code&gt;sku&lt;/code&gt;, &lt;code&gt;condition(enum: mint_sealed/mint_loose/used_excellent/used_good/damaged)&lt;/code&gt;, &lt;code&gt;rarity(enum: common/uncommon/rare/grail)&lt;/code&gt;, &lt;code&gt;images&lt;/code&gt;, &lt;code&gt;purchasePrice&lt;/code&gt;, &lt;code&gt;purchaseDate&lt;/code&gt;, &lt;code&gt;currentValue&lt;/code&gt; (override median), &lt;code&gt;quantity&lt;/code&gt;, &lt;code&gt;status(owned/wishlist/sold)&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;, &lt;code&gt;notes&lt;/code&gt;, &lt;code&gt;sourceUrl&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;collection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Curated showcase&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;title&lt;/code&gt;, &lt;code&gt;owner&lt;/code&gt;, &lt;code&gt;category(ref)&lt;/code&gt;, &lt;code&gt;items(ref[])&lt;/code&gt;, &lt;code&gt;isPublic&lt;/code&gt;, &lt;code&gt;coverImage&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;priceHistory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Market intelligence&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;item(ref)&lt;/code&gt;, &lt;code&gt;source(tokopedia/shopee/bukalapak/ebay/manual)&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt;, &lt;code&gt;currency&lt;/code&gt;, &lt;code&gt;recordedAt&lt;/code&gt;, &lt;code&gt;conditionAtSource&lt;/code&gt;, &lt;code&gt;isOutlier&lt;/code&gt; (excluded via &lt;code&gt;isOutlier != true&lt;/code&gt;), orderings by &lt;code&gt;recordedAt desc&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;wishlist&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hunt + alerts&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;title&lt;/code&gt;, &lt;code&gt;category(ref)&lt;/code&gt;, &lt;code&gt;targetPrice&lt;/code&gt;, &lt;code&gt;priority(low/medium/high/grail)&lt;/code&gt;, &lt;code&gt;alertActive&lt;/code&gt;, &lt;code&gt;notes&lt;/code&gt;, &lt;code&gt;referenceUrl&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Relations matter: &lt;code&gt;collectibleItem.category -&amp;gt; hobbyCategory&lt;/code&gt;, &lt;code&gt;priceHistory.item -&amp;gt; collectibleItem&lt;/code&gt;, &lt;code&gt;collection.items -&amp;gt; collectibleItem[]&lt;/code&gt;, &lt;code&gt;wishlist.category -&amp;gt; hobbyCategory&lt;/code&gt;. Validations (&lt;code&gt;required&lt;/code&gt;, &lt;code&gt;min(0)&lt;/code&gt;), &lt;code&gt;initialValue&lt;/code&gt;, &lt;code&gt;preview&lt;/code&gt;, and &lt;code&gt;orderings&lt;/code&gt; are set — judges can verify in Studio.&lt;/p&gt;

&lt;p&gt;Config in &lt;code&gt;sanity.config.ts&lt;/code&gt;:&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;71m89sy5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;basePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/studio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;structureTool&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;visionTool&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;h2&gt;
  
  
  GROQ — Only Works Because It’s Structured
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// sanity/lib/queries.ts — Portfolio stats
{
  "totalItems": count(*[_type=="collectibleItem" &amp;amp;&amp;amp; status=="owned"]),
  "totalPurchase": math::sum(*[_type=="collectibleItem" &amp;amp;&amp;amp; status=="owned"].purchasePrice),
  "totalMarket": math::sum(*[_type=="collectibleItem" &amp;amp;&amp;amp; status=="owned"].currentValue),
  "wishlistCount": count(*[_type=="wishlist"]),
  "grails": *[_type=="collectibleItem" &amp;amp;&amp;amp; rarity=="grail" &amp;amp;&amp;amp; status=="owned"]{title, currentValue}
}

// Items with gain + 5 last prices (outlier-aware)
*[_type=="collectibleItem" &amp;amp;&amp;amp; status=="owned"] | order(currentValue desc){
  title, purchasePrice, currentValue,
  "gain": currentValue - purchasePrice,
  "gainPercent": round(((currentValue - purchasePrice)/purchasePrice)*100),
  "priceHistory": *[_type=="priceHistory" &amp;amp;&amp;amp; item._ref==^._id &amp;amp;&amp;amp; isOutlier != true]
    | order(recordedAt desc)[0..5]{price, recordedAt, source}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try on prod: &lt;code&gt;https://71m89sy5.apicdn.sanity.io/v2024-01-01/data/query/production?query=*[_type=="collectibleItem"]{title,currentValue}&lt;/code&gt; — returns 3 docs, not mock.&lt;/p&gt;




&lt;h2&gt;
  
  
  Build Process — Honest Writeup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Vibe-coded? Yes, but not blindly.&lt;/strong&gt; Started with &lt;code&gt;npm create sanity@latest&lt;/code&gt; / &lt;code&gt;create-next-app&lt;/code&gt; prompt from Sanity’s “niche-collector” starter (Project &lt;code&gt;71m89sy5&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt;, monorepo &lt;code&gt;studio&lt;/code&gt; + &lt;code&gt;web&lt;/code&gt;). I kept the Studio &lt;strong&gt;embedded&lt;/strong&gt; in Next.js at &lt;code&gt;app/studio/[[...tool]]&lt;/code&gt; (NextStudio) instead of standalone — easier for Vercel single deployment, judged as “custom app on top of content”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where Sanity features were used deep:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom schemas with references + enums (not a blog template)&lt;/li&gt;
&lt;li&gt;Vision for GROQ debugging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;basePath: '/studio'&lt;/code&gt; + CORS for embedded Studio (had to add &lt;code&gt;localhost:3000&lt;/code&gt; + Vercel domains via &lt;code&gt;npx sanity cors add --credentials&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;math::sum&lt;/code&gt; not &lt;code&gt;sum&lt;/code&gt; — learned via CLI error &lt;code&gt;Undefined function sum&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;imageUrlBuilder&lt;/code&gt; ready for future &lt;code&gt;images[0]&lt;/code&gt; thumbnails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rough edges I hit and fixed:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm EACCES mkdir ~/.npm/_cacache&lt;/code&gt; → used &lt;code&gt;npm_config_cache=/tmp/npm-cache&lt;/code&gt; (macOS root-owned cache bug)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Tool not found: studio&lt;/code&gt; → missing &lt;code&gt;basePath&lt;/code&gt; in &lt;code&gt;sanity.config.ts&lt;/code&gt;, fixed + restart dev&lt;/li&gt;
&lt;li&gt;Hydration mismatch &lt;code&gt;data-new-gr-c-s-check-loaded&lt;/code&gt; (Grammarly) → added &lt;code&gt;suppressHydrationWarning&lt;/code&gt; in &lt;code&gt;app/layout.tsx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;swr&lt;/code&gt; default import error with Sanity + Next 16 Turbopack → wrapped Studio in &lt;code&gt;'use client'&lt;/code&gt; &lt;code&gt;Studio.tsx&lt;/code&gt; + pinned &lt;code&gt;swr@2.3.7&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;No Output Directory dist&lt;/code&gt; on Vercel → set &lt;code&gt;vercel.json {framework: "nextjs", outputDirectory: ".next"}&lt;/code&gt; (initial &lt;code&gt;vercel link&lt;/code&gt; detected no framework)&lt;/li&gt;
&lt;li&gt;Canonical mismatch &lt;code&gt;niche-collector.vercel.app&lt;/code&gt; vs &lt;code&gt;sanity-challenge.vercel.app&lt;/code&gt; → set &lt;code&gt;NEXT_PUBLIC_SITE_URL&lt;/code&gt; + redeploy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What I didn’t do (and why):&lt;/strong&gt; No App SDK custom app (would duplicate Studio for this scope) and no Workflows — portfolio doesn’t need approval flows. A polished blog template would have scored lower on “thoughtfulness of schema”, so I kept the data model niche.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Next.js 16 (App Router, Turbopack) + Tailwind 4 + Sanity 6 + next-sanity 13, edge OG &lt;code&gt;1200×630&lt;/code&gt;, &lt;code&gt;sitemap&lt;/code&gt;/&lt;code&gt;robots&lt;/code&gt;, JSON-LD &lt;code&gt;WebApplication&lt;/code&gt;, MIT license.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Run Locally
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dnysaz/niche-collector.git
&lt;span class="nb"&gt;cd &lt;/span&gt;niche-collector

&lt;span class="nv"&gt;npm_config_cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/npm-cache npm &lt;span class="nb"&gt;install
cp&lt;/span&gt; .env.local.example .env.local
&lt;span class="c"&gt;# NEXT_PUBLIC_SANITY_PROJECT_ID=71m89sy5&lt;/span&gt;
&lt;span class="c"&gt;# NEXT_PUBLIC_SANITY_DATASET=production&lt;/span&gt;

&lt;span class="nv"&gt;npm_config_cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/npm-cache npx sanity login &lt;span class="nt"&gt;--provider&lt;/span&gt; google
&lt;span class="nv"&gt;npm_config_cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/npm-cache npx sanity dataset import sanity/seed.ndjson production &lt;span class="nt"&gt;-p&lt;/span&gt; 71m89sy5
&lt;span class="nv"&gt;npm_config_cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/npm-cache npx sanity cors add http://localhost:3000 &lt;span class="nt"&gt;--credentials&lt;/span&gt;

&lt;span class="nv"&gt;npm_config_cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/npm-cache npm run dev &lt;span class="c"&gt;# http://localhost:3000/studio + /collection&lt;/span&gt;
npm run build &lt;span class="c"&gt;# Route: / , /collection (1m), /studio, /opengraph-image (ƒ)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seed has 14 docs — open Studio, edit &lt;code&gt;currentValue&lt;/code&gt; of Camaro, watch &lt;code&gt;/collection&lt;/code&gt; recompute gain.&lt;/p&gt;




&lt;h2&gt;
  
  
  Submission Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[x] Sanity Project ID: &lt;code&gt;71m89sy5&lt;/code&gt; (in post + &lt;code&gt;sanity.config.ts&lt;/code&gt; + &lt;code&gt;.env.local&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[x] Dataset: &lt;code&gt;production&lt;/code&gt; (public query URL above)&lt;/li&gt;
&lt;li&gt;[x] Live demo: &lt;a href="https://sanity-challenge.vercel.app" rel="noopener noreferrer"&gt;https://sanity-challenge.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[x] Studio: &lt;a href="https://sanity-challenge.vercel.app/studio" rel="noopener noreferrer"&gt;https://sanity-challenge.vercel.app/studio&lt;/a&gt; (no login required for view, CORS enabled)&lt;/li&gt;
&lt;li&gt;[x] GitHub: &lt;a href="https://github.com/dnysaz/niche-collector" rel="noopener noreferrer"&gt;https://github.com/dnysaz/niche-collector&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;li&gt;[x] Honest writeup above (not 3 sentences)&lt;/li&gt;
&lt;li&gt;[x] Tag: &lt;code&gt;#sanitychallenge&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  If I Had More Time
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Scraper cron (Vercel Cron) that hits Tokopedia/Shopee search via &lt;code&gt;marketplaceKeywords&lt;/code&gt; → creates &lt;code&gt;priceHistory&lt;/code&gt; docs → &lt;code&gt;currentValue = median(last 7 non-outlier)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Wishlist alert email when &lt;code&gt;min(priceHistory.price) &amp;lt;= targetPrice&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;App SDK&lt;/code&gt; custom dashboard for collection showcase (filter by &lt;code&gt;isPublic&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading — happy collecting! 🏎️🤖⌨️&lt;/p&gt;

</description>
      <category>github</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>EnvGo: Stop Leaking Your API Keys, Seriously Guys</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Tue, 22 Sep 2026 00:25:34 +0000</pubDate>
      <link>https://dev.to/ketutdana/envgo-stop-leaking-your-api-keys-seriously-guys-aj5</link>
      <guid>https://dev.to/ketutdana/envgo-stop-leaking-your-api-keys-seriously-guys-aj5</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;p&gt;Let me be honest with you. I did something stupid before.&lt;/p&gt;

&lt;p&gt;I put my OpenAI API key directly inside my JavaScript file. 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sk-live-abc123...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And pushed it. And yeah, anyone who opened DevTools could see it. My $5 credit gone in one night because someone scraped my key and used it. Painful.&lt;/p&gt;

&lt;p&gt;If you are a frontend dev, solo learner, or just building a cool landing page with vanilla HTML + JS, you probably faced this same problem. You want to call an API, but you don't want to learn Express, setup Node, deploy a backend, just to hide ONE key. That feels overkill, right?&lt;/p&gt;

&lt;p&gt;That's why I made &lt;strong&gt;EnvGo&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, What is EnvGo?
&lt;/h3&gt;

&lt;p&gt;EnvGo is a super simple idea. It's a &lt;strong&gt;single Go binary&lt;/strong&gt; (around 2-8 MB, no Node, no npm install, no &lt;code&gt;node_modules&lt;/code&gt; drama) that does two jobs at once:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Serves your static HTML files&lt;/li&gt;
&lt;li&gt;Holds your &lt;code&gt;.env&lt;/code&gt; secrets safely on the server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The magic is in how it handles secrets. You never write the real key in your JS. You just write a placeholder:&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="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bearer {OPENAI_API_KEY}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your browser sends literally &lt;code&gt;{OPENAI_API_KEY}&lt;/code&gt; as text. EnvGo, running on the server, swaps it with the real value from your &lt;code&gt;.env&lt;/code&gt; and forwards it to OpenAI. The secret never, ever reaches the browser. Not in DevTools, not in Network tab, not in memory. Clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Built This?
&lt;/h3&gt;

&lt;p&gt;I see many beginners stuck here. They can make a beautiful site with AI (Cursor, Claude), but once they need an API key, tutorials say "create a backend" and they give up.&lt;/p&gt;

&lt;p&gt;EnvGo is the bridge — from &lt;code&gt;index.html&lt;/code&gt; to "needs one secret" without learning a framework. Designer, student, or prototyping fast? This is for you. Need a database or auth? Use Next.js. EnvGo solves ONE problem well, intentionally.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works (30 seconds)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myapp &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;myapp
envgo init      &lt;span class="c"&gt;# creates .env, index.html&lt;/span&gt;
&lt;span class="c"&gt;# put real key in .env&lt;/span&gt;
envgo run dev   &lt;span class="c"&gt;# http://127.0.0.1:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTML: &lt;code&gt;&amp;lt;div id="MY_SECRET"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; + &lt;code&gt;&amp;lt;script src="/__env.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; shows &lt;code&gt;✓ Success (hidden)&lt;/code&gt;. JS calls &lt;code&gt;/proxy&lt;/code&gt; with a token; for production, define fixed routes in &lt;code&gt;envgo.routes.json&lt;/code&gt; and call &lt;code&gt;fetch("/api/chat")&lt;/code&gt;. Hot-reload, dashboard, and typo detection included.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to Download?
&lt;/h3&gt;

&lt;p&gt;It's free, MIT licensed, no telemetry, no account needed. Just grab the binary:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://envgo.dev/download/" rel="noopener noreferrer"&gt;https://envgo.dev/download/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have builds for macOS (Apple Silicon &amp;amp; Intel), Linux (amd64 &amp;amp; arm64), and Windows. Or get it from GitHub:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/dnysaz/envgo/releases/latest" rel="noopener noreferrer"&gt;https://github.com/dnysaz/envgo/releases/latest&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All links there always point to the latest version. Latest is &lt;strong&gt;v1.0.1&lt;/strong&gt; now with the new &lt;code&gt;MODE_PUBLIC&lt;/code&gt; via &lt;code&gt;.env&lt;/code&gt; feature.&lt;/p&gt;

&lt;p&gt;Full docs are at &lt;strong&gt;&lt;a href="https://envgo.dev" rel="noopener noreferrer"&gt;https://envgo.dev&lt;/a&gt;&lt;/strong&gt; — super honest about limitations too.&lt;/p&gt;

&lt;h3&gt;
  
  
  I Need Your Feedback!
&lt;/h3&gt;

&lt;p&gt;This is made with love, but I'm sure it's not perfect. If the error message is confusing, or install fails on your laptop, or you have an idea — please tell me!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Bug or idea? Open an issue: &lt;code&gt;github.com/dnysaz/envgo/issues&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Security concern? Check &lt;code&gt;SECURITY.md&lt;/code&gt; (report privately)&lt;/li&gt;
&lt;li&gt;  Just want to say hi or ask? Start a discussion on GitHub.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try EnvGo and it saves you one hour of backend setup, that's a win for me. Give it a star, try it on your next static project, and let me know what you think in the comments below.&lt;/p&gt;

&lt;p&gt;Thanks for reading, guys. Happy coding and keep your keys safe!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;— Ketut Dana&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>go</category>
      <category>security</category>
    </item>
    <item>
      <title>I Secured workatbali.com &amp; workinbali.com — Looking for Serious Collaborators to Build a Bali Tech Startup!</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Tue, 08 Sep 2026 08:48:19 +0000</pubDate>
      <link>https://dev.to/ketutdana/i-secured-workatbalicom-workinbalicom-looking-for-serious-collaborators-to-build-a-bali-tech-f89</link>
      <guid>https://dev.to/ketutdana/i-secured-workatbalicom-workinbalicom-looking-for-serious-collaborators-to-build-a-bali-tech-f89</guid>
      <description>&lt;p&gt;Hi DEV Community! 👋&lt;/p&gt;

&lt;p&gt;I'm Ketut Dana, a software engineer and local developer based directly here in Bali, Indonesia.&lt;/p&gt;

&lt;p&gt;I just officially secured two high-potential domains: workatbali.com and workinbali.com.&lt;/p&gt;

&lt;p&gt;Given Bali's position as a global hub for remote workers, digital nomads, and tech talent, I am planning to build a platform/startup around these domains. Whether it's a dedicated job board, ecosystem platform, talent network, or remote-work directory for Bali, the possibilities are open to strong execution.&lt;/p&gt;

&lt;p&gt;I’m looking for serious collaborators or a co-founder who wants to build this together from the ground up—whether you are a fellow developer, UI/UX designer, marketer, or product strategist.&lt;/p&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;p&gt;Serious and committed individuals only.&lt;/p&gt;

&lt;p&gt;Passionate about building products for the remote work/tech ecosystem in Bali.&lt;/p&gt;

&lt;p&gt;Since I am a native local based in Bali, we can easily coordinate on-site or work asynchronously.&lt;/p&gt;

&lt;p&gt;If you are interested in collaborating, let's connect:&lt;/p&gt;

&lt;p&gt;Email: &lt;a href="mailto:workinbali26@gmail.com"&gt;workinbali26@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WhatsApp: +62 8580 5566344&lt;/p&gt;

&lt;p&gt;Let’s build something valuable together!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>CloudBanana DE — Your VPS Just Got a Desktop Environment</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Sat, 18 Jul 2026 08:02:18 +0000</pubDate>
      <link>https://dev.to/ketutdana/cloudbanana-de-your-vps-just-got-a-desktop-environment-2amj</link>
      <guid>https://dev.to/ketutdana/cloudbanana-de-your-vps-just-got-a-desktop-environment-2amj</guid>
      <description>&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuz5glhvs38nxunzk7405.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuz5glhvs38nxunzk7405.png" alt=" " width="800" height="500"&gt;&lt;/a&gt;# CloudBanana DE — Your VPS Just Got a Desktop Environment&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written for dev.to • July 2026 • &lt;a href="https://github.com/dnysaz/cloudbanana.de" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hey everyone! 👋&lt;/p&gt;

&lt;p&gt;So I've been working on this open-source project for a while, and I'm really excited to finally share it with everyone. It's called &lt;strong&gt;CloudBanana DE&lt;/strong&gt; — basically, a web-based desktop environment for managing your Linux VPS.&lt;/p&gt;

&lt;p&gt;I know what you're thinking: &lt;em&gt;"Another server management panel?"&lt;/em&gt; Not this time. This one is &lt;strong&gt;different&lt;/strong&gt;. Not a dashboard with a bunch of buttons — it's a full-blown desktop. Like, you open your browser, and there's a login screen, a taskbar, a dock, windows you can drag around. It feels like using a real computer, but it's all running in your browser, connected to your VPS.&lt;/p&gt;

&lt;p&gt;Let me break it down with the classic 5W + 1H so you can see the full picture.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu2i8g41iy1ozpt6fuyd8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu2i8g41iy1ozpt6fuyd8.png" alt=" " width="800" height="500"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft5pvem33glc8xmoejq0x.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft5pvem33glc8xmoejq0x.png" alt=" " width="800" height="500"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fss1cgms5qikkt6xxjp2c.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fss1cgms5qikkt6xxjp2c.png" alt=" " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is CloudBanana DE?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CloudBanana Desktop Environment&lt;/strong&gt; is a lightweight, web-based desktop environment that runs in your browser and connects to your Linux VPS. It gives you a Windows/macOS-like graphical interface with windows, taskbar, file manager, terminal, dock, and &lt;strong&gt;30+ built-in applications&lt;/strong&gt; — all without needing SSH or opening a terminal.&lt;/p&gt;

&lt;p&gt;Think of it like this: instead of remembering 50 different Linux commands just to manage your server, you get a proper GUI where you can click, drag, and explore. It's built with &lt;strong&gt;React 19 + FastAPI&lt;/strong&gt; and runs on any Debian-based VPS (Ubuntu 22.04/24.04 recommended).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CloudBanana DE?
&lt;/h2&gt;

&lt;p&gt;Because managing a VPS through the terminal can be a pain — especially if you're not a Linux power user. Here's the problem most people face:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to remember &lt;strong&gt;hundreds of CLI commands&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Switching between SSH sessions is annoying&lt;/li&gt;
&lt;li&gt;Dashboard panels (CyberPanel, aaPanel) are just forms — not real GUIs&lt;/li&gt;
&lt;li&gt;Coolify is great but it's Docker-centric and still CLI-heavy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CloudBanana DE solves all of that. You get a real desktop environment where you can open a file manager, drag files around, edit code in VS Code-quality Monaco editor, run terminal commands if you want, install software with one click — all from your browser. No SSH client needed. No command memorization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The "aha" moment:&lt;/strong&gt; When you realize you can manage Nginx, databases, Laravel projects, SSL certificates, cron jobs, and even browse the web — all from the same browser tab. And everything &lt;strong&gt;survives page reload&lt;/strong&gt;. Close the tab, open it again, your windows are right where you left them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Who is it for?
&lt;/h2&gt;

&lt;p&gt;Basically anyone who runs a Linux VPS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web developers&lt;/strong&gt; who deploy and manage Laravel, PHP, or Node.js apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sysadmins&lt;/strong&gt; who want a GUI for server monitoring and file management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DevOps beginners&lt;/strong&gt; who find the terminal intimidating&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agency owners&lt;/strong&gt; who manage multiple client websites on a single VPS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosters&lt;/strong&gt; who run their own services (Nextcloud, WordPress, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Students&lt;/strong&gt; learning Linux server administration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When can you use it?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Right now!&lt;/strong&gt; CloudBanana DE v0.1.0 is already available and working. It's in &lt;strong&gt;beta&lt;/strong&gt; so there might be some rough edges, but the core features are solid and usable daily.&lt;/p&gt;

&lt;p&gt;The installer script takes about 5-10 minutes to set everything up: Python venv, Node.js, Nginx, systemd service, firewall rules — all automated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does it run?
&lt;/h2&gt;

&lt;p&gt;Any &lt;strong&gt;Debian-based Linux distribution&lt;/strong&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;Node.js 18+&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;systemd&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optimized for &lt;strong&gt;Ubuntu 22.04/24.04 LTS&lt;/strong&gt;, but works on Debian, Linux Mint, Pop!_OS, etc. You can install it on a $5 VPS from DigitalOcean, Linode, Vultr, or any provider. After installation, access it through your browser at &lt;code&gt;http://your-server:8888&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;Here's the quick install (it's literally 3 commands):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/dnysaz/cloudbanana.de.git
&lt;span class="nb"&gt;cd &lt;/span&gt;cloudbanana.de
&lt;span class="nb"&gt;sudo &lt;/span&gt;bash install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Python dependencies and Node.js&lt;/li&gt;
&lt;li&gt;Build the React frontend&lt;/li&gt;
&lt;li&gt;Set up Nginx reverse proxy on port 8888&lt;/li&gt;
&lt;li&gt;Create a systemd service (auto-starts on reboot)&lt;/li&gt;
&lt;li&gt;Configure UFW firewall&lt;/li&gt;
&lt;li&gt;Install the &lt;code&gt;cloudbanana&lt;/code&gt; CLI tool&lt;/li&gt;
&lt;li&gt;Optionally set up HTTPS via Let's Encrypt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After installation, you can manage the service with simple CLI commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cloudbanana start     &lt;span class="c"&gt;# Start the service&lt;/span&gt;
cloudbanana stop      &lt;span class="c"&gt;# Stop the service&lt;/span&gt;
cloudbanana status    &lt;span class="c"&gt;# Check if it's running&lt;/span&gt;
cloudbanana logs      &lt;span class="c"&gt;# View real-time logs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Cool Features (a quick tour)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Actual Desktop Environment
&lt;/h3&gt;

&lt;p&gt;Not a boring dashboard — a real desktop with windows, dock, start menu, desktop icons, wallpaper picker (20+ built-in), and even a calendar popup on the taskbar. You can drag windows around, resize them, minimize, maximize. It feels like using macOS or Windows, but in a browser tab.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monaco Code Editor
&lt;/h3&gt;

&lt;p&gt;Yes, the same editor VS Code uses. Syntax highlighting, minimap, multiple cursors, multiple tabs that &lt;strong&gt;survive reload&lt;/strong&gt;, drag-and-drop tab reordering, file tree sidebar, and an integrated terminal panel. Basically VS Code in your browser, connected to your VPS filesystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket Terminal
&lt;/h3&gt;

&lt;p&gt;Full bash shell with xterm-256color emulation, multi-tab support, resizable panel. You can run any command right from the browser. Perfect for when you still need that CLI power.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web Server Management
&lt;/h3&gt;

&lt;p&gt;Nginx config editor with syntax testing before saving. PHP version manager. SSL certificate viewer and Let's Encrypt auto-installer. Subdomain manager that generates Nginx configs automatically. Hosts file editor with confirmation modal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Tools
&lt;/h3&gt;

&lt;p&gt;Query MySQL and PostgreSQL directly from the UI. Browse SQLite databases, execute SELECT/PRAGMA queries. No more phpMyAdmin headaches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Laravel Wizard
&lt;/h3&gt;

&lt;p&gt;Full Laravel project setup wizard — clone from Git or upload ZIP, auto-install Composer, configure .env, run migrations, create Nginx vhost, build assets. All from one interface. Plus a management dashboard to toggle sites online/offline, rollback migrations, change PHP version per project.&lt;/p&gt;

&lt;h3&gt;
  
  
  49 One-Click Software Packages
&lt;/h3&gt;

&lt;p&gt;Docker, Nginx, Apache, Python, Node.js, PostgreSQL, MongoDB, Redis, Rust, Go, Certbot, Grafana, Prometheus, Portainer, PM2, Fail2ban, Netdata, Composer, Yarn, FFmpeg, and many more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Banana Browser
&lt;/h3&gt;

&lt;p&gt;A built-in web proxy browser that runs inside your desktop. Cookie persistence, YouTube embed conversion, anti-frame-busting, SPA navigation support. Optional Playwright headless Firefox engine. Browse the web from your server.&lt;/p&gt;

&lt;h3&gt;
  
  
  System Monitoring
&lt;/h3&gt;

&lt;p&gt;Real-time CPU per-core, RAM, Swap, Disk (multi-partition), Network I/O. Live desktop widgets showing system stats. Process viewer with kill capability. Audit logs tracking login/logout and admin actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: Games &amp;amp; Media
&lt;/h3&gt;

&lt;p&gt;Snake, Ping Pong, BNote (multi-tab text editor with syntax highlighting), BWeb (WebView iframe), Media Viewer for images and videos. Because managing a server shouldn't be boring.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Since this runs on your server, security matters. Here's what's built in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT with httpOnly cookies + CSRF double-submit pattern&lt;/li&gt;
&lt;li&gt;Rate limiting on all auth endpoints&lt;/li&gt;
&lt;li&gt;Account lockout after 5 failed attempts (15 min cooldown)&lt;/li&gt;
&lt;li&gt;PBKDF2 password hashing (100,000 iterations)&lt;/li&gt;
&lt;li&gt;Path traversal prevention on all file operations&lt;/li&gt;
&lt;li&gt;Private host blocking in proxy and wget&lt;/li&gt;
&lt;li&gt;Separate system user with scoped sudo privileges&lt;/li&gt;
&lt;li&gt;Read-only SQLite query mode&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; There's no email-based password recovery yet (it's still beta), so please use a &lt;strong&gt;strong password&lt;/strong&gt;. Your feedback and bug reports are very welcome!&lt;/p&gt;
&lt;/blockquote&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg31ns1i8a3e2rz9okwc9.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg31ns1i8a3e2rz9okwc9.png" alt=" " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison: CloudBanana vs Other Panels
&lt;/h2&gt;

&lt;p&gt;Here's why CloudBanana DE is different from CyberPanel, aaPanel, and Coolify:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;CloudBanana DE&lt;/th&gt;
&lt;th&gt;Others&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Desktop UI&lt;/td&gt;
&lt;td&gt;✅ Full desktop&lt;/td&gt;
&lt;td&gt;❌ Dashboard only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH-Free&lt;/td&gt;
&lt;td&gt;✅ 100% browser&lt;/td&gt;
&lt;td&gt;❌ SSH required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Editor&lt;/td&gt;
&lt;td&gt;✅ Monaco (VS Code)&lt;/td&gt;
&lt;td&gt;❌ Basic / None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket Terminal&lt;/td&gt;
&lt;td&gt;✅ Full PTY bash&lt;/td&gt;
&lt;td&gt;⚠️ Basic / None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in Web Browser&lt;/td&gt;
&lt;td&gt;✅ Banana Browser&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Software Install&lt;/td&gt;
&lt;td&gt;✅ 49 packages&lt;/td&gt;
&lt;td&gt;⚠️ Limited / Docker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laravel Management&lt;/td&gt;
&lt;td&gt;✅ Wizard + Dashboard&lt;/td&gt;
&lt;td&gt;❌ Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-User Login&lt;/td&gt;
&lt;td&gt;✅ GDM-style picker&lt;/td&gt;
&lt;td&gt;❌ Single admin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Window Persistence&lt;/td&gt;
&lt;td&gt;✅ Survives reload&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Theme &amp;amp; Wallpapers&lt;/td&gt;
&lt;td&gt;✅ 20+ wallpapers&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;✅ MIT (100% open)&lt;/td&gt;
&lt;td&gt;⚠️ Partial / AGPLv3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;p&gt;Built with modern, battle-tested technologies:&lt;/p&gt;

&lt;p&gt;React 19 • TypeScript + Vite 8 • FastAPI • SQLite + SQLModel • JWT + CSRF • Zustand 5 • xterm.js • Nginx • systemd • Playwright • Lucide Icons • SlowAPI&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/etc/cloudbanana/
├── backend/
│   ├── app/
│   │   ├── main.py           # FastAPI app (2500+ lines)
│   │   ├── auth.py           # JWT, hashing, rate limiter
│   │   ├── models.py         # SQLModel models
│   │   ├── database.py       # SQLite + WAL mode
│   │   ├── apps.py           # 49 software definitions
│   │   ├── browser_proxy.py  # BananaBrowser proxy
│   │   ├── playwright_browser.py
│   │   └── utils/system.py
│   └── requirements.txt
├── frontend/
│   ├── src/
│   │   ├── App.tsx            # Main React app
│   │   ├── main.tsx           # Entry point
│   │   ├── api.ts             # HTTP client + auth
│   │   ├── types.ts           # TypeScript types
│   │   ├── style.css          # 2500+ lines of CSS
│   │   ├── store/             # Zustand stores
│   │   └── components/        # 30+ React components
│   └── package.json
├── scripts/                   # 48 install scripts
├── install.sh                 # Master installer
├── cloudbanana.sh             # CLI tool
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;CloudBanana DE is still in &lt;strong&gt;beta&lt;/strong&gt;, but it's already pretty usable. I built it because I was tired of switching between SSH sessions and dashboard panels just to manage my servers. I wanted something that feels like a real operating system.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;100% open source&lt;/strong&gt; (MIT license), so you can self-host it on your own VPS. No SaaS fees, no data leaving your server, no subscriptions.&lt;/p&gt;

&lt;p&gt;If you try it, I'd love to hear your feedback! Drop an issue on GitHub, leave a comment here, or contribute a PR. Let's make VPS management less painful for everyone. ✌️&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/dnysaz/cloudbanana.de" rel="noopener noreferrer"&gt;github.com/dnysaz/cloudbanana.de&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Landing Page: &lt;a href="https://cloudbanana.de" rel="noopener noreferrer"&gt;https://cloudbanana.de&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Report Issues: &lt;a href="https://github.com/dnysaz/cloudbanana.de/issues" rel="noopener noreferrer"&gt;github.com/dnysaz/cloudbanana.de/issues&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Made with ❤️ for the VPS community&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vps</category>
      <category>server</category>
      <category>hosting</category>
      <category>ai</category>
    </item>
    <item>
      <title>Just having fun at only4.fun</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Thu, 07 May 2026 05:53:37 +0000</pubDate>
      <link>https://dev.to/ketutdana/just-having-fun-at-only4fun-54ng</link>
      <guid>https://dev.to/ketutdana/just-having-fun-at-only4fun-54ng</guid>
      <description>&lt;p&gt;don't let your country lose on this game, join now at &lt;a href="https://only4.fun" rel="noopener noreferrer"&gt;https://only4.fun&lt;/a&gt; , TAP to win!!&lt;/p&gt;

</description>
      <category>fun</category>
      <category>justforfun</category>
      <category>code</category>
      <category>node</category>
    </item>
    <item>
      <title>I Just Launched KeyYap — A Text-Only Social Platform for Introverts</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Mon, 04 May 2026 05:17:41 +0000</pubDate>
      <link>https://dev.to/ketutdana/i-just-launched-keyyap-a-text-only-social-platform-for-introverts-35mi</link>
      <guid>https://dev.to/ketutdana/i-just-launched-keyyap-a-text-only-social-platform-for-introverts-35mi</guid>
      <description>&lt;p&gt;Hey Dev.to! 👋&lt;/p&gt;

&lt;p&gt;I just launched something I've been building: &lt;strong&gt;KeyYap&lt;/strong&gt; — a text-only social platform for introverts. It's live right now at &lt;a href="https://keyyap.com" rel="noopener noreferrer"&gt;keyyap.com&lt;/a&gt; and I'd love for you to check it out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Honestly? I got tired of social media feeling like a performance.&lt;/p&gt;

&lt;p&gt;Every platform wants you on camera. Instagram wants perfect photos. TikTok wants you to film yourself. Even Twitter feels like a constant battle for attention and engagement.&lt;/p&gt;

&lt;p&gt;I kept thinking — where do you go when you just want to &lt;em&gt;say something&lt;/em&gt;? Not perform. Not film yourself. Just share a thought with people who might actually care?&lt;/p&gt;

&lt;p&gt;That gap is why KeyYap exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is KeyYap?
&lt;/h2&gt;

&lt;p&gt;KeyYap is simple.&lt;/p&gt;

&lt;p&gt;You write. You post. People read it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;512 characters max&lt;/strong&gt; — enough to say something real, not enough to write an essay&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text only&lt;/strong&gt; — no photos, no videos, nothing but words&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emoji avatars&lt;/strong&gt; — pick an emoji that represents you, no selfies required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No algorithm pressure&lt;/strong&gt; — just a clean, honest feed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built for introverts&lt;/strong&gt; — safe, low-pressure, judgment-free&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it like TikTok — but instead of scrolling through videos, you scroll through thoughts. Real, human, unfiltered thoughts.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Name
&lt;/h2&gt;

&lt;p&gt;KeyYap. Key + Yap.&lt;/p&gt;

&lt;p&gt;"Yapping" has a bad reputation. People use it as an insult — "stop yapping," "you yap too much." Like having things to say is a character flaw.&lt;/p&gt;

&lt;p&gt;We think that's wrong. Yapping is human. It's how we process the world, find our people, and make sense of what's happening around us.&lt;/p&gt;

&lt;p&gt;KeyYap is just a good place to do it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A good place for yapping.&lt;/em&gt; 🌙&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Current Status
&lt;/h2&gt;

&lt;p&gt;KeyYap is in &lt;strong&gt;public beta&lt;/strong&gt; right now.&lt;/p&gt;

&lt;p&gt;It works. You can sign up, create posts, follow people, like, comment, and explore the feed. It's real and it's live.&lt;/p&gt;

&lt;p&gt;Is it perfect? No. It's beta. There are rough edges and things I'm still improving. But I believe in shipping early and iterating based on real feedback from real users — not building in silence forever.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd Love From You
&lt;/h2&gt;

&lt;p&gt;This is where I genuinely need help.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://keyyap.com" rel="noopener noreferrer"&gt;keyyap.com&lt;/a&gt; — sign up, post something, explore. Even just one yap would mean a lot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tell me what's broken.&lt;/strong&gt; If something doesn't work, I want to know. Comment here or reach out directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tell me what's missing.&lt;/strong&gt; What feature would make you actually use this regularly?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tell me if the concept resonates.&lt;/strong&gt; Is "text-only social for introverts" something you'd actually use? Or is it solving a problem that doesn't exist?&lt;/p&gt;

&lt;p&gt;I'm building this in public and every piece of honest feedback shapes what KeyYap becomes next.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Coming Next
&lt;/h2&gt;

&lt;p&gt;I'm actively working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better trending algorithm&lt;/li&gt;
&lt;li&gt;Improved notifications&lt;/li&gt;
&lt;li&gt;More profile customization&lt;/li&gt;
&lt;li&gt;Performance improvements&lt;/li&gt;
&lt;li&gt;Mobile experience polish&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And longer term — if there's enough community interest — a proper mobile app.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;I built KeyYap because I needed it myself.&lt;/p&gt;

&lt;p&gt;A place to share thoughts without performing. Without worrying about how I look. Without fighting an algorithm. Just a clean space to yap freely with people who get it.&lt;/p&gt;

&lt;p&gt;If that sounds like something you need too — come join us.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://keyyap.com" rel="noopener noreferrer"&gt;keyyap.com&lt;/a&gt;&lt;/strong&gt; — A good place for yapping. 🌙&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks for reading. Would love to hear your honest thoughts — good, bad, or brutally critical. Drop them in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Building KeyYap: Crafting a Premium "Yapping" Platform</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Fri, 17 Apr 2026 09:34:09 +0000</pubDate>
      <link>https://dev.to/ketutdana/building-keyyap-crafting-a-premium-yapping-platform-i0k</link>
      <guid>https://dev.to/ketutdana/building-keyyap-crafting-a-premium-yapping-platform-i0k</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;In the era of "over-engineered" social media, I wanted to build a place where the focus is simple: quick thoughts, community, and clean aesthetics.&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;KeyYap&lt;/strong&gt;, a platform designed for the modern "Yapper." It’s built to feel premium, move fast, and provide a distraction-free space for sharing. Today, I’m diving into the design and tech choices that make KeyYap unique.&lt;/p&gt;

&lt;p&gt;The Tech Stack Performance was non-negotiable. Here is the architecture behind the platform:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Framework&lt;/strong&gt;: Next.js (App Router) - Leveraging server components for speed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-time Database&lt;/strong&gt;: Supabase - Handling our "Yaps," interactions, and content delivery seamlessly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styling&lt;/strong&gt;: Tailwind CSS - Allowing for precise control over the layout and typography.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Icons&lt;/strong&gt;: Lucide React - For a minimalist and modern UI.&lt;/p&gt;

&lt;p&gt;Design Philosophy: The Art of Spacing Most social platforms feel cluttered. For KeyYap, I went the other way. I believe that white space is a premium feature.&lt;/p&gt;

&lt;p&gt;Generous Padding: I implemented a spacious vertical layout (py-8 md:py-10 for posts). This gives every conversation its own space and prevents the "doom-scrolling" fatigue.&lt;/p&gt;

&lt;p&gt;Typography First: By focusing on clean fonts and balanced line heights, I ensured that the reading experience is front and center.&lt;/p&gt;

&lt;p&gt;Native Integration: Marketing as Content One of the core features of KeyYap is how I handle promotions. Instead of jarring, ugly banners that break the flow, I built a Native Integration System.&lt;/p&gt;

&lt;p&gt;Advertisements on KeyYap are designed to look and feel like organic posts. By matching the typography, spacing, and interaction buttons, I ensure that every piece of content—whether organic or promoted—feels like it belongs on the platform. This creates a much higher quality experience for the user.&lt;/p&gt;

&lt;p&gt;Overcoming the "Social Media" Load Building a feed isn't just about fetching data; it's about how that data feels when it loads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hydration &amp;amp; SEO&lt;/strong&gt;: By using Next.js, I ensured that the initial "Yaps" are rendered on the server, making the page load feel instant while also being indexed by search engines.&lt;/p&gt;

&lt;p&gt;Layout Stability: I spent a lot of time ensuring that the layout doesn't shift during loading (CLS), creating a smooth, stable experience from the first millisecond.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s Next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;KeyYap is currently in &lt;strong&gt;Public Beta&lt;/strong&gt;, and the community feedback has been amazing. I am continually refining the "Yap" experience to keep it as the "good place for yapping."&lt;/p&gt;

&lt;p&gt;Building a social space is about more than just code; it’s about creating a vibe. With Next.js and Supabase, I was able to turn that vibe into a functional, premium reality.&lt;/p&gt;

&lt;p&gt;Check it out here: &lt;strong&gt;&lt;a href="https://keyyap.vercel.app" rel="noopener noreferrer"&gt;https://keyyap.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy Coding! 🚀 Have questions about my native integration or feed layout? Let’s chat in the comments!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>supabase</category>
      <category>nextjs</category>
      <category>javascript</category>
    </item>
    <item>
      <title>XtermChat | A Terminal Chat App With a Built-in Server Monitoring Bot</title>
      <dc:creator>Ketut Dana</dc:creator>
      <pubDate>Sun, 15 Mar 2026 13:28:24 +0000</pubDate>
      <link>https://dev.to/ketutdana/xtermchat-a-terminal-chat-app-with-a-built-in-server-monitoring-bot-nde</link>
      <guid>https://dev.to/ketutdana/xtermchat-a-terminal-chat-app-with-a-built-in-server-monitoring-bot-nde</guid>
      <description>&lt;p&gt;A few months ago I got tired of giving my team's conversations to third-party servers. So I built XtermChat — a self-hosted chat system that runs entirely in the terminal.&lt;/p&gt;

&lt;p&gt;Since then, it has grown into something I didn't originally plan: a full &lt;strong&gt;client-server chat system&lt;/strong&gt; with a terminal TUI, a web admin panel, and a bot that monitors your VPS and sends alerts directly into your chat rooms.&lt;/p&gt;

&lt;p&gt;This post is about what it became.&lt;/p&gt;




&lt;h2&gt;
  
  
  What XtermChat Is Now
&lt;/h2&gt;

&lt;p&gt;At its core, XtermChat is still simple: a Python Flask server, a SQLite database, and a CLI client. But it now ships with three ways to use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Terminal TUI&lt;/strong&gt; — the original interface. Run &lt;code&gt;xtc start:chat @general&lt;/code&gt; and you get a full terminal UI with three panels, dual-focus mode, emoji shortcuts, link detection, and clipboard copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Web Admin Panel&lt;/strong&gt; — run &lt;code&gt;xtc start:web&lt;/code&gt; and open &lt;code&gt;localhost:5000&lt;/code&gt;. Full admin panel with dashboard, room management, chat with link previews (OG image, title, description), and bot management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Bot System&lt;/strong&gt; — run &lt;code&gt;xtc start:bot&lt;/code&gt; and a setup wizard walks you through configuring a monitoring bot that runs as a background process on your VPS.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bot System
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most excited about. The idea is simple: instead of setting up a separate alerting tool, XtermChat already has rooms and messaging — so why not use that infrastructure for server monitoring too?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xtc start:bot
&lt;span class="go"&gt;
┌──────────────────────────────────────┐
│   XTERMCHAT  ·  BOT SETUP            │
└──────────────────────────────────────┘

▸ SELECT ROOM
  1. @general    OPEN   by KETUT
  2. @alerts     OPEN   by KETUT

▸ Bot name: MONITOR

▸ SELECT BOT TASKS
  1.  Resource Monitor     CPU, RAM, Disk usage
  2.  Process Monitor      Watch if a service dies
  3.  Uptime Watchdog      Ping a URL every N minutes
  4.  Port Checker         Verify ports are open
  5.  SSL Cert Checker     Alert before cert expires
  6.  Log Watcher          Tail a log for keywords
&lt;/span&gt;&lt;span class="c"&gt;  ...
&lt;/span&gt;&lt;span class="go"&gt;
▸ Select tasks: 1,3

✓ Config saved  (bot_id: 1)
✓ Bot started on server  (PID: 24891)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot runs as a background process on the VPS. It reads its config from the database, checks at the configured interval, and sends alerts as normal messages to any room you choose.&lt;/p&gt;

&lt;p&gt;An alert looks like this in your chat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️ RESOURCE ALERT on srv1260384 [15 Mar 2026 08:30:00]
  CPU   85%  (limit 80%)
  RAM   91%  (limit 85%)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because it's just a message in a room, you can see it from the terminal TUI, the web admin, or any client connected to the server.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;The whole thing is two repos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;xtc-server&lt;/strong&gt; — lives on your VPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xtc-server/
├── server.py       Flask app, all API + bot routes
├── db.py           SQLite init (users, rooms, messages, bots)
├── room.py         Room CRUD, bcrypt passwords
├── connection.py   Message save/retrieval
└── bot_runner.py   Bot background process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;xtc-client&lt;/strong&gt; — lives on your machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xtc-client/
├── xtc.py          CLI entry point, command dispatcher
├── utils.py        Hardware UUID identity
├── commands/
│   ├── chat.py     Terminal TUI
│   ├── bot.py      Bot setup wizard
│   ├── bot_stop.py Stop/list bots
│   ├── listBots.py List all registered bots
│   └── deleteBot.py Delete bots
└── web/
    ├── app.py      Flask web server (port 5000)
    └── html/       5 admin pages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client sends a &lt;code&gt;POST /bot/start&lt;/code&gt; to the server, which spawns &lt;code&gt;bot_runner.py&lt;/code&gt; as a background process. The bot reads its config from the database and starts monitoring. Stop it with &lt;code&gt;xtc stop:bot 1&lt;/code&gt; which sends &lt;code&gt;POST /bot/kill&lt;/code&gt; — the server kills the PID and updates the database.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Web Admin
&lt;/h2&gt;

&lt;p&gt;The web admin surprised me with how useful it turned out. I built it for team members who don't use the terminal, but I ended up using it myself because the chat bubble UI with link previews is genuinely nicer for long conversations.&lt;/p&gt;

&lt;p&gt;The chat page fetches Open Graph metadata for any URL shared in a message — image, title, description, favicon. It's cached per session so the same URL isn't fetched twice.&lt;/p&gt;

&lt;p&gt;One thing worth noting: the web admin uses a &lt;strong&gt;5-digit PIN&lt;/strong&gt; you choose at login, while the CLI uses a &lt;strong&gt;hardware UUID&lt;/strong&gt; auto-generated from your machine. Both work with the same server and the same rooms. The difference is that CLI identity is device-bound (if you reinstall your OS, your PIN changes), while web identity is portable.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;SQLite is underrated.&lt;/strong&gt; The entire server state — users, rooms, messages, bot configs — lives in one file. Backup is &lt;code&gt;cp xtc.db backup.db&lt;/code&gt;. For a team of 2–50 people on a $5 VPS, it's more than enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;REST over WebSocket was the right call.&lt;/strong&gt; Polling every 2 seconds is fine for this use case and dramatically simpler to implement, debug, and extend. The bot just makes HTTP requests too — same pattern everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardware UUID as identity is surprisingly clean.&lt;/strong&gt; No passwords to remember. Your machine is your identity. The tradeoff is that switching devices requires an admin to reset your entry, but for a small team that's a non-issue.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server:&lt;/strong&gt; &lt;a href="https://github.com/dnysaz/xtc-server" rel="noopener noreferrer"&gt;github.com/dnysaz/xtc-server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client:&lt;/strong&gt; &lt;a href="https://github.com/dnysaz/xtc-client" rel="noopener noreferrer"&gt;github.com/dnysaz/xtc-client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://xtermchat.vercel.app" rel="noopener noreferrer"&gt;xtermchat.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Setup takes about 10 minutes. The docs cover everything from server setup to HTTPS to the full bot task reference.&lt;/p&gt;

&lt;p&gt;If you run a small team, manage a homelab, or just want your chat data to stay on your own infrastructure — give it a try. And if you find something broken or have a feature idea, issues and pull requests are very welcome.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Python · Runs on a $5 VPS · MIT License&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
