{"id":20239504,"url":"https://github.com/profjordanov/sports-system","last_synced_at":"2025-04-10T19:41:00.118Z","repository":{"id":37689705,"uuid":"195846353","full_name":"profjordanov/sports-system","owner":"profjordanov","description":" React/Redux and .NET Core based sport system to bet for matches.","archived":false,"fork":false,"pushed_at":"2025-03-21T06:41:33.000Z","size":2142,"stargazers_count":17,"open_issues_count":5,"forks_count":15,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-21T07:29:38.592Z","etag":null,"topics":["asp-net-core-2-2","cqrs","domain-driven-design","event-sourcing","functional-programming","hateoas","hateoas-hal","rest-api","restful-api"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/profjordanov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-08T16:06:20.000Z","updated_at":"2025-03-21T06:40:24.000Z","dependencies_parsed_at":"2024-11-14T08:49:55.138Z","dependency_job_id":null,"html_url":"https://github.com/profjordanov/sports-system","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profjordanov%2Fsports-system","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profjordanov%2Fsports-system/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profjordanov%2Fsports-system/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profjordanov%2Fsports-system/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/profjordanov","download_url":"https://codeload.github.com/profjordanov/sports-system/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248281414,"owners_count":21077423,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asp-net-core-2-2","cqrs","domain-driven-design","event-sourcing","functional-programming","hateoas","hateoas-hal","rest-api","restful-api"],"created_at":"2024-11-14T08:39:09.315Z","updated_at":"2025-04-10T19:41:00.093Z","avatar_url":"https://github.com/profjordanov.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JBet\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)\n\n[![Build status](https://ci.appveyor.com/api/projects/status/5xu73ew2on693vhe?svg=true)](https://ci.appveyor.com/project/profjordanov/sports-system)\n\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/2e0461ba54e148bea7bb3b5a81e76924)](https://www.codacy.com/app/profjordanov/sports-system?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=profjordanov/sports-system\u0026amp;utm_campaign=Badge_Grade)\n\nWeb based sport system to bet for matches, played by teams.\nAs a whole, this project aims to implement most of the [AspNetCore-Developer-Roadmap](https://github.com/MoienTajik/AspNetCore-Developer-Roadmap)\n\n## Data Model\n### The system holds teams, players, matches, comments, users, bets and votes.\n- [x] Teams have name, nick name (optional), web site (optional), date founded (optional) and a set of players.\n- [x] Players have name, date of birth, height, and may be part of some team or be unemployed.\n- [x] Teams play matches. Each match has home team, away team, date and time and a set of comments.\n- [x] Comments have content (text), date and time and owner user (author).\n- [x] Users have username, email and password (encrypted). Users hold also a set of bets and a set of comments for the matches.\n- [x] Users can bet some money for the home or away team for existing match.\n- [x] Users can vote for a team (give +1) ones.\n\n## Features\n1. Domain-Driven Design in Practice a.k.a [DDD](https://en.wikipedia.org/wiki/Domain-driven_design)\n2. REST with [HATEOAS](https://github.com/riskfirst/riskfirst.hateoas) by following [HAL](http://stateless.co/hal_specification.html)\n3. Command and Query Responsibility Segregation (CQRS) via [MediatR](https://github.com/jbogard/MediatR)\n4. Functional style command/query handlers via robust option/maybe type [Optional](https://github.com/nlkl/Optional)\n\nExamples:\n```csharp\n// LoginHandler.cs\npublic Task\u003cOption\u003cJwtView, Error\u003e\u003e Handle(Login command, CancellationToken cancellationToken = default) =\u003e\n    ValidateCommand(command).FlatMapAsync(cmd =\u003e\n    FindUser(command.Email).FlatMapAsync(user =\u003e\n    CheckPassword(user, command.Password).FlatMapAsync(_ =\u003e\n    GetExtraClaims(user).MapAsync(async claims =\u003e\n    GenerateJwt(user, claims)))));\n```\n5. Event-sourcing via [Marten](https://jasperfx.github.io/marten/)\n6. A complete integration tests suite\n\nExamples:\n```csharp\n// AuthControllerTests.cs\n[Theory]\n[CustomizedAutoData]\npublic async Task LoginShouldSetProperHttpOnlyCookie(Register register)\n{\n    // Arrange\n    await _authHelper.Register(register);\n\n    var loginCommand = new Login\n    {\n        Email = register.Email,\n        Password = register.Password\n    };\n\n    // Act\n    var response = await _fixture.ExecuteHttpClientAsync(client =\u003e\n        client.PostAsJsonAsync(AuthRoute(\"login\"), loginCommand));\n\n    // Assert\n    var token = (await response\n            .ShouldDeserializeTo\u003cLoginResource\u003e())\n        .TokenString;\n\n    response.Headers.ShouldContain(header =\u003e\n        header.Key == \"Set-Cookie\" \u0026\u0026\n        header.Value.Any(x =\u003e x.Contains(AuthConstants.Cookies.AuthCookieName) \u0026\u0026 x.Contains(token)));\n}\n```\n7. Real-time communications through SignalR\n8. AutoMapper\n9. EntityFramework Core with PostgreSQL Server and ASP.NET Identity\n10. JWT authentication/authorization\n11. File logging with Serilog\n12. Stylecop\n13. Swagger UI + Fully Documented Controllers\n14. Global Model Errors Handler\n15. Global Environment-Dependent Exception Handler\n16. Thin Controllers\n\nExamples:\n```csharp\n// BetsController.cs\n/// \u003csummary\u003e\n/// Logged-in users can bet for the home team.\n/// \u003c/summary\u003e\n/// \u003cparam name=\"input\"\u003eHTTP request.\u003c/param\u003e\n[HttpPost(\"home-team\", Name = nameof(BetForHomeTeam))]\n[ProducesResponseType(typeof(UserMatchBetResource), (int)HttpStatusCode.Created)]\npublic async Task\u003cIActionResult\u003e BetForHomeTeam([FromBody] MatchHomeBetInput input) =\u003e\n    (await Mediator.Send(new UserBetForHomeTeam(input, CurrentUserId))\n        .MapAsync(_ =\u003e ToEmptyResourceAsync\u003cUserMatchBetResource\u003e()))\n        .Match(resource =\u003e CreatedAtAction(nameof(BetForHomeTeam), resource), Error);\n```\n17. [FluentValidation](https://fluentvalidation.net/)\n18. Neat folder structure\n```\n├───client\n│   ├───public\n│   │   ├───index.html\n│   │   └───manifest.json\n│   ├───src\n│   │   ├───api\n│   │   ├───components\n│   │   ├───redux\n│   │   └───utils\n├───server\n│   ├───configuration\n│   │   ├───analyzers.ruleset\n│   │   └───stylecop.json\n│   ├───src\n│   │   ├───Jbet.Api\n│   │   ├───Jbet.Business\n│   │   ├───Jbet.Core\n│   │   ├───Jbet.Domain\n│   │   └───Jbet.Persistence\n│   └───tests\n│       └───Jbet.Tests\n```\n### Test Suite\n19. Arrange Act Assert Pattern\n20. xUnit\n21. Autofixture\n22. Moq\n23. Shouldly\n24. FakeItEasy\n25. Respawn\n\n# Functionality\n- [x] Anonymous users can register user account by email and password.\n- [x] Anonymous users can login by email and password.\n- [x] Logged-in users can logout.\n- [x] Anonymous users can view the home page, holding the top 3 matches (having most bets) and best 3 teams (most voted).\n- [x] Anonymous users can view all matches (ordered by date, with paging).\n- [x] Logged-in users can view team details (information about the team and its players).\n- [x] Logged-in users can vote for a team (no more than once).\n- [x] Logged-in users can view match details (home team, away team, date and comments).\n- [x] Logged-in users can add comments for given match.\n- [x] Logged-in users can bet for the home or away team.\n- [x] Logged-in users can create a new team and assign players to the new team.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprofjordanov%2Fsports-system","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprofjordanov%2Fsports-system","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprofjordanov%2Fsports-system/lists"}