Web based sport system to bet for matches, played by teams. As a whole, this project aims to implement most of the AspNetCore-Developer-Roadmap
- Teams have name, nick name (optional), web site (optional), date founded (optional) and a set of players.
- Players have name, date of birth, height, and may be part of some team or be unemployed.
- Teams play matches. Each match has home team, away team, date and time and a set of comments.
- Comments have content (text), date and time and owner user (author).
- Users have username, email and password (encrypted). Users hold also a set of bets and a set of comments for the matches.
- Users can bet some money for the home or away team for existing match.
- Users can vote for a team (give +1) ones.
- Domain-Driven Design in Practice a.k.a DDD
- REST with HATEOAS by following HAL
- Command and Query Responsibility Segregation (CQRS) via MediatR
- Functional style command/query handlers via robust option/maybe type Optional
Examples:
// LoginHandler.cs
public Task<Option<JwtView, Error>> Handle(Login command, CancellationToken cancellationToken = default) =>
ValidateCommand(command).FlatMapAsync(cmd =>
FindUser(command.Email).FlatMapAsync(user =>
CheckPassword(user, command.Password).FlatMapAsync(_ =>
GetExtraClaims(user).MapAsync(async claims =>
GenerateJwt(user, claims)))));
- Event-sourcing via Marten
- A complete integration tests suite
Examples:
// AuthControllerTests.cs
[Theory]
[CustomizedAutoData]
public async Task LoginShouldSetProperHttpOnlyCookie(Register register)
{
// Arrange
await _authHelper.Register(register);
var loginCommand = new Login
{
Email = register.Email,
Password = register.Password
};
// Act
var response = await _fixture.ExecuteHttpClientAsync(client =>
client.PostAsJsonAsync(AuthRoute("login"), loginCommand));
// Assert
var token = (await response
.ShouldDeserializeTo<LoginResource>())
.TokenString;
response.Headers.ShouldContain(header =>
header.Key == "Set-Cookie" &&
header.Value.Any(x => x.Contains(AuthConstants.Cookies.AuthCookieName) && x.Contains(token)));
}
- Real-time communications through SignalR
- AutoMapper
- EntityFramework Core with PostgreSQL Server and ASP.NET Identity
- JWT authentication/authorization
- File logging with Serilog
- Stylecop
- Swagger UI + Fully Documented Controllers
- Global Model Errors Handler
- Global Environment-Dependent Exception Handler
- Thin Controllers
Examples:
// BetsController.cs
/// <summary>
/// Logged-in users can bet for the home team.
/// </summary>
/// <param name="input">HTTP request.</param>
[HttpPost("home-team", Name = nameof(BetForHomeTeam))]
[ProducesResponseType(typeof(UserMatchBetResource), (int)HttpStatusCode.Created)]
public async Task<IActionResult> BetForHomeTeam([FromBody] MatchHomeBetInput input) =>
(await Mediator.Send(new UserBetForHomeTeam(input, CurrentUserId))
.MapAsync(_ => ToEmptyResourceAsync<UserMatchBetResource>()))
.Match(resource => CreatedAtAction(nameof(BetForHomeTeam), resource), Error);
- FluentValidation
- Neat folder structure
├───client
│ ├───public
│ │ ├───index.html
│ │ └───manifest.json
│ ├───src
│ │ ├───api
│ │ ├───components
│ │ ├───redux
│ │ └───utils
├───server
│ ├───configuration
│ │ ├───analyzers.ruleset
│ │ └───stylecop.json
│ ├───src
│ │ ├───Jbet.Api
│ │ ├───Jbet.Business
│ │ ├───Jbet.Core
│ │ ├───Jbet.Domain
│ │ └───Jbet.Persistence
│ └───tests
│ └───Jbet.Tests
- Arrange Act Assert Pattern
- xUnit
- Autofixture
- Moq
- Shouldly
- FakeItEasy
- Respawn
- Anonymous users can register user account by email and password.
- Anonymous users can login by email and password.
- Logged-in users can logout.
- Anonymous users can view the home page, holding the top 3 matches (having most bets) and best 3 teams (most voted).
- Anonymous users can view all matches (ordered by date, with paging).
- Logged-in users can view team details (information about the team and its players).
- Logged-in users can vote for a team (no more than once).
- Logged-in users can view match details (home team, away team, date and comments).
- Logged-in users can add comments for given match.
- Logged-in users can bet for the home or away team.
- Logged-in users can create a new team and assign players to the new team.