A complete history of every architectural decision, refactor, and evolution of this project — from a simple monolithic CLI to a layered JavaFX desktop application with a planned PostgreSQL persistence layer.
- Project Evolution Overview
- Phase 1 — Foundation
- Phase 2 — Domain Enrichment
- Phase 3 — Service & Auth Layer
- Phase 4 — BigDecimal & Precision Refactor
- Phase 5 — View-Based Architecture (MVC Refactor)
- Phase 6 — Repository Pattern & Clean Architecture
- Phase 7 — JavaFX Presentation Layer
- Phase 8 — JDBC & PostgreSQL Integration Plan
- Architecture Diagrams
- Key Design Decisions
ff1d708 Initial commit
│
▼
c8708d6 Banking System partially established
│
▼ ── Phase 1: Domain Models (Customer, Account, Transaction)
│
▼ ── Phase 2: BigDecimal precision, encapsulation
│
▼ ── Phase 3: Service layer, Authentication, Authorization
│
▼ ── Phase 4: Monolithic CLI → View-based MVC refactor
│
▼ ── Phase 5: Repository Pattern, CustomerRepository
│
▼ ── Phase 6: JavaFX Presentation Layer
│
52c2f8b HEAD — JavaFX app + JDBC plan ready
Commits: ff1d708 → c8708d6 → 420c6fc → 4ee85af
The initial skeleton of the system — a basic Account class and a partially established banking system with no validation, no service layer, and no separation of concerns.
| Commit | Change |
|---|---|
ff1d708 |
Initial commit |
c8708d6 |
Banking System partially established |
420c6fc |
README documentation |
4ee85af |
Updated README |
BankingSystem.java ← everything in one place
Account.java ← basic fields, no validation
Customer.java ← minimal
Commits: 9ba8fed → 48ca965 → 5bc8d6d → 9b3a900 → 73ed008 → 1529e71 → dfac086
9ba8fed — IdGenerator
Introduced IdGenerator for UUID-based customer ID generation. First step toward unique identity management.
48ca965 — BankService
Created BankService as the central orchestrator for customer management and account creation. This was the seed of the service layer.
5bc8d6d — Customer account management
Enhanced Customer class with addAccount() and proper account list management. Introduced the composition relationship between Customer and Account.
9b3a900 — National ID Validation
First version of Egyptian National ID validation. Introduced NationalIdValidator with format and governorate code checks.
dfac086 — AccountType enum + validation
Refactored Account class with proper validation and introduced AccountType enum (SAVINGS / CURRENT). First use of polymorphism hint.
1529e71 + 25956df — Transaction recording
Implemented Transaction recording inside account operations. Added Instant timestamp management.
At this point the project was still tightly coupled — BankService, CLI, and domain logic were mixing. The next phases would separate them.
Commits: f5ff636 → 0cf1c29 → f8af15c → 337ff45 → 9486eb0 → 7358633 → 137a8aa
f5ff636 — Employee & Role classes
Created Employee and Role (later renamed EmployeeRole) as first-class domain objects. Employees are now Person subtypes with role-based identity.
0cf1c29 — Authentication & Authorization
Introduced AuthenticationService and AuthorizationService as separate concerns. Login validation and role checking extracted from the CLI.
f8af15c — Login validation
Hardened authentication with proper credential matching and exception throwing on failure.
337ff45 — ResourceNotFoundException & UnauthorizedException
First custom exception hierarchy for the service layer. Operations now fail with meaningful typed exceptions instead of null returns or generic errors.
9486eb0 — AccountService
Extracted AccountService from BankService. First step in decomposing the monolithic service.
7358633 — Employee & login refactor
Improved AuthenticationService and Employee — better login validation, proper field management, password matching method.
137a8aa — RBAC in deposit/withdrawal
Role-Based Access Control enforced at the service layer for financial operations. Tellers can deposit/withdraw. CS cannot. Managers can do everything.
BankEmployeeCLI → BankService
→ AuthenticationService
→ AuthorizationService
→ AccountService
Commits: dcfd80d → 19028c5 → 33d0495 → f05a4c7 → b073234
Using double or float for financial amounts is a critical bug. 0.1 + 0.2 = 0.30000000000000004 in floating point. Banking systems require exact decimal arithmetic.
dcfd80d — BigDecimal migration
Replaced all monetary double values with BigDecimal across Account, Transaction, and related classes. This is a breaking change that touched every layer.
f05a4c7 — Map-based account storage
Refactored account storage in BankService from List<Account> to Map<String, Account> for O(1) lookup by account number. First performance-aware data structure decision.
b073234 — BigDecimal normalization + CustomerRepository
Critical fix: introduced SCALE = 2 and RoundingMode.HALF_UP normalization so all balances have exactly 2 decimal places (500.00 not 500). Also introduced CustomerRepository as a dedicated data store — seeds the Repository Pattern.
// Before
private double balance;
// After
private BigDecimal balance; // normalized to 2 decimal places
private static final int SCALE = 2;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;This commit fixed a class of test failures where
assertEquals(500.00, balance)was failing becausebalancewas500without scale.
Commits: 95e9569 → 6bff539 → Add(feat) view-based architecture
BankEmployeeCLI.java had grown to 700+ lines. It was handling:
- Login UI
- Menu display
- Customer operations
- Account operations
- Transaction operations
- Input validation
- Display formatting
This violated Single Responsibility Principle and made the class unmaintainable.
95e9569 — LoginView + MenuView
Extracted login handling and menu display into dedicated view classes. BankEmployeeCLI became a thin controller.
6bff539 — CustomerView, AccountView, TransactionView, InputValidator
Full MVC decomposition:
Before: After:
BankEmployeeCLI.java (700+ lines) BankEmployeeCLI.java (~100 lines)
├── LoginView.java
├── MenuView.java
├── CustomerView.java
├── AccountView.java
├── TransactionView.java
└── InputValidator.java
- Each view class: ~100–200 lines
InputValidatorreused across all views (DRY principle)CustomerView.findCustomerByNationalId()shared byAccountViewandTransactionView- Business logic untouched — only presentation changed
Commits: b073234 → cd00e9b → c23d4d9 → f13f3ed
cd00e9b — Project structure reorganization
Moved source files under main/java and added test/ directory. Standard Maven layout enforced. This enabled proper JUnit 5 integration.
c23d4d9 — Role rename: Role → EmployeeRole
Renamed Role enum to EmployeeRole across the entire codebase for clarity and consistency. Updated all references in Employee, AuthorizationService, AuthenticationService, and controllers.
f13f3ed — Withdrawal fee tests
Updated all JUnit tests to account for the 1% withdrawal fee. Tests now calculate expectedBalance = deposit - (withdrawal + withdrawal * 0.01) explicitly. This hardened the test suite significantly.
BankService
├── CustomerRepository ← findByNationalId(), save(), clear()
├── AccountRepository ← findByNumber(), exists(), save()
└── TransactionRepository ← findByAccountNumber(), save()
All repositories support clear() for test isolation via BankService.reset().
Commits: e13dd59 → eab2f46 → 09fa2ec → 9f02967 → 7533cca → e718c8a → ea85a86
JavaFX was added as a separate presentation layer that calls only the Service Layer. It never touches repositories directly — maintaining Clean Architecture.
JavaFX Controllers → BankService → Repositories → In-Memory
e13dd59 — MainApp + Navigation
MainApp.java added as the JavaFX entry point. NavigationManager introduced for screen switching. SessionManager handles the currently logged-in employee across screens.
eab2f46 — FXML files
All FXML layouts created:
login.fxmldashboard.fxmlcustomer_form.fxml/customer_list.fxmlaccount_form.fxml/account_list.fxmltransaction_form.fxml/transaction_history.fxml
09fa2ec — EmployeeAware interface
Introduced EmployeeAware interface implemented by all controllers that need the current employee. SessionManager injects the employee after every screen navigation.
public interface EmployeeAware {
void setEmployee(Employee employee);
}9f02967 — Dynamic fee calculation in UI
TransactionFormController enhanced with real-time fee calculation display. When a teller types a withdrawal amount, the UI shows the 1% fee and total deduction live — before confirming.
7533cca — Readability refactor
TransactionFormController and TransactionHistoryController cleaned up. FXML column widths adjusted for proper table layout.
e718c8a — Enhanced export
Transaction export refactored: customer-specific export and all-transactions export. File handling improved with proper append-only logic and duplicate prevention.
ea85a86 — Initial FXML resources
Final FXML files and resource structure committed. CSS theme (bank-theme.css) added for consistent banking UI.
presentation/
├── controllers/
│ ├── LoginController.java
│ ├── DashboardController.java
│ ├── DashboardHomeController.java
│ ├── CustomerFormController.java
│ ├── CustomerListController.java
│ ├── AccountFormController.java
│ ├── AccountListController.java
│ ├── TransactionFormController.java
│ ├── TransactionHistoryController.java
│ └── EmployeeAware.java ← interface for session injection
└── util/
├── NavigationManager.java
├── SessionManager.java
└── AlertHelper.java
Status: Planned — next milestone
Document:docs/PostgreSQL_JDBC_Plan.docx
The current system uses in-memory repositories — data is lost on every restart. The next step is replacing those repositories with a real persistence layer.
| SQLite | MySQL | PostgreSQL | |
|---|---|---|---|
| Server-based | ❌ | ✅ | ✅ |
| Full ACID | ✅ | ✅ | |
| Stored Procedures | ❌ | ✅ | |
| Banking standard | ❌ | ✅ | |
| Spring Boot default | ❌ | ✅ |
Four tables mapped directly to the domain model:
-- ENUMs
CREATE TYPE employee_role AS ENUM ('CS', 'TELLER', 'MANAGER');
CREATE TYPE account_type AS ENUM ('SAVINGS', 'CURRENT');
CREATE TYPE txn_type AS ENUM ('DEPOSIT', 'WITHDRAWAL', 'TRANSFER');
-- Tables
employees ── id, username, password, national_id, role, is_active
customers ── id, name, national_id, email, phone, is_deleted
accounts ── account_number, customer_id (FK), type, balance NUMERIC(19,4), overdraft_limit
transactions ── id, account_number (FK), type, amount, fee, total, balance_after, employee_id (FK)
-- Indexes
CREATE INDEX idx_customers_national_id ON customers(national_id);
CREATE INDEX idx_accounts_customer_id ON accounts(customer_id);
CREATE INDEX idx_transactions_account ON transactions(account_number);
CREATE INDEX idx_transactions_timestamp ON transactions(timestamp DESC);
NUMERIC(19,4)is used for all monetary values — neverFLOATorDOUBLE.
The JDBC layer will be added as a new package without touching existing code:
repository/ ← kept as-is (used by JUnit tests)
infrastructure/
├── DatabaseConnection.java ← HikariCP connection pool
└── dao/
├── CustomerDao.java ← replaces CustomerRepository in production
├── AccountDao.java ← replaces AccountRepository in production
└── TransactionDao.java ← replaces TransactionRepository in production
The most critical pattern — the withdraw operation uses manual transaction management:
connection.setAutoCommit(false); // START TRANSACTION
try {
// 1. SELECT ... FOR UPDATE (lock the row — prevent race conditions)
// 2. Validate balance / overdraft rules
// 3. UPDATE accounts SET balance = new_balance
// 4. INSERT INTO transactions (audit record)
connection.commit(); // COMMIT ✅
} catch (Exception e) {
connection.rollback(); // ROLLBACK ❌ — data stays consistent
throw e;
} finally {
connection.setAutoCommit(true);
}Three stored procedures planned in PL/pgSQL:
| Procedure | Purpose |
|---|---|
sp_deposit(account, amount, employee...) |
Atomic deposit + audit insert |
sp_withdraw(account, amount, employee...) |
Atomic withdraw with overdraft check + FOR UPDATE lock |
sp_get_account_statement(account, from, to) |
Filtered transaction history |
| Step | Task | Estimated Time |
|---|---|---|
| 1 | Install PostgreSQL, create database | 1 day |
| 2 | Run DDL script | 2 hours |
| 3 | Add Maven dependencies (PostgreSQL driver + HikariCP) | 30 min |
| 4 | DatabaseConnection.java with HikariCP |
2 hours |
| 5 | CustomerDao.java |
3 hours |
| 6 | AccountDao.java |
3 hours |
| 7 | TransactionDao.java with ACID transactions |
4 hours |
| 8 | Stored Procedures in PostgreSQL | 4 hours |
| 9 | Wire into BankService via config |
2 hours |
| 10 | Run full JUnit test suite | 3 hours |
Once JDBC is complete, migration to Spring Boot is straightforward:
JDBC (Now) Spring Boot (Future)
──────────────────────────────────────────────────────
CustomerDao (manual SQL) → CustomerRepository extends JpaRepository
PreparedStatement boilerplate → Zero SQL for basic CRUD
Manual commit/rollback → @Transactional annotation
ResultSet mapping → @Entity auto-mapping
┌─────────────────────────────────────────────┐
│ Presentation Layer │
│ JavaFX Controllers │ CLI Views │
│ (presentation/) │ (view/) │
└──────────────┬──────────────────────────────┘
│ calls only
┌──────────────▼──────────────────────────────┐
│ Service Layer │
│ BankService │ AuthenticationService │
│ AccountService │ TransactionService │
│ AuthorizationService │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ Repository Layer │
│ CustomerRepository │ AccountRepository │
│ TransactionRepository │
│ (in-memory HashMap) │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Presentation Layer │
│ JavaFX Controllers │ CLI Views │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ Service Layer │
│ (ZERO changes needed) │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ Infrastructure Layer (NEW) │
│ CustomerDao │ AccountDao │
│ TransactionDao │ DatabaseConnection │
│ (JDBC + HikariCP) │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ PostgreSQL Database │
│ employees │ customers │ accounts │
│ transactions │
│ + Stored Procedures │
└─────────────────────────────────────────────┘
Financial amounts must use NUMERIC(19,4) in SQL and BigDecimal in Java. Floating point arithmetic is unsuitable for money.
In-memory repositories are kept for unit testing. JDBC DAOs will be used in production. BankService.reset() enables clean test isolation.
Role checks happen inside AuthorizationService, not in the UI. This means both the CLI and JavaFX UI are protected by the same rules — no duplication.
Transaction objects are immutable after creation. The transaction log is an append-only audit trail — records are never updated or deleted.
Customers and accounts use is_deleted / is_active flags instead of hard deletes. Banking systems require full audit history.
employee_name and employee_role are stored directly in the transactions table (not just the FK). This ensures the audit log remains accurate even if an employee's details change later.
The withdraw stored procedure uses SELECT ... FOR UPDATE to lock the account row. This prevents race conditions if two tellers attempt to withdraw from the same account simultaneously.
This document is auto-generated from the git commit history and reflects the actual evolution of the codebase.