Skip to content

O TFC é um site informativo sobre partidas e classificações de futebol!

Notifications You must be signed in to change notification settings

MarcleyRosa/TFC

Repository files navigation

Boas vindas ao repositório do TFC!

O TFC é um site informativo sobre partidas e classificações de futebol! ⚽️

Nesse projeto, existe um back-end usando TypeScript, Node.js, docker e também utilizando modelagem de dados através do Sequelize.respeitando as regras de negócio, e com a API sendo consumida por um front-end do projeto.

Para adicionar uma partida é necessário ter um token, portanto a pessoa deverá estar logada para fazer as alterações. O back-end implementa regras de negócio para popular adequadamente a tabela disponível no front-end que será exibida para o usuário do sistema.

front-example

Estrutura do projeto

O projeto é composto de 4 entidades importantes para sua estrutura:

1️⃣ Banco de dados:

  • Será um container docker MySQL já configurado no docker-compose através de um serviço definido como db.
  • Tem o papel de fornecer dados para o serviço de backend.
  • Você também pode conectar a um Cliente MySQL (Workbench, Beekeeper, DBeaver e etc), colocando as credenciais configuradas no docker-compose no serviço db.

2️⃣ Back-end:

  • Deve rodar na porta 3001, pois o front-end faz requisições para ele nessa porta por padrão;
  • A aplicação deve ser inicializada a partir do arquivo app/backend/src/server.ts;

3️⃣ Front-end:

  • O front se comunica com serviço de back-end pela url http://localhost:3001 através dos endpoints.

4️⃣ Docker:

  • O docker-compose tem a responsabilidade de unir todos os serviços conteinerizados (backend, frontend e db) e subir o projeto completo com o comando npm run compose:up ou npm run compose:up:dev;

Orientações

Iniciando o projeto
  1. Clone o repositório git clone git@github.com:MarcleyRosa/TFC.git
  • Entre na pasta do repositório que você acabou de clonar:

    • cd TFC
    1. Instale as dependências *npm install
Configurações mínimas para execução do projeto

Na sua máquina você deve ter:

  • Sistema Operacional Distribuição Unix
  • Node versão 16
  • Docker
  • Docker-compose versão >=1.29.2

➡️ O node deve ter versão igual ou superior à 16.14.0 LTS:

  • Para instalar o nvm, acesse esse link;
  • Rode os comandos abaixo para instalar a versão correta de node e usá-la:
    • nvm install 16.14 --lts
    • nvm use 16.14
    • nvm alias default 16.14

➡️ Odocker-compose deve ter versão igual ou superior àˆ1.29.2:

Configuração Docker

Docker e Docker-compose 🐳

⚠ O docker-compose precisa estar na versão 1.29 ou superior. ⚠ Veja aqui a documentação para atualizar o docker-compose.

⚠️ Atenção:

  • O arquivo docker-compose.yml também pode ser utilizado para executar a aplicação na sua máquina local, para isso é necessário executar o comando npm run compose:up na raiz do projeto.

  • Obs.: Se você quiser fazer o build da aplicação usando o docker-compose.dev.yml, você pode usar o comando: npm run compose:up:dev -- --build.

Inicialização do compose e verificação dos logs das aplicações
  • Considerando o uso do parâmetro healthcheck em cada container do seu docker-compose.yml, a inicialização dos containers deve aguardar o comando de status de saúde (o que valida se aquele container está operacional ou não):
    • No container db, representado por um comando ping no banco de dados;
    • No back-end, representado por um comando lsof, que vai procurar aplicações ativas na porta definida (por padrão, no caso 3001);
    • No front-end, representado por um comando lsof, que vai procurar aplicações ativas na porta definida (por padrão, no caso 3000).

Criação dos containers concluída com sucesso!

sempre considerando as premissas anteriores.

  • Nesse caso, a partir da pasta ./app (onde está seu docker-compose), é possível rodar o comando docker-compose logs (Para ver todos os status) ou docker-compose logs <nome-do-seu-serviço> (Para mostrar somente o de um escopo específico).
    • No nosso contexto, rodando o comando docker-compose logs backend:

docker-compose logs backend

Variáveis de ambiente

No diretório app/backend/ renomeie o arquivo .env.example para .env e configure os valores de acordo com o cenário do seu ambiente (credenciais de banco de dados, secrets desejadas e etc). Isso vai permitir que você inicialize a aplicação fora do container e ela se conecte com seu banco local caso deseje.

./app/backend/.env.example

JWT_SECRET=jwt_secret
APP_PORT=3001
DB_USER=seu_user
DB_PASS=sua_senha
DB_HOST=localhost
DB_PORT=3306
Sequelize

⚠️ O package.json do diretório app/backend contém um script db:reset que é responsável por "dropar" o banco, recriar e executar as migrations e seeders. Você pode executá-lo com o commando npm run db:reset se por algum motivo precisar recriar a base de dados;

Testes de cobertura

Para rodar testes de cobertura no seu back-end, utilize o comando: npm run test:coverage.

⚠️ Para que o comando acima funcione localmente (fora do container) você deverá configurar na raiz do back-end o seu arquivo .env.


Database

  • Comece rodando o comando npm run build na pasta do back-end para fazer o build da aplicação;

Users e Login

Introdução
  • A rota utilizada deve ser (/login);

  • A rota deve receber os campos email e password e esses campos devem ser validados no banco de dados:

    • O campo email deve receber um email válido;
    • O Campo password deve ter mais de 6 caracteres.
  • O body da requisição deve conter o seguinte formato:

    {
      "email": "string",
      "password": "string"
    }

Times

Introdução
  • O consumo da rota /teams retorna os nomes dos times associados à partida na renderização do front-end
Exemplos de Retorno

O endpoint /teams retorna todos os times.

[
  {
    "id": 1,
    "teamName": "Avaí/Kindermann"
  },
  {
    "id": 2,
    "teamName": "Bahia"
  },
  {
    "id": 3,
    "teamName": "Botafogo"
  },
  ...
]

O endpoint /teams/:id retorna os dados de um time específico

{
  "id": 5,
  "teamName": "Cruzeiro"
}

Partidas

Introdução
  • Será validado que, ao escolher a opção de partidas em andamento, serão filtradas todas as partidas em andamento;

  • Essa requisição deverá usar query string para definir o parâmetro: ex: matches?inProgress=true

Exemplos de Retorno

Exemplo de retorno da requisição:

[
  {
    "id": 41,
    "homeTeamId": 16,
    "homeTeamGoals": 2,
    "awayTeamId": 9,
    "awayTeamGoals": 0,
    "inProgress": true,
    "homeTeam": {
      "teamName": "São Paulo"
    },
    "awayTeam": {
      "teamName": "Internacional"
    }
  },
  {
    "id": 42,
    "homeTeamId": 6,
    "homeTeamGoals": 1,
    "awayTeamId": 1,
    "awayTeamGoals": 0,
    "inProgress": true,
    "homeTeam": {
      "teamName": "Ferroviária"
    },
    "awayTeam": {
      "teamName": "Avaí/Kindermann"
    }
  }
]
  • Essa requisição deverá usar query string para definir o parâmetro. ex: matches?inProgress=false

Exemplo de retorno da requisição:

[
  {
    "id": 1,
    "homeTeamId": 16,
    "homeTeamGoals": 1,
    "awayTeamId": 8,
    "awayTeamGoals": 1,
    "inProgress": false,
    "homeTeam": {
      "teamName": "São Paulo"
    },
    "awayTeam": {
      "teamName": "Grêmio"
    }
  },
  {
    "id": 2,
    "homeTeamId": 9,
    "homeTeamGoals": 1,
    "awayTeamId": 14,
    "awayTeamGoals": 1,
    "inProgress": false,
    "homeTeam": {
      "teamName": "Internacional"
    },
    "awayTeam": {
      "teamName": "Santos"
    }
  }
]
  • A partida só pode ser criada com token JWT validado;

  • O corpo da requisição terá o seguinte formato:

{
  "homeTeamId": 16, // O valor deve ser o id do time
  "awayTeamId": 8, // O valor deve ser o id do time
  "homeTeamGoals": 2,
  "awayTeamGoals": 2,
}
  • Retorno caso a partida seja inserida com sucesso:
{
  "id": 1,
  "homeTeamId": 16,
  "homeTeamGoals": 2,
  "awayTeamId": 8,
  "awayTeamGoals": 2,
  "inProgress": true,
}
  • Será recebido o id pelo parâmetro da URL;

  • O corpo da requisição terá o seguinte formato:

{
  "homeTeamGoals": 3,
  "awayTeamGoals": 1
}

Leaderboards (placares)

Introdução

▶️ Regras de negócios para a classificação dos times:

- `Classificação`: Posição na classificação;
- `Time`: Nome do time;
- `P`: Total de Pontos;
- `J`: Total de Jogos;
- `V`: Total de Vitórias;
- `E`: Total de Empates;
- `D`: Total de Derrotas;
- `GP`: Gols marcados a favor;
- `GC`: Gols sofridos;
- `SG`: Saldo total de gols;
- `%`: Aproveitamento do time.

Ordem para desempate

1º Total de Vitórias;

2º Saldo de gols;

3º Gols a favor;

4º Gols sofridos.

- Os endpoints dessa seção, irão alimentar uma tabela idêntica ao exemplo abaixo no front-end:

| Classificação | Time        | P   | J   | V   | E   | D   | GP  | GC  | SG  | %    |
| ------------- | ----------- | --- | --- | --- | --- | --- | --- | --- | --- | ---- |
| 1             | Ferroviária | 38  | 15  | 12  | 2   | 1   | 44  | 13  | 31  | 84.4 |
Retorno Esperado
[
  {
    "name": "Palmeiras",
    "totalPoints": 13,
    "totalGames": 5,
    "totalVictories": 4,
    "totalDraws": 1,
    "totalLosses": 0,
    "goalsFavor": 17,
    "goalsOwn": 5,
    "goalsBalance": 12,
    "efficiency": 86.67
  },
  {
    "name": "Corinthians",
    "totalPoints": 12,
    "totalGames": 5,
    "totalVictories": 4,
    "totalDraws": 0,
    "totalLosses": 1,
    "goalsFavor": 12,
    "goalsOwn": 3,
    "goalsBalance": 9,
    "efficiency": 80
  },
  {
    "name": "Santos",
    "totalPoints": 11,
    "totalGames": 5,
    "totalVictories": 3,
    "totalDraws": 2,
    "totalLosses": 0,
    "goalsFavor": 12,
    "goalsOwn": 6,
    "goalsBalance": 6,
    "efficiency": 73.33
  },
  ...
]