{"id":47979119,"url":"https://github.com/marvinrichter/spring-hexagonal-archetype","last_synced_at":"2026-04-04T11:00:45.492Z","repository":{"id":345094957,"uuid":"1184477141","full_name":"marvinrichter/spring-hexagonal-archetype","owner":"marvinrichter","description":"Maven archetype for Spring Boot 4 + Java 25 hexagonal architecture, enforced by ArchUnit","archived":false,"fork":false,"pushed_at":"2026-03-17T17:28:30.000Z","size":90,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-18T06:19:17.865Z","etag":null,"topics":["archunit","hexagonal-architecture","java","maven-archetype","ports-and-adapters","spring-boot","spring-boot-4","testcontainers"],"latest_commit_sha":null,"homepage":"https://marvin-richter.de","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/marvinrichter.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-17T16:15:13.000Z","updated_at":"2026-03-17T17:28:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/marvinrichter/spring-hexagonal-archetype","commit_stats":null,"previous_names":["marvinrichter/spring-hexagonal-archetype"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/marvinrichter/spring-hexagonal-archetype","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvinrichter%2Fspring-hexagonal-archetype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvinrichter%2Fspring-hexagonal-archetype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvinrichter%2Fspring-hexagonal-archetype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvinrichter%2Fspring-hexagonal-archetype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marvinrichter","download_url":"https://codeload.github.com/marvinrichter/spring-hexagonal-archetype/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marvinrichter%2Fspring-hexagonal-archetype/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31397056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: 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":["archunit","hexagonal-architecture","java","maven-archetype","ports-and-adapters","spring-boot","spring-boot-4","testcontainers"],"created_at":"2026-04-04T11:00:17.437Z","updated_at":"2026-04-04T11:00:45.459Z","avatar_url":"https://github.com/marvinrichter.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# spring-hexagonal-archetype\n\nA Maven archetype that generates a production-ready Spring Boot 4 project wired for\n**hexagonal (ports-and-adapters) architecture** — with ArchUnit enforcement, Testcontainers\nintegration tests, and Micrometer observability baked in from day one.\n\nNot because it's fashionable, but because it consistently delivers the one thing\nlegacy codebases lack: a seam. A place where you can swap the database, add a\nmessage broker, or extract a service without touching the domain.\n\n---\n\n## Why hexagonal architecture?\n\nMost Spring Boot projects start flat — controllers calling repositories, `@Service`\nclasses importing JPA entities, business logic scattered across layers that were\nnever really layers at all. That's fine until it isn't: until you need to replace\nHibernate, add a second delivery mechanism (gRPC, events), or test the core logic\nwithout spinning up a database.\n\nHexagonal architecture gives you a **pure domain core** surrounded by **ports**\n(interfaces your application defines) and **adapters** (implementations that talk\nto the outside world). The domain doesn't know Spring exists. The adapters don't\nknow about each other.\n\nThe payoff isn't theoretical. It shows up the first time you:\n- Unit-test a use case with no mocks beyond a simple stub\n- Swap H2 for PostgreSQL in tests with zero code changes\n- Add a CLI adapter alongside the REST adapter in an afternoon\n\nThis archetype encodes those constraints structurally so you can't accidentally\nviolate them — and ArchUnit will tell you immediately if you try.\n\n---\n\n## What's generated\n\n```\nsrc/\n├── main/java/{package}/\n│   ├── domain/                          # Pure Java. Zero framework imports.\n│   │   ├── Order.java                   # Aggregate root with lifecycle methods\n│   │   ├── OrderId.java                 # Typed identifier (no raw Strings/UUIDs)\n│   │   └── Money.java                   # Value object with currency\n│   │\n│   ├── application/\n│   │   ├── port/\n│   │   │   ├── in/PlaceOrderUseCase.java    # Inbound port (interface + Command/Result)\n│   │   │   └── out/OrderRepository.java     # Outbound port (interface)\n│   │   └── service/PlaceOrderService.java   # Use case implementation\n│   │\n│   └── adapter/\n│       ├── in/web/\n│       │   ├── OrderController.java     # REST adapter — depends on port, not service\n│       │   ├── PlaceOrderRequest.java\n│       │   └── OrderResponse.java\n│       └── out/persistence/\n│           ├── JpaOrderRepository.java  # Outbound adapter — implements port\n│           ├── OrderEntity.java         # JPA entity (separate from domain object)\n│           ├── OrderMapper.java         # Maps between domain and persistence model\n│           └── SpringDataOrderRepository.java\n│\n└── test/java/{package}/\n    ├── architecture/\n    │   └── ArchitectureTest.java        # ArchUnit rules — enforced on every build\n    ├── adapter/in/web/\n    │   └── OrderControllerTest.java     # @WebMvcTest slice\n    ├── adapter/out/persistence/\n    │   └── OrderRepositoryTest.java     # Repository test against H2\n    └── application/\n        └── PlaceOrderIntegrationTest.java  # Full round-trip against PostgreSQL (Testcontainers)\n```\n\n**One complete vertical slice:** `POST /orders` → `PlaceOrderUseCase` → `Order.placeOrder()` → `JpaOrderRepository` → PostgreSQL.\n\n---\n\n## Architecture rules enforced by ArchUnit\n\nEvery build verifies these constraints. Violations fail the build.\n\n| Rule | What it prevents |\n|------|-----------------|\n| Domain has no Spring imports | `@Service`, `@Entity` leaking into domain logic |\n| Domain has no Jakarta EE imports | JPA annotations polluting the aggregate root |\n| Domain has no adapter imports | Domain knowing how it's persisted or served |\n| Application has no adapter imports | Use cases importing controllers or JPA repos |\n| All ports are interfaces | Concrete classes masquerading as ports |\n| Inbound adapters don't import outbound adapters | Controllers calling JPA repos directly |\n| Outbound adapters don't import inbound adapters | Repos knowing about HTTP layer |\n\n---\n\n## Getting started\n\n**Prerequisites:** Java 25, Maven 3.9+, Docker (for integration tests)\n\n### Generate a project\n\n```bash\nmvn archetype:generate \\\n  -DarchetypeGroupId=io.github.marvinrichter \\\n  -DarchetypeArtifactId=spring-hexagonal-archetype \\\n  -DarchetypeVersion=1.0.0 \\\n  -DgroupId=com.example \\\n  -DartifactId=my-service \\\n  -Dpackage=com.example.myservice \\\n  -DinteractiveMode=false\n```\n\n### Run the tests\n\n```bash\ncd my-service\n\n# Unit tests + ArchUnit architecture tests\n./mvnw test\n\n# Integration tests (requires Docker — starts PostgreSQL via Testcontainers)\n./mvnw verify\n```\n\n### Start the application\n\n```bash\n./mvnw spring-boot:run\n# POST http://localhost:8080/orders\n# GET  http://localhost:8080/actuator/health\n# GET  http://localhost:8080/actuator/prometheus\n```\n\n---\n\n## Stack\n\n| Concern | Choice | Why |\n|---------|--------|-----|\n| Framework | Spring Boot 4 | Current baseline; Jakarta EE 11 throughout |\n| Java | 25 | Records, pattern matching, virtual threads |\n| Architecture enforcement | ArchUnit 1.4.1 | Compile-time layer violations → build failure |\n| Integration tests | Testcontainers 2.0.3 + PostgreSQL | Real database, no flakiness from mocks |\n| Unit-level repo tests | H2 | No Docker dependency for fast feedback |\n| Observability | Micrometer + Actuator + Prometheus | Wired, not bolted on |\n| Validation | Jakarta Validation (Bean Validation 3) | Standard; no custom framework |\n\n---\n\n## What's not included (and why)\n\n- **Security** — auth strategy is project-specific; the archetype doesn't assume OAuth2, API keys, or mTLS\n- **Flyway / Liquibase** — schema management belongs to the team's migration discipline, not the archetype\n- **Docker Compose** — Testcontainers handles the test environment; production compose is deployment concern\n- **Lombok** — reduces boilerplate but obscures what the archetype is demonstrating; Java records cover most cases\n\n---\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarvinrichter%2Fspring-hexagonal-archetype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarvinrichter%2Fspring-hexagonal-archetype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarvinrichter%2Fspring-hexagonal-archetype/lists"}