{"id":16559901,"url":"https://github.com/jaguililla/hexagonal_spring","last_synced_at":"2025-04-06T04:06:55.079Z","repository":{"id":243271611,"uuid":"811528238","full_name":"jaguililla/hexagonal_spring","owner":"jaguililla","description":"Spring template for a REST service designed with Hexagonal architecture","archived":false,"fork":false,"pushed_at":"2025-03-04T20:48:39.000Z","size":181,"stargazers_count":122,"open_issues_count":9,"forks_count":11,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-30T03:03:06.057Z","etag":null,"topics":["archunit","clean-architecture","docker","docker-compose","gatling","hexagonal-architecture","java","kafka","paketo-buildpack","pitest","postgres","spring-boot","testcontainers"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaguililla.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","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-06-06T19:16:43.000Z","updated_at":"2025-03-19T20:08:58.000Z","dependencies_parsed_at":"2024-06-07T18:44:44.384Z","dependency_job_id":"4cfd7cc2-f8b1-4d1e-b448-1630d24a0a08","html_url":"https://github.com/jaguililla/hexagonal_spring","commit_stats":{"total_commits":69,"total_committers":1,"mean_commits":69.0,"dds":0.0,"last_synced_commit":"e116d9006c7f3a70efbddcfed242a8f7df158a39"},"previous_names":["jaguililla/hexagonal_spring"],"tags_count":11,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaguililla%2Fhexagonal_spring","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaguililla%2Fhexagonal_spring/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaguililla%2Fhexagonal_spring/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaguililla%2Fhexagonal_spring/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaguililla","download_url":"https://codeload.github.com/jaguililla/hexagonal_spring/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247430864,"owners_count":20937874,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["archunit","clean-architecture","docker","docker-compose","gatling","hexagonal-architecture","java","kafka","paketo-buildpack","pitest","postgres","spring-boot","testcontainers"],"created_at":"2024-10-11T20:27:30.238Z","updated_at":"2025-04-06T04:06:55.020Z","avatar_url":"https://github.com/jaguililla.png","language":"Java","readme":"\n\u003e # 🎯 ABOUT\n\u003e This is a 'best practices' template project for Spring Boot with Hexagonal Architecture. However,\n\u003e it is an opinionated take on that.\n\u003e\n\u003e DISCLAIMER: I'm by no means an expert on Spring Boot, one reason to do this is to learn it.\n\u003e Opinions are welcomed (with proper reasoning), check the [contributing] section to share your\n\u003e thoughts.\n\u003e\n\u003e The project is mirrored on [GitLab](https://gitlab.com/jaguililla/hexagonal_spring) for CI\n\u003e demonstration purposes.\n\u003e\n\u003e Have fun!\n\n[contributing]: https://github.com/jaguililla/hexagonal_spring/contribute\n\n# 🗓️ Appointments\nExample application to create appointments (REST API). Appointments are stored in a relational DB\n(Postgres), and their creation/deletion is published to a Kafka broker.\n\n## 📘 Architecture\n* [Hexagonal]/[Onion]/[Clean] Architecture\n* OpenAPI code generation (server and client)\n\n[Hexagonal]: https://alistair.cockburn.us/hexagonal-architecture\n[Onion]: https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1\n[Clean]: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html\n\n## 🧰 Stack\n* Java 21\n* Spring 3.3 (configurable server, 'undertow' by default)\n  * Actuator (healthcheck, etc.)\n* Flyway (chosen over Liquibase for its simplicity)\n* Postgres\n* Kafka\n\n## 🏎️ Runtime\n* Cloud Native Buildpacks (building)\n* Docker Compose (local environment with the infrastructure)\n\n## 🧪 Test\n* ArchUnit (preferred over Java modules: it allows naming checks, etc.)\n* Testcontainers (used to provide a test instance of Postgres and Kafka)\n* Pitest (mutation testing, nightly)\n\n## ⚒️ Development\n* SDKMAN (allows to use simpler runners on CI)\n* Maven Wrapper (Maven can be provided by SDKMAN, however, Maven Wrapper has better IDE support)\n* Editorconfig (supported by a lot of editors, rules limited though)\n* CI pipelines for GitHub and GitLab\n\n## 📑 Requirements\n* Docker Compose\n* JDK 21+\n* SDKMAN (optional, recommended)\n\n## 🤔 Design Decisions\n* Simplicity and pragmatism over Hexagonal Architectures 'by the book'.\n* Minimal: don't use libraries to implement easy stuff (even if that's boring).\n* Start small, split and refactor when features are added (I.e.: split services into use cases).\n* Prefer flat structure (avoid empty parent packages if possible).\n* Small coupling with Spring (easier to migrate, to other frameworks/toolkits).\n* Not use Spring integrations if a library can be used directly.\n* No Spring profiles (settings are loaded from the environment).\n* Split API spec in different files for future modularity.\n* Prefer service independence over code reuse (sharing libraries among microservices).\n* Docker Compose profiles are used to separate infrastructure from a complete local environment.\n* Atomicity in notifiers (with outbox pattern) should be done with a different notifier adapter.\n* No input ports: they don't need to be decoupled, they just use the domain (and that's acceptable).\n\n## 📖 Architecture\n![Architecture Diagram](https://raw.githubusercontent.com/jaguililla/hexagonal_spring/main/doc/architecture.svg)\n* **Port**: interface to set a boundary between application logic and implementation details.\n* **Adapter**: port implementation to connect the application domain with the system's context.\n* **Domain**: application logic and model entities.\n* **Service**: implement operations with a common topic altogether. Usually calls driven ports.\n* **UseCase/Case**: single operation service (isolate features). They can coexist with services.\n* **Output/Driven Adapter**: implementation of ports called from the domain.\n* **Input/Driver Adapter**: commands that call application logic (don't require a port).\n\n## 📚 Design\n* The REST API controller and client are generated from the OpenAPI spec at build time.\n* `domain` holds business logic (services and/or use cases) and driven ports (interfaces).\n* `domain.model` keeps the structures relevant to the application's domain. The more logic added to\n  an entity, the better (it could be easily accessed by many different services, or use cases).\n* `notifiers` and `repositories` driven adapters (implementations of driven ports).\n* `controllers` driver adapter (adapters without interface).\n* Subpackages can be created for different adapter implementations (to isolate their code).\n* More information about each package rules can be found on their Javadoc documentation.\n\n## 🎚️ Set up\n* With SDKMAN: `sdk env install`\n* If SDKMAN is not available, JDK 21+ must be installed.\n\n## ▶️ Commands\nAll commands assume a Unix like OS.\n\nThe most important commands to operate the project are:\n\n* Build: `./mvnw package`\n* Documentation: `./mvnw site`\n* Run: `./mvnw spring-boot:run`\n* Build image: `./mvnw verify` or `./mvnw spring-boot:build-image`\n\nTo run or deploy the application:\n\n* Start infrastructure (for running locally): `docker-compose up -d`\n* Run JAR locally: `java -jar target/appointments-0.1.0.jar`\n* Run container: `docker-compose --profile local up`\n\n## 🤖 Service Management\n* You can check the API spec using [Swagger UI](http://localhost:8080/swagger-ui/index.html).\n\n### Docker\nAt the `docker-compose.yml` you can find the information on how to run the application as a\ncontainer, adjusting the configuration for running it on different environments.\n\nTwo Docker compose profiles are used:\n- Default profile (no profile parameter): to allow starting only the infrastructure, this is useful\n  to start the application from the IDE\n- Local profile (--profile local): which also starts a container using the image of this application\n\n### Testing\nThe verification requests can be executed with: `src/test/resources/requests.sh`, or\n`PORT=9090 src/test/resources/requests.sh` if you want to run them to a different port.\n\nThe health check endpoint is: http://localhost:18080/actuator/health\n\n### Stress Testing (Gatling)\n[Gatling settings] can be overridden creating a `gatling.conf` file at the test resources. The\nconfiguration options and their default values can be checked [here][gatlingDefaults].\n\nThose parameters can also be overwritten by system properties from the command line. I.e.:\n`-D gatling.core.encoding=utf-8`\n\nTo run the Gatling test, execute `./mvnw -P gatling` at the shell.\n\n[Gatling settings]: https://docs.gatling.io/reference/script/core/configuration\n[gatlingDefaults]: https://github.com/gatling/gatling/blob/main/gatling-core/src/main/resources/gatling-defaults.conf\n","funding_links":[],"categories":["\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaguililla%2Fhexagonal_spring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaguililla%2Fhexagonal_spring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaguililla%2Fhexagonal_spring/lists"}