Skip to content

DavorPenzar/hat-trick

Repository files navigation

Hat-Trick

Online betting shop simulator.

Author: Davor Penzar
Date: February, 2023

Nota Bene. If you find any problems with running the app, even if the app ran successfully before but then you synchronised the repository with the origin, make sure you check the important notes under the Running the App heading. If you do not find the answer to your problems, keep reading the complete text on how to run the app—maybe you missed a step. If nothing seems to solve the problem, you may create an issue or contact me personally; otherwise you could try to debug the problem yourself.

Licence

This repository is licensed under the GNU General Public Licence v3.0. Its dependencies might be licensed under different licences: before using the code for purposes other than personal, see which dependencies are used and under what licences they are issued.

Info

This repository implements a simple online betting shop simulator. The shop is implemented through all three:

  1. Database – the simulator generates and maintains its own database. There is no need to connect it to an existing one or creating it manually.
  2. Web API – apart from the database and the front-end application, there is an API layer in the middle that connects the two, simultaneously enforcing the betting shop's rules, ensuring proper data is put into the database, and delivering the data in the correct scale (e. g. serving only the relevant events) and format (JSON) to the front end.
  3. Front end – the interactive web application with user-friendly interface (graphical user interface (GUI)) that allows the user to explore the offer, place bets, deposit and withdraw money to/from their account, and check their past tickets.

The actual layered abstraction/implementation of the app is the following:

Main Layer Project Layer Implementation
Database Database SQLite (can be easily changed—see below)
Database HatTrick.Models Database model C#, .NET
Back end HatTrick.DAL DAL C#, .NET, Entity Framework
Back end HatTrick.BLL BLL C#, .NET
Back end HatTrick.API Web API C#, ASP.NET, Swashbuckle
Front end HatTrick.Web GUI Vue.js, TypeScript, JavaScript, Bootstrap

Since Entity Framework is used for accessing the database, without any custom SQL code but using code-first approach, with just a few changes in the AppSettings and Startup one can migrate the app from SQLite to many others DBMSes: see here and here. In fact, you can choose one of the few DBMSes provided in advance simply by altering the "DatabaseProvider" in the development AppSettings:

Note, however, that the data persisted in one database is not automatically migrated to the other. Furthermore, changing the DBMS while the app is running may cause unexpected problems, potentially resulting in uncaught exceptions: the app ensures the database exists only at the startup, but assumes its existence during the runtime. If the requested database does not exist at the startup, the app creates it and fills it with initial sample data; otherwise it uses the existing database, including the data it holds. Any time the app tries to connect to the database later during the runtime, the checkup and initialisation are skipped.

The app was meant to be implemented from a DBMS-agnostic point of view, and to simulate scalable real-world apps where possible, therefore issues like this one were ignored. Instead, asynchronous methods were preferred as advised here, even though SQLite is used by default.

The resulting database model is visualised as a directed graph in the DatabaseModel.dgml file, which was auto-generated from the Context class using EF Core Power Tools.

Running the App

IMPORTANT.

  1. After synchronising your local repository with the origin:
    1. If the solution was open in an IDE before, during and after the synchronisation, it would be a good practice to close and reopen it. Just in case.
    2. Regardless, it would be the best practice to delete your local database before running the app again. I might have changed the model and/or the sample data, making the old database inadequate for the rest of the code and the intended app experience.
    3. If there are problems with building/running the app, try deleting the old compilation results and recompiling from scratch:
      1. terminate all app-related processes or simply close all command-line interpreters/shells in which the app is running,
      2. exit the IDE in which the solution is open,
      3. in the C# projects delete the obj/ and bin/ directories, in the Vue.js project delete the obj/ and node_modules/ directories,
      4. recompile the solution.
  2. If everything seems to compile but the front-end web page does not display, even after the back end has started and having refreshed the front end, uncomment the line 3 and comment the line 2 in main.ts.

Prerequisites

I am not sure which are the minimal versions of Node.js and Vue CLI required for the code to be successfully compiled and run. Actually, maybe Node.js alone is sufficient for simply running the already set up HatTrick.Web. Otherwise, the versions mentioned above may in fact be insufficient, as the code was built on versions higher than the ones listed.

Universal Guidelines

First, clone the repo. Once the code is available locally, the app must be run in development mode—this refers to the HatTrick.API and HatTrick.Web projects. It cannot run in production mode because the connection string is currently set only in the development AppSettings, and the Vue.js proxy server is set only for the devServer.proxy in vue.config. See below how to achieve running in development mode.

Running Using Visual Studio

The application is implemented as a Visual Studio Solution. The simplest way to run the app is to open the HatTrick.sln solution in Visual Studio, and run the HatTrick.API and HatTrick.Web projects in parallel: see here and here. By default, the app will run in development mode, but this can be changed, as explained here and here.

Running Manually

Again, the HatTrick.API and HatTrick.Web projects must be run in parallel. To run the former in development mode, see here and here; note that the Development environment is already defined in the launchSettings. To run the latter in development mode, see here; more about running the HatTrick.Web is available in its own README.

Remarks

Obviously, this is a simulator. What ever the user does with the money using the app, no real-world transactions take place in the background. Also, although the original (non-promoted) offer, which is currently available through sample data, was copied from one Croatian betting provider at one specific point in time, the coefficients do not necessarily reflect competitors' potential to accomplish the favourable outcomes.

However, there are some more important implications, regarding the architecture of the solution at hand:

  1. All web API endpoints allow passing a time point, either for searching the database (e. g. not to display past events) or for specifying when a certain user-initiated action was done. Also, the front end maintains its own hard-coded fixed time-point at which all actions are done, and it passes it in all communication with the back end. In reality, the server would take care of recording time, and it would not expose any functionality for manipulating it. This was done mainly to make sure the offer never expires on the front end.
    • IMPORTANT. When testing the web API, make sure you pass a time-point no earlier than the 1st of January, 2023, and no later than the 8th of February, 2023. If no time-point is passed, or a too early or a too late one is passed, the offer might seem empty, even though there are clearly some data in the database.
  2. No authentication is implemented in the app. The database allows having multiple users, each ticket and transaction must be related to a registered active user (at the time), and the front end keeps a hard-coded user id which it then uses for communicating with the back end. On the other hand, the back end accepts the id as any other parameter, meaning that every one could send requests to the back end on behalf of any one else, simply by passing the other user's id. If the requests were otherwise valid, the back end would accept them—which is a major vulnerability, especially when dealing with financial transactions.
  3. The code is far from ideal. First of all, this was my first serious experience with Vue.js, and therefore I am probably not even aware of all the downsides of my solution there. Also, regarding the front end, the web design could be much better, but I mostly focused on the business logic in the app, and merely made a simple Bootstrap-powered web page for the highest layer. Second of all, some C# classes in the back end could probably be split into smaller classes, using a higher level of abstraction, but this is something one would do in a professional environment, for a production-quality code, having serious resources available (e. g. time, money, people…).
  4. The database model is very simplified and exposes only the entities and properties needed for the app. In real life, there is some additional information that would be associated with the entities used by the app:
    • value segmentation of users – as the segmentation is needed only for internal business processes, it is irrelevant for a simulator like this one,
    • stake factor grading of users – similar to the previous, only it could be used to further limit the maximal amount to bet, which adds no value to the simulator,
    • entities for tournaments, competitors, and maybe even locations – sure, the tournaments table could be utilised for this app to present the events in the offer groupped by tournaments, but, for it to make sense, more events should be present in the sample data; for other tables I do not see a signifficant value they would add to the app if present,
    • keeping track of rescheduled events and having the rescheduled events reference the original events – again, I only see the value added by this in internal business processes, such as when analysing how many different events were offered during a certain period (month, year, &c.).
  5. Although the database model is simplified, the sample data contains some unused entries which fit into the model, but utilising them would make the simulator much more complex than it is (e. g. live fixtures or cashed out ticket status).
  6. The offer could be a little more diverse. Primarily, there are only two types of markets, and one of them is available only for a single event. However, the offer is here just to present the data in the database and to allow the user to place a bet. Extending the offer would make the simulator seem more realistic, but no additional functionality would be added to the simulator. As one can easily copy the offer from an existing betting provider, without much creativity, I decided not to pursue this goal, but to focus more on the business logic and the design.
  7. The app includes some functionality to display tickets differently depending on their status and resolution (cash-out/win/lose). However, to see this, the sample data should be extended. I might add additional data to the database, but probably will not.