Reusable Signal Store
Problem
Many application screens repeat the same behavior: load a list, select an item, filter results, update data, and show loading or error states. Without a shared pattern, this logic easily ends up inside every component. That makes screens harder to maintain and causes similar features to be built in slightly different ways.
Constraints
The solution needed to stay small and understandable. This project is not a large enterprise application, so a heavy state management setup would add unnecessary complexity. At the same time, the code still needed enough structure to support different screens, such as participants and transaction requests, without duplicating the same state logic everywhere.
Architectural Choices
The project uses a reusable EntityStore for common entity behavior. It handles loading, selection, filtering, finding items by ID, loading states, error states, and basic create, update, and delete flows.
Each feature store then adds only what is specific to that domain. The participant store defines participant IDs, participant filtering, and update behavior. The transaction request store uses the same base store, but adds status filtering and workflow actions like approve and reject.
Angular Signals are used for UI state, so components can easily read values such as loading, filteredEntities, and selectedEntity. RxJS is still used for asynchronous data access, where it fits naturally.
Alternatives
One alternative is using no store at all. In that case, each component would manage its own loading state, selected item, filters, API calls, and updates. This can work for very small applications, but it quickly leads to repeated code and inconsistent behavior.
Another alternative is using a heavier framework like NgRx. NgRx is powerful for large applications with complex global state, but it introduces more moving parts: actions, reducers, selectors, effects, and additional files. For these entity screens, that would make a relatively simple problem feel much larger.
Why This Solution
The reusable signal store gives the project a middle ground. It is more structured than putting all state directly in components, but lighter than a full NgRx setup.
It reduces repetition, keeps components focused on the user interface, and makes new entity screens faster to build. At the same time, it remains flexible: participants and transaction requests use the same store pattern, but still keep their own filters, data models, and business actions.
This makes the solution well suited for small to medium business applications where many screens share the same basic behavior but still need their own feature-specific logic.
View the example project on GitHub