{"id":13565282,"url":"https://github.com/andreschaffer/event-sourcing-cqrs-examples","last_synced_at":"2025-04-03T22:30:56.815Z","repository":{"id":38315405,"uuid":"93197679","full_name":"andreschaffer/event-sourcing-cqrs-examples","owner":"andreschaffer","description":"Event Sourcing and CQRS in practice.","archived":false,"fork":false,"pushed_at":"2024-10-16T17:40:57.000Z","size":483,"stargazers_count":560,"open_issues_count":3,"forks_count":118,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-10-18T15:27:46.711Z","etag":null,"topics":["cqrs","cqrs-es","ddd","domain-driven-design","event-sourcing","event-store","events","hexagonal-architecture","java"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andreschaffer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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":"2017-06-02T19:30:49.000Z","updated_at":"2024-10-16T17:40:58.000Z","dependencies_parsed_at":"2023-02-10T08:16:02.730Z","dependency_job_id":"2dfeefd0-3d96-4ea4-bb12-61599f500324","html_url":"https://github.com/andreschaffer/event-sourcing-cqrs-examples","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreschaffer%2Fevent-sourcing-cqrs-examples","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreschaffer%2Fevent-sourcing-cqrs-examples/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreschaffer%2Fevent-sourcing-cqrs-examples/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreschaffer%2Fevent-sourcing-cqrs-examples/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreschaffer","download_url":"https://codeload.github.com/andreschaffer/event-sourcing-cqrs-examples/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247089952,"owners_count":20881895,"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":["cqrs","cqrs-es","ddd","domain-driven-design","event-sourcing","event-store","events","hexagonal-architecture","java"],"created_at":"2024-08-01T13:01:43.734Z","updated_at":"2025-04-03T22:30:56.152Z","avatar_url":"https://github.com/andreschaffer.png","language":"Java","funding_links":[],"categories":["Java","Sample Projects"],"sub_categories":["JVM languages"],"readme":"![Build](https://github.com/andreschaffer/event-sourcing-cqrs-examples/workflows/Build/badge.svg)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/299df5b2515003778612/test_coverage)](https://codeclimate.com/github/andreschaffer/event-sourcing-cqrs-examples/test_coverage)\n[![Maintainability](https://api.codeclimate.com/v1/badges/299df5b2515003778612/maintainability)](https://codeclimate.com/github/andreschaffer/event-sourcing-cqrs-examples/maintainability)\n[![Dependabot](https://img.shields.io/badge/Dependabot-enabled-blue?logo=dependabot)](https://docs.github.com/en/github/administering-a-repository/keeping-your-dependencies-updated-automatically)\n\n# Event Sourcing and CQRS Examples\nThis project aims to provide examples of how to use Event Sourcing and CQRS applied to a minimalistic bank context.  \n\nWe assume the reader has basic knowledge of Event Sourcing and CQRS concepts.  \nIf you want to brush up on the subject we suggest reading:  \n- [https://martinfowler.com/eaaDev/EventSourcing.html](https://martinfowler.com/eaaDev/EventSourcing.html)\n- [https://martinfowler.com/bliki/CQRS.html](https://martinfowler.com/bliki/CQRS.html)\n\n## Domain overview\nIn this minimalistic bank, a _client_ can _open_ one or more _accounts_.  \nOn each _account_, the _client_ can _deposit_ or _withdraw_ money.  \nThe history of an _account's transactions_ is available to the _client_ as well as a summary of the _client's accounts_.\n\n## Design choices\n### Architecture overview\n      Event Store   Projections\n        +----+        +----+\n        |    |        |    |\n        | DB |        | DB |\n        +--+-+        +-+--+\n          ^             ^\n          |             |\n    +------------+------------+\n    |     |      |      |     |\n    |     |    Events   |     |\n    |     +------+----+ |     |\n    |     |      |    | |     |\n    |     +      |    v +     |\n    |   Domain   |   Read     |\n    |   Model    |   Model    |\n    |            |            |\n    +------------+------------+\n    |                         |\n    |           API           |\n    |                         |\n    +-------------------------+ \n\n#### Ports and Adapters\nFor the Domain Model, we chose the Ports and Adapters structure because we wanted to protect the domain logic from\nall the technical concerns.\n\nFor more information about it read [here](http://www.dossier-andreas.net/software_architecture/ports_and_adapters.html).\n\n#### Package by Feature\nFor the Read Models, we chose the Package by Feature structure because we would not benefit from isolating the layers\nand instead we put all feature related parts close together. \n\nFor more information about it read [here](http://www.javapractices.com/topic/TopicAction.do?Id=205).\n\n### DDD and REST\nThere has been a myth of DDD and REST being incompatible due to DDD being all about behaviour\nwhereas REST is all about state.  \nIn this project we followed both techniques quite strictly and hope that the result shows that they can be well combined.  \nNote: We did not include REST hypermedia controls as we believe it is a big subject in itself and didn't want to shift focus from Event Sourcing and CQRS.\n\n### Event Sourcing and CQRS (finally!)\nWe have taken a pragmatic approach when combining Event Sourcing and CQRS. \nBy the book, CQRS proposes a complete separation between the read/query and write/command sides,\nbut that's not what we have here.\nThe approach we've taken instead:\n- The writes/commands are all on the domain model side and processed by aggregates;\n- The reads/queries are both in the domain model side and in the read model side.\n  - The queries in the domain model side are only allowed when the data we need is a single aggregate itself.\n    The reason being that we can only query the event store by aggregate id\n    and we can actually fulfill those queries by replaying that single aggregate events.\n  - For any other kind of query, we don't want to compromise the domain model.\n    Therefore, we create read models to fulfill those queries.\n    They are basically projections, potentially built from different events and aggregates\n    that can be queried by more appropriate fields. \n    \n#### Events\nEvents are a thing from the past. It communicates a significant change that _happened_. \n\n##### Idempotency when replaying events\nWhen replaying events, we don't want to execute any business logic because we can't change history. We only want to do assignments.  \nA simple example is with a deposit event: instead of adding the deposited amount to the balance when replaying (business logic), we want \nthe updated balance already available so that we can just assign it. This makes it possible to replay the event multiple times with the same outcome.\n\n##### Ordering of events\nIn a distributed world, event timestamps are unreliable for ordering - machines have their own clocks.  \nInstead we can make the ordering explicit with an event version.\nIn this project we use event versioning in two ways:\n- In the write/command side, we use it for protecting ourselves from race conditions via optimistic locking;\n- In the read/query side, we use it for commutative reasons, meaning events can come out of order and we can still handle them properly.\n\nIf you are interested in this topic, we also recommend reading about [Lamport timestamps](https://en.wikipedia.org/wiki/Lamport_timestamps) and [Vector clocks](https://en.wikipedia.org/wiki/Vector_clock) as alternatives.\n\n## Trying it out\n### Requirements\n- Java 14\n- Maven\n\n### Building the application\n` mvn clean verify `\n\n### Starting the application\n` java -jar target/bank-service-1.0-SNAPSHOT.jar server src/environments/development.yml `\n\n### Examples of use\n#### Create a client\n` curl -v -X POST -H \"Content-Type: application/json\" -d '{\"name\":\"Jane Doe\", \"email\":\"jane.doe@example.com\"}' http://localhost:8080/clients `\n\nCheck the created client in the response's 'Location' header.\n\n#### Create an account for the client\n` curl -v -X POST -H \"Content-Type: application/json\" -d '{\"clientId\":\"{CLIENT_ID}\"}' http://localhost:8080/accounts `\n\nCheck the created account in the response's 'Location' header.\n\n#### Make a deposit to the account\n` curl -v -X POST -H \"Content-Type: application/json\" -d '{\"amount\":1000000}' http://localhost:8080/accounts/{ACCOUNT_ID}/deposits `\n\n#### Check that you created a millionaire!\n` curl -v http://localhost:8080/accounts/{ACCOUNT_ID} `\n\n#### More operations\nGo ahead and check the code! :)\n\n# Contributing\nIf you would like to help making this project better, see the [CONTRIBUTING.md](CONTRIBUTING.md).  \n\n# Maintainers\nSend any other comments, flowers and suggestions to [André Schaffer](https://github.com/andreschaffer) and [Dan Eidmark](https://github.com/daneidmark).\n\n# License\nThis project is distributed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreschaffer%2Fevent-sourcing-cqrs-examples","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreschaffer%2Fevent-sourcing-cqrs-examples","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreschaffer%2Fevent-sourcing-cqrs-examples/lists"}