{"id":26572258,"url":"https://github.com/harunou/react-tanstack-react-query-clean-architecture","last_synced_at":"2025-03-23T00:28:18.080Z","repository":{"id":279973767,"uuid":"940615636","full_name":"harunou/react-tanstack-react-query-clean-architecture","owner":"harunou","description":"Frontend application build with Clean Architecture in mind. Simple. Flexible. Clean.","archived":false,"fork":false,"pushed_at":"2025-03-20T13:22:13.000Z","size":223,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-20T14:33:37.669Z","etag":null,"topics":["clean-architecture","react","tanstack-react-query","typescript","zustand"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/harunou.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yaml","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},"funding":{"buy_me_a_coffee":"harunou"}},"created_at":"2025-02-28T13:46:15.000Z","updated_at":"2025-03-20T13:22:16.000Z","dependencies_parsed_at":"2025-02-28T19:51:13.979Z","dependency_job_id":"861af802-9ece-4c63-8659-78851eedb94f","html_url":"https://github.com/harunou/react-tanstack-react-query-clean-architecture","commit_stats":null,"previous_names":["harunou/react-tanstack-react-query-clean-architecture"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harunou%2Freact-tanstack-react-query-clean-architecture","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harunou%2Freact-tanstack-react-query-clean-architecture/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harunou%2Freact-tanstack-react-query-clean-architecture/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/harunou%2Freact-tanstack-react-query-clean-architecture/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/harunou","download_url":"https://codeload.github.com/harunou/react-tanstack-react-query-clean-architecture/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245040219,"owners_count":20551297,"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":["clean-architecture","react","tanstack-react-query","typescript","zustand"],"created_at":"2025-03-23T00:28:17.431Z","updated_at":"2025-03-23T00:28:18.065Z","avatar_url":"https://github.com/harunou.png","language":"TypeScript","funding_links":["https://buymeacoffee.com/harunou"],"categories":[],"sub_categories":[],"readme":"# Clean Architecture Implementation for React Application with Tanstack React Query and Zustand\n\nThis project demonstrates a\n[Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\nimplementation in a React application using TanStack React Query and Zustand.\n\nBy applying Clean Architecture principles, this project maintains structural\nintegrity, remains straightforward and 💡 easy to understand. The project\ndemonstrates that implementing Clean Architecture in frontend applications\ndoesn't have to result in unnecessary 🤯 complexity or overengineering.\n\n## Benefits\n\n1. Limited context and low cognitive load, when working with a codebase.\n2. Independent, reusable and portable code units with separated concerns.\n3. Unified control and data flow throughout the application.\n4. Testable code with clear boundaries for unit and integration tests, where\n   tests are inline application specifications.\n\nApart from human developers, these benefits apply well to AI assistants, helping\nreduce code entropy through multiple repeated iterations.\n\n## Definition of units\n\n- **Enterprise Business Entity (EB Entity)**: Unit that encapsulates enterprise\n  business rules and data.\n- **Application Business Entity (AB Entity)**: Unit that encapsulates\n  application-specific business rules and data.\n- **Store**: An aggregate unit that maintains a collection of enterprise\n  business entities and/or application business entities and their states.\n- **Selector**: Unit that derives values or data structures from the state\n  without modifying it, implementing read-only queries against the state,\n  implements application business rules.\n- **Transaction**: Unit with logic that transitions a store between two valid\n  states, ensuring business rules are maintained.\n- **Use Case**: Unit that orchestrates the flow of data in the application by\n  coordinating entities, gateways, and transactions to fulfill specific user\n  goals, implements application business rules.\n- **Controller**: Unit that handles input data from the view and converts it\n  into use case invocations.\n- **Presenter**: Unit that transforms the application state into output data\n  suitable for the view, often using selectors.\n- **View**: Unit that is responsible for displaying information to the user\n  based on the data prepared by the presenter and for capturing user input and\n  transferring it to the controller.\n- **Gateway**: Unit that isolates external resources by providing interfaces for\n  data access, mapping data from external resources into entities, and potentially\n  caching data.\n- **External Resource**: External systems or services that the application\n  interacts with, such as APIs, databases, storages, or other applications.\n\n## Definition of concepts utilized by the units\n\n- **Enterprise Business Rules and Data**: The most general and high-level rules\n  and data that would exist even if the application didn't. These are\n  enterprise-wide rules that rarely change and are independent of any specific\n  application.\n- **Application Business Rules and Data**: Rules and data specific to the\n  application's functionality and presentation. This includes how business\n  concepts are presented to users, interaction flows, UI state management, and\n  application-specific behaviors. These are more likely to change compared to\n  enterprise rules.\n- **State**: The value of a store at a given point in time, typically\n  represented as an object structure.\n- **Valid State**: One of a finite number of store values that is conceptually\n  considered valid according to business and application rules.\n\n## Clean Architecture Implementation\n\nThe diagram below represents Clean Architecture implementation for a typical\nfrontend application with a store and API integration. The implementation can be\nused with any modern reactive frontend framework, like React, Vue, Svelte, or\nAngular.\n\n![diagram](docs/fe-ca-diagram.png)\n\n## Dependency Graphs\n\nDependency graph of the code units.\n\n![dependency overview](dependency-graph.svg)\n\n## File Structure of Orders Module\n\n```console\n./src/features/orders\n├── api\n│   ├── api.types.ts\n│   ├── httpClient\n│   │   ├── httpClient.ts\n│   │   └── index.ts\n│   ├── index.ts\n│   └── OrdersApi\n│       ├── index.ts\n│       ├── OrdersApi.factory.ts\n│       ├── OrdersApi.ts\n│       └── OrdersApi.types.ts\n├── cli\n│   ├── cli.tsx\n│   ├── commands\n│   │   ├── DeleteOrder.tsx\n│   │   ├── index.ts\n│   │   └── SwitchOrdersResource.tsx\n│   └── index.ts\n├── gateways\n│   ├── index.ts\n│   └── OrdersGateway\n│       ├── hooks\n│       │   ├── index.ts\n│       │   ├── useDeleteOrderItemKey.ts\n│       │   ├── useDeleteOrderItemOptions.ts\n│       │   ├── useDeleteOrderKey.ts\n│       │   ├── useDeleteOrderOptions.ts\n│       │   ├── useGetOrdersKey.ts\n│       │   ├── useGetOrdersOptions.ts\n│       │   └── useOrdersGateway.ts\n│       ├── index.ts\n│       ├── LocalOrdersGateway\n│       │   ├── index.ts\n│       │   ├── LocalOrdersGateway.spec.ts\n│       │   └── LocalOrdersGateway.ts\n│       ├── makeOrderEntities.ts\n│       └── RemoteOrdersGateway\n│           ├── index.ts\n│           ├── mappers.ts\n│           ├── RemoteOrdersGateway.spec.ts\n│           └── RemoteOrdersGateway.ts\n├── hooks\n│   ├── selectors\n│   │   ├── index.ts\n│   │   ├── useIsLastItemIdSelector\n│   │   │   ├── index.ts\n│   │   │   ├── select.spec.ts\n│   │   │   ├── select.ts\n│   │   │   └── useIsLastItemIdSelector.ts\n│   │   ├── useIsLastOrderIdSelector.ts\n│   │   ├── useIsOrdersProcessingSelector\n│   │   │   ├── index.ts\n│   │   │   ├── useIsOrdersProcessingSelector.spec.tsx\n│   │   │   └── useIsOrdersProcessingSelector.ts\n│   │   ├── useItemByIdSelector.ts\n│   │   ├── useOrderByIdSelector.ts\n│   │   ├── useOrderIdsSelector.ts\n│   │   ├── useOrdersResourceSelector.ts\n│   │   └── useTotalItemsQuantitySelector\n│   │       ├── index.ts\n│   │       ├── useTotalItemsQuantitySelector.spec.tsx\n│   │       └── useTotalItemsQuantitySelector.ts\n│   └── useCases\n│       ├── index.ts\n│       └── useDeleteOrderUseCase\n│           ├── index.ts\n│           ├── useDeleteOrderUseCase.spec.tsx\n│           └── useDeleteOrderUseCase.ts\n├── index.ts\n├── stores\n│   ├── hooks\n│   │   ├── index.ts\n│   │   └── useOrdersPresentationStore.ts\n│   ├── index.ts\n│   └── ordersPresentationStore.ts\n├── types\n│   ├── entities\n│   │   ├── index.ts\n│   │   ├── ItemEntity\n│   │   │   ├── index.ts\n│   │   │   └── ItemEntity.ts\n│   │   ├── OrderEntity\n│   │   │   ├── index.ts\n│   │   │   └── OrderEntity.ts\n│   │   └── OrdersPresentationEntity.ts\n│   ├── gateways\n│   │   ├── index.ts\n│   │   └── OrdersGateway.ts\n│   ├── index.ts\n│   └── OrdersResource.ts\n├── utils\n│   ├── index.ts\n│   └── testing\n│       ├── index.ts\n│       ├── itemEntityFactory.ts\n│       ├── makeComponentFixture.tsx\n│       ├── makeOrderEntities.ts\n│       ├── orderEntityFactory.ts\n│       └── stubUseOrdersGateway.ts\n└── views\n    ├── containers\n    │   ├── index.ts\n    │   ├── Order\n    │   │   ├── hooks\n    │   │   │   ├── index.ts\n    │   │   │   ├── useController.ts\n    │   │   │   └── usePresenter\n    │   │   │       ├── index.ts\n    │   │   │       ├── usePresenter.spec.ts\n    │   │   │       └── usePresenter.ts\n    │   │   ├── index.ts\n    │   │   ├── Order.tsx\n    │   │   └── Order.types.ts\n    │   ├── OrderItem\n    │   │   ├── hooks\n    │   │   │   ├── index.ts\n    │   │   │   ├── useController\n    │   │   │   │   ├── index.ts\n    │   │   │   │   ├── useController.spec.tsx\n    │   │   │   │   └── useController.ts\n    │   │   │   └── usePresenter.ts\n    │   │   ├── index.ts\n    │   │   ├── OrderItem.tsx\n    │   │   └── OrderItem.types.ts\n    │   ├── Orders\n    │   │   ├── hooks\n    │   │   │   ├── index.ts\n    │   │   │   ├── useController.ts\n    │   │   │   └── usePresenter.ts\n    │   │   ├── index.ts\n    │   │   ├── Orders.spec.tsx\n    │   │   ├── Orders.tsx\n    │   │   └── Orders.types.ts\n    │   └── OrdersResourcePicker\n    │       ├── index.ts\n    │       └── OrdersResourcePicker.tsx\n    ├── index.ts\n    └── testIds.ts\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharunou%2Freact-tanstack-react-query-clean-architecture","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharunou%2Freact-tanstack-react-query-clean-architecture","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharunou%2Freact-tanstack-react-query-clean-architecture/lists"}