{"id":13847329,"url":"https://github.com/yerinadler/typescript-event-sourcing-sample-app","last_synced_at":"2025-03-16T00:04:14.949Z","repository":{"id":39991543,"uuid":"329236332","full_name":"yerinadler/typescript-event-sourcing-sample-app","owner":"yerinadler","description":"Typescript API that implements CQRS \u0026 Event Sourcing","archived":false,"fork":false,"pushed_at":"2024-09-08T08:19:59.000Z","size":471,"stargazers_count":76,"open_issues_count":0,"forks_count":14,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-02-28T14:17:25.254Z","etag":null,"topics":["cqrs","ddd","event-driven-architecture","event-sourcing","kafka","nodejs","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/yerinadler.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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":"2021-01-13T08:06:26.000Z","updated_at":"2025-02-19T09:04:04.000Z","dependencies_parsed_at":"2024-01-15T20:49:27.394Z","dependency_job_id":"caaf29ea-40a5-4bb0-aa0a-375e3cadfaae","html_url":"https://github.com/yerinadler/typescript-event-sourcing-sample-app","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerinadler%2Ftypescript-event-sourcing-sample-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerinadler%2Ftypescript-event-sourcing-sample-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerinadler%2Ftypescript-event-sourcing-sample-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yerinadler%2Ftypescript-event-sourcing-sample-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yerinadler","download_url":"https://codeload.github.com/yerinadler/typescript-event-sourcing-sample-app/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243806046,"owners_count":20350775,"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","ddd","event-driven-architecture","event-sourcing","kafka","nodejs","typescript"],"created_at":"2024-08-04T18:01:16.928Z","updated_at":"2025-03-16T00:04:14.928Z","avatar_url":"https://github.com/yerinadler.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# TypeScript CQRS \u0026 Event Sourcing Boilerplate\n\n**Note:** This project is a experimental project that leverages the concepts of `CQRS` and `Event Sourcing`. However, the events as written in this project are the results of the `Strategic Design` and this project can be used during the `Tactical Design` phase\n\n### Business Scenario\nThe business scenario in this project is the job application. Let's imagine we are building a platform that allows users to apply to their desired jobs. So below is the requirement\n\n1. The admin can create a job with the required information e.g. description, title, etc.\n2. The admin can archive the job but there is no way he/she can delete the job.\n3. The job can be updated at any time.\n4. Once the job is created, the user can browse through the list of applications and may choose to apply to any of them.\n5. After the user successfully filled in the required information. The application is created.\n\n### Foreword from the author\n\nThis API project utilises information from multiple sources to create the fine-tuned API product with the following objectives\n\n1. To build a maintainable enterprise grade application\n2. The application that follows `SOLID` principles as much as possible\n3. To build an application that benefits most of the stakeholders in an organisation\n4. To decouple the read and the write side of the application. Thus, they can be scaled indenpendently\n5. To build the CQRS and Event Sourcing system\n\n### Architecture\n\nThis project uses DDD with Onion Architecture as illustrated in below images\n\nBelow image illustrates the more detailed architecture\n\n![](assets/architecture.png)\n\nIn CQRS \u0026 Event Sourcing systems, the main idea is to implement different data models for read and write sides of the application.\n\nThe workflow is that the write side sends the `commands` to the `command handlers` through `commandBus` to alter the information. The succeeded commands will then generate resulting `events` which are then stored in the `event store`. Finally, the `event handlers` subscribe to events and generate the denormalised data ready for the query. Please note that the events could also be handled by multiple event handlers. Some of them may handle notification tasks.\n\nThe only source of truth of Event Sourcing systems is the `event store` while the data in the read store is simply a derivative of the events generated from the write side. This means we can use totally different data structure between the read and the write sides and we can replay the events from the event store from the whenever we want the regenerate the denormalised data in whatever shapes we want.\n\nIn this example, we use `MongoDB` as an event store and `Redis` as the read store.\n\nThe commands are sent by the frontend to the `commandBus` which then selects appropriate `command handlers` for the commands. The command handlers then prepare the `Aggregate Root` and apply the business logic suitable for them. If the commands succeed, they result in events which will then be sent to the `eventBus` to the `event handlers`. In this example, the eventBus is implemented using `Apache Kafka`.\n\nTo read more about CQRS and Event Sourcing. Please check [this link](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)\n\nIn order to demonstrate the use case with inter-service communication. Two seprate microservices for job and application is created. So a job microservice manages job (create, update, archive) and application microservice manages the user application.\n\nThe pattern in `Event-Driven Architecture` called `Event-Carried State Transfer` is used between job and application microservices. When the job is created, the `JobCreated` event is embedded with the job information as a payload so the application microservice uses this information to replicate the job information for local query. Thus, whenever the application microservice needs the job information, it does not make a direct RPC / REST call to the job microservice at all.\n\n### Technologies\n\n1. Node.js\n2. TypeScript\n3. MongoDB with MongoDB native driver as an event store (mongodb package on NPM)\n4. InversifyJS as an IoC container\n5. Express (via Inversify Express Utils) as an API framework\n6. Redis as a read store for application microservice\n7. Apache Cassandra as a read store for job microservice\n8. Apache Kafka as a message broker / event bus\n\n## Components\n\nThis project follows the standard CQRS \u0026 Event Sourcing applications available on GitHub. Highly inspired by Greg Young's SimpleCQRS project (written in ASP.NET C#).\n\nBelow is the list of components in this project\n\n1. **Domain Model** (Aggregate Root)\u003cbr/\u003e\n   Contains the business logic required for the application\n2. **Commands**\u003cbr/\u003e\n   The command class which implements `ICommand` interface. This reflects the intention of the users to alter the state of the application\n3. **CommandHandlers**\u003cbr/\u003e\n   The command processor managed by `CommandBus`. It prepares the Aggregate Root and applies business logic on it.\n4. **CommandBus**\u003cbr/\u003e\n   The command management object which receieves incoming commands and select appropriate handlers for them. Please note that in order to use the command handlers. They must be registered to the `CommandBus` first at `entrypoint.ts` file.\n5. **Events**\u003cbr/\u003e\n   The resulting objects from describing the changes generated by succeeding commands which are sent through the `EventBus`. This class implements `IEvent` interface.\n6. **Event Store**\n   The storage that stores events. This is the only source of truth of the system (The sequence of events generated by the application).\n7. **EventBus**\u003cbr/\u003e\n   The bus that contains the events where event handlers subscribe to. In this example, `Apache Kafka` is used to implement this\n8. **Event Handlers**\u003cbr/\u003e\n   The event processor. This could be the projector or the denormaliser that generates the data for the read side on the read storage.\n\n## Getting Started\n\nTo run the project, make sure you have these dependencies installed on your system\n\n\u003e The `docker-compose.yml` containing all dependencies for running the project is provided\n\u003e but make sure you have at least 8GB of RAM available on your local machine before running these dependencies\n\n1. Node.js v8 or later\n2. Typescript with `tsc` command\n3. Nodemon\n4. ts-node\n5. MongoDB\n6. Redis Server and Clients (redis-cli)\n7. CQLSH for interacting with Cassandra\n8. Docker installed on the machine\n\nYou also need to setup and initialise MongoDB database. Then, copy the `.env_example` file into `.env` file by firing the command\n\n```bash\ncp .env_template .env\n```\n\nDo adjust the `DB_NAME` and `MONGODB_URI` to match your configuration then run\n\n```bash\nyarn dev\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyerinadler%2Ftypescript-event-sourcing-sample-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyerinadler%2Ftypescript-event-sourcing-sample-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyerinadler%2Ftypescript-event-sourcing-sample-app/lists"}