- Membro 1: Pedro Henrique Moreira Guimarães Cortez - Fullstack
- Membro 2: Caio Henrique de Miranda Onofre - Fullstack
- Membro 3: Caio César Moraes Costa - Fullstack
- Membro 4: Lucas de Oliveira Ferreira - Fullstack
O WastedHours é uma plataforma web voltada para a curadoria, catalogação e avaliação de jogos eletrônicos. Embora adote o tempo de jogo como tema, o objetivo central do sistema é fornecer um ecossistema completo de avaliações guiado por múltiplas métricas de engajamento e satisfação. Usuários podem registrar seu progresso, catalogar títulos, atribuir notas, escrever análises e visualizar rankings baseados na recepção geral da comunidade. A plataforma busca resolver o problema de encontrar recomendações legítimas através de avaliações reais e multifacetadas.
- Linguagem: Python
- Framework Backend: Flask
- Banco de Dados: SQLite (local development)
- Linguagem Frontend: JavaScript / React
- Frontend Build: Vite
- Agentes de IA: Copilot (Gemini/GPT), Claude Code (Haiku/Sonnet), Gemini CLI
- Abra um terminal em
backend - Use um ambiente virtual Python (recomendado)
python -m venv venv
venv\Scripts\Activate # Windows source venv/bin/activate # Linux/Mac
- Instale as dependências:
pip install -r requirements.txt
- Execute o backend:
python app.py
- A API estará disponível em
http://127.0.0.1:5000(sujeito a alteração, confira a saída do terminal)
- Abra um terminal em
frontend - Instale dependências npm:
npm install
- Execute o frontend:
npm run dev
- O site será servido por padrão em
http://localhost:5173(sujeito a alteração, confira a saída do terminal)
Observação: o backend usa um banco de dados SQLite local (
backend/games.db) para acesso aos dados.
O projeto possui testes de unidade/integração no backend (pytest) e testes end-to-end (Playwright).
A partir da pasta backend, com as dependências instaladas:
pytestRoda a suíte e gera o relatório de cobertura no terminal e em backend/htmlcov/index.html.
Cobertura atual: 97% (mínimo exigido: 80%). Os scripts de manutenção em scripts/ (que
acessam a API externa RAWG) são excluídos da medição de cobertura.
A partir da pasta frontend. Na primeira vez, instale o navegador usado nos testes:
npm install
npx playwright install chromiumPara rodar os 4 testes E2E:
npm run e2eO Playwright sobe automaticamente o backend (porta 5000) e o frontend (porta 5173) — ou reusa
caso já estejam rodando. Relatório visual: npm run e2e:report. Modo interativo: npm run e2e:ui.
Fluxos cobertos pelos E2E: registro + login, navegação no catálogo até os detalhes de um jogo, adicionar um jogo à wishlist e avaliar um jogo.
backend/
├── app.py # App factory: configura Flask, registra blueprints
├── models.py # Modelos SQLAlchemy (Game, User, Wishlist, Library, Review, ...)
├── routes/ # Blueprints por domínio — cada arquivo = um grupo de endpoints
│ ├── games.py # GET/POST/PUT/DELETE /api/games, /api/genres, /api/status
│ ├── auth.py # /api/auth/register, /api/auth/login, /api/auth/me
│ ├── wishlist.py # /api/wishlist
│ ├── library.py # /api/library
│ └── reviews.py # /api/reviews, /api/reviews/<id>/user-review
├── utils/ # Funções auxiliares reutilizadas entre rotas
│ ├── auth.py # generate_token, get_authenticated_user, login_required
│ └── helpers.py # wasted_score, parse_date, apply_game_data, ...
└── scripts/ # Scripts avulsos de manutenção
├── populate_db.py # Busca jogos da RAWG API e popula o banco
├── migrate_and_update.py # Altera schema e atualiza detalhes dos jogos
├── migrate_reviews.py # Migração: cria tabela de reviews
└── migrate_wishlist.py # Migração: cria tabelas de usuário e wishlist
Os scripts de manutenção são executados como módulos a partir de dentro de backend/:
python -m scripts.populate_db
python -m scripts.migrate_and_updatefrontend/
├── index.html # Arquivo base do site que o React se insere
├── public/ # Contêm os ícones SVG gerais do site
├── src/ # Código fonte em React
| ├── App.css # Define o estilo base da aplicação
| ├── App.jsx # Define o layout & pontos de acesso das páginas
| ├── assets/ # Não utilizado
| ├── components/ # Componentes reutilizáveis entre as páginas
| | ├── GameCard.jsx # Cartão de um jogo
| | └── NavBar.jsx # Barra de navegação do site
| ├── index.css # Importa os estilos tailwind para o site
| ├── lib/ # Lógica compartilhada entre componentes
| | ├── api.js # Comunicação com o backend
| | ├── auth.jsx # Autenticação do usuário
| | ├── catalogFilters.js # Filtragens customizadas que definimos
| | └── utils.js # Utilidades gerais
| ├── main.jsx # Ponto de entrada para o React
| └── pages/ # Definiões individuais por página
| ├── GameDetails.jsx # Detalhes do jogo
| ├── GamesCatalog.jsx # Catálogo
| ├── Home.jsx # Página inicial
| ├── Library.jsx # Biblioteca do usuário
| ├── Login.jsx # Login no sistema
| ├── Profile.jsx # Perfil do usuário
| ├── Register.jsx # Registro de usuário
| ├── SearchResults.jsx # Resultados da pesquisa
| └── Wishlist.jsx # Lista de desejos
└── tailwind.config.js # Tema de cor do site
- Como jogador, quero criar uma conta para manter um histórico pessoal dos jogos que possuo.
- Como usuário, quero buscar jogos pelo título para verificar as avaliações e diversas métricas de engajamento da comunidade.
- Como jogador, quero registrar as minhas métricas (quantidade de horas jogadas, minha avaliação (nota)) em um título específico para atualizar meu perfil.
- Como colecionador, quero adicionar jogos a uma "Lista de Desejos" para planejar futuras aquisições.
- Como usuário, quero visualizar rankings globais de jogos baseados nas melhores avaliações e métricas de popularidade para descobrir novos títulos.
- Como crítico, quero escrever análises detalhadas sobre minha experiência com um jogo para compartilhar minha opinião.
- Como usuário, quero filtrar jogos por gênero para encontrar novos títulos dentro do meu interesse.
- Como usuário, quero buscar jogos mais curtos para seções rápidas.
erDiagram
GAME {
int id PK
string slug
string name
date released
boolean tba
string background_image
float rating
int rating_top
int metacritic
int playtime
datetime updated
json ratings_distribution
json added_by_status
string esrb_rating
text description
text description_raw
json developers
json publishers
}
PLATFORM {
int id PK
string name
string slug
}
GENRE {
int id PK
string name
string slug
}
TAG {
int id PK
string name
string slug
string language
}
SCREENSHOT {
int id PK
int game_id FK
string image_url
}
USER {
int id PK
string username
string email
string password_hash
datetime created_at
}
WISHLIST {
int id PK
int user_id FK
int game_id FK
datetime added_at
}
LIBRARY {
int id PK
int user_id FK
int game_id FK
datetime added_at
}
REVIEW {
int id PK
int user_id FK
int game_id FK
float rating
int playtime_hours
text review_text
datetime created_at
datetime updated_at
}
%% Many-to-many relationships
GAME ||--o{ PLATFORM : "game_platforms"
GAME ||--o{ GENRE : "game_genres"
GAME ||--o{ TAG : "game_tags"
%% One-to-many relationships
GAME ||--o{ SCREENSHOT : "has"
GAME ||--o{ WISHLIST : "in"
GAME ||--o{ LIBRARY : "in"
GAME ||--o{ REVIEW : "has"
USER ||--o{ WISHLIST : "adds"
USER ||--o{ LIBRARY : "owns"
USER ||--o{ REVIEW : "writes"
flowchart TD
subgraph App["App Layout"]
direction TB
Home["Home (/)", 🏠]:::indigo
GamesCatalog["Games Catalog (/games)"]:::violet
GameDetails["Game Details (/game/:id)"]:::cyan
SearchResults["Search Results (/search)"]:::orange
Wishlist["Wishlist (/wishlist)"]:::fuchsia
Library["Library (/library)"]:::teal
Profile["Profile (/profile)"]:::green
Login["Login (/login)"]:::rose
Register["Register (/register)"]:::yellow
end
%% Navigation flows
Home -->|Clicks on game| GameDetails
Home -->|Browse by genre| SearchResults
Home -->|Use catalog links| GamesCatalog
GamesCatalog --> GameDetails
GamesCatalog --> SearchResults
SearchResults --> GameDetails
GameDetails --> Wishlist
GameDetails --> Library
GameDetails --> Login
Wishlist --> GameDetails
Library --> GameDetails
Login --> Profile
Register --> Profile
Profile --> Home
classDef indigo stroke:#818cf8,fill:#eef2ff
classDef violet stroke:#a78bfa,fill:#f5f3ff
classDef cyan stroke:#22d3ee,fill:#ecfeff
classDef orange stroke:#fb923c,fill:#fff7ed
classDef fuchsia stroke:#e879f9,fill:#fdf4ff
classDef teal stroke:#2dd4bf,fill:#f0fdfa
classDef green stroke:#4ade80,fill:#f0fdf4
classDef yellow stroke:#facc15,fill:#fefce8
classDef rose stroke:#fb7185,fill:#fff1f2