<title>SmartBudgetManager — README</title> <style> :root { --bg: #07070f; --surface: #0f0f1e; --surface2: #161628; --purple: #6c63ff; --pink: #ff6584; --green: #43e97b; --gold: #f7c948; --blue: #4facfe; --text: #e8e8f0; --muted: #6b6b8a; --border: #1e1e38; }
- { margin: 0; padding: 0; box-sizing: border-box; }
body { background: var(--bg); color: var(--text); font-family: 'Syne', sans-serif; overflow-x: hidden; min-height: 100vh; }
/* Animated background */ body::before { content: ''; position: fixed; inset: 0; background: radial-gradient(ellipse 80% 50% at 20% 20%, rgba(108,99,255,0.08) 0%, transparent 60%), radial-gradient(ellipse 60% 40% at 80% 80%, rgba(255,101,132,0.06) 0%, transparent 60%), radial-gradient(ellipse 50% 50% at 50% 50%, rgba(67,233,123,0.03) 0%, transparent 70%); pointer-events: none; z-index: 0; }
.container { max-width: 900px; margin: 0 auto; padding: 40px 24px 80px; position: relative; z-index: 1; }
/* Hero */ .hero { text-align: center; padding: 60px 0 40px; animation: fadeUp 0.8s ease both; }
.hero-emoji { font-size: 80px; display: block; animation: float 3s ease-in-out infinite; filter: drop-shadow(0 0 30px rgba(108,99,255,0.5)); }
@keyframes float { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-12px); } }
.hero h1 { font-size: clamp(2.5rem, 6vw, 4rem); font-weight: 800; margin-top: 20px; background: linear-gradient(135deg, #fff 0%, var(--purple) 50%, var(--pink) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; line-height: 1.1; }
.hero-sub { font-size: 1.1rem; color: var(--muted); margin-top: 16px; font-weight: 400; letter-spacing: 0.02em; }
/* Animated typewriter */ .typewriter { display: inline-block; color: var(--green); font-family: 'JetBrains Mono', monospace; font-size: 0.95rem; margin-top: 12px; border-right: 2px solid var(--green); white-space: nowrap; overflow: hidden; animation: typing 3.5s steps(50) 1s both, blink 0.8s step-end infinite; max-width: 100%; }
@keyframes typing { from { width: 0; } to { width: 100%; } }
@keyframes blink { 50% { border-color: transparent; } }
/* Badges */ .badges { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 24px; }
.badge { padding: 6px 16px; border-radius: 100px; font-size: 0.75rem; font-weight: 600; font-family: 'JetBrains Mono', monospace; letter-spacing: 0.05em; animation: fadeUp 0.6s ease both; }
.badge-purple { background: rgba(108,99,255,0.15); color: var(--purple); border: 1px solid rgba(108,99,255,0.3); } .badge-green { background: rgba(67,233,123,0.12); color: var(--green); border: 1px solid rgba(67,233,123,0.3); } .badge-pink { background: rgba(255,101,132,0.12); color: var(--pink); border: 1px solid rgba(255,101,132,0.3); } .badge-gold { background: rgba(247,201,72,0.12); color: var(--gold); border: 1px solid rgba(247,201,72,0.3); } .badge-blue { background: rgba(79,172,254,0.12); color: var(--blue); border: 1px solid rgba(79,172,254,0.3); }
/* Section */ .section { margin-top: 56px; animation: fadeUp 0.6s ease both; }
.section-label { font-family: 'JetBrains Mono', monospace; font-size: 0.7rem; color: var(--purple); letter-spacing: 0.2em; text-transform: uppercase; margin-bottom: 12px; }
.section h2 { font-size: 1.8rem; font-weight: 800; color: #fff; margin-bottom: 24px; }
/* Feature cards */ .features { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; }
.feature-card { background: var(--surface); border: 1px solid var(--border); border-radius: 20px; padding: 24px; transition: all 0.3s ease; position: relative; overflow: hidden; animation: fadeUp 0.6s ease both; }
.feature-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px; border-radius: 20px 20px 0 0; opacity: 0; transition: opacity 0.3s; }
.feature-card:hover { transform: translateY(-4px); border-color: rgba(108,99,255,0.3); } .feature-card:hover::before { opacity: 1; } .feature-card.purple::before { background: linear-gradient(90deg, var(--purple), var(--blue)); } .feature-card.pink::before { background: linear-gradient(90deg, var(--pink), var(--gold)); } .feature-card.green::before { background: linear-gradient(90deg, var(--green), var(--blue)); }
.feature-icon { font-size: 2rem; margin-bottom: 14px; display: block; }
.feature-card h3 { font-size: 1rem; font-weight: 700; color: #fff; margin-bottom: 8px; }
.feature-card p { font-size: 0.875rem; color: var(--muted); line-height: 1.6; font-weight: 400; }
/* Tech stack */ .tech-grid { display: flex; flex-wrap: wrap; gap: 10px; }
.tech-pill { display: flex; align-items: center; gap: 8px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 10px 16px; font-size: 0.85rem; font-weight: 600; transition: all 0.2s; cursor: default; }
.tech-pill:hover { border-color: var(--purple); background: rgba(108,99,255,0.08); transform: scale(1.03); } .tech-pill span { font-size: 1.2rem; }
/* Steps */ .steps { display: flex; flex-direction: column; gap: 0; }
.step { display: flex; gap: 20px; position: relative; animation: fadeUp 0.5s ease both; }
.step:not(:last-child)::after { content: ''; position: absolute; left: 19px; top: 44px; bottom: -16px; width: 2px; background: linear-gradient(180deg, var(--purple), transparent); }
.step-num { width: 40px; height: 40px; min-width: 40px; border-radius: 12px; background: linear-gradient(135deg, var(--purple), var(--blue)); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 0.9rem; margin-top: 4px; box-shadow: 0 4px 20px rgba(108,99,255,0.3); }
.step-content { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 20px 24px; flex: 1; margin-bottom: 16px; transition: border-color 0.2s; }
.step-content:hover { border-color: rgba(108,99,255,0.25); }
.step-content h3 { font-size: 1rem; font-weight: 700; color: #fff; margin-bottom: 10px; }
.step-content p { font-size: 0.875rem; color: var(--muted); margin-bottom: 12px; line-height: 1.6; }
/* Code blocks */ pre { background: #0a0a16; border: 1px solid var(--border); border-radius: 12px; padding: 16px; overflow-x: auto; position: relative; }
code { font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; color: var(--green); line-height: 1.7; }
.code-comment { color: #3d3d5c; } .code-key { color: var(--blue); } .code-val { color: var(--gold); }
/* Copy button */ .code-wrapper { position: relative; }
.copy-btn { position: absolute; top: 10px; right: 10px; background: rgba(108,99,255,0.2); border: 1px solid rgba(108,99,255,0.3); color: var(--purple); border-radius: 8px; padding: 4px 10px; font-size: 0.7rem; font-family: 'JetBrains Mono', monospace; cursor: pointer; transition: all 0.2s; }
.copy-btn:hover { background: rgba(108,99,255,0.35); }
/* Buttons */ .btn-row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 32px; justify-content: center; }
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 14px 28px; border-radius: 14px; font-weight: 700; font-size: 0.9rem; font-family: 'Syne', sans-serif; cursor: pointer; border: none; text-decoration: none; transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1); position: relative; overflow: hidden; }
.btn::after { content: ''; position: absolute; inset: 0; background: rgba(255,255,255,0.1); opacity: 0; transition: opacity 0.2s; }
.btn:hover { transform: translateY(-3px) scale(1.03); } .btn:hover::after { opacity: 1; } .btn:active { transform: scale(0.97); }
.btn-purple { background: linear-gradient(135deg, var(--purple), #8b5cf6); color: #fff; box-shadow: 0 8px 24px rgba(108,99,255,0.35); }
.btn-green { background: linear-gradient(135deg, #1a3a2a, #1e4a30); color: var(--green); border: 1px solid rgba(67,233,123,0.3); box-shadow: 0 8px 24px rgba(67,233,123,0.1); }
.btn-pink { background: linear-gradient(135deg, #3a1a22, #4a1a28); color: var(--pink); border: 1px solid rgba(255,101,132,0.3); box-shadow: 0 8px 24px rgba(255,101,132,0.1); }
.btn-gold { background: linear-gradient(135deg, #3a2e0a, #4a3a0a); color: var(--gold); border: 1px solid rgba(247,201,72,0.3); box-shadow: 0 8px 24px rgba(247,201,72,0.1); }
/* Env table */ .env-table { width: 100%; border-collapse: collapse; font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; }
.env-table th { text-align: left; padding: 10px 14px; color: var(--muted); border-bottom: 1px solid var(--border); font-weight: 600; }
.env-table td { padding: 10px 14px; border-bottom: 1px solid rgba(30,30,56,0.5); color: var(--text); }
.env-table tr:hover td { background: rgba(108,99,255,0.05); } .env-key { color: var(--blue); } .env-desc { color: var(--muted); font-size: 0.75rem; }
/* Divider */ .divider { height: 1px; background: linear-gradient(90deg, transparent, var(--border), transparent); margin: 48px 0; }
/* Footer */ .footer { text-align: center; padding: 40px 0 20px; color: var(--muted); font-size: 0.85rem; }
.footer strong { color: var(--purple); }
/* Animations */ @keyframes fadeUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
.section:nth-child(2) { animation-delay: 0.1s; } .section:nth-child(3) { animation-delay: 0.2s; } .section:nth-child(4) { animation-delay: 0.3s; }
.feature-card:nth-child(1) { animation-delay: 0.1s; } .feature-card:nth-child(2) { animation-delay: 0.2s; } .feature-card:nth-child(3) { animation-delay: 0.3s; }
.step:nth-child(1) { animation-delay: 0.05s; } .step:nth-child(2) { animation-delay: 0.1s; } .step:nth-child(3) { animation-delay: 0.15s; } .step:nth-child(4) { animation-delay: 0.2s; } .step:nth-child(5) { animation-delay: 0.25s; } .step:nth-child(6) { animation-delay: 0.3s; } .step:nth-child(7) { animation-delay: 0.35s; }
/* Scrollbar */ ::-webkit-scrollbar { width: 6px; } ::-webkit-scrollbar-track { background: var(--bg); } ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
/* Highlight */ .highlight { color: var(--purple); } .highlight-green { color: var(--green); } .highlight-pink { color: var(--pink); }
.warning-box { background: rgba(247,201,72,0.07); border: 1px solid rgba(247,201,72,0.2); border-radius: 12px; padding: 14px 18px; font-size: 0.85rem; color: var(--gold); margin-top: 12px; display: flex; gap: 10px; align-items: flex-start; } </style>
💳 Smart Budget Manager
Zero-effort expense tracking by securely parsing your bank transaction SMSZero-effort expense tracking by securely parsing your bank transaction SMS
✨ Features
Smart SMS Parsing
Automatically extracts amount, merchant, and date from any Indian bank SMS — HDFC, SBI, ICICI, Axis, Kotak and more.
Real-time Dashboard
Beautiful pie charts and category breakdowns give you instant visual clarity on where your money goes.
Secure Cloud Sync
Firebase Auth + Firestore keeps your data encrypted, private, and synced across devices. Only you can see it.
Auto Categorization
Transactions are instantly sorted into Food, Transport, Shopping, Entertainment, Health, Utilities and more.
Monthly Insights
Track this month's spending vs total spend. Pull-to-refresh keeps everything up to date in real time.
Offline-first Design
Parse and preview transactions without internet. Syncs to cloud when connection is restored.
| Feature | Description |
|---|---|
| 🔍 Smart SMS Parsing | Auto-extracts amount, merchant and date from Indian bank SMS |
| 📊 Real-time Dashboard | Pie charts and category breakdowns at a glance |
| 🔐 Secure Cloud Sync | Firebase Auth + Firestore — only you can see your data |
| 🏷️ Auto Categorization | Food, Transport, Shopping, Health, Utilities and more |
| 📱 Monthly Insights | This month vs total spend with pull-to-refresh |
| 🏦 Multi-bank Support | HDFC, SBI, ICICI, Axis, Kotak and most Indian banks |
🛠 Tech Stack
- ⚛️ React Native — Mobile UI
- 📦 Expo SDK 52 — Build and dev tooling
- 🔥 Firebase Auth — Secure authentication
- 🗄️ Firestore — Encrypted cloud database
- 🧭 React Navigation — Tab-based routing
- 📈 React Native Chart Kit — Pie charts
- 🌿 dotenv — Environment variable management
- 📅 date-fns — Date formatting
📋 Prerequisites
Node.js 18+
Download from nodejs.org. Run node --version to verify.
Expo Go App
Install Expo Go from Play Store on your Android device for instant preview.
Firebase Account
Free account at console.firebase.google.com. Enable Auth + Firestore.
Before you begin, make sure you have:
- Node.js 18+ — nodejs.org
- Python 3.10+ — python.org
- Expo Go — Install from Play Store on your Android device
- Firebase account — console.firebase.google.com
- Git — git-scm.com
🚀 Installation Guide
<div class="step">
<div class="step-num">1</div>
<div class="step-content">
<h3>📥 Clone the Repository</h3>
<p>Clone or download the project to your local machine.</p>
<div class="code-wrapper">
<pre><code>git clone https://github.com/yourusername/SmartBudgetManager.git
cd SmartBudgetManager copy
<div class="step">
<div class="step-num">2</div>
<div class="step-content">
<h3>📦 Install Dependencies</h3>
<p>Install all required packages with npm.</p>
<div class="code-wrapper">
<pre><code>npm install
npx expo install expo-asset expo-font expo-secure-store npx expo install @react-native-async-storage/async-storage npx expo install expo-constants copy
<div class="step">
<div class="step-num">3</div>
<div class="step-content">
<h3>🔥 Setup Firebase</h3>
<p>Create a project at <strong style="color:var(--gold)">console.firebase.google.com</strong>, then enable:</p>
<p>→ <span class="highlight">Authentication</span> → Email/Password<br>
→ <span class="highlight-green">Firestore Database</span> → Start in test mode<br>
→ Get your config from Project Settings → Your Apps</p>
</div>
</div>
<div class="step">
<div class="step-num">4</div>
<div class="step-content">
<h3>🔑 Configure Environment</h3>
<p>Create a <code style="color:var(--green);font-family:monospace">.env</code> file in the project root:</p>
<div class="code-wrapper">
<pre><code><span class="code-comment"># .env — never commit this file!</span>
FIREBASE_API_KEY=AIzaSyB_your_key_here FIREBASE_AUTH_DOMAIN=yourproject.firebaseapp.com FIREBASE_PROJECT_ID=yourproject-id FIREBASE_STORAGE_BUCKET=yourproject.firebasestorage.app FIREBASE_MESSAGING_SENDER_ID=123456789012 FIREBASE_APP_ID=1:123456789012:android:abcdef copy
Step 1 — Clone the Repository
git clone https://github.com/YOUR_USERNAME/SmartBudgetManager.git
cd SmartBudgetManagerStep 2 — Install Dependencies
npm install npx expo install expo-asset expo-font expo-secure-store npx expo install @react-native-async-storage/async-storage npx expo install expo-constants npm install dotenv
Step 3 — Setup Firebase
- Go to console.firebase.google.com
- Click Add project and name it
SmartBudgetManager - Left sidebar → Authentication → Get started → Enable Email/Password
- Left sidebar → Firestore Database → Create database → Start in test mode
- Choose asia-south1 (Mumbai) as your region
- Go to Project Settings → Your apps → copy your config values
Step 4 — Configure Environment Variables
Create a .env file in the project root:
FIREBASE_API_KEY=******
FIREBASE_AUTH_DOMAIN=******
FIREBASE_PROJECT_ID=******
FIREBASE_STORAGE_BUCKET=******
FIREBASE_MESSAGING_SENDER_ID=******
FIREBASE_APP_ID=******
⚠️ Never commit.envto git. It is already listed in.gitignore.
Copy your real values from Firebase Project Settings into each field.
Step 5 — Set Firestore Security Rules
In Firebase Console → Firestore → Rules tab, paste:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /transactions/{docId} {
allow read, write: if request.auth != null
&& request.auth.uid == resource.data.userId;
allow create: if request.auth != null
&& request.auth.uid == request.resource.data.userId;
}
}
}
Click Publish.
Step 6 — Start the App
npx expo start --clear
Scan the QR code with Expo Go on your Android phone.
📦 Build APK
To build a standalone APK using EAS:
npm install -g eas-cli npx eas-cli login npx eas-cli build --platform android --profile preview
.env.gitignore <div class="step">
<div class="step-num">5</div>
<div class="step-content">
<h3>🛡️ Set Firestore Security Rules</h3>
<p>In Firebase Console → Firestore → Rules tab, paste:</p>
<div class="code-wrapper">
<pre><code>rules_version = '2';
service cloud.firestore { match /databases/{database}/documents { match /transactions/{docId} { allow read, write: if request.auth != null && request.auth.uid == resource.data.userId; allow create: if request.auth != null && request.auth.uid == request.resource.data.userId; } } } copy
<div class="step">
<div class="step-num">6</div>
<div class="step-content">
<h3>▶️ Start the App</h3>
<p>Launch the Expo development server.</p>
<div class="code-wrapper">
<pre><code>npx expo start --clear</code></pre>
<button class="copy-btn" onclick="copyCode(this)">copy</button>
</div>
<p style="margin-top:10px">Scan the QR code with <strong style="color:var(--purple)">Expo Go</strong> on your Android phone.</p>
</div>
</div>
<div class="step">
<div class="step-num">7</div>
<div class="step-content">
<h3>📦 Build APK (Optional)</h3>
<p>To build a standalone APK using EAS Build:</p>
<div class="code-wrapper">
<pre><code>npm install -g eas-cli
npx eas-cli login npx eas-cli build --platform android --profile preview copy
Download the APK from your expo.dev dashboard and install on your phone.
</div>
🔐 Environment Variables Reference
| Variable | Description | Where to find |
|---|---|---|
| FIREBASE_API_KEY | Firebase Web API Key | Project Settings → General |
| FIREBASE_AUTH_DOMAIN | Authentication domain | Project Settings → Your Apps |
| FIREBASE_PROJECT_ID | Unique project identifier | Project Settings → General |
| FIREBASE_STORAGE_BUCKET | Cloud Storage bucket URL | Project Settings → Your Apps |
| FIREBASE_MESSAGING_SENDER_ID | FCM Sender ID | Project Settings → Cloud Messaging |
| FIREBASE_APP_ID | Firebase App ID | Project Settings → Your Apps |
| Variable | Description | Where to find |
|---|---|---|
FIREBASE_API_KEY | Firebase Web API Key | Project Settings → General |
FIREBASE_AUTH_DOMAIN | Auth domain | Project Settings → Your Apps |
FIREBASE_PROJECT_ID | Project identifier | Project Settings → General |
FIREBASE_STORAGE_BUCKET | Storage bucket URL | Project Settings → Your Apps |
FIREBASE_MESSAGING_SENDER_ID | FCM Sender ID | Project Settings → Cloud Messaging |
FIREBASE_APP_ID | Firebase App ID | Project Settings → Your Apps |
📁 Project Structure
SmartBudgetManager/
├── App.js
├── app.config.js # Expo config with env vars
├── babel.config.js
├── .env # Secret keys (never commit)
├── .env.example # Safe template for teammates
├── scripts/
│ ├── mask_keys.py # Pre-commit secret masking
│ ├── compile_check.py # Multi-language syntax checker
│ └── check_requirements.py
├── src/
│ ├── config/
│ │ └── firebase.js
│ ├── context/
│ │ └── AuthContext.js
│ ├── navigation/
│ │ └── AppNavigator.js
│ ├── screens/
│ │ ├── LoginScreen.js
│ │ ├── DashboardScreen.js
│ │ ├── ImportScreen.js
│ │ └── SettingsScreen.js
│ └── utils/
│ ├── smsParser.js
│ └── transactionStore.js
└── .github/
└── workflows/
└── ci.yml # GitHub Actions CI
🔒 Security
- 🔑 All API keys stored in
.env— never committed to git - 🛡️ Pre-commit hooks automatically mask any exposed secrets
- 🔐 Firebase Auth ensures only authenticated users access data
- 📋 Firestore rules restrict each user to their own transactions only
- 🤖 GitHub Actions CI scans for raw secrets on every push
🤖 Pre-commit Hooks
This project uses pre-commit hooks that run on every git commit:
| Hook | What it does |
|---|---|
trailing-whitespace | Removes trailing spaces |
end-of-file-fixer | Ensures files end with newline |
detect-private-key | Blocks raw PEM/RSA keys |
check-merge-conflict | Blocks unresolved merge conflicts |
flake8 | Python code linting |
mask-secrets | Masks API keys with ******
|
compile-check | Syntax check for 15+ languages |
Supported Languages for Compile Check
Python JavaScript TypeScript Java Kotlin Go Rust Ruby PHP Dart Swift C C++
🏦 Supported Banks (SMS Parsing)
| Bank | Status |
|---|---|
| HDFC Bank | ✅ Supported |
| SBI | ✅ Supported |
| ICICI Bank | ✅ Supported |
| Axis Bank | ✅ Supported |
| Kotak Mahindra | ✅ Supported |
| Yes Bank | ✅ Supported |
| IndusInd Bank | ✅ Supported |
| Other banks | ✅ Generic pattern fallback |
🏷️ Expense Categories
| Category | Keywords Detected |
|---|---|
| 🍕 Food | Zomato, Swiggy, restaurant, cafe, dining |
| 🚗 Transport | Uber, Ola, metro, fuel, IRCTC, Rapido |
| 🛍️ Shopping | Amazon, Flipkart, Myntra, Ajio, Meesho |
| 🎬 Entertainment | Netflix, Prime, Spotify, BookMyShow, PVR |
| 🏥 Health | Apollo, pharmacy, hospital, MedPlus |
| ⚡ Utilities | Jio, Airtel, electricity, broadband |
| 💰 Finance | EMI, loan, insurance, SIP, mutual fund |
| 🛒 Groceries | BigBasket, Blinkit, Zepto, Grofers |
🤝 Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Commit your changes:
git commit -m "Add my feature" - Push to the branch:
git push origin feature/my-feature - Open a Pull Request
Note: Direct commits to
productionbranch are blocked by pre-commit hooks.
📄 License
MIT License — feel free to use, modify and distribute.
🔗 Quick Links
Built with ❤️ using React Native + Firebase
Smart Budget Manager — Track every rupee, effortlessly 💳
💳 Track every rupee, effortlessly
�
0 commit comments