<?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>DEV Community: Bishnu Saha</title>
    <description>The latest articles on DEV Community by Bishnu Saha (@backend_null).</description>
    <link>https://dev.to/backend_null</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3989279%2F266e2ed4-919e-47a8-8b51-fc5a0b3984e3.jpg</url>
      <title>DEV Community: Bishnu Saha</title>
      <link>https://dev.to/backend_null</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/backend_null"/>
    <language>en</language>
    <item>
      <title>I Built a Bilingual Profit Tracker for My Father's Cyber Café — Here's the Stack and a Few Decisions Behind It</title>
      <dc:creator>Bishnu Saha</dc:creator>
      <pubDate>Mon, 06 Jul 2026 12:01:35 +0000</pubDate>
      <link>https://dev.to/backend_null/i-built-a-bilingual-profit-tracker-for-my-fathers-cyber-cafe-heres-the-stack-and-a-few-49kk</link>
      <guid>https://dev.to/backend_null/i-built-a-bilingual-profit-tracker-for-my-fathers-cyber-cafe-heres-the-stack-and-a-few-49kk</guid>
      <description>&lt;p&gt;My father runs a cyber café — one of the small service shops across India (CSCs, cyber cafés, Xerox/DTP counters) that resell government or utility services: Aadhaar updates, PAN cards, printing, bill payments, exam forms. The business model is simple: charge the customer a fixed fee, pay a smaller cost to the portal/vendor that actually processes it, keep the difference.&lt;/p&gt;

&lt;p&gt;The problem is just as simple, and just as easy to miss: he could always tell you how much cash came in for the day. He could almost never tell you how much of that was actually profit, because that means subtracting a different portal cost for every single service, every single transaction, in his head, at the end of a long day.&lt;/p&gt;

&lt;p&gt;So I built Khata ("ledger" in Hindi/Bengali) to do that subtraction for him, automatically, per transaction, in real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define each service once — name (English/Hindi/Bengali), an emoji icon, a default customer charge, and a default portal cost&lt;/li&gt;
&lt;li&gt;Log a transaction in two taps: pick the service, the charge/cost pre-fill, adjust quantity if it's a bulk job (e.g. 100 photocopies in one entry instead of 100 separate rows)&lt;/li&gt;
&lt;li&gt;Dashboard shows today's profit, collections, cost, and transaction count at a glance&lt;/li&gt;
&lt;li&gt;Reports over today/week/month/custom range with a 7-day profit trend chart&lt;/li&gt;
&lt;li&gt;Expense tracking (rent, electricity, stationery) separate from service transactions&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Full UI in English, Hindi, or Bengali&lt;br&gt;
&lt;strong&gt;The stack&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Frontend: React + Vite + TypeScript + Tailwind, i18next for the three locales&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Backend: Node.js + Express + TypeScript&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Auth: JWT in a signed httpOnly cookie — no client-side token handling at all&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database: Postgres via Supabase, but only ever touched from the backend&lt;br&gt;
&lt;strong&gt;A couple of decisions worth mentioning&lt;/strong&gt;&lt;br&gt;
RLS as a deny-by-default wall, not a per-row policy engine. Every table has Row Level Security enabled with zero policies for anon/authenticated. That's deliberate — RLS-enabled-with-no-policies denies all access by default. The backend connects with the service_role key, which bypasses RLS entirely. So the frontend has literally no path to talk to the database directly, and I didn't have to hand-write a policy for every table/role combination. The backend derives shop_id from the session cookie on every request and scopes every query to it, which is the actual multi-tenancy boundary.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Money math lives in the request path, not the UI. profit is a Postgres generated column (customer_charge - cost_paid), computed once, at the source of truth, instead of every consumer re-deriving it (and risking drift between the dashboard, reports, and the table view).&lt;/p&gt;

&lt;p&gt;Quantity as a multiplier, not a loop. Early on the only way to log "100 photocopies" was 100 identical rows. Adding a quantity field that scales charge/cost while staying overridable (for discounts or one-off pricing) removed almost all the friction my father actually complained about.&lt;/p&gt;

&lt;p&gt;i18n wasn't a layer bolted on later. Every service name, every label, is stored/rendered per-language from day one, because the actual users of this app are far more comfortable in Hindi or Bengali than English — an assumption a lot of small-business tools targeting India get backwards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;br&gt;
It's live and free: &lt;strong&gt;&lt;a href="https://khata-ebon.vercel.app/" rel="noopener noreferrer"&gt;https://khata-ebon.vercel.app/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built for one cyber café, but the shape of the problem (charge vs. cost, per transaction, in a language you actually think in) applies to a lot of small shops. Happy to answer questions about any of the above, especially the RLS/multi-tenancy setup — curious how others have handled a similar "backend-only DB access" pattern with Supabase.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>typescript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built a personal expense tracker because I kept lying to myself about money</title>
      <dc:creator>Bishnu Saha</dc:creator>
      <pubDate>Mon, 29 Jun 2026 07:17:47 +0000</pubDate>
      <link>https://dev.to/backend_null/i-built-a-personal-expense-tracker-because-i-kept-lying-to-myself-about-money-2a6d</link>
      <guid>https://dev.to/backend_null/i-built-a-personal-expense-tracker-because-i-kept-lying-to-myself-about-money-2a6d</guid>
      <description>&lt;p&gt;I'm bad with money. Not "forgot to save" bad — "spent ₹4,000 on food delivery in &lt;br&gt;
one week and convinced myself it was fine" bad.&lt;/p&gt;

&lt;p&gt;I tried spreadsheets. I tried apps. Nothing stuck. Either too complex, too ugly, &lt;br&gt;
or needed a subscription for features that should be free.&lt;/p&gt;

&lt;p&gt;So I built Spendly. A simple, fast expense tracker that actually fits how I think &lt;br&gt;
about money.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi6y3qhtce739c08x1v6b.png" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi6y3qhtce739c08x1v6b.png" alt=" " width="799" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Log expenses in under 10 seconds&lt;/li&gt;
&lt;li&gt;Organise by category with custom icons and colours&lt;/li&gt;
&lt;li&gt;Track a monthly budget and see exactly where you're over&lt;/li&gt;
&lt;li&gt;Set savings goals with a visual progress ring&lt;/li&gt;
&lt;li&gt;Recurring expenses that auto-log themselves daily&lt;/li&gt;
&lt;li&gt;Income sources (freelance, salary, side projects)&lt;/li&gt;
&lt;li&gt;Dark mode, because obviously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's live at &lt;a href="https://spendly.it.com" rel="noopener noreferrer"&gt;spendly.it.com&lt;/a&gt; — free, no credit card.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: React + Vite, deployed on Vercel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Express + Prisma, deployed on Render (free tier)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: Supabase (PostgreSQL)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Boring and correct. The free tier combo of Render + Vercel + Supabase means &lt;br&gt;
$0/month to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bugs that taught me things
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The timezone nightmare
&lt;/h3&gt;

&lt;p&gt;I built a "salary cycle" feature — expenses reset on whatever day your salary lands, &lt;br&gt;
not on the 1st of the month. Smart idea. Terrible execution the first time.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;getCycleRange()&lt;/code&gt; helper was mixing local time and UTC. The client (IST, UTC+5:30) &lt;br&gt;
would compute &lt;code&gt;cycleStart&lt;/code&gt; and send it as an ISO string. The server, running UTC, &lt;br&gt;
would parse it and quietly shift into the previous month. Result: empty expense lists &lt;br&gt;
in production, everything working perfectly in local dev.&lt;/p&gt;

&lt;p&gt;Fix: use UTC methods everywhere, consistently.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>I Built a Free Expense Tracker Because I Was Terrible With Money</title>
      <dc:creator>Bishnu Saha</dc:creator>
      <pubDate>Wed, 17 Jun 2026 14:26:06 +0000</pubDate>
      <link>https://dev.to/backend_null/i-built-a-free-expense-tracker-because-i-was-terrible-with-money-4jmo</link>
      <guid>https://dev.to/backend_null/i-built-a-free-expense-tracker-because-i-was-terrible-with-money-4jmo</guid>
      <description>&lt;p&gt;I used to check my bank balance at the end of every month and just stare at it.&lt;/p&gt;

&lt;p&gt;Good salary. Nothing saved. No idea where it went.&lt;/p&gt;

&lt;p&gt;I tried spreadsheets. I tried Mint. I tried YNAB. Every app was either too complex, too expensive, or just not something I'd actually open every day.&lt;/p&gt;

&lt;p&gt;So I built my own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Spendly?&lt;/strong&gt;&lt;br&gt;
Spendly is a free, clean monthly expense tracker built for people who just want to know where their money goes — without learning a new system.&lt;/p&gt;

&lt;p&gt;No bank account linking. No subscription. No complexity.&lt;/p&gt;

&lt;p&gt;Just: open it, add an expense, close it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live: &lt;a href="https://spendly.it.com" rel="noopener noreferrer"&gt;https://spendly.it.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does&lt;/strong&gt;&lt;br&gt;
Add and categorize daily expenses in seconds&lt;br&gt;
Set a monthly budget and track it in real time&lt;br&gt;
Visual donut chart — breakdown by category&lt;br&gt;
Cycle history bars — compare spending month over month&lt;br&gt;
Savings goals tracker&lt;br&gt;
Dark mode&lt;br&gt;
Works on any device — no installation needed&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech stack
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt; — React + Vite, deployed on Vercel&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt; — Node.js + Express + Prisma, deployed on Render&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt; — PostgreSQL via Supabase&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auth&lt;/strong&gt; — JWT stored in localStorage&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hardest bug I fixed&lt;/strong&gt;&lt;br&gt;
The most frustrating bug was a timezone mismatch in production.&lt;/p&gt;

&lt;p&gt;My cycle helper was using local time methods (new Date(year, month, day)) on the client. But the server runs in UTC. So when I was in IST (UTC+5:30), the client sent a cycleStart ISO string that the server mis-parsed into the previous month — returning zero expenses every time.&lt;/p&gt;

&lt;p&gt;Fix: use UTC methods everywhere (getUTCFullYear, getUTCMonth, Date.UTC()) on both client and server.&lt;/p&gt;

&lt;p&gt;Lesson: always use UTC in production. Local time will betray you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I learned building this&lt;/strong&gt;&lt;br&gt;
Free tiers (Vercel + Render + Supabase) are genuinely powerful for solo projects&lt;br&gt;
Render cold starts on free tier are real — first load takes 30-50 seconds&lt;br&gt;
Prisma auto-camelCases column names — monthly_budget becomes monthlyBudget in JS&lt;br&gt;
Building for yourself first makes product decisions 10x easier&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's next&lt;/strong&gt;&lt;br&gt;
Mobile app (React Native)&lt;br&gt;
Recurring expenses&lt;br&gt;
Export to CSV&lt;br&gt;
Email summary every month&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://spendly.it.com" rel="noopener noreferrer"&gt;https://spendly.it.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's completely free. No ads. No premium tier. No credit card.&lt;/p&gt;

&lt;p&gt;I'm at about 10 users right now and genuinely want honest feedback — what would make you actually use an expense tracker every single day?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drop a comment — I read every one.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>react</category>
      <category>sideprojects</category>
    </item>
  </channel>
</rss>
