# challenge-gamersclub Este repositório contém parte (Backend) da solução para o desafio da Gamersclub. ## TOC - [Observações](#Observações) - [Testes e cobertura](#Testes-e-cobertura) - [Desenho da arquitetura](#Desenho-da-arquitetura) - [Modelagem de dados](#Modelagem-de-dados) - [Instalação](#Instalação) - [Configuração](#Configuração) # Observações Para não gerar ruídos no entendimento, na fase de grupos as equipes se confrontam em jogos de ida e volta. O outro ponto, é que fixei o escopo em um simulador de torneio. Logo, o banco em produção ou desenvolvimento é populado inicialmente com algumas informações como: torneio, rounds, grupos e equipes. E no momento que uma requisição é enviada, ele gera as partidas e atualiza as devidas pontuações. Mas ressalvo, que se fosse para sempre criar um novo torneio, rounds, grupos, equipes e etc... A cada nova requisição, também não seria complicado de fazer, na verdade ficaria até mais simples pro meu lado. # Testes e cobertura A API possui testes de unidade e integração que cobrem **93,66%** do código. Isto pode ser convertido em uma confiabilidade de que há apenas **6,34%** de chances de liberação de bugs, caso ocorressem novas manutenções nesse desafio. ![Test coverage](https://iili.io/dfhaWX.png) # Desenho da arquitetura ![Architecture design](https://iili.io/JbBObt.jpg) # Modelagem de dados ![Database modeling](https://iili.io/dd9n72.jpg) # Instalação Requisitos: * [NodeJS](https://nodejs.org/en/) * [Yarn](https://yarnpkg.com/en/) * [Docker](https://docs.docker.com/compose/install/) O Yarn foi escolhido por conta do avançado sistema de cache, entretanto, pode ser utilizado com o npm padrão. ``` bash yarn ``` Após a instação das dependências, deve-se executar o comando para subir a infraestrutura da API (MariaDB, se for o caso. É possível manter o ambiente de desenvolvimento com o SQLite). No diretório raiz do projeto (Para o MariaDB) ```bash sudo docker-composer up ``` Quando a infraestrutura já estiver operacional, execute as migrations. ``` bash yarn sequelize db:migrate ``` Após a execução das migrations, popule o banco com as informações iniciais necessárias. ``` bash yarn sequelize db:seed:all ``` Para rodar o servidor em ambiente de produção ``` bash yarn start ``` Executar o comando para rodar o servidor em ambiente de desenvolvimento. ``` bash yarn dev ``` Executar o comando para depurar a aplicação em ambiente de desenvolvimento. ``` bash yarn debug ``` Executar o comando para rodar os testes de unidade e integração. ``` bash yarn test ``` ## Uso .luiz-ricardo-1/ ├─ .circleci ├─ \_\_tests\_\_ ├─ data ├─ docker ├─ src ├─── app ├─── config ├─── database ├─── errors ├─── helpers ├─── routes └─── services A seguinte estrutura é descrita: * **.circleci/** -> diretório onde ficam os arquivos .yml para configuração do CI/CD. * **\_\_tests\_\_/** -> diretório onde ficam os testes unitários e de integrações. * **data/** -> diretório que contém arquivos temporários dos bancos de dados MariaDB ou SQLite. * **docker/** -> diretório que contém configurações e scripts para inicializar containers do Docker. * **src/** -> diretório que contém todo o código fonte da aplicação (Podendo ser utilizado pelo Webpack para gerar o `dist`. * **app/** -> diretório que contém a regra de negócio da API, como controllers, models e middlewares. * **config/** -> arquivos em JS que fazem o setup de dependências chaves para o correto funcionamento da aplicação. * **database/** -> migrations, seeders e hooks. * **errors/** -> arquivos em JS que representam exceções da aplicação. * **helpers/** -> arquivos em JS que contém funções auxiliares para várias funcionalidades. * **routes/** -> arquivos em JS para realizar o mapeamento das rotas. * **services/** -> abstrações de integrações com serviços externos como por exemplo: Elastic Search, Firebase, etc. # Configuração Realizar cópias do .env.example. ``` bash cp .env.example .env cp .env.example .env.test ``` ## Variáveis de ambiente | Variável | Descrição | |:----------:|:-------------:| | APP_ENV | Ambiente da aplicação, podendo ser *development*, *testing*, *staging* ou *production*. | | APP_SENTRY_DSN | Callback do Sentry para o envio de exceções/logs. | | DB_USERNAME | Usuário do banco de dados. | | DB_PASSWORD | Senha do banco de dados. | | DB_DATABASE | Nome do banco de dados. | | DB_HOST | Endereço do banco de dados. | | DB_DIALECT | Tipo de banco de dados que será utilizado pelo Sequelize. | | DB_STORAGE_SQLITE | Adaptador para ser utilizado na persistência dos dados no SQLite (Para desenvolvimento e testes automatizados). | | DB_OPERATORS_ALIASES | Permitir o uso de apelidos para operações de busca. **Nota: Com o ambiente da aplicação (APP_ENV) definido como *development*, serviços externos como Sentry serão desabilitados.** ### Variáveis de ambiente sugeridas para ambiente de desenvolvimento ###### .env ```env APP_ENV=development APP_SENTRY_DSN= DB_USERNAME=root DB_PASSWORD= DB_DATABASE=gamersclub DB_HOST=localhost # Dialect Options -> sqlite | mariadb DB_DIALECT=sqlite DB_STORAGE_SQLITE=./data/sqlite/database.sqlite DB_OPERATORS_ALIASES=false ``` ###### .env.test ```env APP_ENV=development APP_SENTRY_DSN= DB_USERNAME=root DB_PASSWORD= DB_DATABASE=gamersclub DB_HOST=localhost # Dialect Options -> sqlite | mariadb DB_DIALECT=sqlite DB_STORAGE_SQLITE=./__tests__/database.sqlite DB_OPERATORS_ALIASES=false ``` Exemplos de requisições para teste. Pode ser utilizado também outras ferramentas como [Postman](https://www.postman.com/). Utilizando o CURL, temos: Para simular o torneio: ##### POST - /v1/tournaments/simulate ```bash= curl -XPOST -H 'Content-type: application/json' 'http://localhost:5000/v1/tournaments/simulate' ``` ##### Tipos de repostas possíveis | Code HTTP | Descrição | |:----------:|:-------------:| | 200 | Simulação de torneio realizada com sucesso. | | 500 | Erro interno no servidor. Contacte o administrador. | ##### Estrutura do corpo da resposta em caso de sucesso ```json= { "groups": [ { "id": 1, "name": "Group N", "group_phase_id": 1, "status": true, "createdAt": "2020-07-16T00:32:51.000Z", "updatedAt": "2020-07-16T00:32:51.000Z" }, ... ], "rounds": [ { "id": 1, "name": "Round #ijwo", "playoffs_phase_id": 1, "status": true, "createdAt": "2020-07-16T00:32:52.000Z", "updatedAt": "2020-07-16T00:32:52.000Z" }, ... ] "rankings": [ { "group_id": 1, "team_id": 1, "winning_amount": 3, "defeats_amount": 5, "balance_rounds_in_favor": 15 }, ... ], "matches": [ { "visiting_team_score": 16, "host_team_score": 15, "status": true, "id": 1, "source_id": 1, "source_type": "group", "visiting_team_id": 2, "host_team_id": 1, "updatedAt": "2020-07-16T02:09:50.655Z", "createdAt": "2020-07-16T02:09:49.514Z" }, ... ], "teams": [ { "id": 1, "name": "Flowerpecker Uppobje ", "status": true, "createdAt": "2020-07-16T00:32:52.000Z", "updatedAt": "2020-07-16T00:32:52.000Z" }, ... ], "champion": { "id": 54, "name": "Rhea Gordon ", "status": true, "createdAt": "2020-07-16T00:32:52.000Z", "updatedAt": "2020-07-16T00:32:52.000Z" } } ``` ##### Estrutura do corpo da resposta em caso de falha ```json= "error": { "message": "Server internal error. Contact the administrator." } ``` Para consultar a situação do servidor (health checker): ##### GET - /health ```bash= curl -XGET -H "Content-type: application/json" 'http://localhost:5000/health' ``` ##### Tipos de repostas possíveis | Code HTTP | Descrição | |:----------:|:-------------:| | 200 | Servidor operacional. | | 5XX | Servidor inoperacional. | ##### Estrutura do corpo da resposta ```json= ```