There are four important runnable projects.
| Project | Role |
|---|---|
src/Hosting/Evently.AppHost |
Aspire orchestration and local infrastructure graph |
src/API/Evently.Api |
Main API host for Users, Events, and Attendance |
src/API/Evently.Ticketing.Api |
Separate API host for Ticketing |
src/API/Evently.Gateway |
YARP gateway in front of the APIs |
The src/Common folder contains the cross-cutting building blocks used by the modules.
| Project | Purpose |
|---|---|
Evently.Common.Domain |
base domain types such as Entity, Result, errors, domain events |
Evently.Common.Application |
application abstractions such as commands, queries, event handlers, authorization contracts |
Evently.Common.Infrastructure |
database, messaging, auth, caching, Quartz, OpenTelemetry, inbox/outbox support |
Evently.Common.Presentation |
endpoint discovery and API result helpers |
Evently.Common.Constants |
shared constants such as service names |
These are technical shared libraries, not business shared state.
Each business module follows the same internal shape:
| Layer | Purpose |
|---|---|
Domain |
aggregates, entities, value objects, domain events, business rules |
Application |
commands, queries, handlers, use-case orchestration |
Infrastructure |
EF Core, repositories, inbox/outbox jobs, external integrations |
Presentation |
HTTP endpoints and integration-event entry points |
IntegrationEvents |
contracts that other modules are allowed to depend on |
This is one of the most important patterns in the whole repository. Once you understand one module, the others become much easier to read.
The system is still one overall application, but the modules are split across two API hosts:
Evently.ApihostsUsers,Events, andAttendanceEvently.Ticketing.ApihostsTicketing
That split is operational, not conceptual. The real boundaries are the modules themselves.
Evently.AppHost is the local development composition root.
It starts and wires:
- PostgreSQL
- MongoDB
- Redis
- RabbitMQ
- Keycloak
- the main API
- the ticketing API
- the gateway
It also injects the runtime values the applications need, including:
- connection strings
- broker URI
- identity provider URLs
- gateway destination addresses
- OpenTelemetry export settings
With Aspire, the app projects do not need to hardcode local credentials or local hostnames.
This host:
- adds shared service defaults and telemetry
- loads module-specific configuration files for
events,users, andattendance - registers shared infrastructure
- registers the three modules
- exposes OpenAPI and Scalar in development
- applies EF Core migrations in development
- maps all discovered module endpoints
This host does the same thing for the Ticketing module.
The gateway:
- loads reverse-proxy routes and clusters from configuration
- validates JWT bearer tokens
- exposes health endpoints
- forwards traffic to the main API or the ticketing API
Configuration is intentionally split:
- host-level config lives in each API's
appsettings*.json - module config lives in
modules.<name>.json - local runtime values are injected by Aspire
The main API explicitly loads:
modules.events.jsonmodules.users.jsonmodules.attendance.json
The ticketing API explicitly loads:
modules.ticketing.json
Those module files currently hold things such as inbox and outbox polling intervals and Keycloak-related options for the Users module.
Endpoints are not registered one by one in Program.cs.
Instead:
- each endpoint class implements
IEndpoint - the module presentation assembly is scanned
- all discovered endpoints are registered and later mapped automatically
This keeps the entry point thin and keeps each endpoint near its module logic.
When you run the AppHost locally, the normal sequence is:
- Aspire starts infrastructure containers.
- Aspire injects connection strings and service URLs into the app projects.
- The APIs start, register services, and expose health endpoints.
- In development, EF Core migrations are applied automatically.
- Quartz starts background inbox and outbox jobs.
- MassTransit consumers start listening on RabbitMQ.
- The gateway becomes the front door.
The solution has one local orchestration host, two API hosts, one gateway, a set of shared technical libraries, and four business modules that all follow the same Domain/Application/Infrastructure/Presentation split.