<?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>Forem: Granite Bagas</title>
    <description>The latest articles on Forem by Granite Bagas (@granitebps).</description>
    <link>https://forem.com/granitebps</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%2F245885%2Fd23f52eb-3490-4bbc-856c-83fe658fd8c8.jpeg</url>
      <title>Forem: Granite Bagas</title>
      <link>https://forem.com/granitebps</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/granitebps"/>
    <language>en</language>
    <item>
      <title>The Story Behind mongoose-log-history: From Internal Audit Needs to Open Source</title>
      <dc:creator>Granite Bagas</dc:creator>
      <pubDate>Tue, 24 Jun 2025 14:37:59 +0000</pubDate>
      <link>https://forem.com/granitebps/the-story-behind-mongoose-log-history-from-internal-audit-needs-to-open-source-51j4</link>
      <guid>https://forem.com/granitebps/the-story-behind-mongoose-log-history-from-internal-audit-needs-to-open-source-51j4</guid>
      <description>&lt;p&gt;A while ago, I was working on a project where I needed to implement an &lt;strong&gt;audit log&lt;/strong&gt; for some important data.&lt;br&gt;&lt;br&gt;
The requirements were clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log every change to the data&lt;/li&gt;
&lt;li&gt;Capture the before and after values for each field&lt;/li&gt;
&lt;li&gt;Record who made the change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, I thought, “I’ll just manually log every data change.”&lt;br&gt;
It seemed simple enough—just add some logging code wherever data was updated. I already implement something like this in different project.&lt;/p&gt;

&lt;p&gt;But as the project grew, I realized this approach was getting messy and repetitive. Wouldn’t it be better if I could just plug in a solution and have audit logging work for any model, anywhere in the project? That’s when I decided to build a &lt;strong&gt;Mongoose plugin&lt;/strong&gt; for audit logging.&lt;/p&gt;

&lt;p&gt;Why a plugin?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s easy to add audit logging to any model—just plug it into the schema.&lt;/li&gt;
&lt;li&gt;If I (or anyone else) need audit logs for other data in the future, it’s just a one-line change.&lt;/li&gt;
&lt;li&gt;Maintenance and future improvements become much simpler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, I started building the plugin to fit my project’s needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track changes at the field level (including arrays and nested fields)&lt;/li&gt;
&lt;li&gt;Log before/after values&lt;/li&gt;
&lt;li&gt;Record who made the change&lt;/li&gt;
&lt;li&gt;Support soft delete, batch operations, and contextual logging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the plugin was working and the project was running smoothly, I thought:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;“Why not add more features and open source it? Maybe other developers need this too!”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s how &lt;strong&gt;mongoose-log-history&lt;/strong&gt; was born—a plugin you can drop into any Mongoose project to get robust, flexible audit logging out of the box.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Does mongoose-log-history Do?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatically logs every create, update, delete, and soft delete&lt;/strong&gt; on your Mongoose models&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Field-level change tracking&lt;/strong&gt; (including arrays and nested fields)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch operation support&lt;/strong&gt; (&lt;code&gt;insertMany&lt;/code&gt;, &lt;code&gt;updateMany&lt;/code&gt;, &lt;code&gt;deleteMany&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contextual logging&lt;/strong&gt;: add user info, approval steps, or any custom context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruning utility&lt;/strong&gt;: clean up old logs by date or count&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compression support&lt;/strong&gt;: save space for large document snapshots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discriminator support&lt;/strong&gt;: works with Mongoose inheritance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual logging API&lt;/strong&gt;: for advanced or custom scenarios&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  How Easy Is It to Use?
&lt;/h2&gt;

&lt;p&gt;Just add the plugin to your schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;changeLoggingPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose-log-history&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;created_by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;orderSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changeLoggingPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;modelName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Order&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;trackedFields&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="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tags&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;arrayType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;simple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;arrayType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custom-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;arrayKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sku&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;trackedFields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;qty&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;contextFields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;created_by.name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;singleCollection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;saveWholeDoc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;compressDocs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Order&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;orderSchema&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, every change to your &lt;code&gt;Order&lt;/code&gt; documents is logged automatically!&lt;/p&gt;




&lt;h2&gt;
  
  
  What Does the Log Look Like?
&lt;/h2&gt;

&lt;p&gt;Each log entry includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model and document ID&lt;/li&gt;
&lt;li&gt;The type of change (&lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;An array of field-level changes (with before/after values)&lt;/li&gt;
&lt;li&gt;User/context info (if configured)&lt;/li&gt;
&lt;li&gt;Full document snapshots (if enabled)&lt;/li&gt;
&lt;li&gt;Timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"60f7c2b8e1b1c8a1b8e1b1c8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"change_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"field_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"from_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"to_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"approved"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"change_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"edit"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_by"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"doc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"created_by.name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-06-14T12:34:56.789Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Advanced Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Soft delete support&lt;/strong&gt;: log when a field (e.g., &lt;code&gt;status: 'deleted'&lt;/code&gt;) marks a doc as deleted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual logging API&lt;/strong&gt;: use &lt;code&gt;getTrackedChanges&lt;/code&gt;, &lt;code&gt;buildLogEntry&lt;/code&gt;, etc. for custom flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruning&lt;/strong&gt;: clean up old logs with &lt;code&gt;pruneLogHistory&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compression&lt;/strong&gt;: store large document snapshots efficiently.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/mongoose-log-history" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/mongoose-log-history&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/granitebps/mongoose-log-history" rel="noopener noreferrer"&gt;https://github.com/granitebps/mongoose-log-history&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs:&lt;/strong&gt; See the README for full usage, options, and examples.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Feedback and Contributions
&lt;/h2&gt;

&lt;p&gt;I’d love to hear your feedback, suggestions, or feature requests!&lt;br&gt;&lt;br&gt;
Feel free to open an issue, submit a PR, or just ⭐️ the repo if you find it useful.&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>node</category>
      <category>mongodb</category>
      <category>mongoose</category>
      <category>npm</category>
    </item>
    <item>
      <title>Laravel to Go: My Journey and the Creation of a Fiber API Boilerplate</title>
      <dc:creator>Granite Bagas</dc:creator>
      <pubDate>Sat, 28 Dec 2024 11:35:29 +0000</pubDate>
      <link>https://forem.com/granitebps/laravel-to-go-my-journey-and-the-creation-of-a-fiber-api-boilerplate-2pll</link>
      <guid>https://forem.com/granitebps/laravel-to-go-my-journey-and-the-creation-of-a-fiber-api-boilerplate-2pll</guid>
      <description>&lt;p&gt;After spending more than four years immersed in Laravel, I’ve become very familiar with the MVC (Model-View-Controller) architecture. Its simplicity and structure make it a joy to work with, and Laravel’s thoughtfully organized folders help developers stay on track. You always know where to place your code, and the extensive built-in tools—database connections, Redis, queues, migrations, ORM, and more—make setup seamless. With just a few tweaks to your environment, your app is ready to go.  &lt;/p&gt;

&lt;p&gt;For me, Laravel’s MVC approach remains one of the most robust. The &lt;strong&gt;Model&lt;/strong&gt; defines your data, the &lt;strong&gt;View&lt;/strong&gt; determines what users see, and the &lt;strong&gt;Controller&lt;/strong&gt; manages your business logic. It’s simple yet structured, and Laravel delivers this setup by default, making it an excellent framework for development.  &lt;/p&gt;

&lt;p&gt;But as my career advanced and I worked across industries and businesses, I realized that Laravel’s MVC approach wasn’t always enough, especially for complex applications.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Extending Laravel’s MVC for Complexity
&lt;/h2&gt;

&lt;p&gt;MVC shines for simple applications but can fall short when logic becomes more intricate. For instance, when using Laravel for APIs, the &lt;strong&gt;View&lt;/strong&gt; layer often goes unused. Meanwhile, putting all the logic in controllers can quickly lead to bloated files that are hard to maintain.  &lt;/p&gt;

&lt;p&gt;To address this, I extended Laravel’s MVC structure by introducing &lt;strong&gt;Service&lt;/strong&gt; and &lt;strong&gt;Repository&lt;/strong&gt; layers, creating a flow like this:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controller → Service → Repository → Model&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Controller&lt;/strong&gt;: Handles validation and directs the application flow.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt;: Manages business logic, broken into reusable functions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository&lt;/strong&gt;: Manages database interactions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model&lt;/strong&gt;: Defines the data structure.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This layered approach makes the code more maintainable and scalable. Over time, I became so accustomed to this structure that it felt natural to adopt it in other projects.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Enter Go: A Whole New Challenge
&lt;/h2&gt;

&lt;p&gt;When I started working with Go (Golang), it felt like stepping into uncharted territory. Go is quite different from PHP and lacks an inherent folder structure. It’s also not an object-oriented language, so I couldn’t simply replicate what I knew from Laravel.  &lt;/p&gt;

&lt;p&gt;After some trial and error, I decided to stick with what I was familiar with: the &lt;strong&gt;CSRM&lt;/strong&gt; concept (Controller, Service, Repository, Model). I adapted this structure to Go, even though it required some creative thinking. Additionally, I explored frameworks that could simplify development. I tried &lt;strong&gt;Gin&lt;/strong&gt; and &lt;strong&gt;Fiber&lt;/strong&gt;, ultimately choosing Fiber for its speed, modern features, and active community.  &lt;/p&gt;




&lt;h2&gt;
  
  
  The Birth of My Fiber API Boilerplate
&lt;/h2&gt;

&lt;p&gt;After more than two years of working with Go and Fiber, I decided to create a boilerplate to streamline API development. This wasn’t just for me—I wanted to help others quickly set up their projects too.  &lt;/p&gt;

&lt;p&gt;The result: &lt;strong&gt;&lt;a href="https://github.com/granitebps/fiber-api" rel="noopener noreferrer"&gt;Fiber API Boilerplate&lt;/a&gt;&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;This boilerplate is specifically for APIs, so it doesn’t include features like view rendering or template engines. The folder structure takes inspiration from:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang-standards/project-layout" rel="noopener noreferrer"&gt;Golang Project Layout Standards&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gist.github.com/ayoubzulfiqar/9f1a34049332711fddd4d4b2bfd46096" rel="noopener noreferrer"&gt;Ayoub Zulfiqar’s Project Layout Gist&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also borrowed many ideas from Laravel, such as ORM, database connections, Redis, queues, and authentication. While it’s not as comprehensive as Laravel, it’s more than sufficient for building general APIs.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Features of the Boilerplate
&lt;/h2&gt;

&lt;p&gt;Here’s what the boilerplate currently offers:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt;: Simplified user management out of the box.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Reporting&lt;/strong&gt;: Integrated with Sentry.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Monitoring&lt;/strong&gt;: Uses New Relic for real-time insights.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot Reload&lt;/strong&gt;: Includes &lt;a href="https://github.com/cosmtrek/air" rel="noopener noreferrer"&gt;Air&lt;/a&gt; for faster development.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Code Checks&lt;/strong&gt;: Uses &lt;a href="https://github.com/golangci/golangci-lint" rel="noopener noreferrer"&gt;GolangCI-Lint&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Documentation&lt;/strong&gt;: Built-in Swagger support via &lt;a href="https://github.com/swaggo/swag" rel="noopener noreferrer"&gt;Swag&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Injection&lt;/strong&gt;: Powered by &lt;a href="https://github.com/google/wire" rel="noopener noreferrer"&gt;Google Wire&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Comes with Docker and Supervisor for seamless deployment.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The repository also includes example code and a detailed &lt;strong&gt;README&lt;/strong&gt; to guide you through each folder and feature.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Building for the Future
&lt;/h2&gt;

&lt;p&gt;While the boilerplate is already functional, I have plans to expand it further by adding tools like migrations, event listeners, and commands. It’s an evolving project designed to grow with its users.  &lt;/p&gt;

&lt;p&gt;You’re welcome to explore and use the boilerplate. Feel free to customize it—add tools you like or remove ones you don’t need. If you have suggestions or feature requests, create an issue or submit a pull request.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;Check out the &lt;strong&gt;&lt;a href="https://github.com/granitebps/fiber-api" rel="noopener noreferrer"&gt;Fiber API Boilerplate&lt;/a&gt;&lt;/strong&gt; and take it for a spin. I hope it helps simplify your Go API development journey as much as it has for me. Let’s build something amazing together!  &lt;/p&gt;

</description>
      <category>go</category>
      <category>laravel</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Keeping My Dev Machine Clean with Docker</title>
      <dc:creator>Granite Bagas</dc:creator>
      <pubDate>Sat, 02 Nov 2024 13:35:52 +0000</pubDate>
      <link>https://forem.com/granitebps/keeping-my-dev-machine-clean-with-docker-33fm</link>
      <guid>https://forem.com/granitebps/keeping-my-dev-machine-clean-with-docker-33fm</guid>
      <description>&lt;p&gt;If you’re a software developer, you know the deal: we’re always installing tools. Databases, message brokers, Redis—whatever the project calls for, we grab it. But here’s the thing: a lot of these tools only get used occasionally. Maybe I need RabbitMQ for a project one month, then it sits there unused until the next time I need it. Or maybe I just following a tutorial that used database that I rarely used like PostgreSQL.&lt;/p&gt;

&lt;p&gt;Now, if all of these tools are installed directly on my laptop, they start to hog resources, slowing things down even when I’m not using them. It’s annoying to have my laptop feeling sluggish just because I’ve got background services running for stuff I don’t even need every day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter Docker: My On-Demand Toolbox
&lt;/h3&gt;

&lt;p&gt;To deal with this, I started using Docker to handle the tools I don’t need constantly running. With Docker, I can spin up a tool only when I need it and shut it down when I’m done. Super easy and way more efficient!&lt;/p&gt;

&lt;p&gt;I also set up a few Docker Compose files for my go-to tools, so whenever I need, say, RabbitMQ or MongoDB, I just type &lt;code&gt;docker compose up&lt;/code&gt;, and boom—my tool’s ready. And when I’m done, I just stop the container. I can even delete the image if I want to. Clean and simple.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker Compose Files for Common Tools
&lt;/h3&gt;

&lt;p&gt;Here are the Docker Compose files I put together for a few popular tools. Just create a folder for spesific tools, like &lt;code&gt;rabbitmq&lt;/code&gt;. Then create a &lt;code&gt;docker-compose.yaml&lt;/code&gt; it that folder. Whenever you want to use it, just go to that directory, then run &lt;code&gt;docker compose up&lt;/code&gt;. If you finished, just press &lt;code&gt;Ctrl + C&lt;/code&gt; to stop the container. Feel free to use them if you’re looking to keep your dev environment streamlined!&lt;/p&gt;




&lt;h3&gt;
  
  
  1. RabbitMQ
&lt;/h3&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For GUI, use &lt;code&gt;guest:guest&lt;/code&gt; to login
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rabbitmq&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbitmq:3-management&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rabbitmq&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5672:5672&lt;/span&gt;   &lt;span class="c1"&gt;# for sender and consumer connections&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;15672:15672&lt;/span&gt; &lt;span class="c1"&gt;# for serve RabbitMQ GUI&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Dev/docker/rabbitmq/data/:/var/lib/rabbitmq&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Dev/docker/rabbitmq/log/:/var/log/rabbitmq&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rabbitmq-network&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rabbitmq-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. MongoDB
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongodb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodb&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;27017:27017&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/mongodb/data/:/data/db&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_username&lt;/span&gt;
      &lt;span class="na"&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_password&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mongodb-network&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mongodb-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. PostgreSQL
&lt;/h3&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From &lt;code&gt;pgadmin&lt;/code&gt; GUI, please use &lt;code&gt;host.docker.internal&lt;/code&gt; as host.&lt;/li&gt;
&lt;li&gt;You can remove &lt;code&gt;pgadmin&lt;/code&gt; if you want.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_password&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/postgresql/postgres/data/:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5432:5432&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres-network&lt;/span&gt;

  &lt;span class="na"&gt;pgadmin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dpage/pgadmin4&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pgadmin&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_completed_successfully&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8888:80&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;PGADMIN_DEFAULT_EMAIL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_email@gmail.com&lt;/span&gt;
      &lt;span class="na"&gt;PGADMIN_DEFAULT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_password&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/postgresql/pgadmin/data/:/var/lib/pgadmin&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres-network&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. MySQL
&lt;/h3&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can remove &lt;code&gt;phpmyadmin&lt;/code&gt; if you want.&lt;/li&gt;
&lt;li&gt;From &lt;code&gt;phpmyadmin&lt;/code&gt; GUI, please use &lt;code&gt;host.docker.internal&lt;/code&gt; as host/server
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mysql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_password&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/mysql/data/:/var/lib/mysql&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3306:3306&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mysql-network&lt;/span&gt;

  &lt;span class="na"&gt;phpmyadmin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;phpmyadmin/phpmyadmin:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;phpmyadmin&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;mysql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_completed_successfully&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_password&lt;/span&gt;
      &lt;span class="na"&gt;PMA_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
      &lt;span class="na"&gt;PMA_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3307&lt;/span&gt;
      &lt;span class="na"&gt;PMA_ARBITRARY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:80&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mysql-network&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mysql-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Redis
&lt;/h3&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From &lt;code&gt;redisinsight&lt;/code&gt; GUI, please use &lt;code&gt;host.docker.internal&lt;/code&gt; as host&lt;/li&gt;
&lt;li&gt;You can remove &lt;code&gt;redisinsight&lt;/code&gt; if you want.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/redis/redis/data/:/data&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;6379:6379&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis-network&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis-server --appendonly yes --requirepass granite97&lt;/span&gt;

  &lt;span class="na"&gt;redisinsight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis/redisinsight:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redisinsight&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_completed_successfully&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/redis/redisinsight/data/:/data&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5540:5540&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis-network&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. SonarQube
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sonarqube&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarqube:community&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarqube&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;SONAR_ES_BOOTSTRAP_CHECKS_DISABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/sonarqube/data/:/opt/sonarqube/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/sonarqube/extensions/:/opt/sonarqube/extensions&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${HOME}/Development/docker/sonarqube/logs/:/opt/sonarqube/logs&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;9000:9000&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sonarqube-network&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Create a new Docker network.&lt;/span&gt;
  &lt;span class="na"&gt;sonarqube-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;

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

&lt;/div&gt;






&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;Using Docker for these tools has made my life so much easier. Now, instead of bogging down my machine with stuff I only need once in a while, I just spin things up as needed. No more unnecessary background processes, and no more cluttered dev environment.&lt;/p&gt;

&lt;p&gt;So if your machine’s feeling the weight of too many tools, give this Docker approach a try. Hopefully, these Docker Compose files can help make your setup a little lighter and faster. Cheers!&lt;/p&gt;

&lt;h3&gt;
  
  
  Side Notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Please change the volume path to your desire. In my case, the volume of each tools will be in &lt;code&gt;/Users/granitebps/Development/docker/{tools_folder}/&lt;/code&gt;. If you want it as is, thats fine. Just make sure folder &lt;code&gt;Development/docker&lt;/code&gt; is exists in your &lt;code&gt;$HOME&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;If you want to connect to the service from other docker container, please change from &lt;code&gt;localhost&lt;/code&gt; or &lt;code&gt;127.0.0.1&lt;/code&gt; to &lt;code&gt;host.docker.internal&lt;/code&gt;. Basically, you cannot access &lt;code&gt;localhost&lt;/code&gt; of the host machine from docker container, so to tell docker container to used &lt;code&gt;localhost&lt;/code&gt; of the host machine, we changed it to &lt;code&gt;host.docker.internal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you want to use lighter version of every tools, you can append &lt;code&gt;alpine&lt;/code&gt; on the image name. But make sure the image have &lt;code&gt;alpine&lt;/code&gt; version in docker hub. Also, please note that &lt;code&gt;alpine&lt;/code&gt; version have less functionality than the normal version.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Puasa Sunnah Calendar</title>
      <dc:creator>Granite Bagas</dc:creator>
      <pubDate>Tue, 29 Oct 2024 14:34:11 +0000</pubDate>
      <link>https://forem.com/granitebps/puasa-sunnah-calendar-34d5</link>
      <guid>https://forem.com/granitebps/puasa-sunnah-calendar-34d5</guid>
      <description>&lt;h2&gt;
  
  
  Introducing the Puasa Sunnah Calendar: Your Go-To Guide for Sunnah Fasting Dates
&lt;/h2&gt;

&lt;p&gt;I'm excited to share a project I've been working on: the &lt;strong&gt;Puasa Sunnah Calendar&lt;/strong&gt;! Whether you're looking to keep track of Sunnah fasting days or plan ahead, this site makes it easy to stay organized with an updated fasting schedule throughout the year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Puasa Sunnah Calendar?
&lt;/h2&gt;

&lt;p&gt;Sunnah fasting, which includes significant days like Mondays, Thursdays, and the Ayyamul Bidh (White Days), offers a chance to observe additional acts of worship beyond Ramadan. However, keeping track of these dates manually can be challenging, especially as they change year to year. The Puasa Sunnah Calendar helps solve this problem by providing an intuitive, visual calendar that makes it easy to see all Sunnah fasting days at a glance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features of the Puasa Sunnah Calendar
&lt;/h2&gt;

&lt;p&gt;Here's what you can expect from the Puasa Sunnah Calendar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complete Sunnah Fasting Schedule&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The calendar includes all key Sunnah fasting days for each month, so you can easily find and prepare for the upcoming dates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easy-to-Use Interface&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The calendar layout is designed for simplicity, making it quick to check which days to mark in your schedule.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Always Up-to-Date&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
As the dates change each year, we’ve ensured that the calendar remains accurate and automatically updated, so you never miss out on important fasting days.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to Use It
&lt;/h2&gt;

&lt;p&gt;Using the Puasa Sunnah Calendar is simple! Just head to &lt;a href="https://puasa-sunnah.granitebps.com" rel="noopener noreferrer"&gt;puasa-sunnah.granitebps.com&lt;/a&gt; and take a look at the calendar view. You can see each fasting day laid out, making it easy to plan around your schedule. This tool is ideal for anyone aiming to deepen their religious practices or simply stay informed about Sunnah fasting days without the hassle of manual tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join the Community
&lt;/h2&gt;

&lt;p&gt;I’d love to get feedback from you! The Puasa Sunnah Calendar is built with the community in mind, so if you have any suggestions for improvements or features, don’t hesitate to reach out. Whether you’re new to observing Sunnah fasting or have been fasting for years, this tool is here to support your journey.&lt;/p&gt;




&lt;p&gt;Check out the &lt;strong&gt;Puasa Sunnah Calendar&lt;/strong&gt; here: &lt;a href="https://puasa-sunnah.granitebps.com" rel="noopener noreferrer"&gt;puasa-sunnah.granitebps.com&lt;/a&gt;. I hope it helps make Sunnah fasting more accessible and easier to plan for everyone!&lt;/p&gt;

&lt;p&gt;Let me know what you think in the comments or by reaching out directly. Your feedback is invaluable in making this tool the best it can be!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My Terminal Setup as Full Stack Developer</title>
      <dc:creator>Granite Bagas</dc:creator>
      <pubDate>Mon, 10 Apr 2023 15:48:45 +0000</pubDate>
      <link>https://forem.com/granitebps/my-terminal-setup-as-full-stack-developer-1k7o</link>
      <guid>https://forem.com/granitebps/my-terminal-setup-as-full-stack-developer-1k7o</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AwQ2Fl9wNgMI-zUOYgb-_Pg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AwQ2Fl9wNgMI-zUOYgb-_Pg.png" alt="Warp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a Full Stack Developer, a terminal is essential for daily work. It provides a faster and more efficient way to execute various tasks, especially when dealing with servers and command-line tools. Sometimes it is much easier to use a terminal than a GUI. Some actions also need to perform in the terminal than the GUI provided by the app. While the default terminal on macOS is sufficient, it lacks some features and customization options that can improve my workflow.&lt;/p&gt;

&lt;p&gt;Therefore, having a well-configured terminal setup is crucial for productivity and efficiency. In this blog post, I’ll take you through my terminal setup, highlighting the tools and configurations that make my workflow smoother and more enjoyable. Whether you’re a seasoned developer or just starting, you’re sure to pick up some tips and tricks to level up your terminal game. So, let’s dive in and see how you can make your terminal work even better for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Terminal
&lt;/h2&gt;

&lt;p&gt;For a long time, I used Iterm2 when coding using Macbook. I like it compared to the MacOS terminal. Iterm2 offers an extensive range of customization options, from color schemes to keyboard shortcuts. This flexibility allows me to tailor the terminal emulator to my specific needs and preferences, further enhancing my productivity. Recently, I tried using Warp and my first impression was, “Wow, this is intriguing!” One thing that caught my attention was how the output of the commands I entered appeared from the bottom and moved upwards. Not to mention, Warp has built-in features for history and autocomplete that are even better than those in Iterm2. What’s more, Warp boasts an AI assistant that can help me when I forget a certain command. I must say, using Warp has truly elevated my command-line experience.&lt;/p&gt;

&lt;p&gt;In this blog post, I’ll be sharing with you how I set up my terminal, whether it’s using Iterm2 or Warp. Plus, I’ll be throwing in a few tricks on how to use them both simultaneously without any hiccups. So if you’re ready to take your command-line game to the next level, keep reading!&lt;/p&gt;

&lt;h2&gt;
  
  
  Iterm2
&lt;/h2&gt;

&lt;p&gt;Firstly, let’s install Iterm2 using this command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

brew install --cask iterm2


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

&lt;/div&gt;

&lt;p&gt;or you can simply visit the Iterm2 website at &lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;Iterm2&lt;/a&gt;. Once installed, open Iterm2 and let’s start tinkering with your terminal! However, for me, I didn’t need to make many changes to the default Iterm2 settings. There are numerous features that you can explore to make your terminal experience even better.&lt;/p&gt;

&lt;p&gt;After installing Iterm2, I recommend going further and installing Oh My Zsh to enhance your terminal’s functionality. With Oh My Zsh, you can easily manage your plugins, themes, and shortcuts, making your terminal experience more personalized and efficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oh My Zsh
&lt;/h2&gt;

&lt;p&gt;Oh My Zsh is an open-source framework that enhances the functionality of the ZSH shell. It offers hundreds of plugins that can help streamline workflow and save time, making developers more efficient and productive. Oh, My Zsh also provides an easy way to manage shell configuration and customize themes, aliases, and environment variables. In summary, Oh My Zsh is a great tool that can take your terminal experience to the next level.&lt;/p&gt;

&lt;p&gt;To install it go to &lt;a href="https://ohmyz.sh" rel="noopener noreferrer"&gt;Oh My Zsh&lt;/a&gt; website and run this command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"


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

&lt;/div&gt;

&lt;p&gt;It will create a &lt;code&gt;.zshrc&lt;/code&gt; file. After that, I will install Powerlevel10k. Powerlevel10k is a Zsh theme to customize my terminal. First I will install zsh-completions and zsh-syntax-highlighting using this command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

brew install zsh-completions zsh-syntax-highlighting


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

&lt;/div&gt;

&lt;p&gt;After that run this command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k 


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

&lt;/div&gt;

&lt;p&gt;to install Oh My Zsh. To configure Oh My Zsh theme, update your &lt;code&gt;.zshrc&lt;/code&gt; file to this &lt;code&gt;ZSH_THEME="powerlevel10k/powerlevel10k”&lt;/code&gt;. Run &lt;code&gt;source ~/.zshrc&lt;/code&gt; and run &lt;code&gt;p10k configure&lt;/code&gt;. It will ask you a couple of questions to customize your Oh My Zsh. Select the configuration according to your wishes. After that, edit &lt;code&gt;.zshrc&lt;/code&gt; file again and change this line &lt;code&gt;plugins=(git zsh-autosuggestions zsh-syntax-highlighting)&lt;/code&gt; to enable all the plugins that have already been installed before. Run source &lt;code&gt;~/.zshrc&lt;/code&gt; again to implement the changes immediately.&lt;/p&gt;

&lt;p&gt;You can also enable Shell Integration to open more features. You can read about Iterm2 Shell Integration in here &lt;a href="https://iterm2.com/documentation-shell-integration.html" rel="noopener noreferrer"&gt;https://iterm2.com/documentation-shell-integration.html&lt;/a&gt;. To enable it, go to the Iterm2 menu, and click Install Shell Integration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ASvnBp0aYFJG8BBHhhCYrkA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ASvnBp0aYFJG8BBHhhCYrkA.png" alt="Iterm2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Side note, by default powerlevel10k, will truncate your local branch name if longer than 32 characters. To disable it and show the full local branch name, open &lt;code&gt;~/.p10k.zsh&lt;/code&gt; go to line 400 and comment this line&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3096%2F1%2AaglFxmz1j6mVPDUy5aww0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3096%2F1%2AaglFxmz1j6mVPDUy5aww0w.png" alt="powerlevel10k"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end, my Iterm2 is just like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5708%2F1%2AwyfSG9dHrcwiXMac0Ic3Hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5708%2F1%2AwyfSG9dHrcwiXMac0Ic3Hg.png" alt="iterm2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can reconfigure your powerlevel10k by running &lt;code&gt;p10k configure&lt;/code&gt; again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Warp
&lt;/h2&gt;

&lt;p&gt;For installing Warp, you can go to the Warp website &lt;a href="https://app.warp.dev/referral/2VQEE9" rel="noopener noreferrer"&gt;Warp&lt;/a&gt; or run this command to install it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

brew install --cask warp


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

&lt;/div&gt;

&lt;p&gt;And you’re done! Yes, that’s simple. That’s why I like Warp. Warp already shipped with powerful suggestions and history features, so you don’t need any additional plugins. For you that already installed Iterm2 and don’t want to uninstall Iterm2, these are some additional steps you need to do and it’s already mentioned in Warp docs.&lt;/p&gt;

&lt;p&gt;In your .zshrc file, edit this line to disable Iterm2 Shell Integration. Docs for this step are here &lt;a href="https://docs.warp.dev/features/prompt#iterm2" rel="noopener noreferrer"&gt;https://docs.warp.dev/features/prompt#iterm2&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    if [[ $TERM_PROGRAM != "WarpTerminal" ]]; then
    ##### WHAT YOU WANT TO DISABLE FOR WARP - BELOW

    test -e "${HOME}/.iterm2_shell_integration.zsh" &amp;amp;&amp;amp; source "${HOME}/.iterm2_shell_integration.zsh"

    ##### WHAT YOU WANT TO DISABLE FOR WARP - ABOVE
    fi


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

&lt;/div&gt;

&lt;p&gt;To disable powerlevel10k, edit this line in your .zshrc file. Docs for this step are here &lt;a href="https://docs.warp.dev/features/prompt#disabling-unsupported-prompts-for-warp-e.g.-powerlevel10k-p10k" rel="noopener noreferrer"&gt;https://docs.warp.dev/features/prompt#disabling-unsupported-prompts-for-warp-e.g.-powerlevel10k-p10k&lt;/a&gt;.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
# Initialization code that may require console input (password prompts, [y/n]
# confirmations, etc.) must go above this block; everything else may go below.
if [[ $TERM_PROGRAM != "WarpTerminal" ]]; then
    if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
      source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
    fi
fi
&lt;/code&gt;&lt;/pre&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;In conclusion, setting up your terminal as a full-stack developer is essential to enhance productivity, efficiency, and enjoyment of development. Customization and efficiency are key in choosing the right tools and configuring them to fit your workflow. You can try Iterm2, Warp, or any other terminal to find your best terminal configuration. I hope this post has given you some ideas for how to improve your terminal setup. So, start exploring and find the setup that works best for you!&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>My Installed App as Developer</title>
      <dc:creator>Granite Bagas</dc:creator>
      <pubDate>Sat, 01 Apr 2023 22:00:46 +0000</pubDate>
      <link>https://forem.com/granitebps/my-installed-app-as-developer-440g</link>
      <guid>https://forem.com/granitebps/my-installed-app-as-developer-440g</guid>
      <description>&lt;p&gt;Hi, my name is Granit and I’m a Full Stack Developer. As a full-stack developer, I sometimes build an API, a website, and a mobile application at work and for my project. For that, I used many applications to help me build those things. And by the way, I’m using Macbook Air M1 2020 with 8GB RAM and 256GB storage.&lt;/p&gt;

&lt;p&gt;In this article, I will list some of the installed apps on my MacBook. Some of these apps will be only available on mac OS, but I will also provide alternatives for any Windows and Linux user out there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Brave
&lt;/h2&gt;

&lt;p&gt;For my browser of choice, I used &lt;a href="https://brave.com" rel="noopener noreferrer"&gt;Brave&lt;/a&gt;. I choose Brave because it is based on Chromium and has a security feature that I want, also I already used Brave in the past. I installed some extensions and I will write another post talking about my browser extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AlyJh_k0MfH6ujsobKM2Ajw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AlyJh_k0MfH6ujsobKM2Ajw.png" alt="Brave"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to the Brave website or use this command brew install — cask brave-browser to install Brave. For alternatives browser, I recommended &lt;a href="https://vivaldi.com" rel="noopener noreferrer"&gt;Vivaldi&lt;/a&gt;, &lt;a href="https://www.mozilla.org/en-US/firefox/new" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt;, and &lt;a href="https://www.google.com/chrome/" rel="noopener noreferrer"&gt;Chrome&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notion
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://affiliate.notion.so/cakzfw7mz6tq" rel="noopener noreferrer"&gt;Notion&lt;/a&gt; for dumping some notes, ideas, to-do lists, and pretty much everything that I need to write down. I save some important stuff, project idea, note-taking app, and much more. Notion has so many features that I can utilize and the best part is it free.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AdZfvJjQasVRI6K09CbEIJw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AdZfvJjQasVRI6K09CbEIJw.png" alt="Notion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to Notion website or use this command brew install — cask notion to install it. My alternative for Notion is &lt;a href="https://evernote.com/" rel="noopener noreferrer"&gt;Evernote&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bitwarden
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://bitwarden.com/" rel="noopener noreferrer"&gt;Bitwarden&lt;/a&gt; is a password manager that I used for quite some time. The biggest advantage is open source and free. Another advantage of Bitwarden is you get unlimited devices. That feature is the most I wanted.&lt;/p&gt;

&lt;p&gt;You can go to the Bitwarden website or use this command brew install — cask bitwarden to install it. For alternatives, I recommended &lt;a href="https://www.lastpass.com/" rel="noopener noreferrer"&gt;LastPass&lt;/a&gt;, &lt;a href="https://1password.com/" rel="noopener noreferrer"&gt;1Password&lt;/a&gt;, and &lt;a href="https://www.dashlane.com/" rel="noopener noreferrer"&gt;Dashlane&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  AppCleaner
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://freemacsoft.net/appcleaner/" rel="noopener noreferrer"&gt;AppCleaner&lt;/a&gt; is an app that I used for uninstalling my app. You can just drag the app to AppCleaner then AppCleaner will detect any junk file from that app. When we uninstall the app, all the junk files will also be deleted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AnnK6nQebW3o9dkXRLbk44Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AnnK6nQebW3o9dkXRLbk44Q.png" alt="AppCleaner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to the AppCleaner website to install it. For alternatives, I will be recommending &lt;a href="https://cleanmymac.com/" rel="noopener noreferrer"&gt;CleanMyMac&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Warp
&lt;/h2&gt;

&lt;p&gt;For the terminal, I’m using &lt;a href="https://app.warp.dev/referral/2VQEE9" rel="noopener noreferrer"&gt;Warp&lt;/a&gt;. The unique feature from Warp is every time you run a command, the output will be shown from the bottom and will continue to the top. The autocomplete and history are also very well-built.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5752%2F1%2ADEM-PPJ2k5CCQgYcJgR-NA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5752%2F1%2ADEM-PPJ2k5CCQgYcJgR-NA.png" alt="Warp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to the Warp website or run a command brew install — cask warp to install it. My terminal alternative besides Warp is &lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;Iterm2&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raycast
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.raycast.com/" rel="noopener noreferrer"&gt;Raycast&lt;/a&gt; is my app of choice for replacing Spotlight which is free. Raycast has a store so you can install plugins for your Raycast to boost your productivity. Raycast also already shipped with a lot of helpful features and automation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3024%2F1%2AfL_aPL4mav_-tEckE2D_jQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3024%2F1%2AfL_aPL4mav_-tEckE2D_jQ.png" alt="Raycast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to the Raycast website or run this command brew install raycast to install it. For alternatives, you can stick to Spotlight or install &lt;a href="https://www.alfredapp.com/" rel="noopener noreferrer"&gt;Alfred&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;For text editor or IDE of my choice is &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt;. VS Code has a lot of features and support for so many programming languages. I installed some extensions and I will write another post to show you the extensions that I used.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2A6XtSTYetKEGwQBadlAXDJw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2A6XtSTYetKEGwQBadlAXDJw.png" alt="VS Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to VS Code website or use this command brew install — cask visual-studio-code to install it. For alternatives, I will recommend &lt;a href="https://www.sublimetext.com/" rel="noopener noreferrer"&gt;Sublime Text&lt;/a&gt; and IDE from &lt;a href="https://www.jetbrains.com/" rel="noopener noreferrer"&gt;JetBrains&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rectangle
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://rectangleapp.com/" rel="noopener noreferrer"&gt;Rectangle&lt;/a&gt; is an app that can move and resize apps just like a Windows laptop. You can snap windows to the top left, top right, bottom left, bottom right, and many more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3100%2F1%2AbhSkz4exwB2N8kioLJmCqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3100%2F1%2AbhSkz4exwB2N8kioLJmCqw.png" alt="Rectangle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to Rectangle website or use this command brew install — cask rectangle to install it. I don’t think many alternatives to Rectangle are free, but you can try &lt;a href="https://magnet.crowdcafe.com/" rel="noopener noreferrer"&gt;Magnet&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://getkap.co/" rel="noopener noreferrer"&gt;Kap&lt;/a&gt; is an app to record your screen. I use Kap primarily in my work to record some flow of a website. Kap produces small video sizes with good quality compared to other screen recording apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aly8P_L0yz6OAzvCmhiv2mw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aly8P_L0yz6OAzvCmhiv2mw.png" alt="Kap"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You go to the Kap website or use this command brew install — cask kap to install it. For alternatives, I will recommend &lt;a href="https://monosnap.com/" rel="noopener noreferrer"&gt;Monosnap&lt;/a&gt; or &lt;a href="https://www.bandicam.com/" rel="noopener noreferrer"&gt;Bandicam&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequel Ace
&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://sequel-ace.com/" rel="noopener noreferrer"&gt;Sequel Ace&lt;/a&gt; for MySQL database management. It’s free and it gets the job done when I’m working with MySQL. If you used Sequel Pro, you will be familiar with Sequel Ace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2Abb5GxgYaZqJ5mJiHcTaNGQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2Abb5GxgYaZqJ5mJiHcTaNGQ.png" alt="Sequel Ace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to the Sequel Ace website or use this command brew install — cask sequel-ace to install it. Another app that you can use is &lt;a href="https://tableplus.com/" rel="noopener noreferrer"&gt;Table Plus&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Another Redis Desktop Manager
&lt;/h2&gt;

&lt;p&gt;For Redis management, I used &lt;a href="https://goanother.com/" rel="noopener noreferrer"&gt;Another Redis Desktop Manager&lt;/a&gt; for the GUI. It makes it easier to manage my Redis, like showing, updating, and deleting Redis data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4400%2F1%2ASS6lUqoTeiLZ6BGMFlJoPQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4400%2F1%2ASS6lUqoTeiLZ6BGMFlJoPQ.png" alt="Another Redis Desktop Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to Another Redis Desktop Manager website or use this command brew install — cask another-redis-desktop-manager to install it. For alternatives, I recommended &lt;a href="https://getmedis.com/" rel="noopener noreferrer"&gt;Medis&lt;/a&gt; and &lt;a href="https://redis.com/redis-enterprise/redis-insight/" rel="noopener noreferrer"&gt;RedisInsight&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Postman
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; for testing my API. I come with a lot of features, like standard HTTP requests, Websocket, event gRPC, mocking server, and many more. Postman collection has also already been a standard for developers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AfmnzrAUnq1pwUoJtpDHAAA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AfmnzrAUnq1pwUoJtpDHAAA.png" alt="Postman"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to Postman website or use this command brew install — cask postman to install it. Alternatives besides Postman are &lt;a href="https://insomnia.rest/" rel="noopener noreferrer"&gt;Insomnia&lt;/a&gt; and &lt;a href="https://firecamp.io/" rel="noopener noreferrer"&gt;Firecamp&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Itsycal
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.mowglii.com/itsycal/" rel="noopener noreferrer"&gt;Itsycal&lt;/a&gt; is a menu bar calendar that I used to check schedules. Primarily I used it in my work to check meeting schedules. It’s minimalist and serves me well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AgPI_aLY3140GFhr5pZQlUA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AgPI_aLY3140GFhr5pZQlUA.png" alt="Itsycal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to Itsycal website or use this command brew install — cask itsycal to install it. I don’t have any alternatives for Itsycal, but you can search that works for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; is an app that I used to containerize my app. So basically I can run my app or website with a specific environment that I defined. I also can run some apps like Redis Server or MySQL server without installing them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AD74l8r5cH3FZp_TxE_9gug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AD74l8r5cH3FZp_TxE_9gug.png" alt="Docker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to Docker website or use this command brew install — cask docker to install it. I used Docker for a long time, but you can try &lt;a href="https://podman.io/" rel="noopener noreferrer"&gt;Podman&lt;/a&gt; if you want alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenVPN
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://openvpn.net/" rel="noopener noreferrer"&gt;OpenVPN&lt;/a&gt; is a VPN client that I used primarily for work. We used VPN to connect to the dev server and we are using VPN. I also sometimes used that to open websites that got blocked in Indonesia like Reddit.&lt;/p&gt;

&lt;p&gt;You can go to OpenVPN website or use this command brew install — cask openvpn-connect to install it. For alternatives, I recommended &lt;a href="https://nordvpn.com/" rel="noopener noreferrer"&gt;NordVPN&lt;/a&gt;, &lt;a href="https://www.privateinternetaccess.com/" rel="noopener noreferrer"&gt;Private Internet Access&lt;/a&gt;, and &lt;a href="https://protonvpn.com/" rel="noopener noreferrer"&gt;Proton VPN&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  WPS Office
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.wps.com/" rel="noopener noreferrer"&gt;WPS Office&lt;/a&gt; is an app that I used to work on docs, spreadsheets, PowerPoints, and PDFs. It’s an alternative to Microsoft Office for my Mac. It’s free for the most part and got the job done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2A_sb750kf3Rl0yG51QXekRQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2A_sb750kf3Rl0yG51QXekRQ.png" alt="WPS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to the WPS Office website or use this command brew install — cask wpsoffice to install it. For alternatives, you can use &lt;a href="https://www.office.com/" rel="noopener noreferrer"&gt;Microsoft Office&lt;/a&gt; or &lt;a href="https://www.libreoffice.org/" rel="noopener noreferrer"&gt;LibreOffice&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Studio
&lt;/h2&gt;

&lt;p&gt;As Full Stack Developer, sometimes I also develop a mobile app using &lt;a href="https://developer.android.com/studio" rel="noopener noreferrer"&gt;Android Studio&lt;/a&gt;. But I used Android Studio primarily for the Android emulator. For the programming language I used React Native, so I used VS Code for the text editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F1%2ACqsK6jVe_X_mMVRtmUq_UQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3200%2F1%2ACqsK6jVe_X_mMVRtmUq_UQ.png" alt="Android Studio"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to the Android Studio website or use this command brew install — cask android-studio to install it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dropzone
&lt;/h2&gt;

&lt;p&gt;Another app that I installed is &lt;a href="https://aptonic.com/" rel="noopener noreferrer"&gt;Dropzone&lt;/a&gt;. I used Dropzone to easily copy and move files. It’s free and easy to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AnxFu99RRTEZWvPZOAo63qA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AnxFu99RRTEZWvPZOAo63qA.png" alt="Dropzone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to the Dropzone website or use this command brew install — cask dropzone to install it.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Desktop
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://desktop.github.com/" rel="noopener noreferrer"&gt;GitHub Desktop&lt;/a&gt; for managing my local repository easily. I still use the terminal to do some Git action, but in some cases, it’s easier to use GitHub Desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2ATS_pjYjyw2FjFMlkPpoLXQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2ATS_pjYjyw2FjFMlkPpoLXQ.png" alt="GitHub Desktop"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to GitHub Desktop website or use this command brew install — cask github to install it. For alternatives, you can use &lt;a href="https://www.sourcetreeapp.com/" rel="noopener noreferrer"&gt;Sourcetree&lt;/a&gt; or &lt;a href="https://www.gitkraken.com/" rel="noopener noreferrer"&gt;GitKraken&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  MongoDB Compass
&lt;/h2&gt;

&lt;p&gt;I also work with MongoDB, so I used &lt;a href="https://www.mongodb.com/products/compass" rel="noopener noreferrer"&gt;MongoDB Compass&lt;/a&gt; for the GUI. It makes me easy to do some queries for MongoDB. It’s free to download and easy to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AL7m-G1H5T9cG2Sj3kSH98Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F5760%2F1%2AL7m-G1H5T9cG2Sj3kSH98Q.png" alt="MongoDB Compass"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can go to MongoDB Compass website or use this command brew install — cask mongodb-compass to install it. For alternatives, you can use &lt;a href="https://studio3t.com/" rel="noopener noreferrer"&gt;Studio 3T&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope that the apps that I used can give you some inspiration for using them and help you save time and increase your efficiency. If you have any questions about any of these apps and services, feel free to contact me.&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
