CoreBank is a full-stack, secure digital banking platform designed for private banking recruitment portfolios. It showcases high-concurrency transaction safety (ACID), cryptographic security compliance, modern state propagation, and a premium mobile user experience.
graph TD
subgraph Mobile Client [Flutter Mobile App]
UI[UI Widgets & Themes] --> VM[Riverpod Notifiers]
VM --> Cache[Hive Preferences]
VM --> KeyStore[Secure Storage Keychain/Keystore]
VM --> API[Dio HTTP Client]
end
subgraph Containerized Backend [Spring Boot Service]
API --> Filter[JWT Security Filters]
Filter --> Controller[Rest Controllers]
Controller --> Service[Transfer & Account Services]
Service --> Lock[Pessimistic Locking & Order Resolver]
Lock --> Repo[JPA Repositories]
end
subgraph Database [PostgreSQL]
Repo --> DB[(PostgreSQL Database)]
end
Private banking applications demand strict consistency and protection against race conditions like the double-spend vulnerability.
During funds transfers, raw balances must be protected from concurrent writes:
- The system requests a database-level lock using JPA's
LockModeType.PESSIMISTIC_WRITEon both the sender's and receiver's account entities. - This blocks other threads from reading or modifying these balances until the current transaction commits or rolls back.
When two concurrent transactions try to lock the same two accounts in opposite orders (e.g. Account A sending to Account B, while Account B sends to Account A), a deadlock can occur. CoreBank solves this deterministically:
- Before acquiring database locks, the transfer service sorts the account numbers lexicographically (alphabetically).
- Locks are always acquired in sorted order (smaller account ID first), making circular wait states mathematically impossible.
- All database write services are annotated with Spring's
@Transactional(using PostgreSQL as the transactional resource). - If any validation or network step fails mid-transfer, both accounts automatically rollback to their exact pre-transaction values, maintaining zero-leak database consistency.
CoreBank implements bank-standard security schemes to protect user sessions both over the network and locally on the device:
- Protected by JSON Web Tokens (JWT) signed with HMAC-SHA-384 algorithm.
- Local JWT Expiration Check: On application startup, a custom parser checks the
expclaim claim in the JWT. If the token has expired, the session is invalidated immediately, bypassing the passcode unlock screen and directing the user to the main password login screen. - Dio API Error Interceptor: Intercepts
401 Unauthorizedand403 Forbiddenresponses inside the Dio client layer (AuthInterceptor) to clear expired tokens, log the user out of Riverpod, and trigger GoRouter redirect to/loginautomatically.
- Sensitive credentials (email/password) are stored on disk using hardware-backed Android Keystore and iOS Keychain via
flutter_secure_storage. - Private preferences (Theme selection, biometric toggle) are stored locally in Hive boxes.
- Passwords are salted and hashed on the backend using BCrypt before persistence in PostgreSQL.
- Biometric Bypass: Fingerprint/FaceID local authentication uses
local_auth. - App Lockscreen: A custom, responsive numeric keypad overlay (
UnlockScreen) prompts for a 4-digit PIN (default:1234) on every app launch. - App Lifecycle Observer: Employs
WidgetsBindingObserverto detect when the app is minimized (paused/inactive) and locks the viewport immediately. Re-entering the app requires a biometric scan or passcode verification to prevent unauthorized physical access.
- Implements
fl_chartto render balance trend curves over selected periods (This Month, Last Month, etc.). - Balances are computed chronologically by traversing recent transactions backwards from the current balance.
- Uses the
pdfpackage to construct printable account statements locally. - Formats statements into styled tabular PDF files containing the bank header, account overview metrics, net flow calculations, and full transaction history, saved securely using
path_provider.
- Keypad overlay requiring authorization (
1234or Biometric check) before submitting any outgoing transaction.
- Uses
flutter_local_notificationsto fire transaction success banners at the top of the OS status bar upon transfer completion.
You can add this description to the Projects section of your CV:
CoreBank — Secured Digital Banking Application (Full-Stack)
- Architecture: Engineered a secure full-stack banking app using Spring Boot, PostgreSQL, Docker Compose, and Flutter.
- ACID Concurrency Locks: Prevented double-spend race conditions by implementing JPA Pessimistic Locking (
PESSIMISTIC_WRITE) on balances, resolving database deadlocks through alphabetical account ID sorting. - Hardware-Backed Session Security: Implemented JWT token security, BCrypt password hashing, and encrypted credentials storage using Android Keystore / iOS Keychain (
flutter_secure_storage). - Passcode & Biometric App Lock: Built a local passcode unlock sheet matching a background lifecycle observer to lock the viewport instantly when the app is minimized, requiring a fingerprint scan or 4-digit PIN on resume.
- Dio Client Interceptors: Built custom interceptors to capture expired token responses (
401/403), clear the cache, and redirect to the login screen. - Dynamic UX Details: Integrated customized financial analytics line graphs (
fl_chart), physical PDF generation (pdf), and local receipt push notifications.
- Docker / Docker Desktop
- Flutter SDK (stable channel)
Navigate to the root directory containing the docker-compose.yml file and start the backend stack:
docker compose up -d --buildThis launches the backend Spring application, PostgreSQL DB, RabbitMQ, and Redis instances.
Navigate to the mobile app folder, fetch packages, and run:
cd mobile_app
flutter pub get
flutter run- Email:
alice@corebank.com - Password:
password123 - Unlock/Transfer PIN:
1234