my-company-monolith

Monolith

View the Project on GitHub ivans-innovation-lab/my-company-monolith

projects/my-company-monolith CircleCI

This version of the application is deployed as a single monolithic application.

Domain Driven Design (DDD) is applied through Event Sourcing and CQRS. How Event Sourcing enables deployment flexibility - the application can be migrated and deployed as a microservices.

Table of Contents

Patterns and techniques:

  1. Command and Query Responsibility Separation (CQRS)
  2. Event Sourcing

Technologies

Key benefits

  1. Simple to develop - the goal of current development tools and IDEs is to support the development of monolithic applications
  2. Simple to deploy - you simply need to deploy the WAR/JAR file on the appropriate runtime
  3. Simple to scale - you can scale the application by running multiple copies of the application behind a load balancer
  4. Easy implementation of eventually consistent business transactions that could span multiple components
  5. Automatic publishing of events whenever data changes
  6. Reliable auditing for all updates

How it works

GitHub Logo

The application is literally split into a command-side (domain) component and a query-side (materialized view) component (this is CQRS in its most literal form).

Communication between the two components is event-driven and the demo uses simple event store (Database in this case - JPA) as a means of passing the events between components.

The command-side (domain) processes commands. Commands are actions which change state in some way. The execution of these commands results in Events being generated which are persisted by Axon, and propagated out to other components. In event-sourcing, events are the sole records in the system. They are used by the system to describe and re-build domain aggregates on demand, one event at a time.

The query-side (materialized view) is an event-listener and processor. It listens for the Events and processes them in whatever way makes the most sense. In this application, the query-side just builds and maintains a materialised view which tracks the state of the individual agregates (Project, Blog, …).

This application have REST API’s which is used to access capabilities of the domain and all materialized views.

Development

This project is driven using Maven.

Running instructions

Prerequisite

Step 1: Clone the project

$ git clone https://github.com/ivans-innovation-lab/my-company-monolith.git

Step 2: Run it

This application depends on other libraries (all available under http://maven.idugalic.pro/)

$ cd my-company-monolith
$ ./mvnw clean install
$ ./mvnw spring-boot:run

Issuing Commands & Queries with CURL

Get the JWT token

JWT (shortened from JSON Web Token) is the missing standardization for using tokens to authenticate on the web in general, not only for REST services. Currently, it is in draft status as RFC 7519. It is robust and can carry a lot of information, but is still simple to use even though its size is relatively small. Like any other token, JWT can be used to pass the identity of authenticated users between an identity provider and a service provider (which are not necessarily the same systems). It can also carry all the user’s claim, such as authorization data, so the service provider does not need to go into the database or external systems to verify user roles and permissions for each request; that data is extracted from the token.

Here is how JWT is designed to work:

$ curl testjwtclientid:MaYzkSjmkzPC57L@localhost:8080/oauth/token -d grant_type=password -d username=john.doe -d password=jwtpass

You’ll receive a response similar to below

{
 "access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDM3MTQ2MTgsInVzZXJfbmFtZSI6ImpvaG4uZG9lIiwiYXV0aG9yaXRpZXMiOlsiU1RBTkRBUkRfVVNFUiJdLCJqdGkiOiJiMDI5MGI3MS0zOTY2LTQ4ZTEtYThhOC02MzkzZjJjMjM1ZTYiLCJjbGllbnRfaWQiOiJ0ZXN0and0Y2xpZW50aWQiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.HJLARs7Q2Fdpkl0CP5X1hV6jBtri9tkIof61w16_X7w",
 "token_type":"bearer",
 "expires_in":43199,
 "scope":"read write",
 "jti":"b0290b71-3966-48e1-a8a8-6393f2c235e6"
 }

Create Blog post

Make sure to include correct access token below.

$ curl -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST -d '{"title":"xyz","rawContent":"xyz","publicSlug": "publicslug","draft": true,"broadcast": true,"category": "ENGINEERING", "publishAt": "2018-12-23T14:30:00+00:00"}' http://127.0.0.1:8080/api/blogpostcommands

Publish Blog post

$ curl -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST -d '{"publishAt": "2016-12-23T14:30:00+00:00"}' http://127.0.0.1:8080/api/blogpostcommands/{id}/publishcommand

UnPublish Blog post

$ curl -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST  http://127.0.0.1:8080/api/blogpostcommands/{id}/unpublishcommand

Query Blog posts

$ curl -H "Authorization: Bearer <TOKEN>" http://127.0.0.1:8080/api/blogposts

Create Project

$ curl -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST -d '{"name":"Name","repoUrl":"URL","siteUrl": "siteUrl","description": "desc"}' http://127.0.0.1:8080/api/projectcommands

Update Project

$ curl -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST -d '{"name":"Name2","repoUrl":"URL2","siteUrl": "siteUrl2","description": "desc2"}' http://127.0.0.1:8080/api/projectcommands/{id}/updatecommand

Activate Project

$ curl -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST http://127.0.0.1:8080/api/projectcommands/{id}/activatecommand

DeActivate Project

$ curl -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST http://127.0.0.1:8080/api/projectcommands/{id}/deactivatecommand

Query Projects

$ curl curl -H "Authorization: Bearer <TOKEN>" http://127.0.0.1:8080/api/projects

Create team

$ curl  -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST -d '{"name":"Name","description": "sdfsdfsdf"}' http://localhost:8080/api/teamcommands

Query team

$ curl  -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>"  http://localhost:8080/api/team

Activate team

$ curl  -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST  http://localhost:8080/api/teamcommands/<TEAM_ID>/activatecommand

Passivate team

$ curl  -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST  http://localhost:8080/api/teamcommands/<TEAM_ID>/passivatecommand

Add member to the team

$ curl  -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST  -d '{"userId":"user-id","weeklyHours": "100"}' http://localhost:8080/api/teamcommands/<TEAM_ID>/addmembercommand

Remove member from the team

$ curl  -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST  http://localhost:8080/api/teamcommands/<TEAM_ID>/removemembercommand/<MEMBER_ID>

Assign project to the team

$ curl  -H "Content-Type: application/json" -H "Authorization: Bearer <TOKEN>" -X POST  http://localhost:8080/api/teamcommands/<TEAM_ID>/assigncommand/<PROJECT_ID>

Angular application

Angular 5 application is a consumer of this API and represents the Front-end part of the solution.

References and further reading


Created by Ivan Dugalic@lab. Need Help? Join our Slack team.