<?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: PARITOSH</title>
    <description>The latest articles on DEV Community by PARITOSH (@kparitosh760).</description>
    <link>https://dev.to/kparitosh760</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%2F4159550%2Ff73b88aa-dd80-4793-9c7e-879f9269c183.jpg</url>
      <title>DEV Community: PARITOSH</title>
      <link>https://dev.to/kparitosh760</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kparitosh760"/>
    <language>en</language>
    <item>
      <title>Spend Review: I read my friend's bank statement so she never has to</title>
      <dc:creator>PARITOSH</dc:creator>
      <pubDate>Sat, 03 Oct 2026 16:25:54 +0000</pubDate>
      <link>https://dev.to/kparitosh760/spend-review-i-read-my-friends-bank-statement-so-she-never-has-to-2jo</link>
      <guid>https://dev.to/kparitosh760/spend-review-i-read-my-friends-bank-statement-so-she-never-has-to-2jo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built this for my friend Sagrika, who spends like the money is not real and then&lt;br&gt;
arrives at the end of the month genuinely puzzled about where it went. Not reckless,&lt;br&gt;
exactly just a hundred small decisions that never felt like decisions, and no way to&lt;br&gt;
see them stacked up. Her bank sends her a statement every month. She has never once&lt;br&gt;
read it, and having now read one myself, I understand why.&lt;/p&gt;

&lt;p&gt;Every Indian bank hands you a statement and calls it insight. HDFC's is a 342-row&lt;br&gt;
&lt;code&gt;.xls&lt;/code&gt; where the first 20 rows are your address, the transaction you care about is&lt;br&gt;
described as &lt;code&gt;UPI-SOMTHING HOSPITALITY PVT-Q6245659728@YBL-YESB0YBLUPI-645845694696-PAID&lt;br&gt;
VIA SUPERMONEY&lt;/code&gt;, and nothing anywhere tells you that you spent ₹6,755 on food.&lt;/p&gt;

&lt;p&gt;The usual fix is to upload the statement to a budgeting site. That is the part I&lt;br&gt;
would not do. A bank statement is a complete record of where you were and who you&lt;br&gt;
paid for six months — it is not a file to hand to a free web service in exchange for&lt;br&gt;
a pie chart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spend Review&lt;/strong&gt; is a single-file Streamlit app that reads the statement, finds the&lt;br&gt;
real transaction table inside the bank's formatting, and sorts six months of spending&lt;br&gt;
into 14 categories. It holds nothing. The file is parsed in memory and gone when you&lt;br&gt;
close the tab.&lt;/p&gt;

&lt;p&gt;Upload, and you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total spent, total received, transaction count&lt;/li&gt;
&lt;li&gt;Spend per category with each category's share&lt;/li&gt;
&lt;li&gt;Top 20 payees, with the bank's narration string cleaned into an actual name&lt;/li&gt;
&lt;li&gt;A filterable table of every transaction, downloadable as CSV&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole app. It doesn't set budgets, it doesn't send reminders, and it will&lt;br&gt;
never tell her to stop buying things. It just makes six months of small decisions&lt;br&gt;
visible in one screen, which turns out to be the part that was missing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/FeIFKTT9Fo0" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Hosted demo: &lt;strong&gt;&lt;a href="https://spend-review.onrender.com" rel="noopener noreferrer"&gt;https://spend-review.onrender.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Free tier, so the first load takes about a minute while the service wakes up — give it&lt;br&gt;
a moment before deciding it's broken. Nothing you upload is stored, by the service or&lt;br&gt;
by me; the file is parsed in memory and dropped when you close the tab.&lt;/p&gt;

&lt;p&gt;In the recording: six months of an HDFC statement goes in as the bank exported it,&lt;br&gt;
342 rows of letterhead and footer and all, and 294 categorised transactions come out.&lt;br&gt;
The surprise is not the food row. It's that the subscriptions row is more than twice&lt;br&gt;
as large, spread over fourteen charges small enough that none of them ever felt like&lt;br&gt;
spending money.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Pager-dot" rel="noopener noreferrer"&gt;
        Pager-dot
      &lt;/a&gt; / &lt;a href="https://github.com/Pager-dot/spend-review" rel="noopener noreferrer"&gt;
        spend-review
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Streamlit app that categorises HDFC bank statement spending
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Spend Review&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A small Streamlit app that reads an HDFC Bank account statement (&lt;code&gt;.xls&lt;/code&gt; / &lt;code&gt;.xlsx&lt;/code&gt;)
and groups the transactions into spending categories.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live demo: &lt;a href="https://spend-review.onrender.com" rel="nofollow noopener noreferrer"&gt;https://spend-review.onrender.com&lt;/a&gt;&lt;/strong&gt; — free tier, so the first load
takes about a minute while the service wakes up. Nothing you upload is stored.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run locally&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install -r requirements.txt
streamlit run app.py&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Then upload your statement in the browser.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it shows&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Total spent, total received, transaction count&lt;/li&gt;
&lt;li&gt;Spend by category, with each category's share&lt;/li&gt;
&lt;li&gt;Top payees&lt;/li&gt;
&lt;li&gt;A filterable transaction table, downloadable as CSV&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Categories&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Categorisation is keyword matching on the transaction narration. The rules live in
the &lt;code&gt;RULES&lt;/code&gt; dict at the top of &lt;code&gt;app.py&lt;/code&gt; — add keywords there to tune it.&lt;/p&gt;
&lt;p&gt;Person-to-person UPI transfers fall into a single &lt;code&gt;Transfers to People&lt;/code&gt; bucket,
since those narrations carry only a name and no merchant information.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Privacy&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Uploaded statements are parsed in memory and never written…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Pager-dot/spend-review" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Streamlit, pandas, and about 200 lines of Python. No model, no API, no database. The&lt;br&gt;
interesting parts were all in the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;The honest version of my answer is that open innovation let me not use an API at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It costs nothing and cannot be taken away.&lt;/strong&gt; No key, no account, no quota, no&lt;br&gt;
pricing-page change in eighteen months. &lt;code&gt;pip install -r requirements.txt&lt;/code&gt; and it runs,&lt;br&gt;
today or in five years, with the Wi-Fi off. Free-tier API keys are the one component&lt;br&gt;
of a weekend project most likely to be dead before anyone else tries to run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;Built in an evening with Claude Code. The useful division of labour turned out to be&lt;br&gt;
that it did the archaeology and I did the judgement calls.&lt;/p&gt;

&lt;p&gt;It opened the &lt;code&gt;.xls&lt;/code&gt;, found the header at row 20, worked out that &lt;code&gt;xlrd&lt;/code&gt; was required,&lt;br&gt;
built the keyword rules from the actual narration strings in my statement rather than&lt;br&gt;
from a guess about Indian merchants, and caught the &lt;code&gt;$PORT&lt;/code&gt; binding issue before the&lt;br&gt;
first Render deploy instead of after it.&lt;/p&gt;

&lt;p&gt;Two moments worth recording. When I asked it to make a public repo it checked what was&lt;br&gt;
staged and grepped the committed history for my account number and card digits before&lt;br&gt;
pushing — the statement was gitignored, but it verified rather than assumed. And when I&lt;br&gt;
said &lt;em&gt;"make sure nothing is stored"&lt;/em&gt;, it came back with the &lt;code&gt;cache_data&lt;/code&gt; decorator it&lt;br&gt;
had itself added two steps earlier, and explained why that was the one thing in the app&lt;br&gt;
that broke the promise. I would not have found that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;Best Use of Render&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
