Journal of CashAccount Microservice: Add Type Entities

Donnie Z
4 min readJun 1, 2024

--

Continuing from previous development journal, realizing the lacks of depth on requirement and hence modelling, Solution Architect mandated to improve the overall design, at least by logically define grouping of CashAccount, Transaction, and AccountOwner and persists it in configurable and extensible form.

ERD of Improved Models

Introducing types entities:

  1. AccountOwnerType
  2. AccountType
  3. AccountTransactionType
ERD after addition of three Types entities

Identified Types Based On Requirement

With the guidance from (hypothetical) Business Analyst, several examples of the types has been identified and most probably will be added into the system out-of-the-box.

AccountOwnerType

Examples of Account Owner Type:

  • BANK_SELF, the bank itself
  • STAFF, staff of the bank, might entitled to special rates, transaction fees, discount, etc.
  • INDI, individual customer
  • CORP, corporate or organization customer.
    Currently has same handling and process as INDI type.

AccountType

Examples of Account Type:

  • SAVING, minimum balance = 0, applicable only for STAFF, INDI and CORP owner type
  • DRAWERS, minimum balance = 0, can be owned only by the bank itself, to be used when customer deposit or withdraw cash via teller.
  • CLEARING, can be owned only by the bank itself, to be used for incoming/outgoing transfer.
  • INTERNAL, can be owned only by the bank itself, Account for bank internal only.

AccountTransactionType

Examples of Account Transaction Type:

  • Internal Transfer, applicable from customer to customer accounts
  • Incoming Transfer, applicable from clearing to customer account
  • Outgoing Transfer, applicable from customer account to clearing
  • Adjustments Transaction. Only for internal use only, requires C Level and Finance Dept. approval.”

These examples restrict the usage of each types depends on the business scenarios, for example, Internal Transfer only applicable between customer accounts. This restriction is not supported by the ERD above.

Type Applicability

The restriction, or in positive term, the applicability, can be implemented in Entity model as a join table. Take AccountTransactionType as an example. An AccountTransactionType is only applicable to few distinct AccountType. For detailed example, Internal Transfer is applicable from customer to customer accounts, and Outgoing Transfer is applicable from customer account to clearing account. Hence in AccountTransactionType we add a join table to determine its applicability to fromAccountType and toAccountType.

public class AccountTransactionType {
@Id
private String typeCode;
private String name;
private String notes;

@ManyToMany
@JoinTable
private Set<AccountType> applicableFromAccountTypes;

@ManyToMany
@JoinTable
private Set<AccountType> applicableToAccountTypes;
}
Updated Entity Class Diagram

After added the join tables, our ERD grow into this:

Improved ERD after addition of Types and Join Tables

Types Records Initialization

For this round of development, it is decided to use sql file to insert those out-of-the-box types records. Several testers prefer curl script to initialize the records, however programmers contest it that it requires the microservice to be up to be able to load the seeds data hence it was declined (although the records was actually inserted by programmers via postman as part of their development testing!).

Spring Data Rest — Inserting foregin key

During testing using postman to insert into AccountOwner, turns out the OwnerType is not inserted without any error message. Rather than struggling with how to make Spring Data Rest works with referenced records, the developer took the right course: implement proper controller for the endpoint.

Spring Data Rest does not (easily?) inserts foreign key field.

The more proper and easily-enhance-able controller:

@RestController
@RequestMapping("/accountOwner")
public class AccountOwnerController {

@Autowired
private AccountOwnerRepository accountOwnerRepository;

@Autowired
private AccountOwnerTypeRepository accountOwnerTypeRepository;

@GetMapping("/{id}")
public AccountOwner get(@PathVariable("id") Long id) {
return accountOwnerRepository.getReferenceById(id);
}

@PostMapping
@Transactional
public AccountOwner create(@RequestBody AccountOwner accountOwner) {
accountOwner.setType(
accountOwnerTypeRepository.findById(accountOwner.getType().getTypeCode())
.orElseThrow(() -> new RuntimeException("ownerType not found")));
return accountOwnerRepository.save(accountOwner);
}
}
AccountOwner record inserted with foreign key type_code, with BUT

The controller works BUT we cannot enforce the id field because it is automatically filled by database. The definition from Entity class: @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; On normal case, this is desireable for primary key to be enforced automatically, but on some case it is not. Programmer decide to take a note on this behavior and let it be for now. The record will be used as a seed anyway, so the plan to take id = 0 as the bank’s id can be done by manually editing the sql insert script.

Final inserted records

The basic settings of types records finally inserted into database

Conclusion

Types Entities has been added accordingly, and several seeds data has been provided as sql script (types applicability is yet to be added).

References

  1. Source code donniexyz/med-spring-boot-demo article/med-3 tag
  2. Working with Relationships in Spring Data REST
  3. Persisting Enums in JPA

--

--