Sample project showing my coding skills.
- Should be production ready as much as possible
- Should use JWE token to pass a user's authentication information
- Should use hexagonal architecture
- Should be written using TDD
- Should have full spectrum of tests: architecture, unit, integration, contract, component
- Creating todo list by user
- Managing (updating & deleting) todo lists by user
- Listing todo lists
- Viewing single todo list
- Limiting the number of created todo lists by each user. At this moment each user can create only 5 todo lists.
- Getting user statistics (number of created lists and max todo lists count)
- List name must have at least 3 characters and no more than 50.
- List can be empty but cannot have more than 25 tasks.
- Task name must have at least 3 characters and no more than 150.
- JDK 17 (tested on Temurin-17.0.2+8)
- Docker and docker-compose with permissions to execute without sudo
- At least 2GB disk space (required by testcontainers)
To simplify running application locally, I decided to create docker-compose file with a few shell scripts. To start the application just execute following command:
$ ./local-setup/compose-up.sh
If you're using windows system, use the command below:
> .\local-setup\compose-up.bat
Docker-compose will start 4 containers, but only two of them will be bind to the host ports.
Application | URL | Credentials |
---|---|---|
Todo list app | http://localhost:8080 | See section "Authorization" |
grafana | http://localhost:3000 | Username: admin Password: adminPass |
There are 2 dashboards imported to local grafana instance. These dashboards should be enough to monitor application state (MVP of course). In the real world, these dashboards should have configured alerts, but I think that dashboards without them are good enough for the demo purposes.
API documentation is automatically generated by springdoc-openapi dependency and is compatible with well known swagger-ui.
To get a look at the documentation just open this page in your web browser: http://localhost:8080/swagger-ui.html
This application uses JWE tokens (RFC7516) to pass authenticated user's data. This way of securing applications is much safer than using JWT, because there is no way to read internal data without knowing secret key.
To make requests authorized, JWE token must be put in "Authorization" header using the "Bearer" scheme (RFC6750, section 2.1).
For example:
$ curl -H "Authorization: Bearer eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiZGlyIn0..cRHGsWBM3Fkrpt4E.6OozLAfwDWdMWP7W0tNpuI_hQl1j2kubru0eyUZE9LtbZXXcJLIee-Pvwv3rlfCi5s2P9_IDr8oI-ke95B-rM1AFWsvOHlUB23jcPL8X3ARWISyLaPWRZglBp2yrS7k7lDAzkwg6s52sPQ.F1jWA0pPp9wAYrf041ez1A" http://localhost:8080/secured-resource
In the table below, you can find few JWE tokens for testing purposes. In real scenario, these tokens should be generated by authentication server.
UUID | Username | Expiration time | JWE Token |
---|---|---|---|
d003065b-adad-426a-8e8b-befe5bd47527 | jkowalski | 2100-01-01T00:00:00Z | eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiZGlyIn0..cRHGsWBM3Fkrpt4E.6OozLAfwDWdMWP7W0tNpuI_hQl1j2kubru0eyUZE9LtbZXXcJLIee-Pvwv3rlfCi5s2P9_IDr8oI-ke95B-rM1AFWsvOHlUB23jcPL8X3ARWISyLaPWRZglBp2yrS7k7lDAzkwg6s52sPQ.F1jWA0pPp9wAYrf041ez1A |
9bf5eb14-7aee-44c6-9a4e-3310d1da8a54 | jnowak | 2100-01-01T00:00:00Z | eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiZGlyIn0..bEpRINka6tf8jVox.1eQhF02Fs5adSPad4soKuX1vL0n2z1J1_1DtpCZXaUKk86CGScV-uiSi-kSd3qFIKlgpA8JKpQCgydygus0htxOrrb1md-KwUEbhxl5m-01MHAavbVADCyt75zhiN0Tj7SHc2hX4KQ.MEFFjGmgEhInQ76bQfI0pw |
b3d53502-858c-46d1-ae02-6a502949400a | jbravo | 2100-01-01T00:00:00Z | eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiZGlyIn0..U3di2TqTFf3PBTO9.2rdNMW-qjbG8fnsMKdpjFxOYOjp7166FT3NWMWfvDhMuyuRScNH1U53WWN1xkBj_GcXTZMEKJYe2keWRg1NjFU8Ydqkr8lfXAyeDE_-mD2GA-vQEJrC7l1tYmW-pRZy5Fz5hxY00xA.VRkMueg6pOhsZR0Ij0elnQ |
Everything should work out-of-the-box. Just run standard gradle command:
$ ./gradlew check
Or if you're using windows system:
> .\gradlew.bat
To ensure that component tests are testing real application instead of custom local stack mixed with stubs and mocks, I decided to use docker-compose to run real docker image with real mongodb. This can make some troubles for example when running in IDE. I tried to make compose-up.sh script executing automatically from IDE on my linux system in many ways, but my IDE (Intellij Idea 2021.3.2) prevent me from doing that. This scripts needs jdk 17 to build fresh JAR and docker-image, but Intellij uses its own jdk (version 11) while executing shell commands. I didn't find any way to change it to jdk17. To my surprise on my windows system everything was working fine, but I decided not to create shared componentTest task for intellij with "before launch" step that is failing on all the other systems.
Before running component tests from IDE, make sure that docker-compose with tests environment is running. To run it manually, execute following command:
- On linux or mac
$ ./gradlew componentTestSetUp
- On windows
> .\gradlew.bat componentTestSetUp