diff --git a/DOMAINMODEL.md b/DOMAINMODEL.md
new file mode 100644
index 000000000..a8f29f3a8
--- /dev/null
+++ b/DOMAINMODEL.md
@@ -0,0 +1,24 @@
+
+# Domain Model – Banking Application
+
+| Class | Fields | Method | What it does | Return values |
+|--------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|------------------------------------------------------------------------|-------------------------------|
+| **Customer** | `customerId: String`
`accounts: Map` | `createCurrentAccount()` | Creates and stores a new CurrentAccount for this customer | `CurrentAccount` |
+| | | `createSavingsAccount()` | Creates and stores a new SavingsAccount for this customer | `SavingsAccount` |
+| | | `getAccount(accountId)` | Retrieves an Account from the customer’s accounts by ID | `Account` |
+| | | `getAccountId()` | Returns the customer’s unique ID | `String` |
+| | | `addAccount(account)` | Adds an Account to the customer’s collection | `void` |
+| **Account (abstract)** | `accountId: String`
`customerId: String`
`balance: int`
`transactions: List` | `deposit(amount)` | Adds funds, updates balance, and records a Transaction | `void` |
+| | | `withdraw(amount)` | Subtracts funds, updates balance, records a Transaction (checks funds) | `void` |
+| | | `generateStatement()` | Processes transactions into a formatted bank statement | `String` |
+| | | `getBalance()` | Returns the current balance | `int` |
+| | | `getAccountId()` | Returns this account’s unique ID | `String` |
+| | | `addTransaction(transaction)` | Adds a Transaction to the account’s ledger | `void` |
+| | | `getTransactions()` | Returns the list of all Transactions for this account | `List` |
+| **CurrentAccount** | *(inherits fields from Account)* | *(inherits all methods from Account)* | Same behavior as Account | Same as Account |
+| **SavingsAccount** | *(inherits fields from Account)* | *(inherits all methods from Account)* | Same behavior as Account | Same as Account |
+| **Transaction** |`accountId: String`
`date: LocalDate`
`amount: float`
`type: String (CREDIT/DEBIT)`
`balanceAtTime: float` | `getDate()` | Returns the transaction date | `LocalDate` |
+| | | `getAmount()` | Returns the transaction amount | `float` |
+| | | `getBalanceAtTime()` | Returns the balance after this transaction | `gloat` |
+| | | `getType()` | Returns whether it was a CREDIT or DEBIT | `String` |
+| | | `getAccountId()` | Returns acountId | `String` |
\ No newline at end of file
diff --git a/src/main/java/com/booleanuk/core/Account.java b/src/main/java/com/booleanuk/core/Account.java
new file mode 100644
index 000000000..877760924
--- /dev/null
+++ b/src/main/java/com/booleanuk/core/Account.java
@@ -0,0 +1,92 @@
+package com.booleanuk.core;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class Account {
+ private final String accountId;
+ private final String customerId;
+ private float balance;
+ private final List transactions;
+
+ public Account(String accountId, String customerId, float balance) {
+ this.accountId = accountId;
+ this.customerId = customerId;
+ this.balance = balance;
+ this.transactions = new ArrayList<>();
+
+ }
+
+ public void deposit(float amount) {
+ if (amount <= 0.0f) {
+ throw new IllegalArgumentException("deposit amount must be positive");
+ }
+ this.balance += amount;
+
+ this.transactions.add(new Transaction(
+ this.accountId, LocalDate.now(), amount,"CREDIT", this.balance
+ ));
+ }
+
+ public void withdraw(float amount) {
+ if (amount <= 0.0f) {
+ throw new IllegalArgumentException("deposit amount must be positive");
+ }
+ this.balance -= amount;
+ this.transactions.add(new Transaction(
+ this.accountId,
+ LocalDate.now(),
+ amount,
+ "DEBIT",
+ this.balance
+ ));
+ }
+
+ public String generateStatement() {
+ DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy");
+ List transactions = new ArrayList<>(this.getTransactions());
+ transactions.sort((a, b) -> b.getDate().compareTo(a.getDate()));
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("date || credit || debit || balance");
+
+ for (int i = 0; i < transactions.size(); i++) {
+ Transaction trans = transactions.get(i);
+ String date = trans.getDate().format(dtf);
+ String credit = "CREDIT".equals(trans.getType()) ? String.format("%.2f", trans.getAmount()) : " ";
+ String debit = "DEBIT".equals(trans.getType()) ? String.format("%.2f", trans.getAmount()) : " ";
+ String balance = String.format("%.2f", trans.getBalanceAtTime());
+
+
+ sb.append("\n")
+ .append(date).append(" || ")
+ .append(credit).append(" || ")
+ .append(debit).append(" || ")
+ .append(balance);
+ }
+
+ return sb.toString();
+
+ }
+
+
+ public float getBalance() {
+ return this.balance;
+ }
+
+ public String getAccountId() {
+ return this.accountId;
+ }
+
+ public void addTransaction(Transaction transaction) {
+ this.transactions.add(transaction);
+ }
+
+
+ public List getTransactions() {
+ return this.transactions;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/booleanuk/core/CurrentAccount.java b/src/main/java/com/booleanuk/core/CurrentAccount.java
new file mode 100644
index 000000000..e32891816
--- /dev/null
+++ b/src/main/java/com/booleanuk/core/CurrentAccount.java
@@ -0,0 +1,8 @@
+package com.booleanuk.core;
+
+public class CurrentAccount extends Account {
+
+ public CurrentAccount(String accountId, String customerId) {
+ super(accountId, customerId, 0.0f);
+ }
+}
diff --git a/src/main/java/com/booleanuk/core/Customer.java b/src/main/java/com/booleanuk/core/Customer.java
new file mode 100644
index 000000000..f0b0fee2d
--- /dev/null
+++ b/src/main/java/com/booleanuk/core/Customer.java
@@ -0,0 +1,43 @@
+package com.booleanuk.core;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class Customer {
+ private String customerId;
+ private Map accounts;
+
+ public Customer(String customerId) {
+ this.customerId = customerId;
+ this.accounts = new HashMap<>();
+ }
+
+ public Account createCurrentAccount(){
+ String accountId = UUID.randomUUID().toString();
+ CurrentAccount newAccount = new CurrentAccount(accountId, this.customerId);
+ this.accounts.put(accountId, newAccount);
+ return newAccount;
+ }
+
+ public Account createSavingsAccount(){
+ String accountId = UUID.randomUUID().toString();
+ SavingsAccount newSavingsAccount = new SavingsAccount(accountId, this.customerId);
+ this.accounts.put(accountId, newSavingsAccount);
+ return newSavingsAccount;
+ }
+
+ public Account getAccount(String accountId){
+ return accounts.get(accountId);
+ }
+
+ public String getCustomerId() {
+ return this.customerId;
+ }
+ public void setCustomerId(String customerId) {}
+
+
+ public void addAccount(Account account){
+ accounts.put(account.getAccountId(), account);
+ }
+}
diff --git a/src/main/java/com/booleanuk/core/Main.java b/src/main/java/com/booleanuk/core/Main.java
new file mode 100644
index 000000000..b9bb3b888
--- /dev/null
+++ b/src/main/java/com/booleanuk/core/Main.java
@@ -0,0 +1,41 @@
+package com.booleanuk.core;
+
+import java.time.LocalDate;
+
+public class Main {
+ public static void main(String[] args) {
+
+ // Create a customer
+ Customer customer = new Customer("C-001");
+ System.out.println("Customer ID: " + customer.getCustomerId());
+ // Create accounts via methods
+ Account current = customer.createCurrentAccount();
+ Account savings = customer.createSavingsAccount();
+
+ System.out.println("Created Current Account ID: " + current.getAccountId());
+ System.out.println("Created Savings Account ID: " + savings.getAccountId());
+
+ Account foundCurrent = customer.getAccount(current.getAccountId());
+ Account foundSavings = customer.getAccount(savings.getAccountId());
+
+ System.out.println("Found Current equals created? " + (foundCurrent == current));
+ System.out.println("Found Savings equals created? " + (foundSavings == savings));
+
+ Account external = new CurrentAccount("ACC-001", "C-001");
+ customer.addAccount(external);
+ System.out.println("Added external account with ID: " + external.getAccountId());
+ System.out.println("Lookup external: " + (customer.getAccount("ACC-001") == external));
+
+ Account account = new CurrentAccount("ACC-023", "C-1");
+
+ // Add the three example transactions
+ account.addTransaction(new Transaction("ACC-023", LocalDate.of(2012, 1, 10), 1000.0f, "CREDIT", 1000.0f));
+ account.addTransaction(new Transaction("ACC-023", LocalDate.of(2012, 1, 13), 2000.0f, "CREDIT", 3000.0f));
+ account.addTransaction(new Transaction("ACC-023", LocalDate.of(2012, 1, 14), 500.0f, "DEBIT", 2500.0f));
+
+ // Print the statement
+ System.out.println(account.generateStatement());
+ }
+
+
+}
diff --git a/src/main/java/com/booleanuk/core/SavingsAccount.java b/src/main/java/com/booleanuk/core/SavingsAccount.java
new file mode 100644
index 000000000..bf6390054
--- /dev/null
+++ b/src/main/java/com/booleanuk/core/SavingsAccount.java
@@ -0,0 +1,8 @@
+package com.booleanuk.core;
+
+public class SavingsAccount extends Account {
+ public SavingsAccount(String accountId, String customerId) {
+ super(accountId, customerId, 0.0f);
+
+ }
+}
diff --git a/src/main/java/com/booleanuk/core/Transaction.java b/src/main/java/com/booleanuk/core/Transaction.java
new file mode 100644
index 000000000..4a08cce98
--- /dev/null
+++ b/src/main/java/com/booleanuk/core/Transaction.java
@@ -0,0 +1,39 @@
+package com.booleanuk.core;
+
+import java.time.LocalDate;
+
+public class Transaction {
+ private String accountId;
+ private LocalDate date;
+ private float amount;
+ private String type;
+ private float balanceAtTime;
+
+ public Transaction(String accountId, LocalDate date, float amount, String type, float balanceAtTime) {
+ this.accountId = accountId;
+ this.date = date;
+ this.amount = amount;
+ this.type = type;
+ this.balanceAtTime = balanceAtTime;
+ }
+
+ public LocalDate getDate() {
+ return date;
+ }
+
+ public float getBalanceAtTime() {
+ return balanceAtTime;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public float getAmount() {
+ return amount;
+ }
+
+ public String getAccountId() {
+ return accountId;
+ }
+}
diff --git a/src/test/java/com/booleanuk/core/AccountTest.java b/src/test/java/com/booleanuk/core/AccountTest.java
new file mode 100644
index 000000000..9fc2e83e1
--- /dev/null
+++ b/src/test/java/com/booleanuk/core/AccountTest.java
@@ -0,0 +1,129 @@
+package com.booleanuk.core;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+
+public class AccountTest {
+
+ @Test
+ public void testDepositForCurrentAccount() {
+ Account account = new CurrentAccount("ACC-001", "C-123");
+ float initialBalance = account.getBalance();
+ float depositAmount = 500.0f;
+
+ account.deposit(depositAmount);
+
+ Assertions.assertEquals(initialBalance + depositAmount, account.getBalance());
+
+ }
+ @Test
+ public void testDepositForSavingAccount() {
+ Account account = new CurrentAccount("ACC-001", "C-123");
+ float initialBalance = account.getBalance();
+ float depositAmount = 400.0f;
+ account.deposit(depositAmount);
+
+ Assertions.assertEquals(initialBalance + depositAmount, account.getBalance());
+ }
+
+
+ @Test
+ public void testMultipleDepositsBalance() {
+ Account account = new CurrentAccount("ACC-001", "C-123");
+
+ account.deposit(1000f);
+ account.deposit(2000f);
+
+ Assertions.assertEquals(3000f, account.getBalance());
+ Assertions.assertEquals(2, account.getTransactions().size());
+ }
+
+ @Test
+ public void testWithdrawForCurrentAccount() {
+ Account account = new CurrentAccount("ACC-001", "C-123");
+
+ account.deposit(500.0f);
+ float startingBalance = account.getBalance();
+
+ float withdrawAmount = 200.0f;
+ account.withdraw(withdrawAmount);
+
+ Assertions.assertEquals(startingBalance - withdrawAmount, account.getBalance());
+
+ }
+
+ @Test
+ public void testMultipleWithdrawals() {
+ Account account = new CurrentAccount("ACC-001", "C-123");
+ account.deposit(1000f);
+
+ account.withdraw(100f);
+ account.withdraw(200f);
+
+ Assertions.assertEquals(700f, account.getBalance(), 0.0001f);
+ Assertions.assertEquals(3, account.getTransactions().size());
+
+ Transaction last = account.getTransactions().get(2);
+ Assertions.assertEquals("DEBIT", last.getType());
+ Assertions.assertEquals(200f, last.getAmount(), 0.0001f);
+ }
+
+ @Test
+ public void testAddTransactionStoresTransaction() {
+ Account account = new CurrentAccount("ACC-100", "C-123");
+
+ Transaction tx = new Transaction("ACC-100", LocalDate.now(), 500, "CREDIT", 500);
+ account.addTransaction(tx);
+
+ Assertions.assertEquals(1, account.getTransactions().size());
+ Assertions.assertEquals(tx, account.getTransactions().get(0));
+ }
+
+ @Test
+ public void testGetTransactionsInitiallyEmpty() {
+ Account account = new CurrentAccount("ACC-101", "C-123");
+
+ Assertions.assertNotNull(account.getTransactions());
+ Assertions.assertTrue(account.getTransactions().isEmpty());
+
+ }
+
+ @Test
+ public void testGenerateStatementContainsHeader() {
+ Account account = new CurrentAccount("ACC-102", "C-123");
+
+ account.addTransaction(new Transaction("ACC-102", LocalDate.of(2012, 1, 10), 1000f, "CREDIT", 1000f));
+ account.addTransaction(new Transaction("ACC-102", LocalDate.of(2012, 1, 13), 2000f, "CREDIT", 3000f));
+ account.addTransaction(new Transaction("ACC-102", LocalDate.of(2012, 1, 14), 500f, "DEBIT", 2500f));
+
+ String statement = account.generateStatement();
+
+ Assertions.assertTrue(statement.contains("date || credit || debit || balance"));
+ Assertions.assertTrue(statement.contains("14/01/2012"));
+ Assertions.assertTrue(statement.contains("13/01/2012"));
+ Assertions.assertTrue(statement.contains("10/01/2012"));
+ }
+
+ @Test
+ public void testStatementMatchesAcceptanceCriteriaExact() {
+ Account account = new CurrentAccount("ACC-023", "C-1");
+
+ account.addTransaction(new Transaction("ACC-023", java.time.LocalDate.of(2012, 1, 10), 1000.0f, "CREDIT", 1000.0f));
+ account.addTransaction(new Transaction("ACC-023", java.time.LocalDate.of(2012, 1, 13), 2000.0f, "CREDIT", 3000.0f));
+ account.addTransaction(new Transaction("ACC-023", java.time.LocalDate.of(2012, 1, 14), 500.0f, "DEBIT", 2500.0f));
+
+ String expected = String.join("\n",
+ "date || credit || debit || balance",
+ "14/01/2012 || || 500.00 || 2500.00",
+ "13/01/2012 || 2000.00 || || 3000.00",
+ "10/01/2012 || 1000.00 || || 1000.00"
+ );
+
+ Assertions.assertEquals(expected, account.generateStatement());
+ }
+
+
+
+}
diff --git a/src/test/java/com/booleanuk/core/CustomerTest.java b/src/test/java/com/booleanuk/core/CustomerTest.java
new file mode 100644
index 000000000..b1381d9f1
--- /dev/null
+++ b/src/test/java/com/booleanuk/core/CustomerTest.java
@@ -0,0 +1,56 @@
+package com.booleanuk.core;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class CustomerTest {
+
+ @Test
+ public void testCreateCurrentAccount() {
+ Customer customer = new Customer("A1-Idd");
+
+ Account account = customer.createCurrentAccount();
+
+
+ Assertions.assertEquals(account, customer.getAccount(account.getAccountId()));
+ Assertions.assertNotNull(account);
+
+ }
+
+ @Test
+ public void testCreateSavingsAccount() {
+ Customer customer = new Customer("B1-Idd");
+ Account account = customer.createSavingsAccount();
+
+ Assertions.assertEquals(account, customer.getAccount(account.getAccountId()));
+ Assertions.assertNotNull(account);
+ }
+
+ @Test
+ public void testAddAccount() {
+ Customer customer = new Customer("C-123");
+ Account account = new CurrentAccount("ACC-001", "C-123");
+
+ customer.addAccount(account);
+
+ Assertions.assertEquals(account, customer.getAccount("ACC-001"));
+ }
+
+ @Test
+ public void testGetAccountReturnsNullWhenMissing() {
+ Customer customer = new Customer("C-404");
+ Assertions.assertEquals(null, customer.getAccount("does-not-exist"));
+ }
+
+ @Test
+ public void testCreatedAccountsHaveDifferentIds() {
+ Customer customer = new Customer("C-uniq");
+
+ Account a1 = customer.createCurrentAccount();
+ Account a2 = customer.createSavingsAccount();
+
+ Assertions.assertEquals(false, a1.getAccountId().equals(a2.getAccountId()));
+ }
+
+
+}
diff --git a/src/test/java/com/booleanuk/core/TransactionTest.java b/src/test/java/com/booleanuk/core/TransactionTest.java
new file mode 100644
index 000000000..1cfc6981a
--- /dev/null
+++ b/src/test/java/com/booleanuk/core/TransactionTest.java
@@ -0,0 +1,33 @@
+package com.booleanuk.core;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+
+class TransactionTest {
+
+ @Test
+ void creditTransaction_storesAllFields() {
+ LocalDate date = LocalDate.of(2012, 1, 13);
+ Transaction tx = new Transaction("ACC-1", date, 2000.0f, "CREDIT", 3000.0f);
+
+ Assertions.assertEquals("ACC-1", tx.getAccountId());
+ Assertions.assertEquals(date, tx.getDate());
+ Assertions.assertEquals(2000.0f, tx.getAmount(), 0.0001f);
+ Assertions.assertEquals("CREDIT", tx.getType());
+ Assertions.assertEquals(3000.0f, tx.getBalanceAtTime(), 0.0001f);
+ }
+
+ @Test
+ void debitTransaction_storesAllFields() {
+ LocalDate date = LocalDate.of(2012, 1, 14);
+ Transaction tx = new Transaction("ACC-1", date, 500.0f, "DEBIT", 2500.0f);
+
+ Assertions.assertEquals("ACC-1", tx.getAccountId());
+ Assertions.assertEquals(date, tx.getDate());
+ Assertions.assertEquals(500.0f, tx.getAmount(), 0.0001f);
+ Assertions.assertEquals("DEBIT", tx.getType());
+ Assertions.assertEquals(2500.0f, tx.getBalanceAtTime(), 0.0001f);
+ }
+}