<?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: Sudhanshu</title>
    <description>The latest articles on Forem by Sudhanshu (@sudokoi).</description>
    <link>https://forem.com/sudokoi</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%2F411371%2F1b21b4af-ce12-4e06-9ca6-c183ca7017c8.jpg</url>
      <title>Forem: Sudhanshu</title>
      <link>https://forem.com/sudokoi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sudokoi"/>
    <language>en</language>
    <item>
      <title>Expense Buddy: Local-first expense tracking with GitHub sync</title>
      <dc:creator>Sudhanshu</dc:creator>
      <pubDate>Sun, 18 Jan 2026 03:37:22 +0000</pubDate>
      <link>https://forem.com/sudokoi/expense-buddy-local-first-expense-tracking-with-github-sync-3iga</link>
      <guid>https://forem.com/sudokoi/expense-buddy-local-first-expense-tracking-with-github-sync-3iga</guid>
      <description>&lt;p&gt;I’ve tried a bunch of expense trackers over the years, and I kept running into the same problems: slow flows, cluttered screens, and a nagging feeling that I was handing over more data than I should. So I built my own.&lt;/p&gt;

&lt;p&gt;Expense Buddy is a privacy‑first, local‑first expense tracker that stays out of your way. It’s built with React Native (Expo), keeps everything on‑device by default, and gives you optional GitHub sync if you want a personal backup you control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Expense Buddy exists
&lt;/h2&gt;

&lt;p&gt;Most expense trackers either felt slow, intrusive, or vague about where my data lived. I wanted something simple enough to open daily, fast enough to never frustrate me, and honest about storage. Expense Buddy is the result—focused on clarity, speed, and ownership:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local-first&lt;/strong&gt; by default (your data stays on-device)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private&lt;/strong&gt; by design (no analytics, ads, or data selling)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt; on large datasets with a lightweight UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In your control&lt;/strong&gt; with optional GitHub sync to your own repo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feature highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily expense tracking&lt;/strong&gt; with category and payment method tags&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edit expenses&lt;/strong&gt; anytime with a full &lt;strong&gt;history view&lt;/strong&gt; to revisit and update past entries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart GitHub sync&lt;/strong&gt; with incremental, differential, and batched commits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics that go deeper&lt;/strong&gt;: category and payment method breakdowns, instrument‑level splits, plus a spending trend chart&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom categories&lt;/strong&gt; with colors and icons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saved payment instruments&lt;/strong&gt; (cards and UPI IDs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In‑app update notes&lt;/strong&gt; with a “What’s New” sheet after updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Issue reporting&lt;/strong&gt; directly from Settings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Light and dark mode&lt;/strong&gt; with theme‑aware styling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dashboard
&lt;/h2&gt;

&lt;p&gt;The dashboard is my “daily check‑in” screen. It gives me a quick view of recent spending and a simple 7‑day trend. I made the graph tappable because I kept wanting to jump straight into that day’s entries.&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%2Fs8y50ujmcqdrjhu1puaw.jpeg" 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%2Fs8y50ujmcqdrjhu1puaw.jpeg" alt="Dashboard" width="784" height="1600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add expense
&lt;/h2&gt;

&lt;p&gt;Adding an expense should be boring—in a good way. It’s a one‑screen flow with quick category and payment method picks so I can log something in a few seconds and move on.&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%2Fb4b4eruilph2tjsuhubt.jpeg" 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%2Fb4b4eruilph2tjsuhubt.jpeg" alt="Add new expense" width="784" height="1600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Analytics you can trust
&lt;/h2&gt;

&lt;p&gt;I wanted answers, not charts for the sake of charts. The analytics tab helps me see where money goes by &lt;strong&gt;category&lt;/strong&gt;, &lt;strong&gt;payment method&lt;/strong&gt;, and &lt;strong&gt;saved instrument&lt;/strong&gt;, then zoom out with a &lt;strong&gt;spending trend&lt;/strong&gt; view. I also added multiple &lt;strong&gt;time windows&lt;/strong&gt; so I can compare “this week” vs. “the last 3 months” without leaving the screen.&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%2Fbre361r0on8nmq1wjybk.jpeg" 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%2Fbre361r0on8nmq1wjybk.jpeg" alt="Analytics-1" width="784" height="1600"&gt;&lt;/a&gt;&lt;br&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%2Fp1f1tcxlapbvus79zerq.jpeg" 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%2Fp1f1tcxlapbvus79zerq.jpeg" alt="Analytics-2" width="784" height="1600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  History and edits
&lt;/h2&gt;

&lt;p&gt;I mess up entries all the time. The history view lets me browse past entries, open any expense, and fix it in place—no weird edit mode, no hunting.&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%2Fkhu13so61ivzle5104tw.jpeg" 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%2Fkhu13so61ivzle5104tw.jpeg" alt="History" width="784" height="1600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Settings that stay out of your way
&lt;/h2&gt;

&lt;p&gt;Settings are intentionally boring. You can set a &lt;strong&gt;default payment method&lt;/strong&gt;, add &lt;strong&gt;custom categories&lt;/strong&gt; (the app ships with 8 defaults you can edit), manage &lt;strong&gt;saved payment instruments&lt;/strong&gt; for deeper analytics, and enable &lt;strong&gt;GitHub sync&lt;/strong&gt; to keep everything in sync across devices. Auto‑sync can run &lt;strong&gt;on change&lt;/strong&gt; or &lt;strong&gt;on app launch&lt;/strong&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%2Fuaabz0qp9yu29xy08pew.jpeg" 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%2Fuaabz0qp9yu29xy08pew.jpeg" alt="Settings-1" width="784" height="1600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi71tqiewop3lkn2tqfq3.jpeg" 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%2Fi71tqiewop3lkn2tqfq3.jpeg" alt="Settings-2" width="784" height="1600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How GitHub sync works (optional)
&lt;/h2&gt;

&lt;p&gt;I designed GitHub sync to be safe, predictable, and fully optional. Your data stays local unless you explicitly turn this on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily CSV files&lt;/strong&gt;: expenses are stored as &lt;code&gt;expenses-YYYY-MM-DD.csv&lt;/code&gt; in your repo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merge‑first workflow&lt;/strong&gt;: fetch → merge → push, to avoid accidental data loss&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflict handling&lt;/strong&gt;: timestamp‑based resolution, with true conflict prompts only when needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Differential uploads&lt;/strong&gt;: only changed files are uploaded, and changes are &lt;strong&gt;batched into a single commit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settings sync&lt;/strong&gt; (optional): categories and saved instruments can be synced via &lt;code&gt;settings.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Built for speed
&lt;/h2&gt;

&lt;p&gt;I’m allergic to janky lists, so performance was a first‑class goal. Virtualized lists, memoized components, and a lightweight state layer keep things snappy even with long histories. The UI stays minimal so logging an expense takes seconds, not minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No required external accounts to use the app&lt;/li&gt;
&lt;li&gt;GitHub sync is &lt;strong&gt;opt‑in&lt;/strong&gt; and stores files in your own repository (daily CSVs)&lt;/li&gt;
&lt;li&gt;No selling of data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to dig deeper, here are the relevant links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/sudokoi/expense-buddy" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sudokoi/expense-buddy/blob/main/CHANGELOG.md" rel="noopener noreferrer"&gt;Changelog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sudokoi/expense-buddy/blob/main/PRIVACY.md" rel="noopener noreferrer"&gt;Privacy policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sudokoi/expense-buddy/releases/latest" rel="noopener noreferrer"&gt;Latest release&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get involved
&lt;/h2&gt;

&lt;p&gt;Expense Buddy is available on Google Play Store. Give it a try and let me know what you think!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.sudokoi.expensebuddy" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fplay.google.com%2Fintl%2Fen_us%2Fbadges%2Fstatic%2Fimages%2Fbadges%2Fen_badge_web_generic.png" alt="Get it on Google Play" width="646" height="250"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;Originally posted on my &lt;a href="https://sudh.online/blogs" rel="noopener noreferrer"&gt;blog&lt;/a&gt;:&lt;a href="https://sudh.online/blog/expense-buddy" rel="noopener noreferrer"&gt;https://sudh.online/blog/expense-buddy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Expense buddy is open-sourced&lt;/li&gt;
&lt;li&gt;Feel free to reach me out on my socials/email&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>expensetracker</category>
      <category>privacy</category>
      <category>reactnative</category>
      <category>mobile</category>
    </item>
    <item>
      <title>The beginner's guide to Open Source contribution</title>
      <dc:creator>Sudhanshu</dc:creator>
      <pubDate>Sun, 14 Mar 2021 09:10:28 +0000</pubDate>
      <link>https://forem.com/sudokoi/the-beginner-s-guide-to-open-source-contribution-3nke</link>
      <guid>https://forem.com/sudokoi/the-beginner-s-guide-to-open-source-contribution-3nke</guid>
      <description>&lt;p&gt;While in college, I had heard about this amazing month long celebration for open-source called &lt;a href="https://hacktoberfest.digitalocean.com/" rel="noopener noreferrer"&gt;hacktoberfest&lt;/a&gt; where if you make a certain number of contributions to any open-source repository(ies) and your changes are accepted (via pull-requests), you could get swags like T-shirts, stickers and other things. This was interesting for me as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it gave a T-shirt, and I don't know about you but in college days, that was something I could flex in front of others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Years later, being a developer by profession, I wanted to contribute to Open-source but didn't know how. This is a story of how I have started contributing to open-source projects.&lt;/p&gt;

&lt;p&gt;If you, irrespective of being a student, a professional or just someone who wants to contribute to open-source, find it difficult and do not know where/how to start, continue reading.&lt;/p&gt;




&lt;h2&gt;
  
  
  Background knowledge
&lt;/h2&gt;

&lt;p&gt;I suppose you are familiar with some of the terms that are being used in this post, i.e.:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repository&lt;/li&gt;
&lt;li&gt;open-source&lt;/li&gt;
&lt;li&gt;issues&lt;/li&gt;
&lt;li&gt;pull-request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and know how to use git and github.&lt;br&gt;
If not, I have linked some resources at the end which may be helpful.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to contribute
&lt;/h2&gt;

&lt;p&gt;If you are a new contributor, there are a few things you should look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository accepting contributions usually have &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; or something similar which provides the guide and template of how you can add your contributions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Issues&lt;/code&gt; which are comparatively easy have the label of &lt;code&gt;good first issue&lt;/code&gt; on them&lt;/li&gt;
&lt;li&gt;You can choose from the list of issues and if you have the solution for them, &lt;a href="https://makeapullrequest.com/" rel="noopener noreferrer"&gt;make a pull request&lt;/a&gt; for one issue at a time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Barrier:
&lt;/h2&gt;

&lt;p&gt;The problem generally faced when it comes to making a contribution are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to find a repository to contribute to&lt;/li&gt;
&lt;li&gt;not feeling confident enough to contribute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;People often can't find a repository which are accepting contributions or there are too many people wanting to contribute to a repository that they, as a beginner, feel lost and not confident enough to contribute. Popular libraries like &lt;a href="https://github.com/facebook/react" rel="noopener noreferrer"&gt;react&lt;/a&gt;, &lt;a href="https://github.com/mui-org/material-ui" rel="noopener noreferrer"&gt;material-ui&lt;/a&gt; have a lot of contributors.&lt;/p&gt;

&lt;p&gt;Another aspect is that many good open source repos are matured and their codebase is too big...that it is kind of overwhelming for beginners when they don't have a proper plan to navigate through the codebase and know what must exactly be done to accomplish the task they have in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  The way:
&lt;/h2&gt;

&lt;p&gt;I have been part of &lt;a href="https://github.com/OpenSourceRaidGuild" rel="noopener noreferrer"&gt;Open Source Raid Guild&lt;/a&gt; and you can look at the &lt;a href="https://github.com/OpenSourceRaidGuild/tutorial-quest" rel="noopener noreferrer"&gt;tutorial-quest&lt;/a&gt; to know what they do and how they do it, but here's the TL;DR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OSRG is the effort to gamify the open-source world and help lower the barrier for the would-be contributors&lt;/li&gt;
&lt;li&gt;You aren't alone: following the concept of &lt;code&gt;"raiding"&lt;/code&gt;, a &lt;code&gt;guild&lt;/code&gt; of people will always be with you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This solves the above two barriers. You don't have to personally look for a repository and you can always seek help from the &lt;code&gt;guild&lt;/code&gt; whenever you get stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  My experience:
&lt;/h2&gt;

&lt;p&gt;Here's what I have gained while being a part of OSRG:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code-reviews: You have a bunch of people from different time-zones with varying expertise available to review your code, which surely you can't find anywhere else.
Code-reviews help you grow along with the community.&lt;/li&gt;
&lt;li&gt;Part of a community: Being a part of community provides you with a sense of belongingness&lt;/li&gt;
&lt;li&gt;Exposure to tools: Working together in an open group exposes you to many tools that can be difficult to explore on your own or in a closed group&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;You will not be getting a T-shirt by contributing to open-source (at least if it's not October), but giving back to the community which we, as developers, regularly exploit &lt;strong&gt;feels good&lt;/strong&gt;. Communities like &lt;code&gt;OSRG&lt;/code&gt; help lower the entry barrier and can help in your personal/professional growth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners" rel="noopener noreferrer"&gt;intro to git and github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests" rel="noopener noreferrer"&gt;pull-request&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://guides.github.com/features/issues/" rel="noopener noreferrer"&gt;issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://makeapullrequest.com/" rel="noopener noreferrer"&gt;make-a-pull-request&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disclaimer:
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;OSRG&lt;/code&gt; is a &lt;code&gt;JavaScript/TypeScript&lt;/code&gt; focused community, but you can extend the idea that they represent and build your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits:
&lt;/h2&gt;

&lt;p&gt;Cover photo: Photo by &lt;a href="https://unsplash.com/@yancymin?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Yancy Min&lt;/a&gt; on &lt;a href="/s/photos/github?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;br&gt;
Proof reading and providing valuable suggestions: &lt;a href="https://twitter.com/poi_sray" rel="noopener noreferrer"&gt;@poi_sray&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Getting more from your portfolio</title>
      <dc:creator>Sudhanshu</dc:creator>
      <pubDate>Mon, 01 Mar 2021 11:56:21 +0000</pubDate>
      <link>https://forem.com/sudokoi/getting-more-from-your-portfolio-1bgk</link>
      <guid>https://forem.com/sudokoi/getting-more-from-your-portfolio-1bgk</guid>
      <description>&lt;p&gt;You can skip my ramblings and jump straight to the problem.&lt;/p&gt;




&lt;h3&gt;
  
  
  Premise:
&lt;/h3&gt;

&lt;p&gt;You're a developer and you want to show your skills to the world.&lt;br&gt;
You painstakingly improved your design skills to design yourself a website (or asked a friend to do it for you, or, as in &lt;a href="https://www.sudhanshu-ranjan.tech" rel="noopener noreferrer"&gt;my case&lt;/a&gt;, decided to go with someone's open-sourced design, with permission of course.) &lt;/p&gt;

&lt;p&gt;Now the world can see what you do, your past works, your skill sets and what not. Thanks to your friend, your website has smooth animations and it is really a nice-looking, good UX-oriented page that you are really happy about.&lt;/p&gt;

&lt;p&gt;Now, the person visiting your home-on-the-internet is pretty impressed with your portfolio and wants to contact you regarding a work opportunity, or just wants to get in touch. You have your social-links embedded in the portfolio website: &lt;a href="https://twitter.com/__tsuki__42" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/perfectsudh" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt; and all those other sites. But having to go to yet another site just to contact you is discouraging for your visitor.&lt;/p&gt;

&lt;p&gt;However, you have thought of this already and have provided a contact-form in your website from where the visitor can contact you directly, without going anywhere else. Smart!&lt;/p&gt;




&lt;h3&gt;
  
  
  That's where the trouble begins:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The problem: Managing the infrastructure to accept form-data
&lt;/h4&gt;

&lt;p&gt;Here are the bare-minimum things you have to manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An instance (probably on a cloud provider)&lt;/li&gt;
&lt;li&gt;API to connect to the website&lt;/li&gt;
&lt;li&gt;A database to store the records&lt;/li&gt;
&lt;li&gt;Certificates to secure the exposed endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, if you want to get a little fancy, don't forget the overhead of managing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bot protection&lt;/li&gt;
&lt;li&gt;Spam protection&lt;/li&gt;
&lt;li&gt;Exporting data in other formats, such as CSV&lt;/li&gt;
&lt;li&gt;Webhooks&lt;/li&gt;
&lt;li&gt;Email notifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And don't even get me started on the database migration needed if you decide to add/remove/modify the form fields.&lt;/p&gt;

&lt;p&gt;So, now you may ask, "Okay Sudhanshu, tell me, what's the alternative?"&lt;/p&gt;

&lt;p&gt;Glad you asked.&lt;/p&gt;

&lt;h4&gt;
  
  
  The solution:
&lt;/h4&gt;

&lt;p&gt;Give all this management overhead to someone else.&lt;br&gt;
Enter &lt;strong&gt;rake.red&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Forms for Static Pages&lt;br&gt;
Collect info from users without a server or back-end code. Receive submissions in rake.red, direct and secure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let me tell you their features first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No backend architecture required&lt;/li&gt;
&lt;li&gt;You add/edit/remove as many fields in the contact form as and when required&lt;/li&gt;
&lt;li&gt;Spam protection&lt;/li&gt;
&lt;li&gt;Export the records as CSV&lt;/li&gt;
&lt;li&gt;Webhooks to integrate it with custom-services&lt;/li&gt;
&lt;li&gt;If you prefer email notification, you can also turn them on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may ask me, "What's so special about &lt;strong&gt;rake.red&lt;/strong&gt;? There must be other similar services out there."&lt;br&gt;
There are. Even I used to use another service (pageclip) for this.&lt;br&gt;
What's so awesome about rake.red is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct integration to &lt;strong&gt;Discord&lt;/strong&gt; and &lt;strong&gt;Slack&lt;/strong&gt; using webhooks to get all your stuff on the platform of your choice&lt;/li&gt;
&lt;li&gt;Fight the bots with inbuilt &lt;code&gt;honeypot&lt;/code&gt; field&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't know about you, but these two features are what I was searching for in the other similar service. I even had to spin a server-instance just to connect to discord (Yeah, I get the irony. I chose this so that I would not have to manage a server but ended up managing a server).&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion:
&lt;/h3&gt;

&lt;p&gt;If you want a hassle-free, plug and play way to collect info from the visitors and get all the amazing features mentioned above, go check out &lt;a href="https://rake.red" rel="noopener noreferrer"&gt;rake.red&lt;/a&gt;. All the documentation required can be found there and the app is pretty intuitive.&lt;/p&gt;

&lt;p&gt;P.S. This post was not in any way sponsored by rake.red. These are all my personal opinions.&lt;/p&gt;

&lt;p&gt;Credits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cover image by &lt;a href="https://unsplash.com/@joannakosinska" rel="noopener noreferrer"&gt;Joanna Kosinska&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>portfolio</category>
      <category>website</category>
      <category>webdev</category>
    </item>
    <item>
      <title>CI/CD pipeline with Docker, Github actions, Dockerhub and Watchtower</title>
      <dc:creator>Sudhanshu</dc:creator>
      <pubDate>Thu, 13 Aug 2020 05:21:49 +0000</pubDate>
      <link>https://forem.com/sudokoi/ci-cd-pipeline-with-docker-github-actions-dockerhub-and-watchtower-3l3n</link>
      <guid>https://forem.com/sudokoi/ci-cd-pipeline-with-docker-github-actions-dockerhub-and-watchtower-3l3n</guid>
      <description>&lt;p&gt;A CI/CD pipeline for the development phase.&lt;/p&gt;

&lt;p&gt;I wanted to setup a CI/CD pipeline where my application would finally be deployed on my local machine while also using the sweet stuff that github provided with github-actions, &lt;em&gt;local-machine&lt;/em&gt; being the key here.&lt;/p&gt;

&lt;p&gt;There can be many situations where you want the deployment to be local, particularly during the development phase, to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prevent network traffic&lt;/li&gt;
&lt;li&gt;non-transmission of sensitive data&lt;/li&gt;
&lt;li&gt;accommodate frequent changes in the code-base&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  &lt;em&gt;Note:&lt;/em&gt; This article requires you to have the atleast some prior knowledge of docker and github-actions, and docker installed on your local machine.
&lt;/h5&gt;




&lt;h3&gt;
  
  
  1. Dockerizing your application
&lt;/h3&gt;

&lt;p&gt;"Docker is an open platform for developing, shipping, and running applications"&lt;br&gt;
Docker is like a VM but with only the parts necessary to run your applications. Docker provides a comprehensive guide on developing with docker in their documentation, which can be found &lt;a href="https://docs.docker.com/develop/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To "dockerize" an app, you write a Dockerfile. Here's an example of a dockerfile.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  2. Setting up github actions for testing and CI
&lt;/h3&gt;

&lt;p&gt;Once you have the dockerfile, you can build a docker image. A Docker image is a file, comprised of multiple layers, that is used to execute code in a Docker container. A docker image is basically a &lt;em&gt;packaged application&lt;/em&gt; that can be executed as &lt;em&gt;docker containers&lt;/em&gt;. A docker container is just a running docker image.&lt;/p&gt;

&lt;p&gt;Github actions provides an environment for executing "actions", which can perform various tasks. These actions are written as &lt;em&gt;yaml files&lt;/em&gt;, which then execute based on github triggers like &lt;em&gt;pushing to a branch&lt;/em&gt;, &lt;em&gt;initiating a pull-request&lt;/em&gt; etc. Check out the features of github actions &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Dockerhub is an online registry where you can keep your docker images. You do require a dockerhub account to docker images up the registry. If you prefer, you can also make you own registry instead. More on this &lt;a href="https://docs.docker.com/registry/deploying/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below is an example &lt;em&gt;actions.yml&lt;/em&gt; file to build an image and push the image to the Dockerhub.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
The example above uses a custom script &lt;code&gt;ci:docker&lt;/code&gt; to build the docker-image, login into the dockerhub and push the image to the dockerhub using cli. The example is for a node app, but a similar approach can be used for any application.
&lt;h3&gt;
  
  
  3. Watchtower
&lt;/h3&gt;

&lt;p&gt;The center part of this entire pipeline is &lt;em&gt;watchtower&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;"With watchtower you can update the running version of your containerized app simply by pushing a new image to the Docker Hub or your own image registry."&lt;br&gt;
Check out their repo for  more information.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/containrrr" rel="noopener noreferrer"&gt;
        containrrr
      &lt;/a&gt; / &lt;a href="https://github.com/containrrr/watchtower" rel="noopener noreferrer"&gt;
        watchtower
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A process for automating Docker container base image updates. 
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Basically, with watchtower, whenever the image updates in the registry (like Dockerhub), the container is updated with the latest changes.&lt;/p&gt;




&lt;p&gt;Doing these, you have successfully made your CI/CD pipeline which gets updated whenever changes are pushed to the github repo.&lt;br&gt;
The local container takes some time to update once the updated image is pushed to the registry, but setting these whole workflow is simple and works beautifully, at least for the development environment.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>github</category>
      <category>watchtower</category>
      <category>devops</category>
    </item>
    <item>
      <title>Role based access control in React-Redux apps</title>
      <dc:creator>Sudhanshu</dc:creator>
      <pubDate>Thu, 18 Jun 2020 02:07:06 +0000</pubDate>
      <link>https://forem.com/tsuki42/role-based-access-control-in-react-redux-apps-2i53</link>
      <guid>https://forem.com/tsuki42/role-based-access-control-in-react-redux-apps-2i53</guid>
      <description>&lt;p&gt;This assumes you have a basic knowledge of react, react-router, redux and redux-middlewares. Also, you have already implemented authentication in the react-redux app.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I have used redux but the same can be done without relying on redux. So, while some knowledge of redux may help you understand what I have tried to convey, redux isn't a necessity.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;While working in a project, the requirement arose to give the functionality of Role based access control (RBAC) in a client-side-rendered react-app.&lt;/p&gt;

&lt;p&gt;Basically, the application was going to have multiple tiers of users with flexible permissions and depending on the permission granted to any particular user, a component or a part of the application may/may not become accessible to that user.&lt;/p&gt;

&lt;p&gt;Implementing RBAC at the client-side can be divided into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conditional rendering of the components&lt;/li&gt;
&lt;li&gt;Updating the conditions when permissions change&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conditional Rendering of the components:
&lt;/h2&gt;

&lt;p&gt;There are many approaches that can be used for this. One of my initial approach was to wrap the component (say CheckedComponent) with a component (say CheckPermissions) which would conditionally render them based on the permissions given to the current user. This looks something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;em&gt;The user-permissions were stored in the redux-store route-wise.&lt;/em&gt;

&lt;p&gt;The above approach does the job but fails if the &lt;code&gt;&amp;lt;CheckedComponent /&amp;gt;&lt;/code&gt; also requires permission checking, basically making the whole process nested. Also, I didn’t know before-hand the depth of nesting.&lt;/p&gt;

&lt;p&gt;I could also have used HoCs, but they too suffered from the same issue, in my case.&lt;/p&gt;

&lt;p&gt;So, I decided to go with the hooks approach, which looks something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;useAuthorization&lt;/code&gt; hook returns the list of permissions the user has for the given route. This may seem repetitive as this could directly have been taken from the &lt;code&gt;redux-store&lt;/code&gt;, but this hook provided a level of abstraction. Also, if the &lt;em&gt;permission-retrieval logic for the user is changed, only this needed to be changed and everything would still work&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;each component is conditionally rendered based on the user permissions.
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

In this approach, I need to do the same thing again and again, but looks neat for now.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Updating the conditions when permissions change:
&lt;/h2&gt;

&lt;p&gt;In my case, whenever a user logged in, the server responded with a set of permissions associated with that user. I wrote a &lt;b&gt;middleware&lt;/b&gt; which on login-success read the permissions and updated the &lt;code&gt;redux-store&lt;/code&gt;. I am also using redux-persist to save authorization and authentication information about the user in the local storage.&lt;/p&gt;

&lt;p&gt;Now, &lt;b&gt;&lt;em&gt;when the permissions are changed for any user, the user’s authorization-token is expired&lt;/em&gt;&lt;/b&gt;. This is very important or the user-permissions won’t be updated in the redux-store and no change will be visible. The changes with the new permissions are reflected when the user logins again.&lt;/p&gt;



&lt;p&gt;This approach of RBAC may not be what’s ideal, but this works for me. A few important steps I have skipped over, as they are subjective to an application, viz.,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agreeing on the structure of the permissions. In my case, I arranged the permissions &lt;code&gt;route-wise&lt;/code&gt; , but you can use any other structure.&lt;/li&gt;
&lt;li&gt;The &lt;b&gt;redux-middleware&lt;/b&gt; part. This basically takes the server-response and transforms that into the structure mentioned in the first point.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;This post is also availabe as a medium post and can be found here : &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@perfectsudh/role-based-access-control-in-react-redux-apps-8454d4ca1a3b" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dJMXZPGc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/v2/resize:fill:96:96/0%2Aj2g-m5Oy0lx68BSO." alt="Sudhanshu Ranjan"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@perfectsudh/role-based-access-control-in-react-redux-apps-8454d4ca1a3b" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Role based access control in React-Redux apps | by Sudhanshu Ranjan | Medium&lt;/h2&gt;
      &lt;h3&gt;Sudhanshu Ranjan ・ &lt;time&gt;Jun 18, 2020&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hnDHPsJs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/medium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>react</category>
      <category>rbac</category>
      <category>redux</category>
      <category>reacthooks</category>
    </item>
  </channel>
</rss>
