Prod
This commit is contained in:
@@ -52,3 +52,8 @@ VITE_PUSHER_HOST="${PUSHER_HOST}"
|
||||
VITE_PUSHER_PORT="${PUSHER_PORT}"
|
||||
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
|
||||
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
JWT_ISSUER=
|
||||
JWT_AUDIENCE=
|
||||
JWT_PUBLIC_KEY_PEM=
|
||||
JWT_TOKEN=
|
||||
|
||||
379
README.md
379
README.md
@@ -1,49 +1,362 @@
|
||||
# 🎮 Game Ranking API - Microserviço
|
||||
# 🎮 Microsserviço de Rankings de Jogos (Game Ranking API)
|
||||
|
||||
Este é um microserviço desenvolvido em **Laravel 11** para gerenciamento e exposição de rankings de jogos. A API fornece dados sobre os jogos mais jogados, rankings gerais por período e rankings específicos por plataforma.
|
||||

|
||||

|
||||

|
||||
|
||||
## 🚀 Funcionalidades
|
||||
- **Ranking Geral:** Consulta de top 10 (semanal, mensal e anual).
|
||||
- **Mais Jogados:** Listagem baseada no volume de jogadores ativos.
|
||||
- **Filtro por Plataforma:** Rankings específicos para Steam, PlayStation, Xbox e Nintendo.
|
||||
- **Documentação Automática:** Interface interativa via Scribe.
|
||||
---
|
||||
|
||||
## 🛠️ Pré-requisitos
|
||||
- PHP >= 8.2
|
||||
- Composer
|
||||
- Extensão SQLite habilitada no PHP
|
||||
# 📌 Sobre o Projeto
|
||||
|
||||
## 📥 Instalação e Configuração
|
||||
Este microsserviço faz parte do ecossistema **GameVerse**.
|
||||
Ele é responsável por processar, armazenar e disponibilizar estatísticas de engajamento, permitindo que a plataforma exiba rankings dinâmicos e tendências globais.
|
||||
|
||||
1. **Instalar dependências:**
|
||||
```bash
|
||||
composer install
|
||||
Configurar Ambiente:
|
||||
Certifique-se de que o arquivo .env existe e está configurado para SQLite:
|
||||
---
|
||||
|
||||
Snippet de código
|
||||
# 👥 Integrantes
|
||||
|
||||
* Kaiky Andrade de Oliveira
|
||||
* Gabriel Henrique Lina Batista Pereira Nunes
|
||||
|
||||
---
|
||||
|
||||
# 📝 Descrição do Serviço
|
||||
|
||||
O serviço centraliza métricas de performance dos jogos, como:
|
||||
|
||||
* pontuação
|
||||
* tempo de jogo
|
||||
* quantidade de jogadores ativos
|
||||
* evolução de desempenho
|
||||
|
||||
Ele resolve o problema de sobrecarga do sistema principal ao isolar o processamento de grandes volumes de dados estatísticos em um microsserviço dedicado, garantindo que as tabelas de classificação sejam atualizadas e entregues rapidamente aos usuários finais.
|
||||
|
||||
---
|
||||
|
||||
# 🎯 Responsabilidades do Microsserviço
|
||||
|
||||
O serviço possui as seguintes responsabilidades:
|
||||
|
||||
* Fornecer rankings de desempenho semanal, mensal e anual
|
||||
* Listar os jogos mais populares
|
||||
* Exibir histórico de evolução de pontuação
|
||||
* Segmentar rankings por plataforma
|
||||
* Disponibilizar dados estatísticos para outros microsserviços
|
||||
|
||||
---
|
||||
|
||||
# 🛠️ Tecnologias Utilizadas
|
||||
|
||||
* PHP 8.2
|
||||
* Laravel 11
|
||||
* SQLite
|
||||
* Composer
|
||||
* Laravel Scribe (Documentação OpenAPI)
|
||||
|
||||
---
|
||||
|
||||
# ✅ Requisitos Necessários
|
||||
|
||||
Antes de executar o projeto, é necessário possuir instalado:
|
||||
|
||||
* PHP >= 8.2
|
||||
* Composer
|
||||
* Git
|
||||
* SQLite
|
||||
|
||||
---
|
||||
|
||||
# ⚙️ Variáveis de Ambiente
|
||||
|
||||
O projeto utiliza variáveis configuradas no arquivo `.env`.
|
||||
|
||||
Exemplo:
|
||||
|
||||
| Variável | Descrição |
|
||||
| ------------- | ------------------------ |
|
||||
| APP_NAME | Nome da aplicação |
|
||||
| APP_ENV | Ambiente da aplicação |
|
||||
| APP_KEY | Chave do Laravel |
|
||||
| APP_DEBUG | Modo de depuração |
|
||||
| DB_CONNECTION | Banco de dados utilizado |
|
||||
|
||||
---
|
||||
|
||||
# 📥 Instalação do Projeto
|
||||
|
||||
## 1. Clone o repositório
|
||||
|
||||
```bash
|
||||
git clone https://github.com/gabriellina640/api-ranking-jogos.git
|
||||
```
|
||||
|
||||
## 2. Acesse a pasta do projeto
|
||||
|
||||
```bash
|
||||
cd api-ranking-jogos
|
||||
```
|
||||
|
||||
## 3. Instale as dependências
|
||||
|
||||
```bash
|
||||
composer install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# ⚙️ Configuração do .env
|
||||
|
||||
Crie uma cópia do arquivo de ambiente:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Configure o banco SQLite no arquivo `.env`:
|
||||
|
||||
```env
|
||||
DB_CONNECTION=sqlite
|
||||
Preparar o Banco de Dados:
|
||||
Crie o arquivo do banco e popule com dados fictícios:
|
||||
```
|
||||
|
||||
Bash
|
||||
php artisan migrate --seed
|
||||
Gerar a Documentação:
|
||||
---
|
||||
|
||||
Bash
|
||||
# 🗄️ Preparação do Banco de Dados
|
||||
|
||||
Execute as migrations e seeders:
|
||||
|
||||
```bash
|
||||
php artisan migrate:fresh --seed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 📚 Gerar Documentação da API
|
||||
|
||||
Execute o comando:
|
||||
|
||||
```bash
|
||||
php artisan scribe:generate
|
||||
🖥️ Como Usar
|
||||
Para subir o servidor local:
|
||||
```
|
||||
|
||||
Bash
|
||||
---
|
||||
|
||||
# 🚀 Executando o Projeto
|
||||
|
||||
Inicie o servidor Laravel:
|
||||
|
||||
```bash
|
||||
php artisan serve
|
||||
API: http://localhost:8000/api/v1/...
|
||||
```
|
||||
|
||||
Documentação Interativa: http://localhost:8000/docs
|
||||
A aplicação ficará disponível em:
|
||||
|
||||
🛠️ Tecnologias
|
||||
Framework: Laravel 11
|
||||
```bash
|
||||
http://localhost:8000
|
||||
```
|
||||
|
||||
Banco de Dados: SQLite
|
||||
---
|
||||
|
||||
Documentação: Scribe (OpenAPI/Swagger)
|
||||
# 📖 Documentação Interativa da API
|
||||
|
||||
Após iniciar o projeto, acesse:
|
||||
|
||||
```bash
|
||||
http://localhost:8000/docs
|
||||
```
|
||||
|
||||
A documentação gerada pelo Scribe permite:
|
||||
|
||||
* visualizar endpoints
|
||||
* testar requisições
|
||||
* consultar parâmetros
|
||||
* visualizar respostas JSON
|
||||
|
||||
---
|
||||
|
||||
# 🧪 Como Testar o Projeto
|
||||
|
||||
Você pode testar a API utilizando:
|
||||
|
||||
* Scribe
|
||||
* Postman
|
||||
* Insomnia
|
||||
* Thunder Client
|
||||
|
||||
Exemplo:
|
||||
|
||||
```http
|
||||
GET http://localhost:8000/api/v1/rankings/weekly
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 📑 Rotas da API
|
||||
|
||||
| Método | Endpoint | Descrição |
|
||||
| ------ | ------------------------------------- | ---------------------------------------- |
|
||||
| GET | /api/v1/rankings/weekly | Lista o Top 10 jogos da última semana |
|
||||
| GET | /api/v1/rankings/monthly | Lista o Top 10 jogos do último mês |
|
||||
| GET | /api/v1/rankings/yearly | Lista o Top 10 jogos do último ano |
|
||||
| GET | /api/v1/rankings/history/{id} | Busca a evolução de pontuação de um jogo |
|
||||
| GET | /api/v1/games/most-played | Lista os jogos mais jogados |
|
||||
| GET | /api/v1/rankings/platforms/{platform} | Lista rankings por plataforma |
|
||||
|
||||
---
|
||||
|
||||
# 📥 Exemplo de Requisição
|
||||
|
||||
## Buscar ranking semanal
|
||||
|
||||
```http
|
||||
GET /api/v1/rankings/weekly HTTP/1.1
|
||||
Host: localhost:8000
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 📤 Exemplo de Resposta JSON
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Elden Ring",
|
||||
"platform": "Steam",
|
||||
"active_players": 1500000,
|
||||
"weekly_points": 850,
|
||||
"monthly_points": 7000,
|
||||
"yearly_points": 85000,
|
||||
"created_at": "2026-05-04T22:00:00.000000Z",
|
||||
"updated_at": "2026-05-04T22:00:00.000000Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 🔗 Integrações com Outros Microsserviços
|
||||
|
||||
## Quais dados recebe
|
||||
|
||||
O microsserviço recebe:
|
||||
|
||||
* IDs de jogos
|
||||
* parâmetros de filtro
|
||||
* plataformas
|
||||
* períodos de ranking
|
||||
|
||||
---
|
||||
|
||||
## Quais dados retorna
|
||||
|
||||
O serviço retorna:
|
||||
|
||||
* rankings
|
||||
* estatísticas
|
||||
* histórico de pontuação
|
||||
* quantidade de jogadores ativos
|
||||
|
||||
Todos os dados são retornados em formato JSON.
|
||||
|
||||
---
|
||||
|
||||
## Quais serviços consome
|
||||
|
||||
O microsserviço consome:
|
||||
|
||||
* Microsserviço de Telemetria
|
||||
* Microsserviço de Catálogo de Jogos
|
||||
|
||||
---
|
||||
|
||||
## Quais serviços utilizam esta API
|
||||
|
||||
Os serviços que utilizam esta API são:
|
||||
|
||||
* Front-end GameVerse
|
||||
* Microsserviço de Loja
|
||||
* Sistema de Recomendações
|
||||
|
||||
---
|
||||
|
||||
# 🔄 Fluxo Principal do Serviço
|
||||
|
||||
1. O usuário acessa a plataforma GameVerse
|
||||
2. O Front-end solicita os rankings
|
||||
3. O microsserviço consulta o banco SQLite
|
||||
4. Os dados são processados e ordenados
|
||||
5. O JSON é retornado ao Front-end
|
||||
6. Os rankings são exibidos ao usuário
|
||||
|
||||
---
|
||||
|
||||
# ⚠️ Possíveis Erros e Retornos Esperados
|
||||
|
||||
| Código | Erro | Descrição |
|
||||
| ------ | ---------------------- | ------------------------- |
|
||||
| 400 | Dados inválidos | Parâmetros incorretos |
|
||||
| 404 | Jogo inexistente | Jogo não encontrado |
|
||||
| 404 | Plataforma inexistente | Plataforma não encontrada |
|
||||
| 500 | Erro interno | Falha no servidor |
|
||||
| 503 | Serviço indisponível | Banco indisponível |
|
||||
|
||||
---
|
||||
|
||||
# 📤 Exemplo de Erro JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "Jogo não encontrado"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 📁 Estrutura do Projeto
|
||||
|
||||
```bash
|
||||
app/
|
||||
bootstrap/
|
||||
config/
|
||||
database/
|
||||
public/
|
||||
resources/
|
||||
routes/
|
||||
storage/
|
||||
tests/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 📦 Arquivos Obrigatórios da Entrega
|
||||
|
||||
Este repositório contém:
|
||||
|
||||
* README.md
|
||||
* .env.example
|
||||
* Código-fonte completo
|
||||
|
||||
⚠️ A pasta `vendor/` não deve ser enviada para o GitHub.
|
||||
|
||||
---
|
||||
|
||||
# 📌 Participação no Ecossistema GameVerse
|
||||
|
||||
Este microsserviço é responsável por fornecer estatísticas e rankings em tempo real dentro do GameVerse.
|
||||
|
||||
Ele participa diretamente:
|
||||
|
||||
* das vitrines de jogos populares
|
||||
* das recomendações de destaque
|
||||
* dos rankings competitivos
|
||||
* das estatísticas globais da plataforma
|
||||
|
||||
Seu objetivo é garantir alta performance na consulta de dados estatísticos.
|
||||
|
||||
---
|
||||
|
||||
# 📬 Contato
|
||||
|
||||
Projeto acadêmico desenvolvido para a disciplina de Microsserviços — GameVerse.
|
||||
@@ -4,8 +4,6 @@ namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
|
||||
class JwtAuthMiddleware
|
||||
{
|
||||
@@ -24,20 +22,24 @@ class JwtAuthMiddleware
|
||||
|
||||
$token = $matches[1];
|
||||
|
||||
$publicKey = str_replace('\\n', "\n", env('JWT_PUBLIC_KEY_PEM'));
|
||||
[$header, $payload, $signature] = $this->decodeToken($token);
|
||||
|
||||
$decoded = JWT::decode($token, new Key($publicKey, 'RS256'));
|
||||
if (($header['alg'] ?? null) !== 'RS256') {
|
||||
return response()->json(['message' => 'Invalid token algorithm'], 401);
|
||||
}
|
||||
|
||||
if (
|
||||
$decoded->iss !== env('JWT_ISSUER') ||
|
||||
$decoded->aud !== env('JWT_AUDIENCE') ||
|
||||
empty($decoded->sub)
|
||||
!$this->signatureIsValid($token, $signature) ||
|
||||
($payload['iss'] ?? null) !== config('jwt.issuer') ||
|
||||
($payload['aud'] ?? null) !== config('jwt.audience') ||
|
||||
empty($payload['sub']) ||
|
||||
$this->tokenIsExpired($payload)
|
||||
) {
|
||||
return response()->json(['message' => 'Invalid token'], 401);
|
||||
}
|
||||
|
||||
$request->attributes->set('auth', [
|
||||
'id' => $decoded->sub,
|
||||
'id' => $payload['sub'],
|
||||
'token' => $token
|
||||
]);
|
||||
|
||||
@@ -47,4 +49,68 @@ class JwtAuthMiddleware
|
||||
return response()->json(['message' => 'Invalid or expired token'], 401);
|
||||
}
|
||||
}
|
||||
|
||||
private function decodeToken(string $token): array
|
||||
{
|
||||
$parts = explode('.', $token);
|
||||
|
||||
if (count($parts) !== 3) {
|
||||
throw new \InvalidArgumentException('Invalid token structure');
|
||||
}
|
||||
|
||||
return [
|
||||
$this->base64UrlDecodeJson($parts[0]),
|
||||
$this->base64UrlDecodeJson($parts[1]),
|
||||
$this->base64UrlDecode($parts[2]),
|
||||
];
|
||||
}
|
||||
|
||||
private function base64UrlDecodeJson(string $value): array
|
||||
{
|
||||
$decoded = json_decode($this->base64UrlDecode($value), true);
|
||||
|
||||
if (!is_array($decoded)) {
|
||||
throw new \InvalidArgumentException('Invalid token payload');
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
private function base64UrlDecode(string $value): string
|
||||
{
|
||||
$value .= str_repeat('=', (4 - strlen($value) % 4) % 4);
|
||||
$decoded = base64_decode(strtr($value, '-_', '+/'), true);
|
||||
|
||||
if ($decoded === false) {
|
||||
throw new \InvalidArgumentException('Invalid base64url value');
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
private function signatureIsValid(string $token, string $signature): bool
|
||||
{
|
||||
[$header, $payload] = explode('.', $token, 3);
|
||||
$publicKey = str_replace('\\n', "\n", (string) config('jwt.public_key'));
|
||||
|
||||
if ($publicKey === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return openssl_verify(
|
||||
$header . '.' . $payload,
|
||||
$signature,
|
||||
$publicKey,
|
||||
OPENSSL_ALGO_SHA256
|
||||
) === 1;
|
||||
}
|
||||
|
||||
private function tokenIsExpired(array $payload): bool
|
||||
{
|
||||
if (!isset($payload['exp']) || !is_numeric($payload['exp'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return time() >= (int) $payload['exp'];
|
||||
}
|
||||
}
|
||||
7
config/jwt.php
Normal file
7
config/jwt.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'issuer' => env('JWT_ISSUER'),
|
||||
'audience' => env('JWT_AUDIENCE'),
|
||||
'public_key' => env('JWT_PUBLIC_KEY_PEM'),
|
||||
];
|
||||
1388
package-lock.json
generated
Normal file
1388
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user