<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>Thu, 23 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://sauravjalui.com/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>The Most Ambitious Thing I Haven't Built Yet</title><link>https://sauravjalui.com/blog/marketing-crm/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate><guid>https://sauravjalui.com/blog/marketing-crm/</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;
Design Note · Before the Build
&lt;/a&gt;
&lt;p&gt;Everything our marketing team knows about a prospective student lives in someone&amp;rsquo;s phone. A parent enquires through the website, someone WhatsApps them, a trial gets scheduled in a message thread, the student either turns up or doesn&amp;rsquo;t, and somewhere in that chain the only record of what happened is a coordinator&amp;rsquo;s memory. We know how many leads arrive. We are much fuzzier on where they die.&lt;/p&gt;
&lt;p&gt;So I&amp;rsquo;ve spent the last stretch designing a marketing portal to sit inside the platform we already run: lead capture, pipeline stages, WhatsApp at each stage, tasks, campaigns, reporting. &lt;strong&gt;None of it is built.&lt;/strong&gt; What exists is a clickable prototype and a five-sprint plan, and I&amp;rsquo;m writing this before a line of production code on purpose. More on why at the end.&lt;/p&gt;
&lt;h2&gt;Why not just buy a CRM&lt;span class="hx:absolute hx:-mt-20" id="why-not-just-buy-a-crm"&gt;&lt;/span&gt;
&lt;a href="#why-not-just-buy-a-crm" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;This was the first question, and it deserved more than the answer I wanted to give.&lt;/p&gt;
&lt;p&gt;Plenty of CRMs do pipelines and messaging better than anything I&amp;rsquo;d build in five sprints. HubSpot, Zoho, and LeadSquared are all more mature than what I&amp;rsquo;ve drawn, and buying one would have been faster. The honest case for buying is strong, and I want to state it properly rather than knock down a strawman.&lt;/p&gt;
&lt;p&gt;The case for building comes down to one thing: &lt;strong&gt;a bought CRM doesn&amp;rsquo;t know our students.&lt;/strong&gt; It sits outside the platform, so it sees a phone number and a form submission. It cannot tell you that the lead you&amp;rsquo;re about to send a cold SAT welcome to is already enrolled in your IBDP course, or that their sibling took a trial in March, or that the tutor they&amp;rsquo;re being pitched is the one who taught them last year. That context is already in our database. Getting it into an external CRM means building and maintaining a sync, and a sync is a thing that breaks quietly.&lt;/p&gt;
&lt;p&gt;In the prototype, this shows up as an unglamorous detail: a small &lt;strong&gt;STUDENT&lt;/strong&gt; badge on leads who already exist in the portal. It&amp;rsquo;s the whole argument in one label. Same student records, same teacher records, same admins, same permissions model, the one we already fought for during the migration off spreadsheets. Nobody needs a second login or a second set of roles.&lt;/p&gt;
&lt;p&gt;If that badge turns out not to matter, the build-versus-buy call was wrong. I&amp;rsquo;d rather write that sentence now than defend it later.&lt;/p&gt;
&lt;h2&gt;Making &amp;ldquo;WhatsApp Sent&amp;rdquo; a stage&lt;span class="hx:absolute hx:-mt-20" id="making-whatsapp-sent-a-stage"&gt;&lt;/span&gt;
&lt;a href="#making-whatsapp-sent-a-stage" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The pipeline has six stages: lead captured, WhatsApp sent, trial scheduled, trial taken, feedback collected, enrolled or nurture.&lt;/p&gt;
&lt;p&gt;Most CRMs wouldn&amp;rsquo;t make the second one a stage. Sending a message is an &lt;em&gt;activity&lt;/em&gt;, something you log against a lead, not a place the lead sits. Modelling it as a stage is arguably wrong.&lt;/p&gt;
&lt;p&gt;I did it anyway, because of what it forces the funnel to measure. If &amp;ldquo;WhatsApp sent&amp;rdquo; is just an activity, the funnel tracks how prospects behave. If it&amp;rsquo;s a stage, the funnel also tracks &lt;strong&gt;how fast we respond&lt;/strong&gt;. A lead sitting in &amp;ldquo;captured&amp;rdquo; for two days becomes visibly our failure rather than an unremarkable row in a list. Most of our leakage, I suspect, isn&amp;rsquo;t people saying no. It&amp;rsquo;s people not being contacted while they still cared.&lt;/p&gt;
&lt;p&gt;Messages are mapped to stages automatically, and branch on exam type: an SAT lead gets a different welcome from an IBDP lead. Eighteen templates covering welcomes, tips, trial invitations, demo confirmations and reminders, post-demo follow-up, enrollment, cross-sell, re-engagement, deadline nudges, new batches, and festival greetings.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://sauravjalui.com/images/crm-pipeline.webp" alt="The six-stage pipeline, with leads grouped by stage" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;The part that nags you&lt;span class="hx:absolute hx:-mt-20" id="the-part-that-nags-you"&gt;&lt;/span&gt;
&lt;a href="#the-part-that-nags-you" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The last internal tool I worked on taught me an expensive lesson: adoption is a trust problem, and a tool that arrives as something done &lt;em&gt;to&lt;/em&gt; people gets rejected no matter how fast it is.&lt;/p&gt;
&lt;p&gt;So the feature I care most about isn&amp;rsquo;t the pipeline. It&amp;rsquo;s the task queue, the tab that tells a coordinator what&amp;rsquo;s gone wrong: leads with no WhatsApp after 24 hours, demos that finished with no follow-up, anything stale for a week or more. A database waits to be searched. This is supposed to interrupt you.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://sauravjalui.com/images/crm-tasks.webp" alt="The task queue: overdue follow-ups, stale leads, missed post-demo contact" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s the difference between a system of record and a system that does work, and it&amp;rsquo;s the thing I&amp;rsquo;d protect if scope has to be cut. Alongside it sit two guardrails that exist purely because messaging at volume goes wrong in predictable ways: duplicate detection when logging a call, and a spam-health warning when someone is about to bulk-send to a segment that&amp;rsquo;s heard from us too recently.&lt;/p&gt;
&lt;h2&gt;Sequencing is the strategy again&lt;span class="hx:absolute hx:-mt-20" id="sequencing-is-the-strategy-again"&gt;&lt;/span&gt;
&lt;a href="#sequencing-is-the-strategy-again" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Five sprints: core pipeline, then WhatsApp and bulk send, then trial and enrollment, then tasks and campaigns, then reports and calendar.&lt;/p&gt;
&lt;p&gt;The constraint I set was that every sprint has to leave behind something usable on its own. Sprint 1 with nothing after it is still a shared lead list with stages, which beats a phone. Sprint 2 makes the messaging real. Nothing depends on sprint 5 existing.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t a project-management preference, it&amp;rsquo;s the same lesson as the spreadsheet migration: what determines whether a rollout works is the order you do it in and how much people can trust each step. If the first thing the team touches is half a product that only makes sense once all five sprints land, I&amp;rsquo;ve already lost them.&lt;/p&gt;
&lt;h2&gt;What the prototype gets wrong&lt;span class="hx:absolute hx:-mt-20" id="what-the-prototype-gets-wrong"&gt;&lt;/span&gt;
&lt;a href="#what-the-prototype-gets-wrong" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;There is no consent model in it. Not a weak one. None.&lt;/p&gt;
&lt;p&gt;Leads get messaged automatically on stage transition, and there is no opt-in captured, no unsubscribe path, and no record of who asked us to stop. WhatsApp&amp;rsquo;s own rules require opt-in for template messages, and under the DPDP Act this isn&amp;rsquo;t a formality. I built an automation engine and forgot to build the brakes, which is a fairly damning thing to notice about your own design, and exactly the kind of omission that&amp;rsquo;s cheap to fix now and expensive after the first complaint.&lt;/p&gt;
&lt;p&gt;It goes into sprint 1. Not sprint 5.&lt;/p&gt;
&lt;h2&gt;What I think will happen&lt;span class="hx:absolute hx:-mt-20" id="what-i-think-will-happen"&gt;&lt;/span&gt;
&lt;a href="#what-i-think-will-happen" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Here&amp;rsquo;s the part I&amp;rsquo;d normally leave out. Predictions, on record, before the build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The biggest leak is trial scheduled → trial taken.&lt;/strong&gt; Not enquiry-to-contact, which is where everyone assumes the problem is. People book and then don&amp;rsquo;t turn up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The task queue gets used more than the reports.&lt;/strong&gt; Reporting is what gets asked for in meetings; the overdue list is what people open on a Tuesday morning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated messages will out-perform manual ones on speed and under-perform on replies.&lt;/strong&gt; Faster, and slightly more ignorable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The STUDENT badge will matter more than I can currently justify&lt;/strong&gt;, mostly by preventing embarrassment rather than by creating revenue, which makes it hard to measure and easy to cut.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Something in sprints 4–5 won&amp;rsquo;t survive contact with the team.&lt;/strong&gt; I don&amp;rsquo;t know which. Campaign tracking is my guess.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Why publish this now&lt;span class="hx:absolute hx:-mt-20" id="why-publish-this-now"&gt;&lt;/span&gt;
&lt;a href="#why-publish-this-now" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Because a plan you wrote down can be wrong in a way you can check, and a plan you kept in your head gets quietly edited to match whatever happened.&lt;/p&gt;
&lt;p&gt;Once this ships, I&amp;rsquo;ll come back and grade every prediction above. That&amp;rsquo;s the actual point of putting it up before the build: not to look decisive, but to make the follow-up honest. If I&amp;rsquo;m wrong about most of it, that&amp;rsquo;s a more useful post than the one where I explain how it all went according to plan.&lt;/p&gt;</description></item><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. 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>