diff --git a/README.md b/README.md index a315e275..9d90e676 100644 --- a/README.md +++ b/README.md @@ -146,19 +146,19 @@ For the purposes of this project, the meeting groups domain, based on the [Meetu **Meetings** -Main business entities are ```Member```, ```Meeting Group``` and ```Meeting```. ```Member``` can create ```Meeting Group```, be part of ```Meeting Group``` or can attend the ```Meeting```. +Main business entities are ```Member```, ```Meeting Group``` and ```Meeting```. ```Member``` can create ```Meeting Group```, be part of ```Meeting Group``` or can attend the ```Meeting```. -```Meeting Group Member``` can be an ```Organizer``` of this group or normal ```Member```. +A ```Meeting Group Member``` can be an ```Organizer``` of this group or normal ```Member```. Only ```Organizer``` of ```Meeting Group``` can create new ```Meeting```. -```Meeting``` have attendees, not attendees (```Members``` which declare they will not attend the ```Meeting```) and ```Members``` on a ```Waitlist```. +A ```Meeting``` has attendees, not attendees (```Members``` which declare they will not attend the ```Meeting```) and ```Members``` on ```Waitlist```. -```Meeting``` can have an attendees limit. If the limit is reached, ```Members``` can only sign up to ``Waitlist``. +A ```Meeting``` can have attendees limit. If the limit is reach, ```Members``` can only sign up to ``Waitlist``. -```Meeting Attendee``` can bring guests to a ```Meeting```. Number of guests is an attribute of ```Meeting```. Bringing guests can be not allowed. +A ```Meeting Attendee``` can bring guests to the ```Meeting```. Number of guests is an attribute of ```Meeting```. Bringing guests can be unallowed. -```Meeting Attendee``` can have one of two roles : normal ```Attendee``` or ```Host```. ```Meeting``` must have at least one ```Host```. ```Host``` is special role which can edit ```Meeting``` information or change attendees list. +A ```Meeting Attendee``` can have one of two roles : normal ```Attendee``` or ```Host```. A ```Meeting``` must have at least one ```Host```. ```Host``` is a special role which grants permission to edit ```Meeting``` information or change attendees list. **Administration** @@ -172,9 +172,9 @@ Additionally, Meeting organizer can set ```Event Fee```. Each ```Meeting Attende **Users** -Each ```Administrator```,```Member``` and ```Payer``` is an ```User```. To be an ```User```, ```User Registration``` is required and confirmed. +Each ```Administrator```, ```Member``` and ```Payer``` is a ```User```. To be a ```User```, ```User Registration``` is required and confirmed. -Each ```User``` has assigned one or more ```User Role```. +Each ```User``` is assigned one or more ```User Role```. Each ```User Role``` has set of ```Permissions```. ```Permission``` defines whether ```User``` can invoke a particular action. @@ -271,7 +271,7 @@ Each module has static ``Initialize`` method which is invoked in API ``Startup`` ```csharp public static void Initialize( - string connectionString, + string connectionString, IExecutionContextAccessor executionContextAccessor, ILogger logger, EmailsConfiguration emailsConfiguration) @@ -305,7 +305,7 @@ Note: Some people say that processing of command shouldn't return a result. This ### 3.4 Module requests processing CQRS -Commands and Queries processing is separated applying architectural style/pattern [Command Query Responsibility Segregation (CQRS)](https://docs.microsoft.com/pl-pl/azure/architecture/patterns/cqrs). +Commands and Queries processing is separated applying architectural style/pattern [Command Query Responsibility Segregation (CQRS)](https://docs.microsoft.com/pl-pl/azure/architecture/patterns/cqrs). ![](docs/Images/CQRS.jpg) @@ -318,7 +318,7 @@ internal class CreateNewMeetingGroupCommandHandler : ICommandHandler : ICommandHandler where T:IC private readonly ICommandHandler _decorated; public LoggingCommandHandlerDecorator( - ILogger logger, - IExecutionContextAccessor executionContextAccessor, + ILogger logger, + IExecutionContextAccessor executionContextAccessor, ICommandHandler decorated) { _logger = logger; @@ -549,8 +549,8 @@ internal class LoggingCommandHandlerDecorator : ICommandHandler where T:IC { if (_executionContextAccessor.IsAvailable) { - logEvent.AddOrUpdateProperty(new LogEventProperty("CorrelationId", new ScalarValue(_executionContextAccessor.CorrelationId))); - } + logEvent.AddOrUpdateProperty(new LogEventProperty("CorrelationId", new ScalarValue(_executionContextAccessor.CorrelationId))); + } } } } @@ -567,7 +567,7 @@ internal class ValidationCommandHandlerDecorator : ICommandHandler where T private readonly ICommandHandler _decorated; public ValidationCommandHandlerDecorator( - IList> validators, + IList> validators, ICommandHandler decorated) { this._validators = validators; @@ -613,8 +613,8 @@ public class UnitOfWorkCommandHandlerDecorator : ICommandHandler where T:I private readonly MeetingsContext _meetingContext; public UnitOfWorkCommandHandlerDecorator( - ICommandHandler decorated, - IUnitOfWork unitOfWork, + ICommandHandler decorated, + IUnitOfWork unitOfWork, MeetingsContext meetingContext) { _decorated = decorated; @@ -665,7 +665,7 @@ Outbox and Inbox is implemented using two SQL tables and background worker for e ### 3.8 Internal processing -The main principle of this system is that you can change its state only by calling a specific Command. +The main principle of this system is that you can change its state only by calling a specific Command. Sometimes, Command can be called not by API but by processing module itself. The main use case which uses this mechanism is data processing in eventual consistency mode, when we want to process something in a different process and transaction. This applies for example to Inbox processing, because we want to do something (calling a Command) based on Integration Event from Inbox. @@ -732,13 +732,13 @@ public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator if (!authenticationResult.IsAuthenticated) { context.Result = new GrantValidationResult( - TokenRequestErrors.InvalidGrant, + TokenRequestErrors.InvalidGrant, authenticationResult.AuthenticationError); return; } context.Result = new GrantValidationResult( - authenticationResult.User.Id.ToString(), - "forms", + authenticationResult.User.Id.ToString(), + "forms", authenticationResult.User.Claims); } } @@ -756,9 +756,9 @@ public async Task ProposeMeetingGroup(ProposeMeetingGroupRequest { await _meetingsModule.ExecuteCommandAsync( new ProposeMeetingGroupCommand( - request.Name, - request.Description, - request.LocationCity, + request.Name, + request.Description, + request.LocationCity, request.LocationCountryCode)); return Ok(); @@ -791,7 +791,7 @@ Each unit test has 3 standard sections: Arrange, Act and Assert 1. Arrange -The Arrange section is responsible for preparing the Aggregate for testing the public method that we want to test. This public method is often called from the unit tests perspective as SUT (system under test). +The Arrange section is responsible for preparing the Aggregate for testing the public method that we want to test. This public method is often called from the unit tests perspective as SUT (system under test). Creating an Aggregate ready for testing involves **calling one or more other public constructors/methods** on the Domain Model. At first it may seem that we are testing too many things at the same time, but this is not true. We need to be one hundred percent sure, that the Aggregate is in a state exactly as it will be in production. This can only be ensured when: @@ -835,7 +835,7 @@ public void NewUserRegistration_WithUniqueLogin_IsSuccessful() // Act var userRegistration = UserRegistration.RegisterNewUser( - "login", "password", "test@email", + "login", "password", "test@email", "firstName", "lastName", usersCounter); // Assert @@ -871,7 +871,7 @@ public void AddAttendee_WhenMemberIsAlreadyAttendeeOfMeeting_IsNotPossible() var meetingTestData = CreateMeetingTestData(new MeetingTestDataOptions { CreatorId = creatorId - }); + }); var newMemberId = new MemberId(Guid.NewGuid()); meetingTestData.MeetingGroup.JoinToGroupMember(newMemberId); meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 0); @@ -881,7 +881,7 @@ public void AddAttendee_WhenMemberIsAlreadyAttendeeOfMeeting_IsNotPossible() { // Act meetingTestData.Meeting.AddAttendee(meetingTestData.MeetingGroup, newMemberId, 0); - }); + }); } ``` @@ -928,7 +928,7 @@ List of technologies, frameworks and libraries used for implementation: - [.NET Core 2.2](https://dotnet.microsoft.com/download) (platform) - [MS SQL Server Express](https://www.microsoft.com/en-us/sql-server/sql-server-editions-express) (database) -- [Entity Framework Core 2.2](https://docs.microsoft.com/en-us/ef/core/) (ORM Write Model implementation for DDD) +- [Entity Framework Core 2.2](https://docs.microsoft.com/en-us/ef/core/) (ORM Write Model implementation for DDD) - [Autofac](https://autofac.org/) (Inversion of Control Container) - [IdentityServer4](http://docs.identityserver.io) (Authentication and Authorization) - [Serilog](https://serilog.net/) (structured logging)