This is a submission for the GitHub Finish-Up-A-Thon Challenge
What I Built
FinPal is an AI-powered personal finance companion built specifically for India's UPI ecosystem — the world's largest real-time payments network with over 350 million active users.
The problem it solves is real and largely ignored by mainstream finance apps: if you're an Indian user, your transaction history is scattered across Google Pay, PhonePe, Paytm, and your bank's PDF statements. There is no single place to see it all, categorize it, and actually understand where your money goes. Western apps like Mint or YNAB don't understand UPI. Indian banking apps don't talk to each other.
FinPal does. Upload your GPay history CSV, your bank statement PDF, or your PhonePe export — and it parses, categorizes, and analyzes everything in one dashboard using a hybrid rule-based + Google Gemini AI system.
Tech stack: React 18 + TypeScript, Vite, TailwindCSS, shadcn/ui, Framer Motion, Recharts, Node.js + Express backend, Google Gemini AI, Radix UI.
Repo: github.com/Tejas164321/FinPal
Demo
🔗 Live app: finpal.tejasfolio.in
The dashboard shows real financial overview cards, interactive monthly trend charts, category breakdowns, and budget progress tracking. The Transactions page now accepts CSV/PDF uploads, the AI Insights tab runs live Gemini analysis, the Budgets page has full CRUD, and the Investments page has working SIP/FD calculators.
The Comeback Story
Where It Was: The Beautiful Graveyard
Three months ago, I had 137 commits and a project that looked stunning from the outside and was completely hollow on the inside.
The homepage was polished. The dashboard rendered beautiful charts with mock data. The glassmorphism dark UI was exactly what I'd envisioned. And then there were four pages — Transactions, Budgets, AI Insights, and Investments — that each showed a placeholder:
🚧 Coming Soon
This feature is under development
The backend existed (/server) with file processing architecture — multer for uploads, csv-parser, pdf-parse, xlsx — all wired up to handle UPI file formats. But it wasn't connected to anything on the frontend. The Gemini AI integration was marked in the README as "architecture prepared." The SIP calculators were listed under "Future Enhancements."
I'd built the skeleton of something genuinely useful and then got buried in other work. The repo sat there with its four placeholder pages, deployed but empty.
Why It Stalled
The honest reason: I built FinPal in a sprint and the codebase grew faster than my documentation. Coming back to it after two months felt like picking up someone else's project. The component tree was deep. The custom hooks were tightly coupled to mock data. I knew what I wanted to build — I just couldn't remember how I'd set everything up, and re-reading 137 commits of history to reconstruct the mental model felt like a week of work before writing a single line.
That's where GitHub Copilot changed everything.
What Changed: The Before → After
Transactions Page
- Before: Placeholder page with a "Coming Soon" card
- After: Drag-and-drop file upload zone (CSV/PDF/Excel), transaction table with pagination, AI/Rule source indicators per row, search and filter, real-time parsing status
Budgets Page
- Before: Empty shell
- After: Budget creation form with category selection, progress bars with percentage tracking, over-budget alerts, monthly reset logic, edit/delete functionality
AI Insights Page
- Before: Listed in README as "Gemini-powered analysis and chat — architecture prepared"
- After: Live Gemini API integration, spending pattern analysis cards, natural language chat interface, personalized recommendations based on actual uploaded transactions
Investments Page
- Before: "SIP calculators and portfolio comparison" listed under Future Enhancements
- After: SIP calculator with compound interest visualization, FD calculator, maturity comparison chart, editable parameters with real-time chart updates
Backend
- Before: Server folder existed with file processing modules but no connected API routes
-
After:
/api/uploadendpoint fully wired, transaction parsing pipeline connected to frontend, Gemini analysis endpoint live
My Experience with GitHub Copilot
This is the part I want to be specific about, because "Copilot helped me write code faster" is a nothing statement. Here's what it actually did.
1. Re-onboarding to My Own Codebase
The first thing I did after reopening the project was open GitHub Copilot Chat and ask:
"Explain the data flow in this codebase from a file upload to displaying transactions on the dashboard. Reference the actual files."
Copilot walked me through server/server.js → server/processors/ → the React Query hooks in src/hooks/ → the dashboard component. It took 4 minutes to get back the mental model that would have taken me hours of reading commits. That alone was worth it.
2. Generating the Transaction Parser
The most complex piece was the UPI transaction parser. Different banks export CSV in completely different formats. GPay's export has different column headers than HDFC Bank's statement. Copilot generated the initial parsing logic:
// Copilot generated this parsing strategy after I described the problem
const detectFormat = (headers: string[]): 'gpay' | 'phonepe' | 'hdfc' | 'sbi' | 'generic' => {
const headerStr = headers.join(',').toLowerCase();
if (headerStr.includes('transaction id') && headerStr.includes('upi')) return 'gpay';
if (headerStr.includes('transaction ref') && headerStr.includes('phone')) return 'phonepe';
if (headerStr.includes('narration') && headerStr.includes('chq/ref')) return 'hdfc';
if (headerStr.includes('txn id') && headerStr.includes('ref no')) return 'sbi';
return 'generic';
};
const normalizeTransaction = (row: Record, format: string): Transaction => {
const formatMap = {
gpay: { date: 'Date', amount: 'Amount (INR)', description: 'Description', type: 'Transaction Type' },
phonepe: { date: 'Date', amount: 'Amount', description: 'Transaction Details', type: 'Type' },
hdfc: { date: 'Date', amount: 'Withdrawal Amt.', description: 'Narration', type: null },
sbi: { date: 'Txn Date', amount: 'Debit', description: 'Description', type: null },
generic: { date: 'date', amount: 'amount', description: 'description', type: 'type' }
};
// ... normalization logic
};
I described the problem — multiple CSV formats, need a normalizer — and Copilot drafted this structure. I modified the field mappings and added error handling. What would have been 2 hours of trial-and-error across real bank exports took 25 minutes.
3. The Gemini AI Integration
The AI Insights page needed Gemini to analyze spending patterns and return structured recommendations. I prompted Copilot:
"Write a function that sends transaction data to Google Gemini and returns categorized spending insights as structured JSON."
const analyzeWithGemini = async (transactions: Transaction[]): Promise => {
const prompt = `
Analyze these UPI transactions for an Indian user and return a JSON object with:
- topCategories: array of {category, amount, percentage, trend}
- savingsOpportunity: string (specific actionable tip)
- unusualSpending: array of flagged transactions
- monthlyComparison: {current, previous, change}
Transactions: ${JSON.stringify(transactions.slice(0, 50))}
Respond ONLY with valid JSON, no markdown.
`;
const result = await genAI.getGenerativeModel({ model: 'gemini-pro' }).generateContent(prompt);
return JSON.parse(result.response.text());
};
The key insight Copilot helped me land: constraining the output to JSON and specifying the exact schema in the prompt. My initial attempts returned markdown-wrapped JSON that broke the parser. Copilot suggested the "Respond ONLY with valid JSON" constraint after I described the problem.
4. SIP Calculator with Live Chart
The investments page needed a SIP calculator where changing the inputs updates the chart in real time. Copilot wrote the compound interest formula and the Recharts integration in one shot:
const calculateSIP = (
monthlyAmount: number,
annualRate: number,
years: number
): SIPResult[] => {
const monthlyRate = annualRate / 12 / 100;
const months = years * 12;
return Array.from({ length: months }, (_, i) => {
const month = i + 1;
const invested = monthlyAmount * month;
const returns = monthlyAmount *
((Math.pow(1 + monthlyRate, month) - 1) / monthlyRate) *
(1 + monthlyRate);
return {
month,
invested,
returns: Math.round(returns),
gain: Math.round(returns - invested)
};
});
};
I connected this to a useState hook for the inputs and wired the output directly to a Recharts AreaChart. The real-time update as you slide the monthly amount input is one of the most satisfying moments in the whole app.
5. What Copilot Couldn't Do
In the spirit of honesty: Copilot didn't understand the UPI-specific domain context without heavy prompting. It generated generic "credit/debit" category logic that missed obvious Indian patterns like "Swiggy" → Food Delivery, "IRCTC" → Travel, "Zepto" → Groceries. I had to build the Indian merchant categorization rules manually — a lookup table of ~80 common UPI merchant patterns. Copilot helped me structure it, but the domain knowledge was mine.
It also occasionally hallucinated Recharts API props that don't exist. Cross-referencing the Recharts docs was still necessary. Copilot is a fast first draft, not a final implementation.
The Numbers
| Metric | Before | After |
|---|---|---|
| Feature pages working | 2 of 6 | 6 of 6 |
| Lines of code added | — | ~2,400 |
| API endpoints connected | 0 | 4 |
| Time to finish (with Copilot) | Estimated 3 weeks | 8 days |
| File formats supported | 0 | 4 (GPay, PhonePe, HDFC, SBI) |
Why FinPal Matters
350 million Indians transact on UPI every month. The average urban Indian does 40+ UPI transactions monthly — food delivery, transport, groceries, rent. All of it flows through 3-4 different apps with no unified view.
FinPal is the tool I wanted and couldn't find. It's not a generic expense tracker. It's built for the specific reality of how Indian digital payments work: the merchant names, the UPI IDs, the bank statement formats, the SIP culture, the FD-first savings mentality.
GitHub Copilot helped me finish it in 8 days instead of 3 weeks. More importantly, it helped me pick up a codebase I'd half-forgotten and start shipping immediately instead of spending days just getting reoriented.
The project is live. The placeholder pages are gone. FinPal is finally FinPal.
🔗 Live Demo: finpalai.vercel.app
📦 Repo: github.com/Tejas164321/FinPal
If you're an Indian developer building for the UPI ecosystem, I'd love to connect. Drop your thoughts in the comments — especially if you've tried parsing HDFC/SBI statements. The column naming inconsistencies deserve their own post.
Top comments (0)