<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Saurav Jalui – Blog</title><link>https://sauravjalui.com/blog/</link><description>Recent content in Blog on Saurav Jalui</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 19 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://sauravjalui.com/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>From Hashnode to Hugo: Notes From the Move</title><link>https://sauravjalui.com/blog/from-hashnode-to-hugo/</link><pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate><guid>https://sauravjalui.com/blog/from-hashnode-to-hugo/</guid><description>
&lt;p&gt;&lt;img src="https://sauravjalui.com/images/post-hashnode.webp" alt="From a hosted platform to my own stack" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;This blog has a new home. It used to live on Hashnode; it now runs on &lt;a href="https://gohugo.io"target="_blank" rel="noopener"&gt;Hugo&lt;/a&gt; with the &lt;a href="https://github.com/imfing/hextra"target="_blank" rel="noopener"&gt;Hextra&lt;/a&gt; theme, builds on GitHub Actions, and serves for free from GitHub Pages — same domain, same URLs.&lt;/p&gt;
&lt;h2&gt;Why move&lt;span class="hx:absolute hx:-mt-20" id="why-move"&gt;&lt;/span&gt;
&lt;a href="#why-move" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Hashnode was a great starting point, but in 2026 custom domains moved behind their new Pro plan, and that nudged me toward something I&amp;rsquo;d been meaning to do anyway: own the whole stack. Now every post is a Markdown file in a Git repo. No platform, no lock-in, no surprises.&lt;/p&gt;
&lt;h2&gt;The stack&lt;span class="hx:absolute hx:-mt-20" id="the-stack"&gt;&lt;/span&gt;
&lt;a href="#the-stack" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The setup is small enough to describe in one breath: Hugo builds the site, Hextra makes it look good, a GitHub Actions workflow deploys on every push, and four DNS records point the domain at GitHub Pages. Keeping the old URL structure was one config line:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;permalinks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;blog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/:slug/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
aria-label="Copy code"
data-copied-label="Copied!"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That single line is what preserves years of links and search rankings across the move.&lt;/p&gt;
&lt;h2&gt;What broke along the way&lt;span class="hx:absolute hx:-mt-20" id="what-broke-along-the-way"&gt;&lt;/span&gt;
&lt;a href="#what-broke-along-the-way" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Almost nothing — except the time I copied a shortcode block from a &lt;em&gt;rendered&lt;/em&gt; Markdown view and it silently injected blockquote markers into the file, breaking the build with the world&amp;rsquo;s most cryptic error. Lesson learned: always copy from the raw source.&lt;/p&gt;
&lt;h2&gt;What&amp;rsquo;s next&lt;span class="hx:absolute hx:-mt-20" id="whats-next"&gt;&lt;/span&gt;
&lt;a href="#whats-next" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Migrating the full archive over from the Hashnode export, rehosting the images, and then getting back to actually writing. If you&amp;rsquo;re reading this on sauravjalui.com over HTTPS, every piece of the pipeline above did its job.&lt;/p&gt;</description></item><item><title>The Tool Was Faster. They Still Wanted the Spreadsheet Back.</title><link>https://sauravjalui.com/blog/scheduling-portal/</link><pubDate>Sat, 18 Jul 2026 00:00:00 +0000</pubDate><guid>https://sauravjalui.com/blog/scheduling-portal/</guid><description>
&lt;p&gt;We spent a long time building a scheduling portal to kill the spreadsheets it replaced — thousands of students, hundreds of teachers, a shared pool of video links, all of it held together in Sheets and WhatsApp until the whole thing started tearing at the seams. The portal was, by every measure I cared about, better. Booking a year of recurring classes went from copying a weekly sheet dozens of times to a single click.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://sauravjalui.com/images/sheet-before.webp" alt="The old scheduling spreadsheet — colour-coded by hand, full of strikethroughs and pasted links, past its breaking point (names blurred)." loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;And the team still wanted the spreadsheet back.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://sauravjalui.com/images/portal-after.webp" alt="What replaced it — a portal with structured classes, teacher availability, and status at a glance (names blurred)." loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;I sat with that for a while, because it didn&amp;rsquo;t make sense on paper. The tool was faster. People hated it anyway. That gap — &lt;em&gt;faster, and still rejected&lt;/em&gt; — turned out to be the whole story, and unlearning my first instinct about it was the most useful thing I did on this project.&lt;/p&gt;
&lt;h2&gt;It wasn&amp;rsquo;t the tool&lt;span class="hx:absolute hx:-mt-20" id="it-wasnt-the-tool"&gt;&lt;/span&gt;
&lt;a href="#it-wasnt-the-tool" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;My first instinct, of course, was that we&amp;rsquo;d built it wrong. More polish, fewer bugs, better UX — the usual reflexes. And there was real breakage to fix, so that wasn&amp;rsquo;t nothing. But it wasn&amp;rsquo;t the thing.&lt;/p&gt;
&lt;p&gt;The thing was upstream of the code entirely. Features were landing in the portal because &lt;em&gt;management&lt;/em&gt; wanted them, not because the people scheduling all day needed them — and they&amp;rsquo;d show up with no warning, no training, no one asking the team first. So every release, even the good ones, made the tool feel a little more like something being done &lt;em&gt;to&lt;/em&gt; them rather than something built &lt;em&gt;for&lt;/em&gt; them. The portal wasn&amp;rsquo;t failing on what it could do. It was failing on trust. And you can&amp;rsquo;t patch trust with a sprint.&lt;/p&gt;
&lt;h2&gt;The problem was trust, not speed&lt;span class="hx:absolute hx:-mt-20" id="the-problem-was-trust-not-speed"&gt;&lt;/span&gt;
&lt;a href="#the-problem-was-trust-not-speed" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;That reframe changed what the actual work was. If the problem is speed, you optimize code. Because the problem was trust, the work was about &lt;em&gt;who gets to decide what ships&lt;/em&gt; — which is a governance problem wearing a technical costume, and a much less fun one to fix because it means telling powerful people no.&lt;/p&gt;
&lt;h2&gt;What actually moved the needle&lt;span class="hx:absolute hx:-mt-20" id="what-actually-moved-the-needle"&gt;&lt;/span&gt;
&lt;a href="#what-actually-moved-the-needle" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;A few decisions did most of the lifting.&lt;/p&gt;
&lt;p&gt;The first was just naming who the tool is actually for. Internal tools have a pile of roles — coordinators, managers, teachers, everyone — and when their needs collide, somebody has to win. So I said it plainly: the coordinators living in this thing all day are the primary user. Everyone else is secondary. And management is a &lt;em&gt;stakeholder, not a user&lt;/em&gt; — they don&amp;rsquo;t operate the tool, so their requests don&amp;rsquo;t get to walk straight into it. Writing that sentence down was uncomfortable and clarifying in equal measure.&lt;/p&gt;
&lt;p&gt;From there came the rule I&amp;rsquo;m proudest of: requests from the people who use the tool are needs; requests from management are good-to-haves. A good-to-have only ships after the people it affects sign off, and only when nothing they actually need is still waiting. It&amp;rsquo;s a small rule that deliberately makes someone senior wait their turn — which is exactly the point, and exactly why it was hard to hold.&lt;/p&gt;
&lt;p&gt;The last piece was figuring out how we&amp;rsquo;d even know if it worked, and this is where I almost fooled myself. Usage was mandatory, so every usage metric was a lie — logins looked great because nobody had a choice. What I actually needed to measure was whether people would &lt;em&gt;leave if they could&lt;/em&gt;. So: an anonymous monthly pulse, anonymous being non-negotiable, because a team that&amp;rsquo;s nervous will tell a survey with their name on it whatever they think management wants to hear. And alongside it, just watching people work — because you can&amp;rsquo;t intimidate someone&amp;rsquo;s behavior into politeness the way you can a feedback form.&lt;/p&gt;
&lt;h2&gt;The sentence I didn&amp;rsquo;t want to write&lt;span class="hx:absolute hx:-mt-20" id="the-sentence-i-didnt-want-to-write"&gt;&lt;/span&gt;
&lt;a href="#the-sentence-i-didnt-want-to-write" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The part I&amp;rsquo;m most sure about is the part that was hardest to write: the line where I said, out loud, that if we stabilized and polished the thing and people &lt;em&gt;still&lt;/em&gt; wanted the spreadsheet — then scheduling should go back to the spreadsheet, and the portal should keep only what a spreadsheet genuinely can&amp;rsquo;t do. That&amp;rsquo;s a deeply uncomfortable sentence to put in a memo about a tool you helped build. It&amp;rsquo;s also the only thing that made the rest of the plan believable, because it proved I was trying to fix the &lt;em&gt;problem&lt;/em&gt; and not defend the &lt;em&gt;tool&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;What I&amp;rsquo;d carry into the next one&lt;span class="hx:absolute hx:-mt-20" id="what-id-carry-into-the-next-one"&gt;&lt;/span&gt;
&lt;a href="#what-id-carry-into-the-next-one" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If there&amp;rsquo;s one thing I took from this that outlives this one project, it&amp;rsquo;s that adoption is a trust problem far more often than a capability problem — and when you force people to use something, you lose the only honest signal you had. You stop being able to tell whether they&amp;rsquo;re using it because it&amp;rsquo;s good or because they can&amp;rsquo;t escape. And at that point the most valuable thing you can build isn&amp;rsquo;t another feature. It&amp;rsquo;s a way to find out whether they&amp;rsquo;d stay if you opened the door.&lt;/p&gt;</description></item><item><title>Getting a Company Off Excel Without a Revolt</title><link>https://sauravjalui.com/blog/excel-to-portal/</link><pubDate>Sun, 12 Jul 2026 00:00:00 +0000</pubDate><guid>https://sauravjalui.com/blog/excel-to-portal/</guid><description>
&lt;a
class=" not-prose hx:inline-flex hx:items-center hx:rounded-full hx:gap-2 hx:px-3 hx:py-1 hx:text-xs hx:text-gray-600 hx:dark:text-gray-400 hx:bg-gray-100 hx:dark:bg-neutral-800 hx:border-gray-200 hx:dark:border-neutral-800 hx:border hx:hover:border-gray-400 hx:dark:hover:text-gray-50 hx:dark:hover:border-gray-600 hx:transition-all hx:ease-in hx:duration-200"
&gt;
Case Study · Migration
&lt;/a&gt;
&lt;p&gt;&lt;img src="https://sauravjalui.com/images/post-migration.webp" alt="From a wall of spreadsheets to one system" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;For years, the entire operation ran on spreadsheets. Scheduling, teacher availability, who owed how many hours — all of it lived in a sprawl of Sheets, held together by a handful of people who just &lt;em&gt;knew&lt;/em&gt; how it worked. It had run the business for half a decade, and to its credit, it mostly worked.&lt;/p&gt;
&lt;p&gt;Until it didn&amp;rsquo;t, on every axis at once. A typo in the wrong cell quietly broke someone&amp;rsquo;s schedule. Anyone with the link could edit anything, so there was no real notion of permissions. Nothing was logged, so when something went wrong there was no way to reconstruct what happened or who&amp;rsquo;d done it. And none of it scaled — every new teacher, every new cohort made the sheets heavier and the humans holding them more overloaded. The sheet wasn&amp;rsquo;t one problem. It was four, and they were compounding.&lt;/p&gt;
&lt;h2&gt;The easy version of this project would have failed&lt;span class="hx:absolute hx:-mt-20" id="the-easy-version-of-this-project-would-have-failed"&gt;&lt;/span&gt;
&lt;a href="#the-easy-version-of-this-project-would-have-failed" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The tempting way to do this is a big-bang cutover: build the whole portal, pick a Monday, turn off the sheets, send an email. It&amp;rsquo;s clean on a Gantt chart and it&amp;rsquo;s a disaster in practice, because it asks an entire organization to abandon five years of muscle memory overnight and trust software they&amp;rsquo;ve used for a week. The day something breaks — and something always breaks — everyone&amp;rsquo;s instinct is to reach back for the spreadsheet they &lt;em&gt;know&lt;/em&gt;, and now you&amp;rsquo;re running both, badly, with no plan for it.&lt;/p&gt;
&lt;p&gt;So I didn&amp;rsquo;t do that. The migration went team by team, deliberately, and the sequencing was itself a design decision.&lt;/p&gt;
&lt;h2&gt;Starting where it would break&lt;span class="hx:absolute hx:-mt-20" id="starting-where-it-would-break"&gt;&lt;/span&gt;
&lt;a href="#starting-where-it-would-break" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I didn&amp;rsquo;t start with the easiest team. I started with one of the harder ones — the group whose workflows were the least standardized and most likely to surface the ugly edge cases. The logic: if the portal could survive the messy team, the tidy teams would be easy. And if it &lt;em&gt;couldn&amp;rsquo;t&lt;/em&gt;, I wanted to find that out early and cheaply, with one group, instead of discovering it mid-rollout with everyone watching.&lt;/p&gt;
&lt;p&gt;That group knew they were the stress test, and I told them so plainly. Being the guinea pig is more palatable when it&amp;rsquo;s framed as &lt;em&gt;your feedback shapes what everyone else gets&lt;/em&gt; rather than &lt;em&gt;you&amp;rsquo;re the ones we&amp;rsquo;re experimenting on.&lt;/em&gt; The distinction is entirely in the framing, and it matters more than it should.&lt;/p&gt;
&lt;h2&gt;Running two systems on purpose&lt;span class="hx:absolute hx:-mt-20" id="running-two-systems-on-purpose"&gt;&lt;/span&gt;
&lt;a href="#running-two-systems-on-purpose" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;For each team, the sheet didn&amp;rsquo;t die the day the portal arrived. They ran in parallel for a stretch — portal for real work, sheet as the safety net nobody was forced to let go of yet. This is inefficient and I did it anyway, because the alternative — demanding a leap of faith — is how you turn nervous users into hostile ones.&lt;/p&gt;
&lt;p&gt;What actually retires a spreadsheet isn&amp;rsquo;t a mandate. It&amp;rsquo;s the moment someone realizes they haven&amp;rsquo;t opened it in two weeks and don&amp;rsquo;t miss it. You can&amp;rsquo;t order that feeling into existence; you can only make the portal good enough that it happens on its own, and give people the safety net until it does. Once a team stopped reaching for the sheet, &lt;em&gt;then&lt;/em&gt; it went away — team by team, on their timeline, not mine.&lt;/p&gt;
&lt;h2&gt;The hard part was never the software&lt;span class="hx:absolute hx:-mt-20" id="the-hard-part-was-never-the-software"&gt;&lt;/span&gt;
&lt;a href="#the-hard-part-was-never-the-software" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;I could have gotten the permissions model, the approval chains, and the timezone-aware scheduling technically right and still failed completely, because none of that was the actual obstacle. The obstacle was that I was asking people to give up the thing they trusted for the thing they didn&amp;rsquo;t, and no feature list wins that argument. Trust does.&lt;/p&gt;
&lt;p&gt;Building the trust looked like small, unglamorous things. Migrating a team&amp;rsquo;s real data in clean so their first impression of the portal wasn&amp;rsquo;t a mess they had to fix. Making the single most common task genuinely faster than the sheet had been, before touching anything fancy. Sitting with people while they used it instead of reading their complaints in a form. Letting the pilot team&amp;rsquo;s frustrations visibly change the product, so the &lt;em&gt;next&lt;/em&gt; team could see that feedback here actually went somewhere. None of that shows up on a roadmap. All of it was the real work.&lt;/p&gt;
&lt;h2&gt;What I&amp;rsquo;d carry into the next one&lt;span class="hx:absolute hx:-mt-20" id="what-id-carry-into-the-next-one"&gt;&lt;/span&gt;
&lt;a href="#what-id-carry-into-the-next-one" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The lesson that outlives this project: a migration is a trust exercise disguised as a technical one, and the sequencing &lt;em&gt;is&lt;/em&gt; the strategy. Who goes first, how long the old thing survives alongside the new, whether people feel like participants or test subjects — those decisions determined whether this worked far more than any feature did. Excel is gone across the org now, but not because we switched it off. It&amp;rsquo;s gone because, one team at a time, people stopped reaching for it.&lt;/p&gt;</description></item></channel></rss>