A production-grade full-stack banking application with secure JWT authentication, OTP email verification, real-time money transfers with atomic MongoDB transactions, and a modern React dashboard.
Features · Tech Stack · Architecture · Getting Started · API Reference · Database Design · Contributing
- Features
- Tech Stack
- Architecture Overview
- Getting Started
- Running the Application
- API Reference
- Database Design
- Authentication & Security Deep Dive
- Frontend Deep Dive
- Project Structure
- Testing
- Deployment
- Related Documentation
- Contributing
- License
| Feature | Description | Status |
|---|---|---|
| User Registration | Multi-field form with name, Aadhar, phone, email, password, DOB, account type, nickname | ✅ Implemented |
| Email OTP Verification | 6-digit OTP via Azure Communication Services, SHA-256 hashed, 10-min TTL auto-expiry | ✅ Implemented |
| Secure Login | Email + password + account type authentication with bcrypt comparison | ✅ Implemented |
| JWT Access Tokens | 15-minute lifespan, stored in React Context (in-memory), sent via Authorization header |
✅ Implemented |
| JWT Refresh Tokens | 7-day lifespan, HTTP-only secure cookie, SHA-256 hashed in DB, full rotation on each use | ✅ Implemented |
| Session Tracking | IP address and User-Agent recorded per login session with revocation support | ✅ Implemented |
| Password Hashing | bcrypt with 10 salt rounds for all user passwords | ✅ Implemented |
| OTP Hashing | SHA-256 one-way hash for OTP storage | ✅ Implemented |
| Luhn-Valid Card Generation | 16-digit card numbers passing Luhn algorithm validation, uniqueness guaranteed | ✅ Implemented |
| HTTP-Only Secure Cookies | Refresh tokens use httpOnly, secure, sameSite: strict flags |
✅ Implemented |
| CORS Protection | Origin whitelisted to frontend dev server with credentials enabled | ✅ Implemented |
| Duplicate Detection | Registration blocked if email or Aadhar number already exists | ✅ Implemented |
| Google reCAPTCHA | Dependency installed, integration pending | 🔧 Partial |
| Two-Factor Authentication | UI placeholder in Settings | 🚧 Planned |
| Feature | Description | Status |
|---|---|---|
| Send Money (Phone Number) | Transfer by recipient's phone number with password re-verification | ✅ Implemented |
| Send Money (Account Number) | Transfer by recipient's account number | ✅ Implemented |
| Send Money (Bank UPI) | Transfer by UPI ID (e.g., 9876543210@shinrai), extracts phone from UPI |
✅ Implemented |
| Atomic Transactions | MongoDB sessions with startTransaction() / commitTransaction() / abortTransaction() |
✅ Implemented |
| Self-Transfer Prevention | Cannot send money to own account | ✅ Implemented |
| Daily Transfer Limit | ₹1,00,000/day with automatic reset when date changes | ✅ Implemented |
| Monthly Transfer Limit | ₹10,00,000/month with automatic reset when month changes | ✅ Implemented |
| Balance Check | Password-protected balance inquiry with formatted INR display | ✅ Implemented |
| Insufficient Balance Guard | Transfers rejected if balance < amount | ✅ Implemented |
| Paginated Transaction History | Server-side pagination with configurable page size (default: 10) | ✅ Implemented |
| Bill Payments | Dashboard UI icons for Mobile, Electricity, LPG, DTH, Broadband, Credit Card | 🔧 UI-Only |
| EMI Calculator | Interactive loan calculator with adjustable amount (₹10K–₹10L) and tenure (6–84 months) | ✅ Implemented |
| Feature | Description | Status |
|---|---|---|
| Account Overview | Gradient debit/credit card with number, name, validity, CVV | ✅ Implemented |
| QR Code Generation | Auto-generated UPI QR code for instant sharing via react-qr-code |
✅ Implemented |
| Recent Transactions | Last 3 transactions with color-coded debit (red) / credit (green) indicators | ✅ Implemented |
| Quick Transfer Panel | Shortcut buttons: Pay Number, Pay to Bank, Pay to UPI, Check Balance | ✅ Implemented |
| Promotional Offers | Cashback banner section | ✅ Implemented |
| User Profile Card | Name, phone, account number, UPI ID display with QR code | ✅ Implemented |
| Responsive Navbar | Desktop + mobile hamburger navigation with conditional auth buttons | ✅ Implemented |
| Dashboard Sidebar | Icon-based vertical nav: Dashboard, Application, History, Loan, Statement, Settings | ✅ Implemented |
| Settings Page | Profile info, security options, notification preferences, theme selection, danger zone | 🔧 Partial |
| Contact Shortcuts | Avatar circles for frequent contacts | 🔧 UI-Only |
Seven banking service categories accessible from a central grid page with animated cards:
| Service | Route | Status |
|---|---|---|
| Account Management Requests | /account-management |
🔧 Placeholder |
| KYC & Identity Services | /kyc-identity |
🔧 Placeholder |
| Card Services | /card-services |
🔧 Placeholder |
| Loan & Credit Services | /loan-credit-services |
🔧 Placeholder |
| Contact & Communication Updates | /contact-update |
🔧 Placeholder |
| Cheque & Payment Services | /cheque-services |
🔧 Placeholder |
| Internet Banking & Security | /internet-banking |
🔧 Placeholder |
| Page | Route | Description |
|---|---|---|
| Home / Landing | / |
Hero section with gradient text, credit card imagery, CTA, trust indicators |
| About Us | /about-us |
Mission & Vision, statistics (50K+ users, ₹10Cr+ transactions), "Why Choose Us" cards, founder profile |
| Contact | /contact |
Contact info (email, phone, address), contact form (UI-only), quick support cards |
| Loan | /loan |
Loan types, pre-approved offer banner, EMI calculator, active loan display |
| Technology | Version | Purpose |
|---|---|---|
| React | 19 | UI framework with concurrent features |
| Vite | 8 | Build tool with fast HMR and native ESM |
| React Router | 7 | Client-side SPA routing |
| Tailwind CSS | 3 | Utility-first CSS framework |
| shadcn/ui | — | Accessible component primitives (Button, Input, Resizable Navbar) |
| Axios | — | HTTP client for API communication |
| Motion (Framer) | — | Smooth animations and transitions |
| react-qr-code | — | UPI QR code generation |
| Lucide React | — | Icon library |
| Tabler Icons | — | Icon library |
| Font Awesome | — | Icon library |
| clsx + tailwind-merge | — | Dynamic class name merging |
| tw-animate-css | — | Tailwind animation utilities |
| Technology | Version | Purpose |
|---|---|---|
| Node.js | ≥ 16 | JavaScript runtime |
| Express | 5 | HTTP framework with async route handlers |
| MongoDB Atlas | — | Cloud-hosted NoSQL database |
| Mongoose | 9 | ODM with schema validation and middleware |
| jsonwebtoken | — | JWT signing and verification |
| bcrypt | 6 | Password hashing |
| Azure Communication Email | 1.1 | Email delivery via Azure Communication Services |
| Nodemailer | 9 | Email transport (available as alternative) |
| Morgan | — | HTTP request logging |
| cookie-parser | — | Cookie parsing middleware |
| cors | — | Cross-Origin Resource Sharing |
| dotenv | 17 | Environment variable loading |
| Nodemon | 3 | Auto-restart dev server on file changes |
| Service | Purpose | Status |
|---|---|---|
| MongoDB Atlas | Cloud database hosting | ✅ Active |
| Azure Communication Services | Transactional email delivery (OTP) | ✅ Active |
| Supabase | Future use — file uploads, realtime features | 🚧 Client configured |
| Google reCAPTCHA | Bot protection on forms | 🔧 Dependency installed |
┌─────────────────────────────────────────────────────────────────────┐
│ CLIENT (Browser) │
│ React 19 + Vite 8 + Tailwind CSS 3 + shadcn/ui + Motion │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ Home │ │ Login │ │Dashboard │ │ Transfer │ │Settings │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └─────────┘ │
│ │
│ Context Providers: AccessToken, UserData, SideBar, │
│ UserTemp, TransferTo, Transactions │
│ │ │
│ Axios HTTP Client │
└────────────────────────┼────────────────────────────────────────────┘
│ REST API (JSON over HTTPS)
┌────────────────────────┼────────────────────────────────────────────┐
│ ▼ BACKEND (Express 5) │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────┐ │
│ │ Middleware │ │ Controllers │ │ Services │ │
│ │ ├ morgan() │ │ ├ register() │ │ └ sendEmail()│ │
│ │ ├ express.json() │ → │ ├ login() │ → │ │ │
│ │ ├ cors() │ │ ├ verify() │ ├───────────────┤ │
│ │ └ cookieParser() │ │ ├ refreshToken() │ │ Utilities │ │
│ └──────────────────┘ │ ├ getDashboard() │ │ ├ generateOtp │ │
│ │ ├ sendMoney() │ │ └ cardUtil │ │
│ ┌──────────────────┐ │ ├ getTransact() │ └───────────────┘ │
│ │ Routes │ │ └ checkBalance() │ │
│ │ /api/auth/* │ └──────────────────┘ │
│ └──────────────────┘ │ │
│ ┌─────┴──────┐ │
│ │ Models │ │
│ │ User / OTP │ │
│ │ Session/Txn │ │
│ └─────┬──────┘ │
└────────────────────────────────────┼────────────────────────────────┘
│ Mongoose ODM
┌──────┴───────┐
│ MongoDB Atlas │
│ (Cloud DB) │
└──────────────┘
Component Hierarchy:
main.jsx
└── Context Providers (6 nested)
└── BrowserRouter
└── App.jsx
├── Navbar (conditional — hidden on login/register/otp)
├── Routes
│ ├── / → Home
│ ├── /login → Login
│ ├── /create-account → CreateAccount
│ ├── /otp → OtpVerification
│ ├── /dashboard → Dashboard (+ SideBar)
│ ├── /send-money → SendMoney
│ ├── /check-balance → CheckBalance
│ ├── /transactions → Transactions
│ ├── /settings → Settings
│ ├── /loan → Loan
│ ├── /contact → Contact
│ ├── /about-us → AboutUs
│ ├── /application → Application (Service Hub)
│ ├── /account-management → AccountManagement
│ ├── /kyc-identity → KYC
│ ├── /card-services → CardServices
│ ├── /loan-credit-services → LoanServices
│ ├── /contact-update → ContactServices
│ ├── /cheque-services → ChequeServices
│ └── /internet-banking → InternetBanking
└── Footer (conditional — hidden on login/register/otp)
Layered Design:
server.js (Entry Point)
└── app.js (Express Setup)
├── Middleware Stack
│ ├── morgan() → HTTP request logging
│ ├── express.json() → JSON body parsing
│ ├── cors() → Origin: http://localhost:5173
│ └── cookieParser() → Cookie parsing
│
└── Routes
└── /api/auth/* → auth.route.js
├── POST /register → register()
├── POST /verify → verify()
├── POST /login → login()
├── GET /refresh-token → refreshToken()
├── GET /get-dashboardData → getDashboardData()
├── POST /send-money → sendMoney()
├── GET /transactions → getTransactions()
└── POST /check-balance → checkBalance()
HTTP Request Incoming
│
├── morgan() → Log: method, URL, status code, response time
├── express.json() → Parse JSON request body → req.body
├── cors() → Validate origin against whitelist
├── cookieParser() → Parse cookies → req.cookies
│
├── Router Matching → /api/auth/* → authRouter
│
├── Controller Logic
│ ├── Input validation (manual field checks)
│ ├── Database operations (Mongoose queries)
│ ├── External services (Azure Email for OTP)
│ ├── Cryptographic operations (bcrypt, SHA-256, JWT)
│ └── MongoDB transactions (for money transfers)
│
└── JSON Response → { success: boolean, message: string, data?: any }
| Requirement | Version | Download |
|---|---|---|
| Node.js | ≥ 16.0.0 | nodejs.org |
| npm | ≥ 8.0.0 | Bundled with Node.js |
| MongoDB Atlas | Free tier (M0) | mongodb.com/atlas |
| Azure Account | Free tier | azure.microsoft.com |
| Git | Any | git-scm.com |
# 1. Clone the repository
git clone https://github.com/your-username/Shinrai-Bank.git
cd Shinrai-Bank
# 2. Install backend dependencies
cd backend
npm install
# 3. Install frontend dependencies
cd ../frontend
npm install
# 4. Configure environment variables (see next section)
# 5. Start both servers (see "Running the Application")Create a .env file in the backend/ directory with the following variables:
# Server Configuration
BACKEND_PORT=3000
# MongoDB Atlas Connection
MONGODB_URI=mongodb+srv://<username>:<password>@<cluster>.mongodb.net/<database-name>
# JWT Secret Key (use a strong random 256-bit string)
JWT_URI=your-256-bit-secret-key-here
# Azure Communication Services (for email delivery)
AZURE_COMMUNICATION_CONNECTION_STRING=endpoint=https://<resource>.communication.azure.com/;accesskey=<key>
EMAIL_SENDER=DoNotReply@<domain>.azurecomm.net
# Google OAuth2 (optional — for Nodemailer Gmail transport)
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-your-client-secret
GOOGLE_REFRESH_TOKEN=1//your-refresh-token
GOOGLE_EMAIL_USER=your-email@gmail.comBackend Environment Variables Reference:
| Variable | Required | Description |
|---|---|---|
BACKEND_PORT |
✅ | Express server port (default: 3000) |
MONGODB_URI |
✅ | MongoDB Atlas connection string |
JWT_URI |
✅ | Secret key for signing/verifying JWTs |
AZURE_COMMUNICATION_CONNECTION_STRING |
✅ | Azure Communication Services connection string |
EMAIL_SENDER |
✅ | Sender email address for Azure Communication |
GOOGLE_CLIENT_ID |
❌ | Google OAuth2 client ID (for Gmail alternative) |
GOOGLE_CLIENT_SECRET |
❌ | Google OAuth2 client secret |
GOOGLE_REFRESH_TOKEN |
❌ | Gmail API refresh token |
GOOGLE_EMAIL_USER |
❌ | Gmail address for sending |
Create a .env file in the frontend/ directory:
# Backend API Base URL
VITE_BACKEND_PORT=http://localhost:3000/api/auth
# Supabase (optional — future features)
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key| Variable | Required | Description |
|---|---|---|
VITE_BACKEND_PORT |
✅ | Backend API base URL (must include /api/auth) |
VITE_SUPABASE_URL |
❌ | Supabase project URL (future use) |
VITE_SUPABASE_ANON_KEY |
❌ | Supabase anonymous key (future use) |
⚠️ Security: Never commit.envfiles to version control. They are already listed in.gitignore.
-
Create a MongoDB Atlas cluster:
- Go to MongoDB Atlas
- Create a free-tier (M0) cluster
- Create a database user with read/write privileges
-
Whitelist your IP address:
- Navigate to Network Access → Add IP Address
- Add
0.0.0.0/0for development (restrict in production)
-
Get the connection string:
- Click Connect → Connect your application
- Copy the URI and replace
<password>with your database user's password
-
Collections — auto-created by Mongoose on first use:
Collection Purpose TTL usersUser accounts, banking details, card info — otpsEmail verification OTPs 10 minutes sessionsJWT refresh token sessions — transactionsMoney transfer records —
Open two terminals and run:
Terminal 1 — Backend:
cd backend
npm run devBackend starts at
http://localhost:3000
Terminal 2 — Frontend:
cd frontend
npm run devFrontend starts at
http://localhost:5173
Look for these messages in the backend console:
Database connected successfully
Server is running at port 3000 .....
cd frontend
npm run build # Creates optimized build in dist/
npm run preview # Preview production build locallyAll endpoints are prefixed with /api/auth/. The API follows REST conventions and returns JSON responses in this format:
{
"success": true,
"message": "Human-readable status message",
"data": {}
}Register a new user account with OTP email verification.
Request Body:
{
"name": "SK Sahil Uddin",
"email": "sahil@example.com",
"phoneNumber": "9647397722",
"password": "SecurePass123",
"aadharNumber": "123456789012",
"dob": "2000-01-15"
}Responses:
| Status | Description |
|---|---|
201 |
User registered, OTP email sent |
400 |
Missing required field(s) |
409 |
User with this email/Aadhar already exists |
What happens server-side:
- Validates all required fields
- Checks for duplicate email/Aadhar
- Hashes password with bcrypt (10 rounds)
- Generates a Luhn-valid 16-digit card number + 3-digit CVV
- Creates user document in MongoDB
- Generates 6-digit OTP, hashes with SHA-256, stores with 10-min TTL
- Sends OTP email via Azure Communication Services
Verify email address with the OTP sent during registration.
Request Body:
{
"email": "sahil@example.com",
"otp": "482957"
}Responses:
| Status | Description |
|---|---|
200 |
OTP verified, user marked as verified |
401 |
OTP incorrect or expired (>10 minutes) |
404 |
User not found |
Authenticate user and receive JWT tokens.
Request Body:
{
"email": "sahil@example.com",
"password": "SecurePass123",
"accountType": "SAVINGS"
}Response (200):
{
"success": true,
"message": "User login successfully",
"user": {
"name": "SK Sahil Uddin",
"email": "sahil@example.com"
},
"accessToken": "eyJhbGciOiJIUzI1NiIs..."
}Additionally sets: refreshToken HTTP-only cookie (7-day lifetime).
Responses:
| Status | Description |
|---|---|
200 |
Login successful, tokens issued |
401 |
Invalid password |
403 |
Email not verified |
404 |
User not found |
What happens server-side:
- Finds user by email + account type
- Compares password hash with bcrypt
- Verifies
user.verified === true - Signs refresh token (7d) → hashes with SHA-256 → stores in sessions collection
- Signs access token (15m)
- Sets HTTP-only cookie with refresh token
- Returns access token in response body
Rotate access and refresh tokens using the refresh token cookie.
Headers: Automatically sends refreshToken cookie.
Response (200):
{
"message": "Access token refreshed successfully",
"newAccessToken": "eyJhbGciOiJIUzI1NiIs..."
}Additionally: Sets new refreshToken cookie (old one invalidated).
| Status | Description |
|---|---|
200 |
New tokens issued |
401 |
Refresh token missing, invalid, or revoked |
Fetch authenticated user's dashboard data and last 3 transactions.
Headers:
Authorization: Bearer <accessToken>
Response (200):
{
"success": true,
"message": "User data found",
"user": {
"userId": "665a...",
"name": "SK Sahil Uddin",
"email": "sahil@example.com",
"phoneNumber": "9647397722",
"cardType": "DEBIT",
"cardNumber": "4532015112830366",
"cardValid": "2031-06-24T00:00:00.000Z",
"cardCVV": 482,
"verified": true,
"accountNumber": "9647397722",
"transactions": [
{
"_id": "...",
"user1": "...",
"user1Name": "SK Sahil Uddin",
"amount": 500,
"user2": "...",
"user2Name": "John Doe",
"createdAt": "2026-06-24T12:00:00.000Z"
}
]
}
}Transfer money to another user account.
Headers:
Authorization: Bearer <accessToken>
Request Body:
{
"reciverPhoneNumber": "9876543210",
"reciverAccountNumber": null,
"amount": 500,
"password": "SecurePass123"
}Provide either
reciverPhoneNumberORreciverAccountNumber, not both.
Responses:
| Status | Description |
|---|---|
200 |
Transfer successful |
400 |
Invalid amount, missing password, or missing receiver |
401 |
Invalid/missing access token |
403 |
Incorrect password or unverified user |
404 |
Receiver not found |
409 |
Insufficient balance, daily limit reached, monthly limit reached, or self-transfer attempt |
What happens server-side:
- Validates access token and verifies password
- Blocks self-transfer attempts
- Checks and auto-resets daily/monthly limits if date/month changed
- Validates against daily limit, monthly limit, and available balance
- Starts MongoDB transaction session
- Deducts from sender, credits to receiver (atomically)
- Updates sender's daily/monthly transferred amounts
- Creates transaction record
- Commits transaction (or aborts on any error)
Fetch paginated transaction history for the authenticated user.
Headers:
Authorization: Bearer <accessToken>
Query Parameters:
| Param | Default | Description |
|---|---|---|
page |
1 |
Page number |
limit |
10 |
Items per page |
Response (200):
{
"success": true,
"message": "All transactions found",
"transactions": [...],
"totalPages": 5,
"currentPage": 1
}Check account balance (requires password for security).
Headers:
Authorization: Bearer <accessToken>
Request Body:
{
"password": "SecurePass123"
}Response (200):
{
"success": true,
"message": "Balance successfully fetched",
"balance": 9500
}| Status | Description |
|---|---|
200 |
Balance returned |
400 |
Password not provided |
401 |
Invalid/missing access token |
403 |
Incorrect password |
┌─────────────────────────────────────────────────────┐
│ MongoDB Atlas │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐
│ │ users │──│ otps │ │ sessions │ │ txns │
│ │ │ │ (TTL:10m)│ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────┘
│ │
│ users ──< otps (1:N, user has pending OTPs) │
│ users ──< sessions (1:N, user has login sessions)│
│ users ──< transactions (1:N, as sender or receiver)│
└─────────────────────────────────────────────────────┘
The main user document stores all account, banking, card, and KYC information.
| Field | Type | Description | Default |
|---|---|---|---|
name |
String | Full name | Required |
nickName |
String | Account nickname | — |
email |
String | Email address (unique) | Required |
phoneNumber |
String | Phone number (unique) | Required |
aadharNumber |
String | Aadhar ID (unique) | Required |
password |
String | bcrypt hashed password | Required |
dob |
Date | Date of birth | Required |
address |
String | Residential address | — |
accountType |
Enum | SAVINGS | CURRENT | SALARY | FIXED_DEPOSIT |
SAVINGS |
accountNumber |
String | Account number (= phone number) | — |
status |
Enum | ACTIVE | FROZEN | CLOSED | SUSPENDED |
ACTIVE |
bankBalance |
Number | Current balance (INR) | 10000 |
currency |
String | Currency code | INR |
branchCode |
String | Branch identifier | Shinrai Branch of India |
ifscCode |
String | IFSC code | SHIN02042007 |
cardType |
Enum | DEBIT | CREDIT |
DEBIT |
cardNumber |
String | 16-digit Luhn-valid card number | Auto-generated |
cardCVV |
Number | 3-digit security code | Random (100–999) |
cardValid |
Date | Card expiration date | now + 5 years |
dailyTransferLimit |
Number | Max daily transfer (INR) | 100000 |
dailyTransferredAmount |
Number | Transferred today | 0 |
monthlyTransferLimit |
Number | Max monthly transfer (INR) | 1000000 |
monthlyTransferredAmount |
Number | Transferred this month | 0 |
lastDailyReset |
Date | Last daily limit reset timestamp | Date.now |
lastMonthlyReset |
Date | Last monthly limit reset timestamp | Date.now |
kycVerified |
Boolean | KYC verification status | false |
interestRate |
Number | Account interest rate | 0 |
nominee.name |
String | Nominee full name | — |
nominee.relation |
String | Nominee relation | — |
nominee.phone |
String | Nominee phone number | — |
verified |
Boolean | Email verified via OTP | false |
createdAt |
Date | Auto-generated timestamp | Mongoose |
updatedAt |
Date | Auto-generated timestamp | Mongoose |
Stores hashed OTPs with automatic 10-minute expiration via MongoDB TTL index.
| Field | Type | Description |
|---|---|---|
user |
ObjectId | Reference to user document |
email |
String | User's email address |
otp |
String | SHA-256 hashed OTP |
createdAt |
Date | Creation time (expires: 600 seconds) |
Tracks active login sessions with refresh token hashes, client IP, and user-agent.
| Field | Type | Description | Default |
|---|---|---|---|
user |
ObjectId | Reference to user document | Required |
refreshToken |
String | SHA-256 hashed refresh token | Required |
ip |
String | Client IP address | Required |
userAgent |
String | Browser user-agent string | Required |
revoked |
Boolean | Whether session is revoked | false |
createdAt |
Date | Auto-generated | Mongoose |
updatedAt |
Date | Auto-generated | Mongoose |
Records all money transfers between users.
| Field | Type | Description |
|---|---|---|
user1 |
ObjectId | Sender's user ID |
user1Name |
String | Sender's display name |
amount |
Number | Transfer amount (INR) |
user2 |
ObjectId | Receiver's user ID |
user2Name |
String | Receiver's display name |
createdAt |
Date | Auto-generated |
updatedAt |
Date | Auto-generated |
| Decision | Rationale |
|---|---|
| SHA-256 for OTPs | One-way hashing for verification codes — no need to decrypt |
| bcrypt for passwords | Industry standard with salt + work factor to prevent rainbow tables |
| TTL index on OTPs (600s) | MongoDB auto-deletes expired OTPs, no cleanup cron needed |
| Session tracking with IP/UA | Enables suspicious login detection and session management |
| Atomic transactions for transfers | MongoDB sessions ensure both balances update or neither does |
| Phone number as account number | Simplified account lookup and user-friendly transfers |
| 5-year card validity | Realistic card expiration aligned with banking industry standards |
User (Browser) Frontend (React) Backend (Express) MongoDB Azure Email
│ │ │ │ │
├── Fill registration form ──────►│ │ │ │
│ ├── POST /api/auth/register ──►│ │ │
│ │ ├── Validate fields │ │
│ │ ├── Check duplicates ──►│ │
│ │ │◄── Not found ─────────┤ │
│ │ ├── Hash password (bcrypt) │
│ │ ├── Generate Luhn card │
│ │ ├── Generate 6-digit OTP │
│ │ ├── Hash OTP (SHA-256) │
│ │ ├── Create user doc ───►│ │
│ │ ├── Create OTP doc ────►│ (TTL: 10 min) │
│ │◄── 201 { success, user } ────┤ │ │
│◄── Redirect to /otp ───────────┤ ├── Send OTP email ────────────────────────►│
│ │ │ │ Email sent │
├── Enter OTP ──────────────────►│ │ │ │
│ ├── POST /api/auth/verify ────►│ │ │
│ │ ├── Hash input OTP │ │
│ │ ├── Find matching OTP ──►│ │
│ │ ├── Set verified=true ──►│ │
│ │◄── 200 { success } ──────────┤ │ │
│◄── Redirect to /login ─────────┤ │ │ │
User ──► Login Form ──► POST /api/auth/login
│
├── Find user by email + accountType
├── bcrypt.compare(password, hash)
├── Check user.verified === true
│
├── Sign Refresh Token (JWT, 7d expiry)
│ └── Payload: { id: user._id }
├── SHA-256 hash refresh token
├── Create session record (hash, IP, UA)
│
├── Sign Access Token (JWT, 15m expiry)
│ └── Payload: { id: user._id }
│
├── Set cookie: refreshToken (httpOnly, secure, sameSite)
└── Return: { accessToken } in JSON body
┌─── After 15 minutes ───┐
│ │
▼ │
GET /refresh-token ────────────────┘
│
├── Read refreshToken from cookie
├── Verify JWT signature
├── Hash and find matching session (revoked === false)
├── Sign new access token (15m)
├── Sign new refresh token (7d)
├── Update session with new hash
├── Set new cookie
└── Return: { newAccessToken }
| Property | Access Token | Refresh Token |
|---|---|---|
| Storage | React Context (in-memory) | HTTP-only cookie |
| Lifetime | 15 minutes | 7 days |
| Payload | { id: user._id } |
{ id: user._id } |
| Sent via | Authorization: Bearer header |
Cookie (automatic) |
| DB Record | None | SHA-256 hash in sessions collection |
| Purpose | Authenticate API requests | Rotate access tokens |
| Rotation | New one per refresh | New one per use (invalidates old) |
| XSS Protection | Not accessible to scripts (memory only) | httpOnly flag prevents JS access |
Sender ──► POST /api/auth/send-money
│
├── Verify access token (JWT)
├── Find sender by token ID
├── Validate amount > 0
├── Re-verify password (bcrypt)
├── Block self-transfer
│
├── Check daily limit reset (date changed? → reset to 0)
├── Check monthly limit reset (month changed? → reset to 0)
├── Verify daily limit not exceeded
├── Verify monthly limit not exceeded
├── Verify sufficient balance
│
├── ═══ START MongoDB Transaction ═══
│ ├── Find receiver by phone/account number
│ ├── sender.balance -= amount
│ ├── receiver.balance += amount
│ ├── Update sender's daily/monthly totals
│ ├── Create transaction record
│ └── ═══ COMMIT Transaction ═══
│
└── Return: { success, message }
On ANY error → ABORT Transaction (no partial updates)
| Route | Page Component | Layout | Auth Required |
|---|---|---|---|
/ |
Home |
Navbar + Footer | ❌ |
/login |
Login |
Standalone (no Navbar/Footer) | ❌ |
/create-account |
CreateAccount |
Standalone | ❌ |
/otp |
OtpVerification |
Standalone | ❌ |
/dashboard |
Dashboard |
Navbar + Footer + Sidebar | ✅ |
/send-money |
SendMoney |
Navbar + Footer | ✅ |
/check-balance |
CheckBalance |
Navbar + Footer | ✅ |
/transactions |
Transactions |
Navbar + Footer | ✅ |
/settings |
Settings |
Navbar + Footer | ✅ |
/loan |
Loan |
Navbar + Footer | ❌ |
/contact |
Contact |
Navbar + Footer | ❌ |
/about-us |
AboutUs |
Navbar + Footer | ❌ |
/application |
Application |
Navbar + Footer + Sidebar | ✅ |
/account-management |
AccountManagement |
Navbar + Footer | ✅ |
/kyc-identity |
KYC |
Navbar + Footer | ✅ |
/card-services |
CardServices |
Navbar + Footer | ✅ |
/loan-credit-services |
LoanServices |
Navbar + Footer | ✅ |
/contact-update |
ContactServices |
Navbar + Footer | ✅ |
/cheque-services |
ChequeServices |
Navbar + Footer | ✅ |
/internet-banking |
InternetBanking |
Navbar + Footer | ✅ |
The application uses React's Context API with 6 context providers nested in main.jsx:
| Context | Provider | State | Purpose | Consumed By |
|---|---|---|---|---|
TransactionsContext |
Outermost | Transaction list | Store transaction data | Transactions page |
TransferToContext |
Level 2 | Transfer method string | Track selected transfer type (phone/account/UPI) | SendMoney, Dashboard |
UserDataContext |
Level 3 | Full user object + isLogedIn |
Store user profile data and login status | Dashboard, Settings, Navbar, Sidebar |
AccessTokenContext |
Level 4 | accessToken string + loading |
JWT access token + auto-refresh on mount | All API calls |
UserTempContext |
Level 5 | Temp user data { name, email, phone } |
Pass registration data to OTP page | CreateAccount → OtpVerification |
SideBarContext |
Innermost | sideBar string (current route) |
Track active sidebar item based on URL | Sidebar, App |
Auto-refresh mechanism: AccessTokenContext fires a GET /refresh-token request on app mount. While loading, children are not rendered ({!loading && children}), preventing flash of unauthenticated content.
src/
├── components/
│ ├── Navbar.jsx → Responsive navigation with auth-aware buttons
│ ├── Footer.jsx → Site-wide footer with social links + nav
│ ├── SideBar.jsx → Dashboard vertical icon navigation
│ └── ui/ → shadcn/ui primitives
│ ├── button.jsx → Button component with variants
│ ├── input.jsx → Styled input component
│ └── resizable-navbar.jsx → Full navbar system (NavBody, NavItems,
│ MobileNav, NavbarLogo, NavbarButton)
│
├── contexts/ → 6 React Context providers (see State Management)
├── services/
│ ├── api.js → Axios-based API client (7 functions)
│ └── supabaseClient.js → Supabase client instance (future use)
├── config/
│ └── config.js → Vite env variable loader
└── lib/
└── utils.js → clsx + tailwind-merge utility (cn function)
Tailwind CSS 3 (utility classes)
└── shadcn/ui (class-variance-authority components)
└── tw-animate-css (animation utilities)
└── Motion / Framer Motion (complex animations)
Design System Highlights:
- Color Palette: Dark zinc backgrounds (
zinc-950,zinc-900), emerald/cyan accents for CTAs and highlights, gradient cards (pink-to-blue for debit card) - Glassmorphism:
backdrop-blur-xl,bg-white/5,border border-white/10used on cards and panels - Typography: Inter variable font via Tailwind config
- Radial Gradients: Background orbs with
blur-[120px]for ambient lighting effects - Hover Animations: Cards with
hover:mt-0 hover:mb-8lift effect, buttons withgroup-hover:translate-x-1arrow slide - Class Merging:
cn()utility combinesclsx+tailwind-mergeto avoid class conflicts
Shinrai-Bank/
│
├── backend/
│ ├── src/
│ │ ├── config/
│ │ │ ├── config.js # Environment variable loader (dotenv)
│ │ │ └── database.config.js # MongoDB Atlas connection handler
│ │ │
│ │ ├── controllers/
│ │ │ └── auth.controller.js # All business logic (587 lines)
│ │ │ ├── register() # → User registration + OTP
│ │ │ ├── login() # → Authentication + token issuance
│ │ │ ├── verify() # → OTP verification
│ │ │ ├── refreshToken() # → Token rotation
│ │ │ ├── getDashboardData() # → Dashboard data fetch
│ │ │ ├── sendMoney() # → Atomic money transfer
│ │ │ ├── getTransactions() # → Paginated history
│ │ │ └── checkBalance() # → Password-protected balance
│ │ │
│ │ ├── models/
│ │ │ ├── user.model.js # User schema (30+ fields, enums, defaults)
│ │ │ ├── otp.model.js # OTP schema (TTL: 600s auto-delete)
│ │ │ ├── session.model.js # Session schema (IP, UA, revocation)
│ │ │ └── transaction.model.js # Transaction schema (sender, receiver, amount)
│ │ │
│ │ ├── routes/
│ │ │ └── auth.route.js # 8 API endpoint definitions
│ │ │
│ │ ├── services/
│ │ │ └── email.service.js # Azure Communication Services email sender
│ │ │
│ │ ├── utils/
│ │ │ ├── otp.util.js # OTP generation + HTML email template
│ │ │ └── card.util.js # Luhn-valid card number generator
│ │ │
│ │ ├── app.js # Express app (middleware + routes)
│ │ └── server.js # Entry point (DB connect + listen)
│ │
│ ├── .env # Environment variables (not committed)
│ └── package.json # Dependencies + scripts
│
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── Navbar.jsx # Responsive navbar (desktop + mobile)
│ │ │ ├── Footer.jsx # Site-wide footer with links
│ │ │ ├── SideBar.jsx # Dashboard vertical icon nav
│ │ │ └── ui/ # shadcn/ui component primitives
│ │ │ ├── button.jsx
│ │ │ ├── input.jsx
│ │ │ └── resizable-navbar.jsx
│ │ │
│ │ ├── pages/
│ │ │ ├── Home.jsx # Landing page with hero section
│ │ │ ├── Login.jsx # Login form (email + password + type)
│ │ │ ├── CreateAccount.jsx # Registration form (9 fields)
│ │ │ ├── OtpVerification.jsx # OTP input and verification
│ │ │ ├── Dashboard.jsx # Main dashboard (card, txns, transfers, bills)
│ │ │ ├── SendMoney.jsx # Transfer form (3 methods)
│ │ │ ├── CheckBalance.jsx # Password-protected balance check
│ │ │ ├── Transactions.jsx # Paginated transaction history table
│ │ │ ├── Settings.jsx # User settings (profile, security, theme)
│ │ │ ├── Loan.jsx # Loan types + EMI calculator
│ │ │ ├── Contact.jsx # Contact info + form
│ │ │ ├── AboutUs.jsx # About page with stats + team
│ │ │ ├── Application.jsx # Service application hub (7 cards)
│ │ │ ├── AccountManagement.jsx # Placeholder service page
│ │ │ ├── KYC.jsx # Placeholder service page
│ │ │ ├── CardServices.jsx # Placeholder service page
│ │ │ ├── LoanServices.jsx # Placeholder service page
│ │ │ ├── ContactServices.jsx # Placeholder service page
│ │ │ ├── ChequeServices.jsx # Placeholder service page
│ │ │ └── InternetBanking.jsx # Placeholder service page
│ │ │
│ │ ├── contexts/
│ │ │ ├── AccessTokenContext.jsx # JWT + auto-refresh on mount
│ │ │ ├── UserDataContext.jsx # User profile + isLogedIn flag
│ │ │ ├── SideBarContext.jsx # Active sidebar item (URL-driven)
│ │ │ ├── UserTempContext.jsx # Temp data (registration → OTP)
│ │ │ ├── TransferToContext.jsx # Transfer method state
│ │ │ └── TransactionsContext.jsx # Transaction data state
│ │ │
│ │ ├── services/
│ │ │ ├── api.js # Axios API client (7 functions)
│ │ │ └── supabaseClient.js # Supabase client (future use)
│ │ │
│ │ ├── config/
│ │ │ └── config.js # Vite env variable loader
│ │ │
│ │ ├── lib/
│ │ │ └── utils.js # cn() = clsx + tailwind-merge
│ │ │
│ │ ├── assets/ # Static assets (hero.png, SVGs)
│ │ ├── test/ # Test files
│ │ │ └── Test.jsx
│ │ │
│ │ ├── App.jsx # Root component with routing
│ │ ├── App.css # Minimal app styles
│ │ ├── main.jsx # Entry point (context providers + router)
│ │ └── index.css # Global styles + shadcn/ui CSS variables
│ │
│ ├── .env # Frontend env variables
│ ├── vite.config.js # Vite configuration
│ └── tailwind.config.js # Tailwind CSS configuration
│
├── design/ # UI design assets & screenshots
│ ├── Screenshot 2026-06-21 205532.png
│ └── *.jpg, *.png
│
├── postman/ # Postman API collection
├── .github/ # GitHub workflows & config
├── secrets/ # Secret management (gitignored)
│
├── ARCHITECTURE.md # Detailed architecture documentation
├── DATABASE_DESIGN.md # Database schema documentation
├── FEATURE.md # Complete feature catalog (75 features)
├── SETUP_GUIDE.md # Detailed setup & troubleshooting
├── TECHNICAL_DEBT.md # Known issues & improvement areas
├── LICENSE # MIT License
├── .gitignore # Git ignore rules
└── README.md # This file
The backend is configured with Jest and Supertest for API testing:
cd backend
# Run tests
npm test
# Run tests with coverage report
npm run test:coverageConfiguration: Uses --experimental-vm-modules flag for ESM support with Jest.
Dev Dependencies:
jest— testing frameworksupertest— HTTP assertion library@jest/globals— ESM-compatible Jest globals
Test files are located in frontend/src/test/. Run via Vite's test runner or add a test script to package.json.
| Component | Host | URL |
|---|---|---|
| Frontend | Vite dev server | http://localhost:5173 |
| Backend | Nodemon | http://localhost:3000 |
| Database | MongoDB Atlas | Cloud (M0 free tier) |
| Azure Communication Services | Cloud |
| Concern | Recommendation |
|---|---|
| Frontend Hosting | Vercel, Netlify, or CDN-backed static hosting |
| Backend Hosting | Railway, Render, AWS EC2, or Azure App Service |
| Database | MongoDB Atlas M10+ for production workloads |
| Environment Variables | Platform-native secrets management |
| HTTPS | Mandatory — enforce via reverse proxy (nginx) or platform |
| Rate Limiting | Add express-rate-limit middleware |
| Logging | Structured logging with Winston or Pino |
| Monitoring | PM2 process manager with health checks |
| CI/CD | GitHub Actions for automated testing and deployment |
| CORS | Update origin whitelist to production domain |
# Frontend
cd frontend
npm run build # Output: dist/
npm run preview # Local preview of production build
# Backend
cd backend
NODE_ENV=production node src/server.js| Document | Description |
|---|---|
| ARCHITECTURE.md | System design, component diagrams, Mermaid flowcharts, technology decisions |
| DATABASE_DESIGN.md | Complete database schema, ER diagrams, field documentation |
| FEATURE.md | Full feature catalog — 54 implemented, 17 partial, 4 planned (75 total) |
| SETUP_GUIDE.md | Step-by-step setup with troubleshooting guide |
| TECHNICAL_DEBT.md | Known issues, code quality improvements, security enhancements |
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Commit changes:
git commit -m "Add your feature" - Push to branch:
git push origin feature/your-feature - Open a Pull Request
- ES Modules — use
import/export(notrequire) - Naming —
camelCasefor variables/functions,PascalCasefor React components - Files —
.jsxfor React components,.jsfor utilities and backend code - Comments — add JSDoc comments for all exported functions
- Tests — write tests for new features using Jest + Supertest
- Commits — use descriptive commit messages following conventional commits
This project is licensed under the MIT License.
MIT License
Copyright (c) 2026 SK SAHIL UDDIN
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
Built with ❤️ by SK SAHIL UDDIN