<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  
  <title>Abhijit&#39;s Garden</title>
  <subtitle>A blog about my life, things I am currently working &amp; a bit about my life.</subtitle>
  <link href="https://xeromin.in/feed/feed.xml" rel="self" />
  <link href="https://xeromin.in/" />
  <updated>2026-08-01T00:00:00Z</updated>
  <id>https://xeromin.in/</id>
  <author>
    <name>Abhijit Paul</name>
    <email>thexeromin@gmail.com</email>
  </author>
  <entry>
    <title>Using RSS to take control of what I consume</title>
    <link href="https://xeromin.in/blog/using-rss-to-take-control-what-i-consume/" />
    <updated>2026-08-01T00:00:00Z</updated>
    <id>https://xeromin.in/blog/using-rss-to-take-control-what-i-consume/</id>
    <content type="html">&lt;p&gt;Nowadays brain-rot, brain-fog and decision paralysis are becoming increasingly common due to the overwhelming amount of content available on the internet. On top of this, big companies investing heavily to keep us longer on their platform, So it&#39;s easy to get distracted now a days. That&#39;s why, since few days I have been researching about how I can choose what I consume. Then I found out about RSS.&lt;/p&gt;
&lt;p&gt;So what is this RSS?
As per the wikipedia, it&#39;s a web feed that allows users and applications to access updates to websites. Basically it will monitor the websites for new content and show it in my feed aggregator.&lt;/p&gt;
&lt;p&gt;So I started my quest of searching for a good RSS aggregator. Then I found &lt;a href=&quot;https://xeromin.in/blog/using-rss-to-take-control-what-i-consume/inoreader.com&quot;&gt;Inoreader&lt;/a&gt; and used it for few days. But the problem with Inoreader is that it&#39;s bloated. My needs are simple: I just want an simple aggregator to add/remove feed and view their content.&lt;/p&gt;
&lt;p&gt;Then I did some research and discovered a few self-hosted options. Among them, &lt;a href=&quot;https://miniflux.app/&quot;&gt;Miniflux&lt;/a&gt; seemed good for me. I liked it but for me it is also bloated. I have a 5$ server and as per miniflux setup instruction, I don&#39;t wanna use docker. Also it uses &lt;code&gt;postgresql&lt;/code&gt; which I think overkill for my use case. I know there is a way to install it without docker but I don&#39;t wanna go through all those things.&lt;/p&gt;
&lt;p&gt;Then I searched again and found another self-hosted option called &lt;a href=&quot;https://github.com/nkanaev/yarr&quot;&gt;yarr&lt;/a&gt;(yet another RSS reader). I will try setting this one up on my server.&lt;/p&gt;
&lt;p&gt;I am also considering building my own RSS feed reader using simple tech stack like &lt;code&gt;express.js&lt;/code&gt;, &lt;code&gt;pug&lt;/code&gt; and &lt;code&gt;sqlite&lt;/code&gt;. For my use case, this might be the best option.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>I Thought Normalized State Would Fix My Re-render Problem. It Didn&#39;t.</title>
    <link href="https://xeromin.in/blog/normalized-state-rerender-problem/" />
    <updated>2026-04-04T00:00:00Z</updated>
    <id>https://xeromin.in/blog/normalized-state-rerender-problem/</id>
    <content type="html">&lt;p&gt;I was building a Kanban board called &lt;strong&gt;Kantoo&lt;/strong&gt; and hit a classic React performance problem. This is what I tried, what didn&#39;t work, and what actually fixed it.&lt;/p&gt;
&lt;h2 id=&quot;what-i-built-first&quot;&gt;What I Built First&lt;/h2&gt;
&lt;p&gt;I went with a normalized state architecture managed through &lt;code&gt;useReducer&lt;/code&gt;. The idea was simple: instead of deeply nested state, keep everything flat. Each column and card lives in its own lookup object, and you reference them by ID.&lt;/p&gt;
&lt;p&gt;It felt clean.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Even with normalized state, two things were going wrong.&lt;/p&gt;
&lt;p&gt;A single card update was causing every component on the board to re-render, including columns that had nothing to do with that card. I could see it clearly in React DevTools Profiler. The render time for a single card move was sitting at around 55ms.&lt;/p&gt;
&lt;p&gt;I was also passing data to components that didn&#39;t need it. Some components were receiving data purely so they could pass it further down, even though they didn&#39;t use it themselves. Just middlemen adding to the problem.&lt;/p&gt;
&lt;h2 id=&quot;my-first-idea-react-context&quot;&gt;My First Idea: React Context&lt;/h2&gt;
&lt;p&gt;My first thought was to reach for Context. Put state in a provider and read only what each component needs inside a custom hook.&lt;/p&gt;
&lt;p&gt;Sounds good in theory. But here&#39;s the catch: even if you only read one value from context, React still re-renders the component whenever anything in that context changes. The component is subscribed to the entire context object under the hood.&lt;/p&gt;
&lt;p&gt;So Context would just move the problem, not solve it.&lt;/p&gt;
&lt;h2 id=&quot;what-actually-fixed-it-zustand-with-selective-subscriptions&quot;&gt;What Actually Fixed It: Zustand with Selective Subscriptions&lt;/h2&gt;
&lt;p&gt;The real fix is a library that supports selective subscriptions, where a component only re-renders when the specific piece of state it cares about changes. Zustand does exactly this.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This component only re-renders when cards changes&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cards &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useStore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cards&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once I migrated Kantoo to Zustand and combined it with the normalized state architecture I already had, something clicked. Untouched cards stopped re-rendering entirely. A card move now only wakes up the components actually involved.&lt;/p&gt;
&lt;h2 id=&quot;the-results&quot;&gt;The Results&lt;/h2&gt;
&lt;p&gt;I measured both before and after using React DevTools Profiler.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://xeromin.in/blog/normalized-state-rerender-problem/F-3VrmEdvS-1133.avif 1133w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://xeromin.in/blog/normalized-state-rerender-problem/F-3VrmEdvS-1133.webp 1133w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://xeromin.in/blog/normalized-state-rerender-problem/F-3VrmEdvS-1133.jpeg&quot; alt=&quot;React DevTools Profiler - useReducer, 55ms render time&quot; width=&quot;1133&quot; height=&quot;370&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;With useReducer and prop drilling, a single card move produced a render time of around &lt;strong&gt;55ms&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://xeromin.in/blog/normalized-state-rerender-problem/mwyXOxe8wo-1009.avif 1009w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://xeromin.in/blog/normalized-state-rerender-problem/mwyXOxe8wo-1009.webp 1009w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://xeromin.in/blog/normalized-state-rerender-problem/mwyXOxe8wo-1009.jpeg&quot; alt=&quot;React DevTools Profiler - Zustand selective subscriptions, 15ms render time&quot; width=&quot;1009&quot; height=&quot;335&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;After migrating to Zustand with selective subscriptions, the same card move commits in around &lt;strong&gt;15ms&lt;/strong&gt;. That is a ~73% reduction, not from micro-optimizations but from rethinking how state flows through the tree.&lt;/p&gt;
&lt;h2 id=&quot;why-memoization-alone-was-not-enough&quot;&gt;Why Memoization Alone Was Not Enough&lt;/h2&gt;
&lt;p&gt;This tripped me up early. &lt;code&gt;React.memo&lt;/code&gt; only prevents re-renders when props do not change. But when state lives at the top and gets passed down, the parent re-renders on any update and passes new references down, so memo never gets a chance to bail out.&lt;/p&gt;
&lt;p&gt;Zustand&#39;s subscriptions bypass this entirely. Components pull what they need straight from the store and ignore everything else.&lt;/p&gt;
&lt;h2 id=&quot;what-this-taught-me&quot;&gt;What This Taught Me&lt;/h2&gt;
&lt;p&gt;Once you understand the difference it changes how you think about state:&lt;/p&gt;
&lt;p&gt;Context is great for things that rarely change like a theme or current user. Zustand is better when you have frequently updated state that different components care about independently.&lt;/p&gt;
&lt;p&gt;The key phrase is granular subscriptions. Components only pay attention to exactly what they need, nothing more.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Check out &lt;a href=&quot;https://github.com/thexeromin/kantoo&quot;&gt;Kantoo on GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Re-rendering is not a bad thing in React</title>
    <link href="https://xeromin.in/blog/rerendering-is-not-bad/" />
    <updated>2026-03-03T00:00:00Z</updated>
    <id>https://xeromin.in/blog/rerendering-is-not-bad/</id>
    <content type="html">&lt;p&gt;Earlier, I had a misconception that if React re-renders, it’s a bad thing because extra work is being done.&lt;/p&gt;
&lt;p&gt;I believed that when re-rendering happens, React has to do the same work again and again. So I thought, why repeat the same rendering process multiple times?&lt;/p&gt;
&lt;p&gt;While deep diving into React, I learned about the Virtual DOM.&lt;/p&gt;
&lt;p&gt;The real DOM is part of the browser and updating it is expensive. The Virtual DOM, however, is just a JavaScript representation of the real DOM. Updating the Virtual DOM is much cheaper compared to directly manipulating the real DOM.&lt;/p&gt;
&lt;p&gt;Under the hood, when state changes, React creates a new Virtual DOM.&lt;/p&gt;
&lt;p&gt;Then it compares the new Virtual DOM with the previous one. This process is called diffing.&lt;/p&gt;
&lt;p&gt;If React finds differences, it updates only the changed parts in the real DOM instead of re-rendering everything. This entire cycle of creating a new tree, diffing it, and updating the browser is known as Reconciliation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://xeromin.in/blog/rerendering-is-not-bad/EyYac142iE-1024.webp&quot; alt=&quot;Reconciliation Process Diagram&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1024&quot; height=&quot;479&quot;&gt;&lt;/p&gt;
&lt;p&gt;Re-rendering can become a problem in some cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;If a child component performs an expensive task&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;If the child component runs an expensive calculation during rendering, it may slow down performance.&lt;/li&gt;
&lt;li&gt;We can use &lt;code&gt;React.useMemo&lt;/code&gt; to memoize the calculated value so it only recomputes when its dependencies change.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When a parent component updates but the child’s props do not change&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;By default, when a parent re-renders, its child components also re-render.&lt;/li&gt;
&lt;li&gt;We can prevent unnecessary child re-renders by wrapping the child component with &lt;code&gt;React.memo&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When passing a function as a prop&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Every time a parent re-renders, functions inside it are recreated.&lt;/li&gt;
&lt;li&gt;Since functions are compared by reference, React treats it as a new prop, even if the logic is the same.&lt;/li&gt;
&lt;li&gt;We can use the &lt;code&gt;React.useCallback&lt;/code&gt; hook to memoize the function and keep its reference stable between renders.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;final-takeaway&quot;&gt;Final Takeaway&lt;/h2&gt;
&lt;p&gt;Re-rendering itself is not bad in React. React is designed to handle it efficiently using the Virtual DOM. The real problem is unnecessary expensive operations during re-renders, not the re-rendering process itself.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>BloodZone: Building a Scalable, Location-Based Donation Platform</title>
    <link href="https://xeromin.in/blog/bloodzone-case-study/" />
    <updated>2026-02-06T00:00:00Z</updated>
    <id>https://xeromin.in/blog/bloodzone-case-study/</id>
    <content type="html">&lt;h2 id=&quot;the-problem-logistics-not-lack&quot;&gt;The Problem: Logistics, Not Lack&lt;/h2&gt;
&lt;p&gt;In emergency situations, the bottleneck isn&#39;t usually a lack of blood donors; it&#39;s an &lt;strong&gt;information gap&lt;/strong&gt;. Finding a donor with the right blood type within a reachable distance often involves frantic calls and WhatsApp spam.&lt;/p&gt;
&lt;p&gt;I built &lt;strong&gt;BloodZone&lt;/strong&gt; to solve this logistics problem using engineering. The goal was to create an &amp;quot;Uber-like&amp;quot; experience for blood donation: finding the nearest eligible donor in milliseconds, not hours.&lt;/p&gt;
&lt;h2 id=&quot;the-architecture&quot;&gt;The Architecture&lt;/h2&gt;
&lt;p&gt;BloodZone follows a 3-tier architecture designed for speed and reliability. Unlike simple CRUD apps, the complexity here lies in three key areas: the &lt;strong&gt;Geospatial Engine&lt;/strong&gt;, the &lt;strong&gt;Real-Time Communication layer&lt;/strong&gt;, and the &lt;strong&gt;Secure Identity System&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Stack:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mobile:&lt;/strong&gt; React Native (Expo) - Optimized for Android.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API:&lt;/strong&gt; Node.js &amp;amp; Express (TypeScript).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database:&lt;/strong&gt; MongoDB Atlas (Utilizing 2dsphere indexing).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-Time:&lt;/strong&gt; Socket.io with custom middleware guards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth:&lt;/strong&gt; Google OAuth 2.0 (Deep Link + Server Exchange).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://xeromin.in/blog/bloodzone-case-study/xmwGUVUWRF-3027.avif 3027w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://xeromin.in/blog/bloodzone-case-study/xmwGUVUWRF-3027.webp 3027w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://xeromin.in/blog/bloodzone-case-study/xmwGUVUWRF-3027.png&quot; alt=&quot;System Architecture Diagram&quot; width=&quot;3027&quot; height=&quot;2245&quot;&gt;&lt;/picture&gt;
&lt;em&gt;Figure 1: High-level system architecture showing the Round-Trip Auth flow, Geospatial Query engine, and Real-Time Sockets.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;key-engineering-challenges&quot;&gt;Key Engineering Challenges&lt;/h2&gt;
&lt;h3 id=&quot;1-the-radius-problem-geospatial-logic&quot;&gt;1. The &amp;quot;Radius&amp;quot; Problem (Geospatial Logic)&lt;/h3&gt;
&lt;p&gt;The core feature of the app is finding donors within a strict boundary (e.g., exactly 5km). Initially, I considered fetching all users and filtering them in JavaScript, but I realized that would kill performance as the user base grew.&lt;/p&gt;
&lt;p&gt;I moved this logic to the database layer using MongoDB&#39;s &lt;code&gt;$geoWithin&lt;/code&gt; combined with &lt;code&gt;$centerSphere&lt;/code&gt;. The tricky part was the math: MongoDB requires radians, so I had to implement a converter to translate kilometers into radian coordinates relative to Earth&#39;s radius.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// The query that saved me from fetching 10k records&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; users &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; UserModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  location&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    $geoWithin&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      $centerSphere&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;longitude&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; latitude&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        radiusInKm &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6378.1&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Converting km to radians&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-securing-open-sockets-real-time-auth&quot;&gt;2. Securing Open Sockets (Real-Time Auth)&lt;/h3&gt;
&lt;p&gt;I used &lt;strong&gt;Socket.io&lt;/strong&gt; to allow seekers to chat directly with donors. The biggest risk with WebSockets is that they often bypass standard HTTP Auth headers, leaving the chat server vulnerable to spam bots.&lt;/p&gt;
&lt;p&gt;To fix this, I implemented a &lt;strong&gt;Handshake Middleware&lt;/strong&gt;. Before a socket connection is even &amp;quot;upgraded&amp;quot; to a real-time link, the backend intercepts the handshake, extracts the JWT, and verifies the user identity. If the token is invalid, the socket is forcibly disconnected before any data is exchanged.&lt;/p&gt;
&lt;h3 id=&quot;3-deep-link-authentication-handling-state&quot;&gt;3. Deep-Link Authentication (Handling State)&lt;/h3&gt;
&lt;p&gt;Security was a priority, so I didn&#39;t want to handle Google passwords inside the app. I opted for a &amp;quot;Round Trip&amp;quot; Deep Link strategy.&lt;/p&gt;
&lt;p&gt;When a user logs in, the app throws them out to the system browser (Chrome/Safari) for a secure Google login. The challenge was getting them &lt;em&gt;back&lt;/em&gt; into the app with the session intact. I had to configure a custom URL scheme (&lt;code&gt;bloodzone://&lt;/code&gt;) so that once the server verified the user, it could &amp;quot;wake up&amp;quot; the app from the background and inject the secure tokens directly into the device&#39;s secure storage.&lt;/p&gt;
&lt;h3 id=&quot;4-architecting-real-time-alerts-the-push-pipeline&quot;&gt;4. Architecting Real-Time Alerts (The Push Pipeline)&lt;/h3&gt;
&lt;p&gt;Blood donation relies on speed. To ensure donors are notified the second a request is generated nearby, I engineered a custom push notification infrastructure that bridges &lt;strong&gt;Expo&lt;/strong&gt;, &lt;strong&gt;MongoDB Geospatial Queries&lt;/strong&gt;, and &lt;strong&gt;Firebase Cloud Messaging (FCM)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Idempotent Token Synchronization&lt;/strong&gt;
The client lifecycle relies on a custom &lt;code&gt;usePushNotifications&lt;/code&gt; hook to manage tokens. I implemented an &lt;strong&gt;idempotent synchronization pattern&lt;/strong&gt;, ensuring that device tokens in the database remain consistent and unique without redundant network calls or duplicate records on the backend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Geospatial Aggregation Engine&lt;/strong&gt;
The backend utilizes MongoDB’s &lt;code&gt;2dsphere&lt;/code&gt; indexing to execute precise, real-time proximity checks. When a request is triggered, the aggregation pipeline simultaneously filters active users within a &lt;strong&gt;5,000-meter radius&lt;/strong&gt;, excludes the requester, and validates token availability—reducing database load by combining discovery and filtering into a single operation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Modern FCM Delivery Infrastructure&lt;/strong&gt;
I migrated away from legacy server keys in favor of the &lt;strong&gt;Firebase Cloud Messaging V1 API&lt;/strong&gt;. By configuring Expo with a Google Service Account, the system dynamically mints short-lived &lt;strong&gt;OAuth 2.0 access tokens&lt;/strong&gt;. This establishes a secure, authenticated relay for reliable message delivery to Android devices without managing long-lived secrets.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;lessons-learned-and-future-scope&quot;&gt;Lessons Learned &amp;amp; Future Scope&lt;/h2&gt;
&lt;p&gt;Building BloodZone taught me two critical engineering lessons that tutorials don&#39;t cover:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Database &amp;gt; Code:&lt;/strong&gt; My first prototype tried to calculate distances using a JavaScript function. It was slow and crashed the app with large datasets. Moving that logic to MongoDB&#39;s geospatial index reduced query times by ~90%. It taught me to let the database do the heavy lifting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Management is Tricky:&lt;/strong&gt; Handling the &amp;quot;app-to-browser-to-app&amp;quot; jump for OAuth was the hardest bug to squash. I learned the hard way that mobile apps often lose their &amp;quot;state&amp;quot; when backgrounded, requiring robust checks when the app re-mounts.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Current Constraints:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The app is currently optimized and tested for &lt;strong&gt;Android&lt;/strong&gt; devices.&lt;/li&gt;
&lt;li&gt;iOS support is in beta due to specific styling differences in the React Native engine.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Next Steps:&lt;/strong&gt;
Now that the main features are working, I want to fix any small bugs that come up during testing and finish the design tweaks needed to make the app run smoothly.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;project-links&quot;&gt;Project Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://youtube.com/shorts/AOj7_smdNtQ&quot;&gt;Watch Demo Video&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;mailto:thexeromin@gmail.com?subject=BloodZone%20Access&quot;&gt;Request Access (Email)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Note: This project is currently in closed beta.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Hello, World!</title>
    <link href="https://xeromin.in/blog/first-post/" />
    <updated>2026-01-17T00:00:00Z</updated>
    <id>https://xeromin.in/blog/first-post/</id>
    <content type="html">&lt;p&gt;Welcome to my new portfolio and blog!&lt;/p&gt;
&lt;p&gt;As a developer, there is almost a ritualistic obligation to title the first post &lt;strong&gt;&amp;quot;Hello World&amp;quot;&lt;/strong&gt;, so here we are.&lt;/p&gt;
&lt;h2 id=&quot;why-i-built-this&quot;&gt;Why I built this&lt;/h2&gt;
&lt;p&gt;I wanted a space that felt like &lt;em&gt;me&lt;/em&gt;—minimal, fast, and completely under my control. I designed this site from scratch in &lt;strong&gt;Figma&lt;/strong&gt; and built it using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Astro&lt;/strong&gt; for performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt; for styling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TypeScript&lt;/strong&gt; for type safety.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-to-expect&quot;&gt;What to expect&lt;/h2&gt;
&lt;p&gt;I plan to use this space to document my journey in software engineering. You can expect posts about:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Low-level programming&lt;/strong&gt; (C, systems, and networking).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web development&lt;/strong&gt; (building efficient, modern interfaces).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project updates&lt;/strong&gt; (deep dives into tools like &lt;em&gt;Kuan&lt;/em&gt; and &lt;em&gt;Termzic&lt;/em&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thanks for stopping by.&lt;/p&gt;
</content>
  </entry>
</feed>