This repository is organized as an Nx workspace and implements an event-sourced architecture with a React client and a GraphQL query API.
- Event Store:
Uses a MongoDB-backed event store (MongoEventStore) to persist all domain events. Events are versioned and concurrency is enforced. - Event Bus:
Publishes events using BullMQ queues (BullMqEventBus), enabling asynchronous event processing and integration with workers. - Domain Commands & Events:
Domain logic is encapsulated in commands (e.g.,CreateUserCommand,UpdateUserNameCommand) and events (e.g.,UserCreatedEvent,UserNameUpdatedEvent). - Command Handlers:
Command handlers process incoming commands, apply business logic, and emit events to the event store and event bus. - Read Model Projection:
Workers (e.g.,processor-user-events) listen for domain events and update MongoDB read models for efficient querying.
- Apollo Server:
Provides a GraphQL endpoint for querying the read model stored in MongoDB. - Resolvers & Type Definitions:
Loads GraphQL type definitions and resolvers dynamically, supporting modular schema development. - Express Integration:
The GraphQL server is mounted on an Express app, with CORS and logging middleware for development.
- React App:
The client is a React application using React Router for navigation. - Authentication:
Integrates Google OAuth for authentication, storing credentials in session storage and managing user state. - API Communication:
Uses Axios to communicate with the backend API, sending authenticated requests. Will eventually use GraphQL for main queries. - Feature Modules:
Implements feature-based code splitting and lazy loading for scalable UI development. - Lots Management:
- Lot List Table: View, edit, and delete lots in a responsive table.
- Nx Workspace:
Use Nx CLI and Nx Console for code generation, building, and running tasks. - Running the App:
- Start the backend:
nx serve server - Start the event processor:
nx serve processor-user-events - Start the GraphQL query API:
nx serve query - Start the frontend:
nx serve client
- Start the backend:
For development and testing purposes, you can bypass the Google OAuth authentication by setting the BYPASS_AUTH environment variable to true. This is useful for:
- Testing GraphQL Playground without needing authentication tokens
- Local development when you don't want to set up Google OAuth
- Automated testing scenarios
To enable authentication bypass:
- Set the environment variable:
BYPASS_AUTH=true - Start your services (query server, etc.)
- Access GraphQL Playground at
http://localhost:4000/graphqlwithout authentication
Warning: Never use BYPASS_AUTH=true in production environments. This feature should only be used for development and testing.
When authentication is bypassed, a mock user is automatically created with:
- Email:
dev@example.com - Name:
Development User - Sub:
dev-user-123
This project follows a CQRS (Command Query Responsibility Segregation) and Event Sourcing architecture pattern with the Saga pattern for complex business process coordination.
Commands → Command Handlers → Aggregates → Events → Event Store
↓
Event Bus → Sagas/Event Handlers → Read Models
- Commands: Represent user intentions to change system state
- Command Handlers: Process commands and coordinate between aggregates, event store, and event bus
- Example:
CreateLotCommand→CreateLotCommandHandler
- Aggregates: Domain entities that enforce business rules and generate events
- Event Sourcing: State is derived from a sequence of events rather than stored directly
- Example:
LotAggregatemanages lot creation and updates
- Events: Immutable facts about what happened in the system
- Event Store: Persistent storage for all events, providing complete audit trail
- Example:
LotCreatedEvent,LotUpdatedEvent
- Event Bus: Routes events to subscribers (sagas, read model projections, etc.)
- Publishers: Command handlers publish events after successful aggregate operations
- Subscribers: Sagas and event handlers subscribe to relevant events
- Sagas: Coordinate complex business processes across multiple aggregates
- Event-Driven: React to events and orchestrate subsequent operations
- Example:
LotPositionUpdateSagaupdates position overviews when lots change
- Projections: Optimized views of data for queries
- Eventually Consistent: Updated asynchronously via event handlers
- Example: Position overviews with calculated dollar cost averages
@adg/server-shared-kernel: Core abstractions (Event, Command, AggregateRoot, IEventBus, IEventStore)@adg/server-domain-lot-*: Lot domain implementation (commands, events, aggregates, handlers, sagas)@adg/server-domain-position-*: Position domain implementation@adg/global-formulas: Business calculation logic (dollar cost averaging, etc.)@adg/global-models: Shared data models and interfaces@adg/global-validations: Input validation schemas
- Scalability: Separate read and write models can be optimized independently
- Auditability: Complete event history provides full audit trail
- Flexibility: Easy to add new projections and business processes
- Testability: Clear separation of concerns and event-driven architecture
- Consistency: Sagas ensure complex business processes maintain data consistency
For more details, see the individual library and app README files.