A comprehensive Spring Boot REST API for financial transaction management with role-based access control, risk scoring, and automated payment approval workflows.
- User Authentication & Authorization: JWT-based authentication with role-based access control (USER, CHECKER, ADMIN)
- Account Management: Multi-currency account support (USD, CAD, EUR)
- Payment Processing: Internal and external transfers with automatic currency conversion
- Risk Scoring: Automatic risk calculation for payments with auto-approval for low-risk transactions
- Checker Workflow: Approval queue for checkers with risk-based prioritization
- Exchange Rates: Support for international transfers with automatic currency conversion
- n8n Integration: Webhook notifications for payment approvals
- Java 17 - Programming language
- Spring Boot 3.2.0 - Framework
- Maven - Build tool and dependency management
- PostgreSQL 15 - Database
- Docker & Docker Compose - Database containerization
- Spring Web - REST API endpoints
- Spring Data JPA - Database persistence
- Spring Security - Authentication and authorization
- JJWT 0.12.3 - JWT token generation and validation
- BCrypt - Password hashing
- Lombok - Code simplification
- Hibernate - ORM framework
- Java 17 or higher
- Docker Desktop (for PostgreSQL)
- Maven (or use Maven wrapper
mvnw.cmd)
Using Docker (Recommended):
-
Start Docker Desktop
-
Run:
docker-compose up -d
Or use the provided script:
.\start-postgres.ps1 -
Verify it's running:
docker ps
Database Credentials:
- Host:
localhost:5432 - Database:
transactiq_db - Username:
postgres - Password:
postgres
.\mvnw.cmd spring-boot:runWait for:
Tomcat started on port(s): 8080 (http)
Health Check:
curl http://localhost:8080/api/healthOr open in browser: http://localhost:8080/api/health
TransactIQ-backend/
├── src/main/java/com/transactiq/backend/
│ ├── config/ # Configuration classes
│ │ ├── CorsConfig.java # Global CORS configuration
│ │ ├── SecurityConfig.java # Spring Security & JWT setup
│ │ ├── RestTemplateConfig.java # RestTemplate bean
│ │ └── ExchangeRateInitializer.java # Default exchange rates
│ ├── controller/ # REST API endpoints
│ │ ├── AccountController.java # Account management APIs
│ │ ├── AuthController.java # Authentication APIs
│ │ ├── DashboardController.java # Dashboard data APIs
│ │ ├── PaymentController.java # Payment management APIs
│ │ ├── ExchangeRateController.java # Exchange rate APIs
│ │ ├── CheckerDashboardController.java # Checker dashboard APIs
│ │ ├── AdminController.java # Admin panel APIs
│ │ └── HealthController.java # Health check endpoint
│ ├── entity/ # Database entities
│ │ ├── Account.java # Account entity
│ │ ├── Payment.java # Payment entity
│ │ ├── User.java # User entity with roles
│ │ └── ExchangeRate.java # Exchange rate entity
│ ├── repository/ # Data access layer
│ │ ├── AccountRepository.java
│ │ ├── PaymentRepository.java
│ │ ├── UserRepository.java
│ │ └── ExchangeRateRepository.java
│ ├── service/ # Business logic layer
│ │ ├── AccountService.java
│ │ ├── PaymentService.java
│ │ ├── ExchangeRateService.java
│ │ ├── RiskScoreService.java # Risk calculation
│ │ └── N8nNotifier.java # n8n webhook integration
│ ├── filter/ # Security filters
│ │ └── JwtAuthenticationFilter.java
│ ├── util/ # Utility classes
│ │ ├── JwtUtil.java # JWT operations
│ │ ├── RoleUtil.java # Role-based access helpers
│ │ └── SecurityUtil.java # Security context helpers
│ └── TransactIqBackendApplication.java
├── src/main/resources/
│ └── application.yml # Application configuration
├── docker-compose.yml # PostgreSQL container setup
├── init.sql # Database initialization
├── pom.xml # Maven dependencies
└── README.md
id(BIGINT, PRIMARY KEY)username(VARCHAR, UNIQUE, NOT NULL)email(VARCHAR, UNIQUE, NOT NULL)password(VARCHAR, NOT NULL) - BCrypt hashedfirst_name(VARCHAR)last_name(VARCHAR)role(VARCHAR/ENUM) -USER,CHECKER,ADMIN(default:USER)is_active(BOOLEAN, default: true)created_at(TIMESTAMP)
id(BIGINT, PRIMARY KEY)account_number(VARCHAR, UNIQUE, NOT NULL) - Auto-generatedaccount_type(VARCHAR, NOT NULL) -CHECKING,SAVINGS,BUSINESSbalance(DECIMAL, NOT NULL, default: 0.00)currency(VARCHAR(3), NOT NULL) -USD,CAD,EUR(default:USD)is_active(BOOLEAN, default: true)user_id(BIGINT, FOREIGN KEY → users.id)created_at(TIMESTAMP)
id(BIGINT, PRIMARY KEY)transaction_id(VARCHAR, UNIQUE, NOT NULL) - Auto-generatedamount(DECIMAL, NOT NULL, min: 0.01)currency(VARCHAR(3), NOT NULL) - From account currencyconverted_amount(DECIMAL) - Converted amount for different currencyconverted_currency(VARCHAR(3)) - To account currencyexchange_rate(DECIMAL(19, 6)) - Exchange rate usedstatus(VARCHAR) -PENDING,APPROVED,REJECTED,COMPLETEDtransfer_type(VARCHAR) -INTERNAL,EXTERNALrisk_score(DECIMAL(5,2)) - Risk score 0-100risk_level(VARCHAR) -LOW,MEDIUM,HIGH,VERY_HIGHauto_approved(BOOLEAN) - True if auto-approveddescription(VARCHAR)from_account_id(BIGINT, FOREIGN KEY → accounts.id)to_account_id(BIGINT, FOREIGN KEY → accounts.id)created_at(TIMESTAMP)approved_at(TIMESTAMP)approved_by(BIGINT, FOREIGN KEY → users.id)
id(BIGSERIAL, PRIMARY KEY)from_currency(VARCHAR(3), NOT NULL)to_currency(VARCHAR(3), NOT NULL)rate(DECIMAL(19, 6), NOT NULL)is_active(BOOLEAN, default: true)created_at(TIMESTAMP)updated_at(TIMESTAMP)- UNIQUE(from_currency, to_currency)
-
USER (Default)
- Create and view own accounts
- Create payments
- View own payment history
- Cannot approve/reject payments
-
CHECKER
- All USER permissions
- View approval queue
- View risk statistics
- Approve/reject payments
- Cannot manage users
-
ADMIN
- All CHECKER permissions
- Manage users (view, update roles)
- View all accounts
- System administration
All protected endpoints require a JWT token in the Authorization header:
Authorization: Bearer <token>
Register a new user.
Request:
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123"
}Response:
{
"id": 1,
"email": "john@example.com",
"username": "johndoe",
"role": "user",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Login with email and password.
Request:
{
"email": "john@example.com",
"password": "password123"
}Response:
{
"id": 1,
"email": "john@example.com",
"username": "johndoe",
"role": "user",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Get current authenticated user details.
Headers: Authorization: Bearer <token>
Get all accounts for the authenticated user.
Headers: Authorization: Bearer <token>
Response:
[
{
"id": 1,
"accountNumber": "ACC123456789",
"accountType": "CHECKING",
"balance": 5000.00,
"currency": "USD",
"isActive": true,
"createdAt": "2025-01-01T00:00:00"
}
]Create a new account.
Request:
{
"name": "Savings Account",
"type": "savings",
"currency": "USD",
"balance": 1000.00
}Search for external accounts (for external transfers).
Query Parameters:
q(required): Search query (minimum 3 characters)
Get all payments for the authenticated user (or all payments for CHECKER/ADMIN).
Headers: Authorization: Bearer <token>
Response:
[
{
"id": 1,
"transactionId": "TXN123456789",
"amount": 100.00,
"currency": "USD",
"status": "APPROVED",
"riskScore": 5.00,
"riskLevel": "LOW",
"autoApproved": true,
"transferType": "internal",
"fromAccount": { ... },
"toAccount": { ... },
"conversion": { ... },
"createdAt": "2025-01-01T00:00:00"
}
]Create a new payment.
Request:
{
"fromAccountId": 1,
"toAccountId": 2,
"amount": 100.00,
"currency": "USD",
"description": "Payment description",
"transferType": "internal"
}Response:
{
"id": 1,
"amount": 100.00,
"currency": "USD",
"status": "PENDING",
"riskScore": 5.00,
"riskLevel": "LOW",
"autoApproved": false,
"conversion": null
}Approve a payment (CHECKER/ADMIN only).
Headers: Authorization: Bearer <token>
Reject a payment (CHECKER/ADMIN only).
Headers: Authorization: Bearer <token>
Get dashboard data for the authenticated user.
Headers: Authorization: Bearer <token>
Response:
{
"totalBalance": 10000.00,
"recentTransactions": 10,
"activeAccounts": 2,
"pendingPayments": 3,
"approvedPayments": 7,
"currencyBalances": [
{
"currency": "USD",
"balance": 8000.00,
"percentage": 80.0
},
{
"currency": "CAD",
"balance": 2000.00,
"percentage": 20.0
}
]
}Get pending payments sorted by risk score.
Headers: Authorization: Bearer <token>
Get risk statistics.
Headers: Authorization: Bearer <token>
Get complete checker dashboard.
Headers: Authorization: Bearer <token>
Get all users.
Headers: Authorization: Bearer <token>
Update user role.
Request:
{
"role": "checker"
}Get admin dashboard.
Headers: Authorization: Bearer <token>
Get all active exchange rates.
Headers: Authorization: Bearer <token>
Convert amount between currencies.
Query Parameters:
amount(required): Amount to convertfromCurrency(required): Source currency codetoCurrency(required): Target currency code
Health check endpoint (no authentication required).
Response:
{
"status": "UP",
"timestamp": "2025-01-01T00:00:00"
}The system automatically calculates a risk score (0-100) for each payment based on:
- Amount Risk (0-30 points): Higher amounts = higher risk
- Currency Risk (0-20 points): International transfers = higher risk
- Transfer Type Risk (0-15 points): External transfers = higher risk
- Time Risk (0-10 points): Unusual hours (2 AM - 6 AM) = higher risk
- Balance Risk (0-15 points): Low remaining balance = higher risk
- History Risk (0-10 points): First-time recipients = higher risk
- LOW (0-30): Auto-approved if amount is small
- MEDIUM (31-60): Requires manual approval
- HIGH (61-80): Requires manual approval, priority review
- VERY_HIGH (81-100): Requires manual approval, urgent review
Payments are automatically approved if:
- Risk score ≤ 20 AND amount ≤ $10,000
- OR Risk score ≤ 30 AND amount ≤ $1,000
Examples:
- $10 payment → Risk: 0 → Auto-approved ✅
- $500 payment → Risk: 0 → Auto-approved ✅
- $10,000 international transfer → Risk: 40+ → PENDING (manual approval)
⚠️
- USD (US Dollar)
- CAD (Canadian Dollar)
- EUR (Euro)
The system initializes with default exchange rates on startup:
- USD → CAD: 1.350000
- USD → EUR: 0.920000
- CAD → USD: 0.740741
- EUR → USD: 1.086957
When creating a payment between accounts with different currencies:
- System detects currency difference
- Looks up exchange rate from database
- Calculates converted amount
- Stores both original and converted amounts
- On approval, deducts original amount and adds converted amount
Example:
- Transfer $100 USD to CAD account
- Exchange Rate: 1 USD = 1.35 CAD
- Deducts: $100 USD
- Adds: $135 CAD
The system sends webhook notifications to n8n when payments are approved.
Webhook URL: https://ancjainil.app.n8n.cloud/webhook/webhook/payment_approved
Payload:
{
"transactionId": "TXN123456789",
"amount": 100.00,
"currency": "USD",
"approvedBy": "admin",
"approvedAt": "2025-01-01T00:00:00",
"toEmail": "recipient@example.com"
}Note: Auto-approved payments do not trigger n8n notifications.
spring:
datasource:
url: jdbc:postgresql://localhost:5432/transactiq_db
username: postgres
password: postgres
jpa:
hibernate:
ddl-auto: update
show-sql: false
security:
jwt:
secret: your-secret-key-here
expiration: 86400000 # 24 hours
server:
port: 8080
cors:
allowed-origins: http://localhost:5173The backend is configured to allow requests from:
- Origin:
http://localhost:5173(React frontend) - Methods: GET, POST, PUT, DELETE, OPTIONS
- Headers: Authorization, Content-Type
- Credentials: Supported
curl http://localhost:8080/api/healthcurl -X POST http://localhost:8080/api/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"test@example.com","password":"password123"}'curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"password123"}'curl http://localhost:8080/api/accounts \
-H "Authorization: Bearer <token>"docker-compose up -ddocker-compose downdocker-compose logs postgresdocker-compose down -v- Check if another PostgreSQL instance is running
- Stop it or change port in
docker-compose.yml
- Make sure PostgreSQL is running
- Check Docker Desktop is started
- Verify database credentials in
application.yml
- Tokens expire after 24 hours
- Login again to get a new token
- Check risk score (should be ≤ 30 for small amounts)
- Verify sufficient balance in from account
- Check payment status in database
You can override configuration using environment variables:
$env:DB_USERNAME="your_username"
$env:DB_PASSWORD="your_password"
$env:JWT_SECRET="your_secret_key"- Password Hashing: BCrypt with salt
- JWT Tokens: Secure token-based authentication
- Role-Based Access Control: USER, CHECKER, ADMIN roles
- CORS Protection: Configured for specific origins
- Input Validation: Request validation using Jakarta Validation
- SQL Injection Protection: JPA/Hibernate parameterized queries
- Spring Boot Documentation: https://spring.io/projects/spring-boot
- PostgreSQL Documentation: https://www.postgresql.org/docs/
- JWT Documentation: https://jwt.io/
- Create a feature branch
- Make your changes
- Test thoroughly
- Commit and push
- Create a pull request
This project is part of the TransactIQ application.
Built with ❤️ using Spring Boot