{"id":18214468,"url":"https://github.com/daroshchanka/microservices-demo","last_synced_at":"2026-01-28T00:35:31.497Z","repository":{"id":260880267,"uuid":"882604943","full_name":"daroshchanka/microservices-demo","owner":"daroshchanka","description":"Java + Spring Boot microservices implementation demo. REST API and Kafka used for apps communication. Postgres used as database.","archived":false,"fork":false,"pushed_at":"2024-11-03T12:49:51.000Z","size":1205,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-10T12:16:11.007Z","etag":null,"topics":["demo","demo-app","docker","docker-compose","gitlab","gitlab-ci","grafana","java","loki","maven","microservices","monorepo","nexus","postgresql","prometeheus","sonarqube","sonatype-nexus","spring-boot","tempo"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daroshchanka.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-03T09:58:22.000Z","updated_at":"2024-11-03T12:49:54.000Z","dependencies_parsed_at":"2024-11-03T10:19:46.520Z","dependency_job_id":"8c6442f8-f8b2-4e68-a5f7-de1263880083","html_url":"https://github.com/daroshchanka/microservices-demo","commit_stats":{"total_commits":119,"total_committers":2,"mean_commits":59.5,"dds":"0.050420168067226934","last_synced_commit":"ee8dd46e1748cd28f46cb9a7ee2eebd5b00ea0a7"},"previous_names":["daroshchanka/microservices-demo"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/daroshchanka/microservices-demo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daroshchanka%2Fmicroservices-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daroshchanka%2Fmicroservices-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daroshchanka%2Fmicroservices-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daroshchanka%2Fmicroservices-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daroshchanka","download_url":"https://codeload.github.com/daroshchanka/microservices-demo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daroshchanka%2Fmicroservices-demo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28829444,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T23:29:49.665Z","status":"ssl_error","status_checked_at":"2026-01-27T23:25:58.379Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["demo","demo-app","docker","docker-compose","gitlab","gitlab-ci","grafana","java","loki","maven","microservices","monorepo","nexus","postgresql","prometeheus","sonarqube","sonatype-nexus","spring-boot","tempo"],"created_at":"2024-11-03T17:00:20.892Z","updated_at":"2026-01-28T00:35:31.469Z","avatar_url":"https://github.com/daroshchanka.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## microservices-demo\n\n### Overview\n_Java_ + _Spring Boot_ microservices implementation demo.\n\nREST API and _Kafka_ used for apps communication. _Postgres_ used as database.\n\nEach service distributes REST/Kafka contracts for communication as the separate module.\n\n_Swagger_ used to visualize OpenAPI specifications.\n\nIn-memory DB/Kafka implementations used for tests.\n\nEach microservice packaged to the _Docker_ container.\n\nBasic logging tracing and monitoring implemented. \n_Logback_ + _Loki_ + _Grafana_ used to collect and display logs.\n_Logbook_ used for HTTP request and response logging\n\n_Actuator_ API endpoints added to each microservice.\n_Prometheus_ + _Tempo_ + _Grafana_ used for tracing.\n\n_GitlabCI_ used to build the project, monorepo approach used with the corresponding pipeline which triggers\nchild pipelines per each microservice if the code has been changed there.\n\nArtifacts (docker images and .jar contracts) published to _Nexus_ artifacts storage.\n\n_SonarQube_ performs static code analysis and collects tests coverage.\n\n_Kafka UI_ used to view/manage kafka cluster. \n\n__All infrastructure configuration and microservices env defined in docker-compose \nfiles and included as a part of this repo__. But it was designed for local dev environment, not production.\n\n\n### Project details\n\nThere are 3 applications aimed to generate image with some text and manage generated results.\n\n#### 1 image-generation-manager\nSends generate commands to __image-generator__, tracks the generation process state\n\n#### 2 image-generator\nGenerates images by request, uploads generations to __generated-files-storage__, \nnotifies __image-generation-manager__ when generation finished/error\n\n#### 3 generated-files-storage\nExposes api to upload file for storage, and get endpoint to download generated files by id\n\n#### API Flow\n- Create generate image request\n  ```text\n  curl -X 'POST' \\\n    'http://dev-cluster:8081/api/action/generate' \\\n    -H 'accept: */*' \\\n    -H 'Content-Type: application/json' \\\n    -d '{\n    \"imageText\": \"This text is generated by \\nImage Generation Manager API \\nwith font DejaVu Sans\",\n    \"font\": {\n      \"name\": \"DejaVu Sans\",\n      \"size\": 36\n    },\n    \"color\": {\n      \"r\": 222,\n      \"g\": 72,\n      \"b\": 210\n    }\n  }'\n  ```\n  Response:\n  ```text\n  {\n    \"id\": 552,\n    \"processId\": \"912912d8-c7ef-4c98-a4a9-5d8e5ddf083c\",\n    \"createdAt\": \"2024-11-03T11:51:09.021+00:00\",\n    \"updatedAt\": \"2024-11-03T11:51:09.021+00:00\",\n    \"status\": \"IN_PROGRESS\",\n    \"error\": null,\n    \"details\": {\n      \"id\": 552,\n      \"imageText\": \"This text is generated by \\nImage Generation Manager API \\nwith font DejaVu Sans\",\n      \"font\": {\n        \"id\": 552,\n        \"name\": \"DejaVu Sans\",\n        \"size\": 36\n      },\n      \"color\": {\n        \"id\": 552,\n        \"r\": 222,\n        \"g\": 72,\n        \"b\": 210\n      }\n    }\n  }\n  ```\n- Waiting for process to be FINISHED\n  ```text\n  curl -X 'GET' \\\n    'http://dev-cluster:8081/api/processes/912912d8-c7ef-4c98-a4a9-5d8e5ddf083c' \\\n    -H 'accept: */*'\n  ```\n  Response:\n  ```text\n  {\n    \"id\": 552,\n    \"processId\": \"912912d8-c7ef-4c98-a4a9-5d8e5ddf083c\",\n    \"createdAt\": \"2024-11-03T11:51:09.021+00:00\",\n    \"updatedAt\": \"2024-11-03T11:51:10.864+00:00\",\n    \"status\": \"FINISHED\",\n    \"error\": null,\n    \"details\": {\n      \"id\": 552,\n      \"imageText\": \"This text is generated by \\nImage Generation Manager API \\nwith font DejaVu Sans\",\n      \"font\": {\n        \"id\": 552,\n        \"name\": \"DejaVu Sans\",\n        \"size\": 36\n      },\n      \"color\": {\n        \"id\": 552,\n        \"r\": 222,\n        \"g\": 72,\n        \"b\": 210\n      }\n    }\n  }\n  ```\n\n- Find generation result by `processId`\n  ```text\n  curl -X 'GET' \\\n    'http://dev-cluster:8081/api/generation-results?processId=912912d8-c7ef-4c98-a4a9-5d8e5ddf083c' \\\n    -H 'accept: application/json'\n  ```\n  Response:\n  ```text\n  [\n    {\n    \"id\": \"05d95106-473d-4c0d-8a3b-0698e54c8822\",\n    \"relatedProcessId\": \"912912d8-c7ef-4c98-a4a9-5d8e5ddf083c\",\n    \"fileId\": \"39eac44e-bcca-436d-b726-b870cc184e6f\"\n    }\n  ]\n  ```\n\n- Download generated image by `fileId`\n  ```text\n  curl -X 'GET' \\\n    'http://dev-cluster:8083/api/files/39eac44e-bcca-436d-b726-b870cc184e6f' \\\n    -H 'accept: image/png'\n  ```\n  Response:\n- \n  ![generated-image.png](.assets/generated-image.png)\n\n#### Swagger + Kafka UI\n\n![image-generation-manager.png](.assets/image-generation-manager.png)\n\n![kafka-topic-generation-requests.png](.assets/kafka-topic-generation-requests.png)\n\n![kafka-topic-image-generator-events.png](.assets/kafka-topic-image-generator-events.png)\n\n![generated-files-storage.png](.assets/generated-files-storage.png)  \n\n![get-file-by-id.png](.assets/get-file-by-id.png)\n  \n\n### Infrastructure details\n\nThere are 4 docker compose files placed in `infrastructure/envs`.\n\n- `ci` contains Gitlab (with runner) + Nexus + SonarQube\n- `dev` contains `infra` - DB+Kafka for microservices, `apps` - run all microservices, \n  `monitoring` - Grafana + Tempo + Loki + Prometheus + Kafka UI\n\n![containers.png](.assets/containers.png)\n\n#### Gitlab CI\n\n__Runner__\n\n![gitlab-ci-runner.png](.assets/gitlab-ci-runner.png)\n\n__Repo__\n\n![gitlab-ci-repository.png](.assets/gitlab-ci-repository.png)\n\n__CI Pipelines__\n\n![gitlab-ci-monorepo-pipeline.png](.assets/gitlab-ci-monorepo-pipeline.png)\n\n#### SonarQube\n\n```text\nhttp://dev-cluster:9000/projects\n```\n![sonar-qube-projects-list.png](.assets/sonar-qube-projects-list.png)\n\n```text\nhttp://dev-cluster:9000/dashboard?id=image-generator\n```\n![sonar-qube-project-details.png](.assets/sonar-qube-project-details.png)\n\n#### Nexus\n\n__Maven__\n```text\nhttp://dev-cluster:8099/#browse/browse:maven-snapshots:dmax\n```\n![nexus-maven-snapshots.png](.assets/nexus-maven-snapshots.png)\n\n__Docker__\n\n```text\nhttp://dev-cluster:8099/#browse/browse:docker\n```\n![nexus-docker-browse.png](.assets/nexus-docker-browse.png)\n\n![nexus-docker-setup.png](.assets/nexus-docker-setup.png)\n\n### Tracing / Observability\n\n#### Grafana\n__Spring Boot 3.x Statistics Dashboard__\n```text\nhttp://dev-cluster:3000/d/spring_boot_21/spring-boot-3-x-statistics?orgId=1\n```\n![grafana-spring-boot-dashboard.png](.assets/grafana-spring-boot-dashboard.png)\n\n__Logs__\n```text\nhttp://dev-cluster:3000/explore?schemaVersion=1\u0026panes=%7B%22nqv%22:%7B%22datasource%22:%22loki%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%7Bservice_name%3D%5C%22image-generation-manager%5C%22%7D%20%7C%3D%20%60%60%22,%22queryType%22:%22range%22,%22datasource%22:%7B%22type%22:%22loki%22,%22uid%22:%22loki%22%7D,%22editorMode%22:%22builder%22%7D%5D,%22range%22:%7B%22from%22:%22now-5m%22,%22to%22:%22now%22%7D%7D%7D\u0026orgId=1\n```\n![grafana-loki-logs.png](.assets/grafana-loki-logs.png)\n\n__Tracing__\n```text\nhttp://dev-cluster:3000/explore?schemaVersion=1\u0026panes=%7B%22cbg%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceql%22,%22limit%22:20,%22tableType%22:%22traces%22,%22query%22:%22672723ced6d595e5a5b8f73f47ff7dd5%22%7D%5D,%22range%22:%7B%22from%22:%22now-1h%22,%22to%22:%22now%22%7D%7D%7D\u0026orgId=1\n```\n![grafana-tempo-tracing-1.png](.assets/grafana-tempo-tracing-1.png)\n\n```text\nhttp://dev-cluster:3000/explore?schemaVersion=1\u0026panes=%7B%22cbg%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceql%22,%22limit%22:20,%22tableType%22:%22traces%22,%22query%22:%22672723ce116764a3d047c3ba2b5dff66%22%7D%5D,%22range%22:%7B%22from%22:%221730610697157%22,%22to%22:%221730625097157%22%7D%7D%7D\u0026orgId=1\n```\n\n![grafana-tempo-tracing-2.png](.assets/grafana-tempo-tracing-2.png)\n\n\n#### Kafka UI\n\n![kafka-ui-consumers.png](.assets/kafka-ui-consumers.png)\n\n![kafka-ui-topics.png](.assets/kafka-ui-topics.png)\n\n![kafka-ui-event.png](.assets/kafka-ui-event.png)\n\n\n### Disclaimer\nThis project has been implemented in self-education purposes by the person who never developed microservices before.\n\nThis project has been implemented within the limited timeframe 2-3 weeks I've spent ~ 16hours per week,\nso the whole development and infra setup took ~ 40hours.\n\nThere was local bare metal CPU/RAM limitations: 8CPU + 32GB RAM, cloud resources wasn't used.\n\n_Known missing things_:\n\n- Roles and permissions, Keycloack + spring-security\n- REST/Kafka contracts could be distributed not as .jar modules, but as json/yaml\n- DELETE endpoints were not implemented\n- API Gateway could be added\n- Some simple Web UI could be added\n- More advanced CI pipelines with handling release versioning, release version incrementation per service,\n  running released app on dev env + run more e2e system tests\n- More automated tests might be added, especially e2e system tests\n- Tracing might be improved to link rest-\u003ekafka and show the whole flow\n- Kubernetes could be utilized instead of docker-compose\n- Overall infrastructure was designed for local dev environment, not production\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaroshchanka%2Fmicroservices-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaroshchanka%2Fmicroservices-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaroshchanka%2Fmicroservices-demo/lists"}