Architecture
The AngularMicroFrontendsAndMicroServices project shows howto create a holiday booking portal build of 3 microservices with their own mircofrontends that are integrated in 1 customer facing system. The goal of this architecture is to split a system into independent mircoservices based on bounded contexts that can be developed independently by different teams and with technology independence. For the split of the system into microservices bounded contexts of Domain Driven Design should be used. The goal is to create microservices with distinct areas of responsibility. Each team can be responsible for 1 microservice and can develop it in its own rhythm and with its own technology stack.
To archive this architecture vision the Selfcontained Systems architecture is used. It is based on the idea that the microfrontends are integrated in a host system that knows only howto call the microfrontend and a messaging system that enables asynchronous communication between the microservices. That also provides fail safety if one of the microservices fails for a period of time because the other microservices can continue to serve the customers. The asynchronous communication causes eventually consistent behavior that has to be considered in the microservice implementation.
User perspective
The portal use sees the system like this:
For the user it is just one system to use.
System perspective
The payment system needs the information of the booked flights and hotels:
The payment microservice provides the users access to the hotel booking and flight booking microfrontends and receives the messages of the booked hotels and flights for the payment process.
Component perspective
This perspective shows the 3 microservices with their own frontends/backends/databases:
The payment frontend integrates the flight and hotel frontends to show one portal to the user. The flight and hotel backends send the bookings via a queue to the payment backend for billing.
Service architecture
The payment / flight / hotel services are build with different stacks but they share the clean architecture.

The clean architecture has 3 rings in the application. The first has all the connections to other systems like databases, rest interfaces, messaging interfaces, frontend, … and encapsulates the needed libraries and frameworks for this. The second ring has the dto to entity mappers to disconnect the interfaces from the internal data structures and the services that implement the use cases. The services work with the entities and have them in the method signatures. The third ring contains the dtos, entities and some utilities. In theory they should not contain anything of the used frameworks and be decoupled to be able to switch ORMs or Restmappers. In practice that does happen every 1-2 decades if at all and a complete rewrite of the application is probable in such a case. Because of that the entities and dtos do contain framework annotations.
Architecture Goals
This software architecture persues three goals:
-To keep the system / application maintainable in the long term
-To enable the developers to find the location for a application change quickly
-To enable teams to work independently
The first goal can slow the developers down because writing spaghetti code is faster in the short term. The majority of the developers prefer to work in a reasonable architecture because they see the value for maintenance. The second goal saves time on searching for the right place to implement a change in a system and having the confidence to not break something because of surprising side effects. The third goal is to reduce the the communication/coordination efforts between teams. To wait for other teams to provide a feature for your team to be able to continue or start on a feature is slowing down the process. To mitigate that the services should be as independent as they can be with a reasonable effort.
Microservices
FlightSelection
The flightSelection service is build with an Angular frontend and a NestJs backend. The Angular frontend is used to enable a switch to Angular Native Federation if needed. The backend uses TypeOrm for entity mapping and Postgresql to store the entities. The frontend is served in the static directory that contains the compiled Angular frontend. To publish the bookings to the payment service the Mqtt library is used. The Messaging Service used is ActiveMQ Artemis.
The flightSelection service has been the prove of concept for the NestJs framework. The first impression of NestJs is that the switch from Spring Boot is easy. Many concepts like injection and repositories are similar and using them on the node platform worked. Clean architecture was easy to use with Typescript and NestJs. The Mqtt library worked well too. NestJs on Node is an alternative to Spring Boot for non compute intensive applications. Advantages are faster startup time and lower memory footprint.
HotelSelection
The hotelSelection service is build with an Angular frontend and a Kotlin/Spring Boot backend. The Angular frontend is used to enable a switch to Angular Native Federation if needed. The backend uses the usual rest controllers with services and Jpa repositories. To publish the bookings with Mqtt the Eclipse Paho library is used. The Messaging Service used is ActiveMQ Artemis.
The hotelSelection service has been the prove of concept for the use of Kotlin with Spring Boot. The Kotlin support of Spring Boot is very good there have been no problems. Kotlin has advantages to Java like better support of immutability, helpful operators, more elegant stream syntax, … . The difference becomes smaller with newer Java versions like 21. Kotlin is a good alternative if the system is stuck on an older Jdk version. It then provides all the new language features. If the Kotlin features are worth the switch compared to Java 21 is a question everybody has to decide for themself.
Payment
The payment service is build with Angular frontend and Java/Spring Boot backend. The Angular frontend is used to enable a switch to Angular Native Federation if needed. The backend uses the usual rest controllers with services and Jpa repositories. To receive the bookings with Mqtt the Eclipse Paho library is used and the bookings are stored in the database. The Messaging Service used is ActiveMQ Artemis.
The payment service frontend integrates the HotelSelection and FlightSelection frontends with IFrames. That makes the frontends completely independent. The alternative would be Angular Native Federation. That would create a coupling to the Angular Framework but improves the performance of switching the frontends. The backends of the Payment service and the HotelSelection service can be used to evaluate the differences between a Kotlin and a Java Spring Boot implementation.
Conclusion
A Microservice Architecture based on Self Contained Systems with Clean Architecture is a useful compromise of different alternatives. It supports the split of a system in several services based on bounded contexts to enable the independent development of the services by different teams. It has a flexible and stable messaging infrastructure that can mitigate problems with one of the services. It presents a single system to the user without strong coupling and it provides choice of the software stack for the development teams. The software stacks used in this project have there advantages and disadvantages. The selection should be made according to project requirements and developer skills.