<?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: Cahyanudien Aziz Saputra</title>
    <description>The latest articles on DEV Community by Cahyanudien Aziz Saputra (@cas8398).</description>
    <link>https://dev.to/cas8398</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F736584%2F6f6e709e-1c7f-434d-b1dd-88acb8d7da03.jpeg</url>
      <title>DEV Community: Cahyanudien Aziz Saputra</title>
      <link>https://dev.to/cas8398</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cas8398"/>
    <language>en</language>
    <item>
      <title>I Got Tired of Writing the Same Flutter Code Over and Over, So I Made a Package (flow_nav)</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Wed, 03 Jun 2026 04:11:22 +0000</pubDate>
      <link>https://dev.to/cas8398/i-got-tired-of-writing-the-same-flutter-code-over-and-over-so-i-made-a-package-flownav-10h1</link>
      <guid>https://dev.to/cas8398/i-got-tired-of-writing-the-same-flutter-code-over-and-over-so-i-made-a-package-flownav-10h1</guid>
      <description>&lt;h2&gt;
  
  
  The app worked. But only on phone.
&lt;/h2&gt;

&lt;p&gt;Every Flutter project I started ended up the same way.&lt;/p&gt;

&lt;p&gt;I'd build something, it'd look great on my phone, and then I'd open it on a tablet or resize the window on desktop — and it'd just be this sad, stretched list taking up the entire screen. One column. No sidebar. No detail panel. Just vibes.&lt;/p&gt;

&lt;p&gt;So I'd go fix it. And that's where the real pain started.&lt;/p&gt;




&lt;h2&gt;
  
  
  The if-else spiral
&lt;/h2&gt;

&lt;p&gt;You've seen this code. You've probably written it too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;width&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// desktop layout&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;width&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// tablet layout&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// phone layout&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fine for one widget. But then you need it in the AppBar. And the navigation logic. And the detail panel. And the sidebar. And the FAB visibility. And before you know it, every file in your project has this same conditional sitting inside &lt;code&gt;build()&lt;/code&gt;, each with slightly different magic numbers.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;600&lt;/code&gt;. &lt;code&gt;720&lt;/code&gt;. &lt;code&gt;1024&lt;/code&gt;. &lt;code&gt;800&lt;/code&gt;. Scattered everywhere. Not one source of truth.&lt;/p&gt;

&lt;p&gt;And when the designer says "actually let's change the tablet breakpoint to 680" — you grep through 15 files and pray you got them all.&lt;/p&gt;




&lt;h2&gt;
  
  
  Then I tried existing packages
&lt;/h2&gt;

&lt;p&gt;There are some good ones out there. But most of them came with opinions I didn't ask for.&lt;/p&gt;

&lt;p&gt;They'd give me a &lt;code&gt;NavigationRail&lt;/code&gt; I didn't want. Or a &lt;code&gt;Drawer&lt;/code&gt; that looked nothing like my app. Or a pre-built scaffold that handled layout but had no answer for navigation — so I still had to wire up the push/pop myself and figure out when to show a detail panel vs when to push a new route.&lt;/p&gt;

&lt;p&gt;The packages that handled layout didn't handle navigation.&lt;br&gt;&lt;br&gt;
The ones that handled navigation didn't handle layout.&lt;br&gt;&lt;br&gt;
None of them cared about my router.&lt;/p&gt;

&lt;p&gt;I was using GoRouter. The package assumed &lt;code&gt;Navigator.push&lt;/code&gt;. I'd end up writing adapter code just to make the two talk to each other, which kind of defeats the point.&lt;/p&gt;


&lt;h2&gt;
  
  
  The navigation thing was the worst part
&lt;/h2&gt;

&lt;p&gt;Here's the scenario I kept running into:&lt;/p&gt;

&lt;p&gt;User taps an item in a list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;phone&lt;/strong&gt;: push a new route, full screen.&lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;tablet/desktop&lt;/strong&gt;: swap the detail panel on the right. Don't push anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple concept. But the code to handle this correctly — accounting for screen size, calling the right navigation method, keeping the detail panel state in sync — ended up being this tangled mess that lived in every single screen that had a list.&lt;/p&gt;

&lt;p&gt;Every. Single. One.&lt;/p&gt;

&lt;p&gt;I'd copy-paste it, tweak it slightly, forget to update one of the copies, and end up with bugs that only appeared on tablet. The kind that slip past testing because you test on your phone.&lt;/p&gt;


&lt;h2&gt;
  
  
  So I pulled it all out
&lt;/h2&gt;

&lt;p&gt;I started extracting this logic into a shared utility. Then the utility grew. Then I realized it was basically a mini framework for adaptive Flutter apps — and other people probably needed it too.&lt;/p&gt;

&lt;p&gt;That became &lt;code&gt;flow_nav&lt;/code&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.amazonaws.com%2Fuploads%2Farticles%2F056crquok49ckfzbdb0i.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.amazonaws.com%2Fuploads%2Farticles%2F056crquok49ckfzbdb0i.png" alt="flow_nav desktop" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is simple: &lt;strong&gt;you describe your layout once, and the package figures out what to do based on screen size.&lt;/strong&gt; You don't write breakpoint checks. You don't wire up navigation conditionals. You just tell it what your body is, what your detail panel is, what your sidebar is — and it handles the rest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;FlowScaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;FlowAppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'My App'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nl"&gt;toolbarWidget:&lt;/span&gt; &lt;span class="n"&gt;MyDesktopToolbar&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;MyListView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;onItemTap:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;FlowNavController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;context:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DetailPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;item:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;onDetailOpen:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_detail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&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;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;detailPanel:&lt;/span&gt; &lt;span class="n"&gt;_detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;sidebar:&lt;/span&gt; &lt;span class="n"&gt;MySidebar&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;On phone, &lt;code&gt;sidebar&lt;/code&gt; is ignored, &lt;code&gt;detailPanel&lt;/code&gt; is ignored, tapping an item pushes a new route.&lt;br&gt;&lt;br&gt;
On tablet, you get a split view — list on the left, detail on the right.&lt;br&gt;&lt;br&gt;
On desktop, you get three columns — sidebar, list, detail.&lt;/p&gt;

&lt;p&gt;One widget. All three layouts.&lt;/p&gt;


&lt;h2&gt;
  
  
  It doesn't touch your UI
&lt;/h2&gt;

&lt;p&gt;This was the thing I was most careful about.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;flow_nav&lt;/code&gt; has no default styles, no pre-built components, no color scheme, no navigation rail, no drawer chrome. It provides &lt;strong&gt;zero UI opinions&lt;/strong&gt;. Your &lt;code&gt;AppBar&lt;/code&gt; looks like your &lt;code&gt;AppBar&lt;/code&gt;. Your sidebar looks like whatever you pass in. Your detail panel is just a widget.&lt;/p&gt;

&lt;p&gt;The package handles &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;where&lt;/em&gt; things appear. You handle &lt;em&gt;what&lt;/em&gt; they look like.&lt;/p&gt;

&lt;p&gt;That also means it doesn't care about your router. You can plug in GoRouter, GetX, AutoRoute, or just the plain &lt;code&gt;Navigator&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GoRouter&lt;/span&gt;
&lt;span class="n"&gt;FlowNavConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;onPush:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fullscreenDialog&lt;/span&gt; &lt;span class="o"&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="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/detail'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nl"&gt;onPop:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pop&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;Set it once in &lt;code&gt;main.dart&lt;/code&gt; and forget it. &lt;code&gt;FlowNavController.open()&lt;/code&gt; will use your router on phone and skip it entirely on larger screens.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it looks like across screen sizes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Phone&lt;/th&gt;
&lt;th&gt;Tablet&lt;/th&gt;
&lt;th&gt;Desktop&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AppBar&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;Toolbar in split view&lt;/td&gt;
&lt;td&gt;Toolbar above content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layout&lt;/td&gt;
&lt;td&gt;Single column&lt;/td&gt;
&lt;td&gt;List + Detail&lt;/td&gt;
&lt;td&gt;Sidebar + List + Detail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Navigation&lt;/td&gt;
&lt;td&gt;Full-screen push&lt;/td&gt;
&lt;td&gt;Detail panel swap&lt;/td&gt;
&lt;td&gt;Detail panel swap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bottom nav&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Is it perfect?
&lt;/h2&gt;

&lt;p&gt;No. It's 1.0.0.&lt;/p&gt;

&lt;p&gt;There are things I want to add — better animation when the detail panel swaps, a more flexible column sizing API, maybe some helpers for common empty states. If you use it and run into something rough, open an issue. I'll actually look at it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to get it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flow_nav&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;pub.dev&lt;/strong&gt;: &lt;a href="https://pub.dev/packages/flow_nav" rel="noopener noreferrer"&gt;pub.dev/packages/flow_nav&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/cas8398/flow_nav" rel="noopener noreferrer"&gt;github.com/cas8398/flow_nav&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it saves you from writing one more &lt;code&gt;MediaQuery.of(context).size.width &amp;gt; 600&lt;/code&gt; check, it did its job.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>cahyanudien</category>
      <category>wecoded</category>
    </item>
    <item>
      <title>JDU — Jira Desktop Unofficial: I Got Tired of Opening Jira in My Browser. So I Built a Desktop App.</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Sun, 31 May 2026 02:31:24 +0000</pubDate>
      <link>https://dev.to/cas8398/jdu-jira-desktop-unofficial-i-got-tired-of-opening-jira-in-my-browser-so-i-built-a-desktop-app-1o8b</link>
      <guid>https://dev.to/cas8398/jdu-jira-desktop-unofficial-i-got-tired-of-opening-jira-in-my-browser-so-i-built-a-desktop-app-1o8b</guid>
      <description>&lt;p&gt;Every developer has that one browser tab that never closes.&lt;/p&gt;

&lt;p&gt;For me, it was Jira.&lt;/p&gt;

&lt;p&gt;It lived somewhere between Gmail and Stack Overflow, buried under 20 other tabs — waiting for me to accidentally close it and lose the URL I'd typed in three times that morning. One day I just got fed up. Not with Jira itself, but with the &lt;em&gt;friction&lt;/em&gt; of running it inside a browser.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;JDU — Jira Desktop Unofficial&lt;/strong&gt;. A lightweight, dedicated Jira desktop app built with Tauri and Rust.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built JDU (Jira Desktop Unofficial)
&lt;/h2&gt;

&lt;p&gt;Nothing is technically wrong with Jira's web interface. It works fine. But keeping it inside a browser tab means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It competes with 20 other tabs for your attention&lt;/li&gt;
&lt;li&gt;Chrome silently "memory-saves" the tab and you lose your place&lt;/li&gt;
&lt;li&gt;There's no dedicated window you can &lt;code&gt;Cmd+Tab&lt;/code&gt; into directly&lt;/li&gt;
&lt;li&gt;Every browser update is one more thing that could quietly break your workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I wanted was simple: &lt;strong&gt;Jira in its own window. Nothing else.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Tauri — and Not Electron?
&lt;/h2&gt;

&lt;p&gt;This is the first question everyone asks.&lt;/p&gt;

&lt;p&gt;Electron is the obvious choice. It's popular, well-documented, and battle-tested. But Electron ships an &lt;em&gt;entire Chromium browser engine&lt;/em&gt; inside every app — 100MB+ just to render a webpage. That's like buying a cargo ship to deliver a letter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tauri&lt;/strong&gt; takes a smarter approach. It uses the webview that's &lt;em&gt;already installed on your OS&lt;/em&gt; — WebView2 on Windows, WebKit on macOS and Linux. The backend is written in Rust. No bundled browser. No bloat.&lt;/p&gt;

&lt;p&gt;The result speaks for itself:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;JDU (Jira Desktop Unofficial)&lt;/th&gt;
&lt;th&gt;Typical Electron App&lt;/th&gt;
&lt;th&gt;Browser Tab&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory Usage&lt;/td&gt;
&lt;td&gt;~80 MB&lt;/td&gt;
&lt;td&gt;~350 MB&lt;/td&gt;
&lt;td&gt;~150 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup Time&lt;/td&gt;
&lt;td&gt;&amp;lt; 2 seconds&lt;/td&gt;
&lt;td&gt;5–8 seconds&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Download Size&lt;/td&gt;
&lt;td&gt;~8 MB&lt;/td&gt;
&lt;td&gt;~120 MB&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background CPU&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;~8 MB download. ~80 MB RAM. Under 2 seconds to launch.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For an app I have open all day, every day — those numbers matter a lot.&lt;/p&gt;




&lt;h2&gt;
  
  
  What JDU Does (and Doesn't Do)
&lt;/h2&gt;

&lt;p&gt;JDU is a &lt;em&gt;thin wrapper&lt;/em&gt;, not a reimplementation of Jira. It gives Jira its own window and gets out of the way.&lt;/p&gt;

&lt;p&gt;✅ Works with any Jira instance — Cloud, Server, or Data Center&lt;br&gt;&lt;br&gt;
✅ Remembers your Jira URL and window preferences across sessions&lt;br&gt;&lt;br&gt;
✅ Dedicated desktop window, completely separate from your browser&lt;br&gt;&lt;br&gt;
✅ Zero telemetry, zero tracking, zero data collection&lt;br&gt;&lt;br&gt;
✅ Native OS feel — respects system themes&lt;br&gt;&lt;br&gt;
✅ MIT licensed and fully open source  &lt;/p&gt;

&lt;p&gt;❌ Not affiliated with or endorsed by Atlassian&lt;br&gt;&lt;br&gt;
❌ Doesn't handle your credentials — Jira's own login system does, exactly like a browser&lt;br&gt;&lt;br&gt;
❌ Multi-account support isn't here yet (it's on the roadmap)  &lt;/p&gt;

&lt;p&gt;Your login. Your data. Your workflow. JDU just gives it a proper home.&lt;/p&gt;


&lt;h2&gt;
  
  
  Installing JDU
&lt;/h2&gt;

&lt;p&gt;Download is available for &lt;strong&gt;Windows&lt;/strong&gt;, &lt;strong&gt;macOS&lt;/strong&gt;, and &lt;strong&gt;Linux&lt;/strong&gt; from the &lt;a href="https://github.com/cas8398/jira-desktop-unofficial/releases" rel="noopener noreferrer"&gt;GitHub releases page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Prefer to build from source? You'll need Rust, Node.js, and the &lt;a href="https://tauri.app/start/prerequisites/" rel="noopener noreferrer"&gt;Tauri prerequisites&lt;/a&gt;:&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/cas8398/jira-desktop-unofficial
&lt;span class="nb"&gt;cd &lt;/span&gt;jira-desktop-unofficial
pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm tauri build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Honest Part
&lt;/h2&gt;

&lt;p&gt;This isn't a revolutionary product. It's a small tool that solves a specific, annoying problem.&lt;/p&gt;

&lt;p&gt;I built it because I wanted it to exist. I published it because maybe you do too. The source is on GitHub, the license is MIT, and issues and PRs are genuinely welcome.&lt;/p&gt;

&lt;p&gt;If you've ever wished Jira had a real desktop app — &lt;strong&gt;JDU (Jira Desktop Unofficial)&lt;/strong&gt; is the Jira desktop client that Atlassian never built. Free, open source, and under 8 MB.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try JDU:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;a href="https://cas8398.github.io/jira-desktop-unofficial/" rel="noopener noreferrer"&gt;Landing page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/cas8398/jira-desktop-unofficial" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;a href="https://github.com/cas8398/jira-desktop-unofficial/releases" rel="noopener noreferrer"&gt;Download latest release&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>jira</category>
      <category>jdu</category>
      <category>cahyanudien</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Three Phases Everyone Goes Through But Nobody Talks About: Roots, Growth, Sky</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Mon, 18 May 2026 15:16:52 +0000</pubDate>
      <link>https://dev.to/cas8398/three-phases-everyone-goes-through-but-nobody-talks-about-roots-growth-sky-4nja</link>
      <guid>https://dev.to/cas8398/three-phases-everyone-goes-through-but-nobody-talks-about-roots-growth-sky-4nja</guid>
      <description>&lt;p&gt;Have you ever felt stuck — but couldn't point to why?&lt;/p&gt;

&lt;p&gt;Not a work problem. Not a relationship problem. Not one specific thing you could name. Just a heaviness sitting in your chest, and you didn't know how long it had been there.&lt;/p&gt;

&lt;p&gt;I've been there. And when I started writing poetry, I realized — this isn't a unique experience. It's a phase. And almost everyone goes through it.&lt;/p&gt;

&lt;p&gt;We just never gave it a name.&lt;/p&gt;




&lt;h2&gt;
  
  
  Phase One: Roots
&lt;/h2&gt;

&lt;p&gt;This is the hardest phase — because you don't yet know it's a phase.&lt;/p&gt;

&lt;p&gt;It feels like waking up inside a cave. Dark. Quiet. You move, but the weight only gets heavier, not lighter. You ask: &lt;em&gt;where is the light?&lt;/em&gt; But even that question feels exhausting.&lt;/p&gt;

&lt;p&gt;A lot of people stop moving here. Not because they give up — but because they don't know which direction to move.&lt;/p&gt;

&lt;p&gt;What's actually happening: you're putting down roots. Roots aren't visible from the outside. Roots aren't beautiful. They grow downward first, into the darkness, before the tree can stand.&lt;/p&gt;

&lt;p&gt;This isn't regression. This is foundation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Phase Two: Growth
&lt;/h2&gt;

&lt;p&gt;This phase is more confusing than the first — because things look fine on the outside, but something inside still isn't finished.&lt;/p&gt;

&lt;p&gt;You start moving again. There are good moments, bright moments. People say you seem better. You almost believe them.&lt;/p&gt;

&lt;p&gt;But time doesn't stand still. It keeps moving, and you realize — you're not quite ready to keep pretending everything is comfortable. Something is growing, and growth isn't always clean.&lt;/p&gt;

&lt;p&gt;Sometimes growing means letting go. Sometimes it means separating from an older version of yourself. Sometimes it means admitting you need more time than you thought.&lt;/p&gt;

&lt;p&gt;That's not weakness. That's the process.&lt;/p&gt;




&lt;h2&gt;
  
  
  Phase Three: Sky
&lt;/h2&gt;

&lt;p&gt;This isn't the phase where everything is perfect. This isn't a happy ending.&lt;/p&gt;

&lt;p&gt;Sky is the phase where you can see further — not because the problems disappeared, but because you've climbed high enough to see that they're part of a larger landscape.&lt;/p&gt;

&lt;p&gt;Here you start to feel grateful. Not a forced gratitude — but the kind that grows slowly, like realizing that everything heavy from before shaped who you are now.&lt;/p&gt;

&lt;p&gt;And here you understand: this journey never really ends. You just keep walking, with different weight, with slightly more wisdom.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why naming these phases matters
&lt;/h2&gt;

&lt;p&gt;Because when you know you're in the Roots phase — you won't think you're broken.&lt;/p&gt;

&lt;p&gt;When you know you're in the Growth phase — you won't rush to arrive.&lt;/p&gt;

&lt;p&gt;And when you finally reach Sky — you'll look back and understand why all of it needed to happen.&lt;/p&gt;




&lt;p&gt;These three phases are the backbone of my first poetry book, &lt;strong&gt;Stillness That Walks&lt;/strong&gt;. Twenty-four poems, three parts, one journey that offers no answers — only company.&lt;/p&gt;

&lt;p&gt;If you're in one of these phases right now, maybe there's a line in there that feels like yours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cahyanudien.site/stillness-that-walks/" rel="noopener noreferrer"&gt;cahyanudien.site/stillness-that-walks&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cahyanudien Aziz Saputra is the founder of FlagoDNA, a self-taught app developer. He lives in quiet — writing code, assembling logic, arranging meaning. Many people use what he builds. No one knows how many nights he spent in silence. This book is one of the ways he finally spoke.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>stillnessthatwalks</category>
      <category>cahyanudien</category>
      <category>reflection</category>
      <category>books</category>
    </item>
    <item>
      <title>Tiga Fase yang Semua Orang Lewati Tapi Jarang Diakui: Akar, Tumbuh, Langit</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Sat, 16 May 2026 06:58:43 +0000</pubDate>
      <link>https://dev.to/cas8398/tiga-fase-yang-semua-orang-lewati-tapi-jarang-diakui-akar-tumbuh-langit-12lm</link>
      <guid>https://dev.to/cas8398/tiga-fase-yang-semua-orang-lewati-tapi-jarang-diakui-akar-tumbuh-langit-12lm</guid>
      <description>&lt;p&gt;Ada yang pernah merasa terjebak — tapi tidak tahu terjebak di mana?&lt;/p&gt;

&lt;p&gt;Bukan masalah kerjaan. Bukan masalah hubungan. Bukan satu hal yang bisa ditunjuk. Hanya sebuah perasaan berat yang duduk di dada, dan kamu tidak tahu sejak kapan ia di sana.&lt;/p&gt;

&lt;p&gt;Aku pernah di situ. Dan ketika aku mulai menulis puisi, aku sadar — ini bukan pengalaman yang unik. Ini fase. Dan hampir semua orang melewatinya.&lt;/p&gt;

&lt;p&gt;Hanya saja tidak ada yang menyebutnya dengan nama.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fase Pertama: Akar
&lt;/h2&gt;

&lt;p&gt;Ini fase paling berat — karena kamu belum tahu ini sebuah fase.&lt;/p&gt;

&lt;p&gt;Rasanya seperti terbangun di dalam gua. Gelap. Sunyi. Kamu melangkah tapi beban di hati semakin berat, bukan berkurang. Kamu bertanya: &lt;em&gt;di mana cahaya itu?&lt;/em&gt; Tapi bahkan pertanyaan itu terasa menguras tenaga.&lt;/p&gt;

&lt;p&gt;Di sini banyak orang berhenti bergerak. Bukan karena menyerah — tapi karena tidak tahu harus bergerak ke arah mana.&lt;/p&gt;

&lt;p&gt;Yang sebenarnya terjadi: kamu sedang berakar. Akar tidak kelihatan dari luar. Akar tidak indah. Akar tumbuh ke bawah dulu, ke dalam kegelapan, sebelum pohon bisa berdiri.&lt;/p&gt;

&lt;p&gt;Ini bukan kemunduran. Ini fondasi.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fase Kedua: Tumbuh
&lt;/h2&gt;

&lt;p&gt;Fase ini lebih membingungkan dari yang pertama — karena terasa baik-baik saja di luar, tapi di dalam masih ada yang belum selesai.&lt;/p&gt;

&lt;p&gt;Kamu mulai bergerak lagi. Ada momen riang, ada momen gemerlap. Orang-orang bilang kamu sudah baikan. Kamu sendiri hampir percaya.&lt;/p&gt;

&lt;p&gt;Tapi waktu tidak berdiam diri. Ia terus berjalan, dan kamu sadar — jiwa ini belum siap untuk terus berpura-pura nyaman. Ada pertumbuhan yang sedang terjadi, dan pertumbuhan itu tidak selalu mulus.&lt;/p&gt;

&lt;p&gt;Kadang tumbuh artinya melepas. Kadang artinya berpisah dengan versi dirimu yang lama. Kadang artinya mengakui bahwa kamu butuh waktu lebih lama dari yang kamu kira.&lt;/p&gt;

&lt;p&gt;Itu bukan kelemahan. Itu proses.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fase Ketiga: Langit
&lt;/h2&gt;

&lt;p&gt;Ini bukan fase di mana semuanya sempurna. Ini bukan &lt;em&gt;happy ending&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Langit adalah fase di mana kamu bisa melihat lebih jauh — bukan karena masalahnya hilang, tapi karena kamu sudah cukup tinggi untuk melihat bahwa masalah itu bagian dari lanskap yang lebih besar.&lt;/p&gt;

&lt;p&gt;Di sini kamu mulai bisa berterima kasih. Bukan terima kasih yang dipaksakan — tapi yang tumbuh perlahan, seperti menyadari bahwa semua yang berat dulu, membentukmu sekarang.&lt;/p&gt;

&lt;p&gt;Dan di sini kamu sadar: perjalanan ini tidak pernah benar-benar selesai. Kamu hanya terus berjalan, dengan beban yang berbeda, dengan cara yang sedikit lebih bijak.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kenapa penting memberi nama pada fase ini?
&lt;/h2&gt;

&lt;p&gt;Karena ketika kamu tahu kamu sedang di fase Akar — kamu tidak akan mengira dirimu rusak.&lt;/p&gt;

&lt;p&gt;Ketika kamu tahu kamu sedang di fase Tumbuh — kamu tidak akan terburu-buru untuk sampai.&lt;/p&gt;

&lt;p&gt;Dan ketika kamu akhirnya di fase Langit — kamu akan menoleh ke belakang dan mengerti kenapa semua itu perlu terjadi.&lt;/p&gt;




&lt;p&gt;Tiga fase ini yang menjadi tulang punggung buku puisi pertamaku, &lt;strong&gt;Hening yang Berjalan&lt;/strong&gt;. Dua puluh empat puisi, tiga bagian, satu perjalanan yang tidak menawarkan jawaban — hanya menemani.&lt;/p&gt;

&lt;p&gt;Kalau kamu sedang di salah satu fase itu sekarang, mungkin ada baris di sana yang terasa seperti milikmu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cahyanudien.site/hening-yang-berjalan/" rel="noopener noreferrer"&gt;cahyanudien.site/hening-yang-berjalan&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cahyanudien Aziz Saputra adalah pendiri FlagoDNA, pengembang aplikasi yang belajar mandiri. Banyak orang memakai apa yang ia buat. Tidak ada yang tahu berapa malam ia habiskan dalam sunyi. Buku ini adalah salah satu caranya berbicara.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>books</category>
      <category>cahyanudien</category>
      <category>puisi</category>
    </item>
    <item>
      <title>I Write Code All Day. Then I Write Poetry at Night. Here’s Why</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Thu, 14 May 2026 07:14:46 +0000</pubDate>
      <link>https://dev.to/cas8398/i-write-code-all-day-then-i-write-poetry-at-night-heres-why-321c</link>
      <guid>https://dev.to/cas8398/i-write-code-all-day-then-i-write-poetry-at-night-heres-why-321c</guid>
      <description>&lt;p&gt;I never planned to be a poet.&lt;/p&gt;

&lt;p&gt;I planned to be a developer. And that's what happened — I build apps, write code, ship products. A lot of people use what I make. Most of them don't know my name.&lt;/p&gt;

&lt;p&gt;But there are things code cannot fix.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code is a precise language. Poetry is an honest one.
&lt;/h2&gt;

&lt;p&gt;When I write a function, I know what it wants. There's an input, an output, logic in between. Everything is testable. If something's wrong, there's an error message.&lt;/p&gt;

&lt;p&gt;Life doesn't work like that.&lt;/p&gt;

&lt;p&gt;There are days that feel heavy without reason. Losses that never got named. Questions that are more comfortable left unanswered than resolved.&lt;/p&gt;

&lt;p&gt;Code can't hold that. Poetry can.&lt;/p&gt;

&lt;p&gt;Not because poetry has answers — quite the opposite. Poetry is the space where questions are allowed to stay questions. Where "I don't know" isn't an error, it's part of the process.&lt;/p&gt;




&lt;h2&gt;
  
  
  Night is the only honest time
&lt;/h2&gt;

&lt;p&gt;During the day, I'm busy. Features to ship, bugs to fix, notifications that don't stop. All of it is real and needs to get done.&lt;/p&gt;

&lt;p&gt;But the night — the night is mine.&lt;/p&gt;

&lt;p&gt;That's where I started writing. Not with a specific goal. Not with a word count target. Just sitting down and letting something come out.&lt;/p&gt;

&lt;p&gt;Some nights only a few lines came. Some nights nothing at all. But there were nights when I wrote something and felt — &lt;em&gt;this&lt;/em&gt;. This is the thing I couldn't say any other way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two languages, one person
&lt;/h2&gt;

&lt;p&gt;People often ask: how can you be a developer and write poetry?&lt;/p&gt;

&lt;p&gt;The better question might be: how could you not?&lt;/p&gt;

&lt;p&gt;Both are ways of making something from nothing. Both start from a question that doesn't have an answer yet. Both require the patience to sit in uncertainty until something becomes clear.&lt;/p&gt;

&lt;p&gt;The difference — code is done when it runs. Poetry is done when it feels right.&lt;/p&gt;




&lt;h2&gt;
  
  
  Then it became a book
&lt;/h2&gt;

&lt;p&gt;After writing long enough in the nights, I had a collection of words that didn't know where to go.&lt;/p&gt;

&lt;p&gt;I arranged them. Read them again. Removed what wasn't honest, kept what felt true.&lt;/p&gt;

&lt;p&gt;That became &lt;strong&gt;Stillness That Walks&lt;/strong&gt; — my first poetry book. Twenty-four poems in three parts: Roots, Growth, Sky. A journey that doesn't offer conclusions, only company.&lt;/p&gt;

&lt;p&gt;I didn't write it as someone who has arrived. I wrote it as someone still walking.&lt;/p&gt;

&lt;p&gt;Maybe you've been at that point too.&lt;/p&gt;




&lt;p&gt;If you're curious, the book is here: &lt;a href="https://www.cahyanudien.site/stillness-that-walks/" rel="noopener noreferrer"&gt;cahyanudien.site/stillness-that-walks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you're also a developer quietly carrying something — maybe it's time to let it out.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cahyanudien Aziz Saputra is the founder of FlagoDNA, a self-taught app developer. He lives in quiet — writing code, assembling logic, arranging meaning. Many people use what he builds. No one knows how many nights he spent in silence. This book is one of the ways he finally spoke.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>books</category>
      <category>flagodna</category>
      <category>cahyanudien</category>
    </item>
    <item>
      <title>JDU — Jira Desktop Unofficial: A Minimal Jira Desktop Wrapper Built with Tauri | Cahyanudien Blogs</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Thu, 14 May 2026 02:56:35 +0000</pubDate>
      <link>https://dev.to/cas8398/jdu-jira-desktop-unofficial-a-minimal-jira-desktop-wrapper-built-with-tauri-cahyanudien-blogs-i9j</link>
      <guid>https://dev.to/cas8398/jdu-jira-desktop-unofficial-a-minimal-jira-desktop-wrapper-built-with-tauri-cahyanudien-blogs-i9j</guid>
      <description>&lt;h2&gt;
  
  
  Stop letting browser tabs steal your focus.
&lt;/h2&gt;

&lt;p&gt;If you use Jira every day, you already know the feeling. You open a new tab to check a ticket. Five minutes later you're reading an article, skimming a notification, or stuck in a rabbit hole you didn't plan for. The work you opened Jira for? Still waiting.&lt;/p&gt;

&lt;p&gt;This is the problem &lt;strong&gt;JDU — Jira Desktop Unofficial&lt;/strong&gt; was built to solve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JDU&lt;/strong&gt; (short for &lt;em&gt;Jira Desktop Unofficial&lt;/em&gt;) is a minimal, focused desktop wrapper for Jira — built with &lt;a href="https://tauri.app" rel="noopener noreferrer"&gt;Tauri&lt;/a&gt; and Rust. It gives Jira its own dedicated window, completely separate from your browser. No tabs. No distractions. Just your work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;JDU = Jira Desktop Unofficial (JDU) — A Minimal Jira Desktop Wrapper Built with Tauri.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
That's the full name. You'll see it everywhere: in the app, in the releases, and in the community.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;📥 Download&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/cas8398/jira-desktop-unofficial/releases" rel="noopener noreferrer"&gt;github.com/cas8398/jira-desktop-unofficial/releases&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⭐ GitHub&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/cas8398/jira-desktop-unofficial" rel="noopener noreferrer"&gt;github.com/cas8398/jira-desktop-unofficial&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🌐 Project Page&lt;/td&gt;
&lt;td&gt;&lt;a href="https://cas8398.github.io/jira-desktop-unofficial/" rel="noopener noreferrer"&gt;cas8398.github.io/jira-desktop-unofficial&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📖 Medium&lt;/td&gt;
&lt;td&gt;&lt;a href="https://medium.com/@cas8398/jira-desktop-unofficial-a-minimal-jira-desktop-wrapper-built-with-tauri-5ab15a3586aa" rel="noopener noreferrer"&gt;Read the original story&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🖥️ What Is JDU?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;JDU — Jira Desktop Unofficial&lt;/strong&gt; is a desktop application that wraps your Jira instance in a clean, native window. It doesn't add new features to Jira itself — it changes &lt;em&gt;how&lt;/em&gt; you access it.&lt;/p&gt;

&lt;p&gt;Instead of opening Jira inside a browser tab surrounded by noise, JDU gives it its own space. You launch it like you launch Slack or VS Code. It opens directly into Jira. You work. You close it. That's it.&lt;/p&gt;

&lt;p&gt;Under the hood, JDU uses &lt;strong&gt;Tauri&lt;/strong&gt; — a modern framework that combines a Rust backend with your operating system's native webview. This means no Chromium bundled inside, no Node.js bloat, and no 300MB memory drain before you've even logged in.&lt;/p&gt;

&lt;p&gt;It supports &lt;strong&gt;any Jira instance&lt;/strong&gt;: Jira Cloud, Jira Server, and Jira Data Center. On first launch, you paste in your URL. JDU remembers it. Every launch after that goes straight to your board.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✨ Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🖥️ Dedicated Window
&lt;/h3&gt;

&lt;p&gt;Jira gets its own window — completely isolated from your browser. Alt-Tab to JDU the same way you'd switch to Slack or your terminal. Your other tabs stay clean.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚡ Ultra-Lightweight
&lt;/h3&gt;

&lt;p&gt;JDU uses ~80MB of RAM at runtime and downloads at under 8MB. It starts in under 2 seconds. Compare that to a typical Electron app at 350MB RAM and 120MB to download.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔒 Privacy-First
&lt;/h3&gt;

&lt;p&gt;Zero tracking. Zero telemetry. Zero data collection of any kind. Your Jira credentials are handled entirely by Jira's own login system — exactly as in a browser. JDU has no backend servers and sends nothing anywhere. The full source code is on GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌐 Works With Any Jira
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Jira Cloud (&lt;code&gt;*.atlassian.net&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;✅ Jira Server (self-hosted)&lt;/li&gt;
&lt;li&gt;✅ Jira Data Center&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧠 Smart Memory
&lt;/h3&gt;

&lt;p&gt;JDU remembers your Jira URL and window size/position across sessions. Open the app, get straight to your board — no setup, no re-entering URLs.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎨 Custom Backgrounds &amp;amp; Overlay
&lt;/h3&gt;

&lt;p&gt;Starting in v0.1.3, you can personalize the JDU window with 5 curated background images and fine-tune overlay opacity (0–100%) to match your taste.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔄 Dynamic Window Titles
&lt;/h3&gt;

&lt;p&gt;The window title updates as you navigate between Jira pages — so if you use your taskbar or window switcher, you always know exactly where you are.&lt;/p&gt;

&lt;h3&gt;
  
  
  📱 Cross-Platform
&lt;/h3&gt;

&lt;p&gt;JDU runs natively on &lt;strong&gt;Windows&lt;/strong&gt;, &lt;strong&gt;macOS&lt;/strong&gt;, and &lt;strong&gt;Linux&lt;/strong&gt;. Same experience, same performance, everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 Why Not Electron? (And Why This Matters for Jira Users)
&lt;/h2&gt;

&lt;p&gt;This is the question most developers ask first — and it's a fair one. Almost every "desktop wrapper" app you've used was built with Electron. There's a reason JDU is different.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Electron problem
&lt;/h3&gt;

&lt;p&gt;Electron works by bundling an entire copy of Chromium — Google Chrome's rendering engine — into every app. Every. Single. App. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your Jira wrapper carries ~120MB of download just to boot&lt;/li&gt;
&lt;li&gt;It consumes 300–500MB of RAM before you've opened a single ticket&lt;/li&gt;
&lt;li&gt;Startup takes 5–8 seconds&lt;/li&gt;
&lt;li&gt;Background CPU usage stays elevated even when idle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have multiple Electron apps running (Slack, VS Code, Notion, etc.), the cumulative memory cost becomes significant. Adding a Jira Electron wrapper on top of that is just more tax.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tauri approach
&lt;/h3&gt;

&lt;p&gt;Tauri doesn't bundle Chromium. Instead, it uses the &lt;strong&gt;webview already built into your OS&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebView2&lt;/strong&gt; on Windows (powered by Edge)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebKit&lt;/strong&gt; on macOS and Linux&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rendering quality is identical. The resource cost is a fraction. And because the backend is written in Rust — a memory-safe, compiled systems language — the app is secure and fast by design.&lt;/p&gt;

&lt;p&gt;For Jira users specifically, this matters because JDU is likely running all day. A tool you keep open for 8 hours should not be quietly draining your battery and RAM for 8 hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  📈 Performance at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;JDU&lt;/th&gt;
&lt;th&gt;Typical Electron App&lt;/th&gt;
&lt;th&gt;Browser Tab&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory Usage&lt;/td&gt;
&lt;td&gt;~80 MB&lt;/td&gt;
&lt;td&gt;~350 MB&lt;/td&gt;
&lt;td&gt;~150 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup Time&lt;/td&gt;
&lt;td&gt;&amp;lt; 2 seconds&lt;/td&gt;
&lt;td&gt;5–8 seconds&lt;/td&gt;
&lt;td&gt;Instant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Download Size&lt;/td&gt;
&lt;td&gt;~8 MB&lt;/td&gt;
&lt;td&gt;~120 MB&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background CPU&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;High (with other tabs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking / Telemetry&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;Browser-level&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 Getting Started in 60 Seconds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — Download
&lt;/h3&gt;

&lt;p&gt;Head to the &lt;a href="https://github.com/cas8398/jira-desktop-unofficial/releases" rel="noopener noreferrer"&gt;GitHub releases page&lt;/a&gt; and grab the installer for your OS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Install
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🪟 Windows&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Run the &lt;code&gt;.msi&lt;/code&gt; or &lt;code&gt;.exe&lt;/code&gt; installer. JDU requires &lt;strong&gt;Microsoft Edge WebView2&lt;/strong&gt; — most Windows 10/11 machines already have it. If not, &lt;a href="https://developer.microsoft.com/en-us/microsoft-edge/webview2/" rel="noopener noreferrer"&gt;download it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🍎 macOS&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Open the &lt;code&gt;.dmg&lt;/code&gt; file and drag JDU to your Applications folder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🐧 Linux&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Available as &lt;code&gt;.AppImage&lt;/code&gt;, &lt;code&gt;.deb&lt;/code&gt;, or &lt;code&gt;.rpm&lt;/code&gt;. Download the format that fits your distro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔧 Build from Source&lt;/strong&gt;&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/cas8398/jira-desktop-unofficial
&lt;span class="nb"&gt;cd &lt;/span&gt;jira-desktop-unofficial
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm tauri build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Requires Rust, Node.js, and the &lt;a href="https://tauri.app/start/prerequisites/" rel="noopener noreferrer"&gt;Tauri prerequisites&lt;/a&gt; for your platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Launch
&lt;/h3&gt;

&lt;p&gt;Open JDU, paste your Jira instance URL (e.g. &lt;code&gt;https://yourcompany.atlassian.net&lt;/code&gt;), press Enter — and you're in. JDU remembers the URL from now on.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Deep Dive: JDU for Power Jira Users
&lt;/h2&gt;

&lt;p&gt;If you live in Jira — sprints, backlogs, board views, Confluence-linked tickets, JQL filters — here's what JDU specifically does and doesn't change for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  What stays the same
&lt;/h3&gt;

&lt;p&gt;Everything Jira does in the browser works identically in JDU. JDU is a wrapper — it renders the real Jira web interface inside a native window. Your keyboard shortcuts, your saved filters, your board layouts, your integrations — all untouched.&lt;/p&gt;

&lt;h3&gt;
  
  
  What gets better
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Focus&lt;/strong&gt;: No browser tabs means no accidental navigation away from Jira mid-task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switching&lt;/strong&gt;: JDU appears in your taskbar/dock like any native app. Alt-Tab to it in one move.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Window memory&lt;/strong&gt;: JDU remembers where you left the window and how big it was. Reopen it, it's right where you left it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background behavior&lt;/strong&gt;: JDU uses minimal CPU when it's not in focus, unlike a browser tab that may keep running scripts actively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom aesthetic&lt;/strong&gt;: With v0.1.3, you can now set a background image and control overlay opacity — making your Jira window feel more personal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What's still on the roadmap
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Desktop push notifications for Jira updates&lt;/li&gt;
&lt;li&gt;Keyboard shortcut layer for quick actions&lt;/li&gt;
&lt;li&gt;Dark mode and custom theme support&lt;/li&gt;
&lt;li&gt;Multi-account / multi-instance support&lt;/li&gt;
&lt;li&gt;Offline connection status indicators&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔖 What's New in v0.1.3
&lt;/h2&gt;

&lt;p&gt;The latest release brings meaningful visual and UX improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Backgrounds&lt;/strong&gt; — 5 curated Pexels images to personalize your workspace&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Window Titles&lt;/strong&gt; — The title bar updates as you move between Jira pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern UI Redesign&lt;/strong&gt; — Cleaner interface throughout the app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better URL Validation&lt;/strong&gt; — Handles trailing slashes and edge-case URLs correctly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smarter Domain Detection&lt;/strong&gt; — More reliable Cloud vs. Server instance detection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overlay Opacity Control&lt;/strong&gt; — Slider from 0 to 100% to control background darkness&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bug Fix&lt;/strong&gt; — URL validation issue (&lt;a href="https://github.com/cas8398/jira-desktop-unofficial/issues/2" rel="noopener noreferrer"&gt;#2&lt;/a&gt;) resolved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Special thanks to &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/tsenzuk"&gt;@tsenzuk&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;@bupemko&lt;/strong&gt;, &lt;strong&gt;@pdkrg&lt;/strong&gt;, and &lt;strong&gt;@mitrapartha&lt;/strong&gt; for reporting and helping fix the URL validation bug.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Who Should Use JDU?
&lt;/h2&gt;

&lt;p&gt;JDU is for you if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're a &lt;strong&gt;developer, tech lead, or engineering manager&lt;/strong&gt; who navigates Jira daily&lt;/li&gt;
&lt;li&gt;You're a &lt;strong&gt;project manager or Scrum Master&lt;/strong&gt; who lives on the board and backlog views&lt;/li&gt;
&lt;li&gt;You care about &lt;strong&gt;lightweight, efficient tooling&lt;/strong&gt; and hate RAM-hungry Electron apps&lt;/li&gt;
&lt;li&gt;You want a &lt;strong&gt;distraction-free workflow&lt;/strong&gt; and browser tab chaos is real for you&lt;/li&gt;
&lt;li&gt;You value &lt;strong&gt;open-source, auditable software&lt;/strong&gt; with no hidden data collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JDU is probably not for you if you primarily use Jira occasionally and don't mind the browser tab experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤝 Contributing &amp;amp; Community
&lt;/h2&gt;

&lt;p&gt;JDU is fully open source under the MIT license and welcomes contributions of all kinds.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bug reports&lt;/strong&gt; → &lt;a href="https://github.com/cas8398/jira-desktop-unofficial/issues" rel="noopener noreferrer"&gt;GitHub Issues&lt;/a&gt; — include your OS, app version, and steps to reproduce&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature requests&lt;/strong&gt; → &lt;a href="https://github.com/cas8398/jira-desktop-unofficial/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull requests&lt;/strong&gt; → Fork the repo, make your change, open a PR&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give it a star&lt;/strong&gt; → Helps the project get discovered by others who'd benefit from it&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📥 Download JDU Now
&lt;/h2&gt;

&lt;p&gt;Free. Open source. Under 8MB. No Electron. No bloat.&lt;/p&gt;

&lt;p&gt;➡️ &lt;strong&gt;&lt;a href="https://github.com/cas8398/jira-desktop-unofficial/releases" rel="noopener noreferrer"&gt;Download JDU — Jira Desktop Unofficial&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;&lt;a href="https://github.com/cas8398/jira-desktop-unofficial" rel="noopener noreferrer"&gt;Star on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;&lt;a href="https://cas8398.github.io/jira-desktop-unofficial/" rel="noopener noreferrer"&gt;Visit the Project Page&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;🛑 &lt;strong&gt;Disclaimer:&lt;/strong&gt; JDU is an independent, community-built project and is not affiliated with or endorsed by Atlassian. Jira is a registered trademark of Atlassian Corporation Plc. JDU is a desktop wrapper around the official Jira web interface.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Built with ❤️ by &lt;a href="https://github.com/cas8398" rel="noopener noreferrer"&gt;cas8398&lt;/a&gt; using &lt;a href="https://tauri.app" rel="noopener noreferrer"&gt;Tauri&lt;/a&gt; — MIT License&lt;/em&gt;&lt;/p&gt;

</description>
      <category>jdu</category>
      <category>rust</category>
      <category>wecoded</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Aku Nulis Kode Seharian. Lalu Nulis Puisi di Malam Hari. Ini Kenapa</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Wed, 13 May 2026 02:59:01 +0000</pubDate>
      <link>https://dev.to/cas8398/aku-nulis-kode-seharian-lalu-nulis-puisi-di-malam-hari-ini-kenapa-2h7k</link>
      <guid>https://dev.to/cas8398/aku-nulis-kode-seharian-lalu-nulis-puisi-di-malam-hari-ini-kenapa-2h7k</guid>
      <description>&lt;p&gt;Aku tidak pernah merencanakan jadi penyair.&lt;/p&gt;

&lt;p&gt;Aku merencanakan jadi developer. Dan itu yang terjadi — aku membangun aplikasi, menulis kode, merilis produk. Banyak orang memakai apa yang aku buat. Sebagian besar tidak tahu namaku.&lt;/p&gt;

&lt;p&gt;Tapi ada sesuatu yang tidak bisa diselesaikan dengan kode.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kode adalah bahasa yang jelas. Puisi adalah bahasa yang jujur.
&lt;/h2&gt;

&lt;p&gt;Ketika aku menulis fungsi, aku tahu apa yang diinginkan. Ada input, ada output, ada logika di antaranya. Semuanya bisa diuji. Kalau salah, ada pesan error.&lt;/p&gt;

&lt;p&gt;Hidup tidak bekerja seperti itu.&lt;/p&gt;

&lt;p&gt;Ada hari-hari yang terasa panjang tanpa alasan. Ada kehilangan yang tidak sempat diberi nama. Ada pertanyaan yang lebih nyaman dibiarkan menggantung daripada dijawab.&lt;/p&gt;

&lt;p&gt;Kode tidak bisa menampung itu. Puisi bisa.&lt;/p&gt;

&lt;p&gt;Bukan karena puisi punya jawaban — justru sebaliknya. Puisi adalah ruang di mana pertanyaan boleh tetap menjadi pertanyaan. Di mana "aku tidak tahu" bukan error, tapi bagian dari prosesnya.&lt;/p&gt;




&lt;h2&gt;
  
  
  Malam adalah satu-satunya waktu yang jujur
&lt;/h2&gt;

&lt;p&gt;Siang hari aku sibuk. Ada fitur yang harus dirilis, bug yang harus diperbaiki, notifikasi yang tidak berhenti. Semua itu nyata dan perlu dikerjakan.&lt;/p&gt;

&lt;p&gt;Tapi malam — malam adalah milikku sendiri.&lt;/p&gt;

&lt;p&gt;Di situlah aku mulai menulis. Bukan dengan tujuan tertentu. Bukan dengan target kata. Hanya duduk, dan membiarkan sesuatu keluar.&lt;/p&gt;

&lt;p&gt;Beberapa malam yang keluar hanya beberapa baris. Beberapa malam tidak ada apa-apa. Tapi ada malam-malam ketika aku menulis sesuatu dan merasa — &lt;em&gt;ini&lt;/em&gt;. Ini hal yang selama ini tidak bisa kuucapkan dengan cara lain.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dua bahasa, satu orang
&lt;/h2&gt;

&lt;p&gt;Orang-orang sering bertanya: bagaimana bisa kamu developer sekaligus nulis puisi?&lt;/p&gt;

&lt;p&gt;Pertanyaan yang lebih tepat mungkin: bagaimana bisa kamu tidak?&lt;/p&gt;

&lt;p&gt;Keduanya adalah cara untuk membuat sesuatu dari kekosongan. Keduanya dimulai dari pertanyaan yang belum ada jawabannya. Keduanya membutuhkan kesabaran untuk duduk dalam ketidakpastian sampai sesuatu menjadi jelas.&lt;/p&gt;

&lt;p&gt;Bedanya — kode selesai ketika berjalan. Puisi selesai ketika terasa.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lalu jadilah buku
&lt;/h2&gt;

&lt;p&gt;Setelah cukup lama menulis di malam hari, aku punya sekumpulan kata yang tidak tahu harus pergi ke mana.&lt;/p&gt;

&lt;p&gt;Aku susun. Aku baca ulang. Aku hapus yang tidak jujur, aku pertahankan yang terasa benar.&lt;/p&gt;

&lt;p&gt;Jadilah &lt;strong&gt;Hening yang Berjalan&lt;/strong&gt; — buku puisi pertamaku. Dua puluh empat puisi yang dibagi dalam tiga bagian: Akar, Tumbuh, Langit. Sebuah perjalanan yang tidak menawarkan kesimpulan, hanya menemani.&lt;/p&gt;

&lt;p&gt;Aku tidak menulisnya sebagai seseorang yang sudah sampai. Aku menulisnya sebagai seseorang yang masih berjalan.&lt;/p&gt;

&lt;p&gt;Mungkin kamu juga pernah di titik itu.&lt;/p&gt;




&lt;p&gt;Kalau kamu penasaran, bukunya ada di sini: &lt;a href="https://www.cahyanudien.site/hening-yang-berjalan/" rel="noopener noreferrer"&gt;cahyanudien.site/hening-yang-berjalan&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dan kalau kamu juga seorang developer yang diam-diam menyimpan sesuatu — mungkin sudah waktunya dikeluarkan.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cahyanudien Aziz Saputra adalah pendiri FlagoDNA, pengembang aplikasi yang belajar mandiri. Banyak orang memakai apa yang ia buat. Tidak ada yang tahu berapa malam ia habiskan dalam sunyi. Buku ini adalah salah satu caranya berbicara.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>puisi</category>
      <category>cahyanudien</category>
      <category>indiedev</category>
      <category>flagodna</category>
    </item>
    <item>
      <title>The HadisKu Website Needed a Redesign. So I Did It.</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Fri, 08 May 2026 13:26:28 +0000</pubDate>
      <link>https://dev.to/cas8398/the-hadisku-website-needed-a-redesign-so-i-did-it-13ap</link>
      <guid>https://dev.to/cas8398/the-hadisku-website-needed-a-redesign-so-i-did-it-13ap</guid>
      <description>&lt;p&gt;Being an indie developer is simple, actually.&lt;/p&gt;

&lt;p&gt;You update this. You build that. You ship. You look at it a week later and think — hmm. Something's off. Then you fix it.&lt;/p&gt;

&lt;p&gt;That's the whole loop.&lt;/p&gt;




&lt;p&gt;This time it was the HadisKu website.&lt;/p&gt;

&lt;p&gt;HadisKu is my app. A hadis library — 75,000+ hadis from 14 Imam, free, no ads, no subscriptions. I built it because I wanted it to exist. That's the only reason. No business plan. No target market. Just: this should exist, and I'm the one who can make it.&lt;/p&gt;

&lt;p&gt;The app itself felt right. Dark, quiet, focused. The kind of thing you open at night before sleep to read something that actually means something.&lt;/p&gt;

&lt;p&gt;The website didn't feel like that at all.&lt;/p&gt;

&lt;p&gt;It was fine. Informative. It told you what HadisKu was. But it didn't &lt;em&gt;feel&lt;/em&gt; like HadisKu. It felt like a readme. And I kept closing my laptop slightly annoyed about it, for months, without doing anything.&lt;/p&gt;

&lt;p&gt;Then one weekend I just... did something.&lt;/p&gt;




&lt;h2&gt;
  
  
  No plan. Just a feeling.
&lt;/h2&gt;

&lt;p&gt;I didn't sit down with a mood board or a color theory document.&lt;/p&gt;

&lt;p&gt;I sat down and asked: what does HadisKu &lt;em&gt;feel&lt;/em&gt; like?&lt;/p&gt;

&lt;p&gt;Dark. Quiet. A little bit like opening an old book. Gold on the edges, like the border of a manuscript. Arabic text that actually looks like Arabic text, not a font that happens to support it.&lt;/p&gt;

&lt;p&gt;So that's what I built toward. A dark background the color of a room at 3am. Gold as the accent — not flashy gold, old-manuscript gold. A headline font rooted in Arabic typography. And the first thing you see on the page? Not a description of the app. A hadis. Bukhari No. 1.&lt;/p&gt;

&lt;p&gt;Before you read a single word about what HadisKu is, you've already read something from it.&lt;/p&gt;

&lt;p&gt;That felt right.&lt;/p&gt;




&lt;h2&gt;
  
  
  The old site told you. The new one shows you.
&lt;/h2&gt;

&lt;p&gt;That's the difference, honestly.&lt;/p&gt;

&lt;p&gt;The old one said: "HadisKu is an app with 75,000 hadis from 14 Imam."&lt;/p&gt;

&lt;p&gt;The new one just... puts the hadis in front of you. Live, from the database. Arabic text. Indonesian translation. Right there on the landing page.&lt;/p&gt;

&lt;p&gt;You don't need to install anything to know what it is. You already felt it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The question nobody asks about indie work
&lt;/h2&gt;

&lt;p&gt;When you're building alone, you make every call.&lt;/p&gt;

&lt;p&gt;The color. The font. The copy. Whether to add the noise texture on the background (yes) or skip it because nobody will notice (they won't, but I will). Whether the card hover animation lifts 2px or 3px.&lt;/p&gt;

&lt;p&gt;Every single thing is yours.&lt;/p&gt;

&lt;p&gt;That's freedom. Real freedom, not the motivational-poster kind. You answer to nobody. If something looks wrong, you change it. If something looks right, you keep it. No approval needed. No committee.&lt;/p&gt;

&lt;p&gt;But it's also all yours when it's bad. When the site looks off for six months and you keep closing your laptop slightly annoyed — that's yours too. Nobody's going to fix it for you.&lt;/p&gt;

&lt;p&gt;So: is that a burden or a blessing?&lt;/p&gt;

&lt;p&gt;Honestly, both. At the same time. Always.&lt;/p&gt;




&lt;p&gt;I think that's just what indie development is. You carry the whole thing. The weight and the freedom are the same object. You can't separate them.&lt;/p&gt;

&lt;p&gt;And sometimes on a random weekend, you just pick it up and do the thing you'd been putting off.&lt;/p&gt;

&lt;p&gt;The website looks better now.&lt;/p&gt;

&lt;p&gt;On to the next thing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;HadisKu — Kitab Hadis 14 Imam. Free, no ads, no subscriptions.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Android · Windows · Linux · Web&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;a href="https://flagodna-developer.github.io/hadisku/" rel="noopener noreferrer"&gt;HadisKu Web&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>wecoded</category>
      <category>hadisku</category>
      <category>flagodna</category>
      <category>hadith</category>
    </item>
    <item>
      <title>I Was Tired of Writing the Same Logic Twice — So I Built .bridge</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Thu, 07 May 2026 10:41:54 +0000</pubDate>
      <link>https://dev.to/cas8398/i-was-tired-of-writing-the-same-logic-twice-so-i-built-bridge-4ae9</link>
      <guid>https://dev.to/cas8398/i-was-tired-of-writing-the-same-logic-twice-so-i-built-bridge-4ae9</guid>
      <description>&lt;p&gt;If you've ever worked on a full-stack project with Laravel on the backend and TypeScript on the frontend, you know the pain.&lt;/p&gt;

&lt;p&gt;You write a &lt;code&gt;calculateTotal()&lt;/code&gt; function in PHP. Then you write it again in TypeScript. Then maybe a third time for a Node.js script. Same logic. Different syntax. Three places to maintain. Three places to introduce bugs.&lt;/p&gt;

&lt;p&gt;I got tired of it. So I built something.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Here's a real scenario. You have a pricing function in Laravel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculateTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nv"&gt;$tax&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$tax&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$total&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;Your frontend needs the same calculation client-side, so you write it in TypeScript:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tax&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;total&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;Now your product manager asks you to change the formula. You update the PHP. You forget to update the TypeScript. Three weeks later, a bug report comes in because the two implementations drifted apart.&lt;/p&gt;

&lt;p&gt;This happens constantly in full-stack PHP/JS projects. And it's not a skill problem — it's a tooling problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Idea: One Source of Truth
&lt;/h2&gt;

&lt;p&gt;What if you could write the logic once, in a clean neutral syntax, and compile it to whatever target you need?&lt;/p&gt;

&lt;p&gt;That's &lt;code&gt;.bridge&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateTotal(price: float, tax: float): float {
  let total = price * (1 + tax)
  return total
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bridge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you get:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PHP (Laravel-ready)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Bridge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Logic&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculateTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nv"&gt;$tax&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$tax&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$total&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;&lt;strong&gt;TypeScript&lt;/strong&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tax&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;total&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;&lt;strong&gt;Node.js (ESM)&lt;/strong&gt;&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tax&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;total&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;Same logic. Three targets. Zero drift.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;.bridge&lt;/code&gt; uses a TypeScript-like syntax that's intentionally minimal. The type system maps cleanly to each target:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;.bridge&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;PHP&lt;/th&gt;
&lt;th&gt;TypeScript&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;number&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;number&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The compiler reads your &lt;code&gt;.bridge&lt;/code&gt; files and generates idiomatic code for each target — not just a generic translation, but code that fits naturally into a Laravel class or a TypeScript module.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started in 60 Seconds
&lt;/h2&gt;

&lt;p&gt;Install the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @cas8398/bridge-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bridge new my-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get a minimal scaffold:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-app/
├── bridge.config.json
└── src/
    └── logic.bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;src/logic.bridge&lt;/code&gt;, write your shared logic, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bridge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your compiled files land in &lt;code&gt;.bridge/php/&lt;/code&gt;, &lt;code&gt;.bridge/ts/&lt;/code&gt;, and &lt;code&gt;.bridge/node/&lt;/code&gt; — ready to copy into your existing project or reference directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  There's Also a Reverse Command
&lt;/h2&gt;

&lt;p&gt;Already have PHP or TypeScript code you want to bring into &lt;code&gt;.bridge&lt;/code&gt;? There's a command for that too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bridge to-bridge .bridge/php/Logic.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reverse-compiles back into &lt;code&gt;.bridge&lt;/code&gt; syntax, which you can then edit and recompile to all targets. Useful for migrating existing logic incrementally.&lt;/p&gt;




&lt;h2&gt;
  
  
  VS Code Support
&lt;/h2&gt;

&lt;p&gt;There's a VS Code extension with syntax highlighting and snippets for &lt;code&gt;.bridge&lt;/code&gt; files:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://marketplace.visualstudio.com/items?itemName=FlagoDNA.bridge-vscode" rel="noopener noreferrer"&gt;Bridge Language Support on the Marketplace&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;func&lt;/code&gt; + Tab to scaffold a function. Type &lt;code&gt;let&lt;/code&gt; + Tab for a variable. Nothing fancy, but it makes the editing experience feel native.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It's Not
&lt;/h2&gt;

&lt;p&gt;I want to be honest about scope. &lt;code&gt;.bridge&lt;/code&gt; is not a full programming language. It doesn't handle classes, conditionals, loops, or complex control flow yet. Right now it's focused on &lt;strong&gt;pure functions&lt;/strong&gt; — stateless logic that takes inputs and returns outputs.&lt;/p&gt;

&lt;p&gt;That's actually the sweet spot for shared business logic: validation rules, calculations, formatters, transformers. The stuff you really don't want living in two places.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built It as a CLI, Not a Library
&lt;/h2&gt;

&lt;p&gt;I considered building this as a Babel plugin or a TypeScript transformer, but those tie you to a specific ecosystem. A standalone CLI means you can use it regardless of your build toolchain — whether you're on Vite, Laravel Mix, plain webpack, or no bundler at all. It sits outside your stack and just generates files.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLI&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/@cas8398/bridge-cli" rel="noopener noreferrer"&gt;npmjs.com/package/@cas8398/bridge-cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href="https://github.com/cas8398/bridge-cli" rel="noopener noreferrer"&gt;github.com/cas8398/bridge-cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VS Code extension&lt;/strong&gt;: &lt;a href="https://marketplace.visualstudio.com/items?itemName=FlagoDNA.bridge-vscode" rel="noopener noreferrer"&gt;marketplace.visualstudio.com/items?itemName=FlagoDNA.bridge-vscode&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's early, rough in places, and very much a raw dev release — but the core idea works. If you've felt this pain on a PHP/JS full-stack project, I'd love to know if &lt;code&gt;.bridge&lt;/code&gt; fits your workflow.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with TypeScript. MIT licensed. Feedback welcome via GitHub Issues.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bridge</category>
      <category>dotbridge</category>
      <category>wecoded</category>
    </item>
    <item>
      <title>Bridge: Write Logic Once, Compile Everywhere | Cahyanudien Blogs</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Wed, 06 May 2026 08:34:24 +0000</pubDate>
      <link>https://dev.to/cas8398/bridge-write-logic-once-compile-everywhere-cahyanudien-blogs-2h5c</link>
      <guid>https://dev.to/cas8398/bridge-write-logic-once-compile-everywhere-cahyanudien-blogs-2h5c</guid>
      <description>&lt;p&gt;Sometimes the problem isn’t complexity.&lt;/p&gt;

&lt;p&gt;It’s repetition.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem I Keep Hitting
&lt;/h2&gt;

&lt;p&gt;In almost every project, I end up writing the same logic twice.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validation rules&lt;/li&gt;
&lt;li&gt;Price calculations&lt;/li&gt;
&lt;li&gt;Data transformations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once in backend (PHP),&lt;br&gt;
and again in frontend (TypeScript).&lt;/p&gt;

&lt;p&gt;It’s not hard.&lt;br&gt;
But it’s &lt;strong&gt;fragile&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One change → forget to sync → subtle bug.&lt;/p&gt;

&lt;p&gt;And over time, that duplication becomes technical debt.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;What if the logic itself was the source of truth?&lt;/p&gt;

&lt;p&gt;Not PHP. Not TypeScript.&lt;/p&gt;

&lt;p&gt;Just &lt;strong&gt;logic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So I started experimenting with a small language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateTax(price: float, rate: float): float {
  let tax = price * rate
  return tax
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then compile it into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP (for backend)&lt;/li&gt;
&lt;li&gt;TypeScript (for frontend)&lt;/li&gt;
&lt;li&gt;Node.js (for shared tooling)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That became &lt;strong&gt;Bridge&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Bridge Actually Is
&lt;/h2&gt;

&lt;p&gt;Bridge is not a framework.&lt;/p&gt;

&lt;p&gt;It’s a &lt;strong&gt;CLI compiler&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;.bridge&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Output: real code (PHP / TS / Node)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No runtime.&lt;br&gt;
No magic.&lt;/p&gt;

&lt;p&gt;Just transformation.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Not Just Use JSON / Schema?
&lt;/h2&gt;

&lt;p&gt;I asked myself the same thing.&lt;/p&gt;

&lt;p&gt;Schemas are good for structure.&lt;br&gt;
But logic is more than structure.&lt;/p&gt;

&lt;p&gt;You can’t express:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;calculations&lt;/li&gt;
&lt;li&gt;conditional logic&lt;/li&gt;
&lt;li&gt;transformations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…cleanly in JSON.&lt;/p&gt;

&lt;p&gt;Bridge sits in that gap:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;structured logic, not just structured data&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


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

&lt;p&gt;I kept it intentionally small.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lexer → tokenize input&lt;/li&gt;
&lt;li&gt;Parser → build AST&lt;/li&gt;
&lt;li&gt;Compiler → generate target code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each target has its own emitter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing fancy. Just predictable output.&lt;/p&gt;


&lt;h2&gt;
  
  
  Example Output
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bridge:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateTax(price: float, rate: float): float {
  let tax = price * rate
  return tax
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;TypeScript:&lt;/strong&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateTax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&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;tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rate&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;tax&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;&lt;strong&gt;PHP:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;calculateTax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nv"&gt;$rate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$rate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$tax&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;Same logic.&lt;br&gt;
Different runtimes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tooling (Important Part)
&lt;/h2&gt;

&lt;p&gt;A language without tooling is painful.&lt;/p&gt;

&lt;p&gt;So I built a simple VS Code extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;syntax highlighting&lt;/li&gt;
&lt;li&gt;snippets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://marketplace.visualstudio.com/items?itemName=FlagoDNA.bridge-vscode" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=FlagoDNA.bridge-vscode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the CLI:&lt;br&gt;
👉 &lt;a href="https://www.npmjs.com/package/@cas8398/bridge-cli" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@cas8398/bridge-cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cas8398/bridge-cli" rel="noopener noreferrer"&gt;https://github.com/cas8398/bridge-cli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cas8398/bridge-vscode" rel="noopener noreferrer"&gt;https://github.com/cas8398/bridge-vscode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Limitations (on purpose)
&lt;/h2&gt;

&lt;p&gt;Bridge is not trying to replace real languages.&lt;/p&gt;

&lt;p&gt;Right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No classes&lt;/li&gt;
&lt;li&gt;No async&lt;/li&gt;
&lt;li&gt;No complex types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It focuses on:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;small, deterministic business logic&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That constraint is intentional.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  1. Small tools are easier to reason about
&lt;/h3&gt;

&lt;p&gt;The moment it tries to do everything, it becomes another language problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Determinism matters more than features
&lt;/h3&gt;

&lt;p&gt;Same input → same output builds trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Most logic duplication is boring, not complex
&lt;/h3&gt;

&lt;p&gt;And boring problems are perfect for automation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where This Might Go
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Better type system&lt;/li&gt;
&lt;li&gt;More targets (Python, Go)&lt;/li&gt;
&lt;li&gt;Watch mode (&lt;code&gt;bridge watch&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Real-world integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or maybe it stays small.&lt;/p&gt;

&lt;p&gt;That’s fine too.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Bridge is just an attempt to reduce friction.&lt;/p&gt;

&lt;p&gt;Not a big framework.&lt;br&gt;
Not a new ecosystem.&lt;/p&gt;

&lt;p&gt;Just a small layer between logic and implementation.&lt;/p&gt;




&lt;p&gt;If this resonates with you, try it.&lt;br&gt;
Or break it. Both are useful.&lt;/p&gt;

</description>
      <category>wecoded</category>
      <category>bridge</category>
      <category>php</category>
      <category>typescript</category>
    </item>
    <item>
      <title>The Sound of Silence: Why I Rewrote the AmalanKu Landing Page</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Tue, 05 May 2026 17:01:57 +0000</pubDate>
      <link>https://dev.to/cas8398/the-sound-of-silence-why-i-rewrote-the-amalanku-landing-page-4a2e</link>
      <guid>https://dev.to/cas8398/the-sound-of-silence-why-i-rewrote-the-amalanku-landing-page-4a2e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Before you read on:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
AmalanKu is a private, offline-first Muslim companion for &lt;em&gt;istiqomah&lt;/em&gt; — no accounts, no ads, no tracking.&lt;br&gt;&lt;br&gt;
&lt;a href="https://amalanku.com" rel="noopener noreferrer"&gt;Visit amalanku.com →&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Mismatch Wasn't Broken Code. It Was Broken Tone.
&lt;/h2&gt;

&lt;p&gt;I didn’t rewrite the &lt;a href="https://amalanku.com" rel="noopener noreferrer"&gt;AmalanKu&lt;/a&gt; website because something was broken. I rewrote it because the website was lying about the heart of the product.&lt;/p&gt;

&lt;p&gt;As developers, we are trained to brag. We want to show off the tech stack, the seamless sync, and the clean data visualization. But AmalanKu isn't a productivity tool or a gamified habit tracker. It is a quiet, digital corner for reflection.&lt;/p&gt;

&lt;p&gt;While the app had found its soul, the landing page was still wearing a corporate SaaS suit. It was pitching features when it should have been offering peace.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two Layers of Subtraction
&lt;/h2&gt;

&lt;p&gt;To fix the mismatch, I had to be ruthless. This wasn't just about changing headlines; it was about changing the medium itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Subtraction in Words
&lt;/h3&gt;

&lt;p&gt;I killed the "marketing" language. If the app is built on the premise of &lt;strong&gt;Digital Zuhud&lt;/strong&gt; (restraint), the website shouldn't sound like it's trying to hit a quarterly sales target.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Removed feature-heavy checklists.&lt;/li&gt;
&lt;li&gt;❌ Removed the "hard sell" tone.&lt;/li&gt;
&lt;li&gt;❌ Removed buzzwords that felt like noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Subtraction in Code
&lt;/h3&gt;

&lt;p&gt;I moved from &lt;strong&gt;Astro JS&lt;/strong&gt; to &lt;strong&gt;bare HTML and CSS&lt;/strong&gt;. Astro is brilliant, but for this project, even a modern framework felt like unnecessary "weight."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Removed JS hydration and bundles.&lt;/li&gt;
&lt;li&gt;❌ Removed analytics and tracking scripts.&lt;/li&gt;
&lt;li&gt;❌ Kept only raw, semantic HTML.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Bare HTML Aligns with Istiqomah
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;App Value&lt;/th&gt;
&lt;th&gt;Website Reflection&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🔒 No tracking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;🌐 Zero analytics or tracking cookies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;📦 Offline-first&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚡ Zero JS, instant load on any network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🧘 No pressure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;🎨 No animated CTAs or urgency tactics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🤲 Private by design&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;💾 No fingerprints, no data collection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If the app promises simplicity, the website shouldn't whisper one thing and shout another. Speed is a form of respect; a 100/100 Lighthouse score is an act of service to the user.&lt;/p&gt;




&lt;h2&gt;
  
  
  The New Narrative: Intention Over Metrics
&lt;/h2&gt;

&lt;p&gt;I realized that by listing "Data Tracking" as a primary headline, I was accidentally telling users: &lt;em&gt;"Focus on the numbers."&lt;/em&gt; But the goal of AmalanKu is to help users focus on the &lt;strong&gt;Creator&lt;/strong&gt;, not the chart.&lt;/p&gt;

&lt;p&gt;The new landing page follows a different flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Intention:&lt;/strong&gt; &lt;em&gt;"Istiqomah Dalam Setiap Amalan"&lt;/em&gt; — start with the &lt;em&gt;Why&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Privacy:&lt;/strong&gt; Clear, bold statements about data staying local.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Growth:&lt;/strong&gt; Presenting the "Level Amalan" (Pemula to Berkembang) as a journey, not a task list.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Community:&lt;/strong&gt; Real words from the Ummah, from Makassar to Jakarta.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Closing: Silence as Honesty
&lt;/h2&gt;

&lt;p&gt;The AmalanKu website didn’t become better because I added "better" code. It became better because I finally learned when to shut up. &lt;/p&gt;

&lt;p&gt;In a world where apps fight for every second of your attention, providing a space that asks for nothing and gives you back your privacy is the ultimate feature. Sometimes, the most honest way to communicate is through silence—and in web development, that silence is bare HTML.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Experience the quiet for yourself at &lt;a href="https://amalanku.com" rel="noopener noreferrer"&gt;amalanku.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🤲 &lt;a href="https://play.google.com/store/apps/details?id=com.flagodna.amalanku" rel="noopener noreferrer"&gt;Download on Play Store&lt;/a&gt; &lt;/p&gt;

</description>
      <category>amalanku</category>
      <category>islam</category>
      <category>muslim</category>
    </item>
    <item>
      <title>Hijri Today: I Built This Because My Mom Needed It | Cahyanudien Blogs</title>
      <dc:creator>Cahyanudien Aziz Saputra</dc:creator>
      <pubDate>Mon, 04 May 2026 06:08:22 +0000</pubDate>
      <link>https://dev.to/cas8398/hijri-today-i-built-this-because-my-mom-needed-it-cahyanudien-blogs-573e</link>
      <guid>https://dev.to/cas8398/hijri-today-i-built-this-because-my-mom-needed-it-cahyanudien-blogs-573e</guid>
      <description>&lt;p&gt;It started with my mom.&lt;/p&gt;

&lt;p&gt;Not a pitch deck. Not a market research document. Not a monetization strategy.&lt;/p&gt;

&lt;p&gt;Just my mom, asking me — again — what today's date is in Hijri.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Origin Story
&lt;/h2&gt;

&lt;p&gt;My mom is not a tech-savvy person. She doesn't open five apps before breakfast. She doesn't maintain a productivity system. She just wants to know — &lt;em&gt;is today a fasting day? What's the Hijriah date? Is Ramadan close?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Simple questions. And every single time, she had to either open a browser, dig through a calendar app, or ask someone.&lt;/p&gt;

&lt;p&gt;I watched her do this for months before it finally clicked: &lt;strong&gt;this shouldn't be hard.&lt;/strong&gt; This information should just &lt;em&gt;be there&lt;/em&gt;, on her home screen, waiting for her — the way the clock and the weather are.&lt;/p&gt;

&lt;p&gt;So I built it. Not because I saw a gap in the market. Because I saw a gap in my mom's morning.&lt;/p&gt;

&lt;p&gt;That's &lt;strong&gt;Hijri Today&lt;/strong&gt; — or &lt;em&gt;"Hijri Hari Ini"&lt;/em&gt; as we say in Indonesian.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It Does (And Why It's Different)
&lt;/h2&gt;

&lt;p&gt;A lot of Islamic calendar apps exist. Most of them require you to &lt;em&gt;open&lt;/em&gt; the app. You unlock your phone, find the icon, tap it, wait for it to load, see the date, close it, and go on with your day.&lt;/p&gt;

&lt;p&gt;That's friction my mom doesn't need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hijri Today is a home screen widget.&lt;/strong&gt; No tapping required. No opening required. The Hijriah date is just &lt;em&gt;there&lt;/em&gt;, on your home screen, updated automatically — the same way your wallpaper clock is.&lt;/p&gt;

&lt;p&gt;It sounds small. It isn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  From 1.0.0 to 1.0.6: The Real Changelog
&lt;/h2&gt;

&lt;p&gt;Building in public means being honest about the journey. Here's what actually changed across every release — no spin, no invented features.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌱 v1.0.0 — It Works
&lt;/h3&gt;

&lt;p&gt;The first version did one thing: show the Hijriah date on your home screen. That's it. One widget style. English and Arabic only. No customization, no settings to get lost in.&lt;/p&gt;

&lt;p&gt;It was rough. But my mom could see the date without opening anything, and that felt like everything.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I shipped before I was ready, because the alternative was never shipping.&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🔧 v1.0.1 — First Iteration
&lt;/h3&gt;

&lt;p&gt;Small fixes, polish on the first release. Getting the foundation stable before adding anything new.&lt;/p&gt;




&lt;h3&gt;
  
  
  🛠️ v1.0.2 — Notifications &amp;amp; Sponsor Portal
&lt;/h3&gt;

&lt;p&gt;Fixed Islamic event notifications that weren't firing correctly — which matters, because missing Eid notifications is not a minor bug. Also added a sponsor portal plugin as infrastructure for sustaining development without charging users or running ads.&lt;/p&gt;




&lt;h3&gt;
  
  
  🌍 v1.0.3 — Localization &amp;amp; Widget Overhaul
&lt;/h3&gt;

&lt;p&gt;This was the first version that made me realize the app could reach beyond Indonesia.&lt;/p&gt;

&lt;p&gt;Added localization support for &lt;strong&gt;13 languages&lt;/strong&gt;: Malay, Urdu, Bengali, Turkish, Hausa, Yoruba, Somali, French, Spanish, and Hindi — alongside the existing English, Arabic, and Indonesian.&lt;/p&gt;

&lt;p&gt;The Islamic community doesn't live in one country. It felt wrong to keep the app feeling like it was built only for mine.&lt;/p&gt;

&lt;p&gt;Also in this version: the widget system was refactored for improved stability, &lt;strong&gt;dynamic color theming&lt;/strong&gt; was introduced, and the &lt;strong&gt;configurable Hijri date offset (±2 days)&lt;/strong&gt; landed — allowing users to adjust the displayed date to match the moon-sighting authority followed in their region. A small toggle with real religious significance: the difference between showing Ramadan starting on the right day or the wrong one.&lt;/p&gt;




&lt;h3&gt;
  
  
  📜 v1.0.4 — Widget Scroll &amp;amp; Shareability
&lt;/h3&gt;

&lt;p&gt;Added &lt;strong&gt;vertical scroll&lt;/strong&gt; to the widget update flow to handle overflow better on different screen sizes.&lt;/p&gt;

&lt;p&gt;Also built out a proper share message — so users who want to recommend the app to family have something worth sending:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Hijri Today is a beautiful and lightweight Android widget displaying the current Hijri date, Islamic events, and Sunnah fasting reminders. 100% Free, No Ads, No Analytics."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That share copy is also a mission statement. It's what I want every person who finds this app to understand in 10 seconds.&lt;/p&gt;




&lt;h3&gt;
  
  
  🗓️ v1.0.5 — 30 Languages, Javanese Calendar, 5 Widget Styles
&lt;/h3&gt;

&lt;p&gt;The biggest release. A lot moved in this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;17 new languages added&lt;/strong&gt;, bringing the total to 30:&lt;br&gt;
Persian, Swahili, Pashto, Punjabi, Tamil, Russian, Uzbek, Kurdish, Portuguese, German, Italian, Dutch, Filipino/Tagalog, Amharic, Kazakh, Albanian, and Bosnian.&lt;/p&gt;

&lt;p&gt;Every language represents a Muslim community that can now see their Hijri date without switching to English first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Javanese Pasaran days&lt;/strong&gt; landed as an optional toggle — the five-day traditional Javanese cycle (Legi, Pahing, Pon, Wage, Kliwon) shown alongside the Hijri date. My app was born in Indonesia, and Javanese Muslim culture has always carried both calendars at once. This made that official.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 widget styles&lt;/strong&gt; introduced: Standard, Minimalist, Jawa, Arabic, and Terpadu (Integrated). Because one design was never going to fit 30 language communities across different visual cultures.&lt;/p&gt;

&lt;p&gt;The UI was also rolled back to the v1.0.3 design — the v1.0.4 UI experiment didn't hold up. Shipping an update sometimes means admitting the previous update was a step backwards and fixing it.&lt;/p&gt;




&lt;h3&gt;
  
  
  🕌 v1.0.6 — Full Islamic Events Restored &amp;amp; Navigation Redesign
&lt;/h3&gt;

&lt;p&gt;Two things changed in this version, and both matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Islamic events restored in full.&lt;/strong&gt; An earlier release had trimmed the events list down — which quietly broke something important. If you're fasting on Arafah or watching for Mawlid an-Nabi, you need the app to actually tell you. This version brought back the complete set: Ramadan, Eid al-Fitr, Eid al-Adha, Islamic New Year, Mawlid an-Nabi, Yawm Arafah, Ashura, and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tab bar moved from top to bottom.&lt;/strong&gt; Small UX change. Big difference in one-handed usability, especially on larger phones. The navigation now sits where your thumb already is.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Philosophy Behind the Product
&lt;/h2&gt;

&lt;p&gt;There are things I decided early and held firm on through every version:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free. No hidden costs, no premium tier.&lt;/strong&gt; The Hijriah date is not a feature — it's something every Muslim deserves access to, without a subscription.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No ads.&lt;/strong&gt; I didn't want anyone's spiritual morning routine interrupted by a banner ad. Clean experience, always.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No unnecessary permissions.&lt;/strong&gt; The app only asks for alarm scheduling permission — nothing else. No location tracking, no contacts, no analytics. Your phone, your data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lightweight.&lt;/strong&gt; This is a widget. It should be invisible, unobtrusive, and fast. Not another battery drain.&lt;/p&gt;




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

&lt;p&gt;I don't have a roadmap to announce. What I have is a commitment to keep shipping.&lt;/p&gt;

&lt;p&gt;Every version so far came from a real observation — something missing, something broken, something that mattered to real people using the app daily. That's how the next version will happen too.&lt;/p&gt;

&lt;p&gt;If you use the app and something bothers you, or something's missing that should be there — leave a review. That's where the next changelog starts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Download It
&lt;/h2&gt;

&lt;p&gt;Hijri Today is available now on the &lt;strong&gt;Google Play Store&lt;/strong&gt; — free, ad-free, and built with care.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://play.google.com/store/apps/details?id=com.flagodna.hijridate" rel="noopener noreferrer"&gt;Get it on Google Play&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  To Every Muslim Who Downloads This
&lt;/h2&gt;

&lt;p&gt;Barakallahu fiikum. 🤲&lt;/p&gt;

&lt;p&gt;I hope this widget makes your morIt started with my mom.&lt;/p&gt;

&lt;p&gt;Not a pitch deck. Not a market research document. Not a monetization strategy.&lt;/p&gt;

&lt;p&gt;Just my mom, asking me — again — what today's date is in Hijri.&lt;/p&gt;

&lt;p&gt;The Real Origin Story&lt;br&gt;
My mom is not a tech-savvy person. She doesn't open five apps before breakfast. She doesn't maintain a productivity system. She just wants to know — is today a fasting day? What's the Hijriah date? Is Ramadan close?&lt;/p&gt;

&lt;p&gt;Simple questions. And every single time, she had to either open a browser, dig through a calendar app, or ask someone.&lt;/p&gt;

&lt;p&gt;I watched her do this for months before it finally clicked: this shouldn't be hard. This information should just be there, on her home screen, waiting for her — the way the clock and the weather are.&lt;/p&gt;

&lt;p&gt;So I built it. Not because I saw a gap in the market. Because I saw a gap in my mom's morning.&lt;/p&gt;

&lt;p&gt;That's Hijri Hari Ini — which literally means "Hijri Today" in Indonesian.&lt;/p&gt;

&lt;p&gt;What It Does (And Why It's Different)&lt;br&gt;
A lot of Islamic calendar apps exist. Most of them require you to open the app. You unlock your phone, find the icon, tap it, wait for it to load, see the date, close it, and go on with your day.&lt;/p&gt;

&lt;p&gt;That's friction my mom doesn't need.&lt;/p&gt;

&lt;p&gt;Hijri Hari Ini is a home screen widget. No tapping required. No opening required. The Hijriah date is just there, on your home screen, updated automatically — the same way your wallpaper clock is.&lt;/p&gt;

&lt;p&gt;It sounds small. It isn't.nings a little simpler. I hope it helps you catch the fasting days you'd have missed. I hope it connects you, just a little more gently, to the Islamic calendar that structures so much of spiritual life.&lt;/p&gt;

&lt;p&gt;And if it helps your mom know what day it is in Hijri — without having to ask anyone — then it's already done its job.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by &lt;a href="https://flagodna.com" rel="noopener noreferrer"&gt;Flagodna&lt;/a&gt; — small apps, real purpose.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>muslim</category>
      <category>productivity</category>
      <category>islam</category>
      <category>flagodna</category>
    </item>
  </channel>
</rss>
