This page is deliberately short. It is here so you can refresh the project quickly before a conversation.
Evently is a modular monolith for event management. It keeps business modules isolated, lets each module own its own data, and uses integration events, inbox/outbox processing, and a saga to coordinate cross-module workflows.
- the code is split into bounded-context-style modules
- modules do not share business internals directly
- modules do not read each other's tables
- communication happens through explicit contracts and messages
- each module has its own domain, application, infrastructure, and presentation layers
Users: profiles, roles, permissions, Keycloak identity mappingEvents: categories, events, ticket types, cancellation coordinationTicketing: carts, orders, payments, ticketsAttendance: check-in and attendance statistics
Because modules are not supposed to reach into each other's storage. They consume integration events and store the data they need locally.
Examples:
UserbecomesCustomerinTicketingUserbecomesAttendeeinAttendanceEventis replicated intoTicketingandAttendanceTicketIssuedIntegrationEventcreates an attendance-side ticket copy
Mostly through RabbitMQ and MassTransit.
Typical flow:
- local command changes state
- aggregate raises domain event
- domain event goes to outbox
- outbox job processes it
- handler publishes integration event
- receiving module stores it in inbox
- inbox job processes it
- integration handler sends a local command
- they make message processing retryable
- they reduce the risk of losing cross-module events
- they support eventual consistency
- they help with idempotency
- they preserve module boundaries
The cancellation saga coordinates event cancellation.
It waits for two independent things to finish in Ticketing:
- payment refunds
- ticket archiving
When both are done, it publishes cancellation completion.
Mostly for the Attendance module's EventStatistics projection. Most other reads still use Dapper over PostgreSQL.
- Keycloak issues tokens and acts as the identity provider
- the
Usersmodule stores local user data and permissions - claims transformation enriches the principal with the local user ID and permission claims
- endpoints authorize against permission codes
This design gets many of the boundary and consistency benefits of microservices without paying the full deployment and operational cost. It is a good middle ground for teams that want clear business separation but do not need separate deployment units yet.
Strong architectural ideas:
- module boundaries
- inbox/outbox
- integration events
- permission flow
- saga coordination
Clearly simplified areas:
- payment gateway is fake
- notification sending is not implemented
- local Keycloak setup depends on persisted dev state
Evently is a modular monolith built with .NET. The important idea is that each module owns its own business logic and persistence model, even though the whole solution runs together. When one module needs another module to react, it publishes integration events through RabbitMQ. Incoming messages are persisted in inbox tables, outgoing domain events are persisted in outbox tables, and Quartz processes both asynchronously. The most interesting workflow is event cancellation, where a saga waits for ticket archiving and payment refunds before marking the cancellation complete.