A production-ready full-stack fintech application with atomic transactions, JWT authentication, and comprehensive security. Built with Node.js/Express, Prisma ORM, PostgreSQL, and React + Vite. Perfect for fintech portfolios, interviews, and learning modern payment system architecture.
Live Features:
- β REST API with Swagger/OpenAPI documentation
- β Full-featured React frontend with user search for recipient lookup
- β Atomic transactions with idempotency support
- β Fintech-grade security (bcrypt, rate limiting, CORS, Helmet)
- β PostgreSQL with Decimal precision for money handling
- β Comprehensive error handling and input validation
- β User Authentication - Register & Login with JWT tokens
- β Wallet Management - Create wallet on signup, check balance, deposit funds
- β Money Transfer - Atomic transactions (deduct + add + log in one operation)
- β Recipient Search - Find users by email for safe transfers
- β Transaction History - Track all sent and received transfers with descriptions
- β Input Validation - Email, password strength, amount validation
- β Rate Limiting - Protect against abuse (configurable)
- β Error Handling - Centralized error middleware with proper HTTP status codes
- π Atomic Transactions - Database-level consistency (all-or-nothing money transfers)
- π JWT Authentication - Secure token-based auth with expiration
- π Password Security - bcryptjs hashing with 10-round salt
- π Precise Money Handling - Prisma Decimal type (prevents float rounding errors)
- β‘ Rate Limiting - Configurable request throttling
- π‘οΈ Security Headers - Helmet.js for OWASP compliance
- π Idempotent Transfers - Retry-safe with Idempotency-Key support
- π Database Indexes - Optimized queries on sender/receiver lookups
- π CORS Protection - Configurable allowed origins
| Layer | Technology |
|---|---|
| Backend | Node.js 18+, Express.js 4 |
| Database | PostgreSQL 12+, Prisma ORM 5 |
| Frontend | React 18, Vite 5, Axios |
| Authentication | JWT (jsonwebtoken) |
| Security | bcryptjs, Helmet, express-rate-limit |
| API Docs | Swagger/OpenAPI 3.0 |
| Testing | Jest, Supertest |
payment-api/
βββ frontend/ # React + Vite app
β βββ src/
β β βββ pages/ # Dashboard, Transfer, Wallet, History, etc.
β β βββ services/ # API clients (authService, transactionService, userService)
β β βββ contexts/ # AuthContext for state management
β β βββ components/ # Reusable UI components
β βββ package.json
β βββ vite.config.js
βββ src/
β βββ app.js # Express app configuration
β βββ server.js # Server bootstrap with JWT_SECRET guard
β βββ controllers/ # HTTP request handlers
β β βββ authController.js # Register/Login
β β βββ walletController.js # Balance/Deposit
β β βββ transactionController.js # Transfer/History
β β βββ userController.js # Search users by email
β βββ services/ # Business logic & DB transactions
β β βββ authService.js
β β βββ walletService.js
β β βββ transactionService.js
β β βββ userService.js
β βββ routes/ # API route definitions
β β βββ authRoutes.js
β β βββ walletRoutes.js
β β βββ transactionRoutes.js
β β βββ userRoutes.js
β βββ middleware/ # Express middleware
β β βββ authMiddleware.js # JWT verification with error differentiation
β β βββ errorMiddleware.js # Centralized error handling
β β βββ rateLimiter.js
β βββ lib/
β β βββ prisma.js # Shared Prisma client
β βββ utils/
β β βββ generateToken.js # JWT utility functions
β β βββ validators.js # Input validation helpers
β βββ config/
β β βββ db.js # Database config
β β βββ swagger.js # OpenAPI specifications
β βββ prisma/
β βββ schema.prisma # Data schema
βββ .env # Environment variables (add your own)
βββ .env.example # Template for .env
βββ package.json
βββ README.md
The frontend is a React + Vite app with secure authentication context and real-time API integration.
- Login - User authentication with JWT persistence
- Register - New user signup with wallet creation
- Dashboard - Overview of balance and recent transactions
- Wallet - Check balance and deposit funds
- Transfer - Search recipients by email, enter amount & optional description
- History - View all sent and received transactions
cd frontend
npm install
npm run dev # Start dev server (http://localhost:5173)
npm run build # Production buildmodel User {
id Int
email String @unique
name String
passwordHash String
wallet Wallet?
sentTransactions Transaction[] @relation("sender")
receivedTransactions Transaction[] @relation("receiver")
createdAt DateTime
updatedAt DateTime
}model Wallet {
id Int
userId Int @unique
balance Decimal @default(0) # Precise money handling
createdAt DateTime
updatedAt DateTime
}model Transaction {
id Int
senderId Int
receiverId Int
amount Decimal
status String @default("completed")
reference String @unique # Unique per transfer
idempotencyKey String @unique # For retry safety
description String? # Payment note
createdAt DateTime
@@index([senderId]) # Query optimization
@@index([receiverId])
}POST /api/auth/register- Create user accountPOST /api/auth/login- Get JWT token
GET /api/wallet/balance- Check wallet balancePOST /api/wallet/deposit- Add funds to wallet
POST /api/transactions/transfer- Send money (with optional idempotency key)GET /api/transactions/history- Get all transactions
GET /api/users/search?email=example- Find users by email (authenticated)
Full Documentation: Visit http://localhost:5000/api-docs for interactive Swagger UI.
git clone https://github.com/MIKECHITI/payment-api.git
cd payment-apinpm install
# Create .env file
cp .env.example .env
# Add to .env:
DATABASE_URL="postgresql://user:password@localhost:5432/payment_api"
JWT_SECRET="your-super-secret-key-min-32-chars"
PORT=5000
NODE_ENV=development
ALLOWED_ORIGIN="http://localhost:5173"
RATE_LIMIT_WINDOW=15
RATE_LIMIT_MAX_REQUESTS=100# Generate Prisma client
npm run prisma:generate
# Create and migrate database
npm run prisma:push
# (Optional) Seed with test data
npm run prisma:seednpm run dev # Development with nodemon
npm start # ProductionBackend runs on http://localhost:5000
cd frontend
npm install
npm run devFrontend runs on http://localhost:5173
Run comprehensive test suite:
npm test # Run all tests
npm run test:watch # Watch modeSee TESTING.md for detailed test documentation and examples.
Visit http://localhost:5000/api-docs to:
- View all endpoint schemas
- Test requests with sample data
- See response formats
- Copy curl commands
See SWAGGER.md for complete guide.
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/payment_api"
# JWT
JWT_SECRET="min-32-character-random-secret-key" # Required for startup
JWT_EXPIRE="7d"
# Server
PORT=5000
NODE_ENV=development|production
# CORS
ALLOWED_ORIGIN="http://localhost:5173" # Frontend URL
# Rate Limiting
RATE_LIMIT_WINDOW=15 # Minutes
RATE_LIMIT_MAX_REQUESTS=100 # Requests per windowβ
Password Security - 10-round bcrypt hashing
β
Token Expiration - JWT expiry control
β
Atomic Transactions - Database-level consistency
β
Input Validation - Email, password, amount checks
β
Rate Limiting - Configurable throttling
β
CORS Protection - Whitelist allowed origins
β
Security Headers - Helmet.js defaults
β
Error Sanitization - No sensitive data in responses
β
Decimal Precision - Prevents float rounding errors
β
Idempotency - Safe retry mechanism for transfers
JWT_SECRET not set:
Error: FATAL: JWT_SECRET is not set in environment
Solution: Add JWT_SECRET to .env before starting server.
Database connection fails:
Error: connect ECONNREFUSED 127.0.0.1:5432
Solution: Ensure PostgreSQL is running on port 5432. Check DATABASE_URL in .env.
Port 5000 already in use:
# Use different port
PORT=3000 npm run devSee LAUNCH.md and QUICKSTART.md for more details.
- π STRUCTURE.md - Detailed project architecture
- π LAUNCH.md - Complete startup guide
- π QUICKSTART.md - 5-minute quick start
- π SWAGGER.md - API documentation guide
- π TESTING.md - Test suite documentation
- π PROJECT_COMPLETE.md - Feature checklist
Add these topics to your repository for better discoverability:
payment-api fintech rest-api express nodejs react prisma postgresql jwt-authentication full-stack atomic-transactions security
This project covers:
- REST API Design - Resource-oriented endpoints
- Database Design - Relationships, transactions, indexes
- Authentication - JWT token lifecycle
- Security - Input validation, password hashing, CORS
- Error Handling - Centralized middleware pattern
- Frontend Integration - React with authenticated API calls
- Testing - Unit and integration test patterns
Perfect for fintech interviews, portfolio demonstration, or learning production API patterns.
ISC
MIKECHITI - GitHub
Questions or Issues? Open an issue on GitHub Issues
Create .env file:
DATABASE_URL="postgresql://user:password@localhost:5432/payment_api"
PORT=5000
NODE_ENV=development
JWT_SECRET=your_jwt_secret_key_change_in_production
JWT_EXPIRE=7d
RATE_LIMIT_WINDOW=15
RATE_LIMIT_MAX_REQUESTS=100# Generate Prisma client
npm run prisma:generate
# Run migrations
npm run prisma:migrate
# Or push schema to DB
npm run prisma:pushnpm start # Production
npm run dev # Development (with nodemon)Server runs on http://localhost:5000
POST /api/auth/register
POST /api/auth/login
GET /api/wallet/balance (requires auth)
POST /api/wallet/deposit (requires auth)
POST /api/transactions/transfer (requires auth)
GET /api/transactions/history (requires auth)
GET /health
curl -X POST http://localhost:5000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"password": "securepassword123"
}'Response:
{
"message": "User registered successfully",
"token": "eyJhbGc...",
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
}curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "john@example.com",
"password": "securepassword123"
}'curl -X GET http://localhost:5000/api/wallet/balance \
-H "Authorization: Bearer <token>"Response:
{
"balance": 0,
"walletId": 1
}curl -X POST http://localhost:5000/api/wallet/deposit \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"amount": 100
}'Response:
{
"message": "Deposit successful",
"balance": 100,
"amount": 100
}curl -X POST http://localhost:5000/api/transactions/transfer \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"receiverId": 2,
"amount": 50
}'Response:
{
"message": "Transfer successful",
"transaction": {
"id": 1,
"reference": "txn_abc123",
"from": "John Doe",
"to": "Jane Smith",
"amount": 50,
"status": "completed",
"timestamp": "2024-01-15T10:30:00Z"
}
}curl -X GET http://localhost:5000/api/transactions/history \
-H "Authorization: Bearer <token>"Response:
{
"transactions": [
{
"id": 1,
"reference": "txn_abc123",
"from": "John Doe",
"to": "Jane Smith",
"amount": 50,
"status": "completed",
"type": "sent",
"timestamp": "2024-01-15T10:30:00Z"
}
],
"total": 1
}The transfer operation uses Prisma $transaction to ensure atomicity:
const result = await prisma.$transaction(async (tx) => {
// All three operations succeed together or fail together
await tx.wallet.update({ ... }); // deduct sender
await tx.wallet.update({ ... }); // add receiver
await tx.transaction.create({ ... }); // log transaction
});- Token generated on login
- Token validated on protected routes
- Prevents unauthorized access
- Email format validation
- Password minimum length
- Amount must be positive number
- Validation errors (400)
- Authorization errors (401)
- Not found errors (404)
- Server errors (500)
-
Atomic Transactions: "Money transfers require atomicity. If any step fails, the entire transaction rolls back to prevent inconsistent state."
-
JWT Authentication: "JWT tokens are stateless and scalable. No need for session storage on the server."
-
Database Design: "One-to-one relationship between users and wallets ensures each user has exactly one wallet. Foreign keys maintain referential integrity."
-
Error Handling: "Comprehensive error handling with proper HTTP status codes and meaningful error messages."
-
Rate Limiting: "Rate limiting prevents abuse and protects against brute force attacks."
-
Input Validation: "Always validate user input before processing to prevent invalid data and potential security issues."
- β Passwords hashed with bcryptjs (10 rounds)
- β JWT tokens with expiration
- β Environment variables for secrets
- β CORS protection
- β Helmet for HTTP headers
- β Rate limiting on all routes
- β Input validation on all endpoints
- Import endpoints into Postman
- Register a test user
- Copy token from response
- Add to
Authorization: Bearer <token>header - Test each endpoint
- Register user 1 (Alice)
- Register user 2 (Bob)
- Alice deposits 100
- Alice transfers 50 to Bob
- Check Alice's balance (should be 50)
- Check Bob's balance (should be 50)
- View transaction history for both
- β
Local server verified on
http://localhost:5000 - β
Swagger docs available at
http://localhost:5000/api-docs - β
Prisma schema synced with
npm run prisma:push - β
Test suite passed successfully with
npm test - β End-to-end flow validated: register β deposit β transfer β history
- Transaction reversal
- Withdrawal functionality
- Admin panel for transaction monitoring
- Webhook notifications
- Two-factor authentication
- Swagger/OpenAPI documentation
- Unit tests with Jest
- Integration tests
- Docker containerization
- Deployment to cloud (AWS, Heroku, etc.)
Solution: Check DATABASE_URL in .env and ensure PostgreSQL is running
Solution: Run npm run prisma:generate
Solution: Add JWT_SECRET to .env
ISC
Built for fintech internship preparation
Ready for your internship interview! This project demonstrates:
- Full-stack API development
- Database design for financial systems
- Authentication & authorization
- Atomic transactions
- Professional code organization
- Error handling & validation