https://github.com/raphaigor/kanastra-spotify-challenge
Desafio técnico para Front End, utilizando React + Next
https://github.com/raphaigor/kanastra-spotify-challenge
Last synced: 16 days ago
JSON representation
Desafio técnico para Front End, utilizando React + Next
- Host: GitHub
- URL: https://github.com/raphaigor/kanastra-spotify-challenge
- Owner: raphaigor
- Created: 2026-06-02T23:36:16.000Z (23 days ago)
- Default Branch: main
- Last Pushed: 2026-06-03T01:09:22.000Z (23 days ago)
- Last Synced: 2026-06-03T02:07:59.562Z (23 days ago)
- Language: TypeScript
- Size: 238 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Spotify Artist Explorer
## Sobre o projeto
Este projeto foi desenvolvido para um desafio técnico frontend com o objetivo de consumir a Spotify Web API de forma segura e construir uma experiência responsiva para explorar artistas, músicas e álbuns.
A aplicação permite pesquisar artistas, selecionar um resultado, visualizar popularidade, seguidores, principais músicas e navegar pela discografia com paginação manual de 20 álbuns por página.
## Funcionalidades
- Busca de artistas por nome.
- Seleção de artista com destaque visual.
- Exibição de nome, popularidade, seguidores, gêneros e link para o Spotify.
- Listagem das principais músicas do artista.
- Listagem de álbuns com 20 itens por página.
- Paginação manual de álbuns.
- Filtro de álbuns por nome.
- Estados de loading, erro e lista vazia.
- Skeleton loading para artistas, detalhes e álbuns.
- Animações suaves de interação em cards, inputs e seleção de artista.
- Transições entre estados de carregamento e conteúdo.
- Interface responsiva para mobile e desktop.
- Tradução tokenizada em `pt-BR` e `en-US`.
- Persistência do idioma em `localStorage` para manter a preferência em futuras entradas na tela.
- Consumo seguro da API do Spotify via API Routes do Next.js.
- Testes unitários mínimos com Vitest e React Testing Library.
- Testes E2E com Cypress usando mocks da API interna.
## Tecnologias utilizadas
- **Next.js**: usado com App Router para compor UI, rotas server-side e API Routes na mesma aplicação.
- **React**: base da componentização e da composição da interface.
- **TypeScript**: garante tipagem para modelos de domínio, responses da API, hooks e services.
- **Tailwind CSS**: acelera a criação de uma UI responsiva e consistente sem sair do componente.
- **Axios**: centraliza requests HTTP tanto para a API interna quanto para a Spotify Web API.
- **TanStack React Query**: gerencia cache, loading, erro, refetch e evita requests desnecessárias.
- **Context API**: mantém estado global de UI, como idioma e artista selecionado, sem prop drilling.
- **Spotify Web API**: fonte dos dados de artistas, músicas e álbuns.
- **Tradução tokenizada**: dicionários tipados em `pt-BR` e `en-US` para textos de interface.
- **Vitest + React Testing Library**: validam componentes, formatadores e mappers com testes unitários rápidos.
- **Cypress**: valida o fluxo principal da aplicação com testes E2E e mocks da API interna.
## Arquitetura do projeto
```text
cypress/
e2e/ # Testes E2E do fluxo principal
fixtures/ # Mocks usados pelo Cypress
support/ # Configurações e comandos de suporte
src/
app/
api/ # API Routes seguras do Next.js
layout.tsx # Layout global e providers
page.tsx # Orquestra a experiência principal
providers.tsx # React Query Provider e UIProvider
components/
common/ # Componentes reutilizáveis e sem regra de domínio
artists/ # Componentes do domínio de artistas
albums/ # Componentes do domínio de álbuns
layout/ # Composição visual da página
constants/ # Query keys, rotas e paginação
contexts/ # Estado global de UI
hooks/ # Hooks de dados e debounce
i18n/ # Dicionários tokenizados
services/ # Comunicação HTTP interna e externa
types/ # Tipos separados por domínio
utils/ # Formatadores e mappers
```
Essa estrutura separa responsabilidades por domínio e por camada. A página principal não contém regra de request nem marcação extensa; ela apenas renderiza o `SpotifyExplorer`.
Os testes E2E ficam fora de `src` porque validam a aplicação pelo ponto de vista do usuário, usando o app em execução e interceptando as rotas internas do Next.js.
## Padrões de componentização
- **common**: componentes genéricos como `Button`, `Input`, `Skeleton`, `ErrorState`, `EmptyState`, `LanguageSwitcher` e `Stat`.
- **artists**: componentes ligados à busca, listagem, card, detalhes e top tracks de artistas.
- **albums**: componentes ligados à busca, grid, card e paginação de álbuns.
- **layout**: composição da tela principal, como hero/header e grid responsivo.
Componentes usam PascalCase, hooks começam com `use`, services descrevem a operação externa e tipos ficam separados por domínio.
## Fluxo de dados
O fluxo de dados segue a cadeia:
```text
UI -> Hook -> Service/API Route -> Spotify API -> Mapper -> UI
```
Exemplo:
```text
ArtistList -> useArtists -> spotifyApi -> /api/spotify/artists -> spotifyClient -> Spotify Web API -> mapArtist -> ArtistCard
```
Os hooks encapsulam React Query e centralizam query keys. Os services encapsulam HTTP. Os mappers deixam explícito o ponto onde a resposta externa pode ser adaptada para o modelo usado pela UI.
## Segurança no consumo da API
As credenciais do Spotify ficam exclusivamente no servidor, em `.env.local`:
```bash
SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=
```
O browser nunca acessa `SPOTIFY_CLIENT_SECRET`. A UI chama apenas rotas internas do Next.js em `/api/spotify/*`. Essas rotas executam o fluxo Client Credentials no servidor e repassam para a UI somente os dados necessários.
## Gerenciamento de estado
- **React Query**: estado assíncrono, cache, loading, erro e refetch de artistas, detalhes e álbuns.
- **Context API**: estado global de UI, como idioma e artista selecionado.
- **Estado local**: filtros e página atual ficam próximos dos componentes que os usam.
Essa separação evita prop drilling, reduz acoplamento e facilita explicar onde cada estado vive.
Na prática, componentes como `ArtistList`, `ArtistDetails` e `AlbumsSection` não precisam receber vários níveis de props. Dados remotos ficam encapsulados nos hooks com React Query, estado global de UI é lido pelo `UIContext`, e interações pontuais como filtro e página atual ficam locais ao componente.
## Testes unitários
Os testes unitários usam Vitest com React Testing Library porque essa combinação valida comportamento de UI com boa velocidade e baixo custo de manutenção.
Foram cobertos pontos críticos para apresentação técnica:
- `ArtistCard`: renderização de nome, popularidade, seguidores e ação de seleção.
- `AlbumCard`: renderização de nome, imagem, ano e total de faixas.
- Formatadores: duração, imagem fallback e número compacto.
- Mappers: garantia de que a UI recebe um contrato próprio e não depende do payload bruto do Spotify.
Para rodar os testes:
```bash
pnpm test
```
Para rodar cobertura:
```bash
pnpm test:coverage
```
## Testes E2E com Cypress
Os testes E2E usam Cypress e interceptam as chamadas da API interna com `cy.intercept`. Dessa forma, o fluxo principal é validado sem depender da API real do Spotify, de credenciais locais ou da disponibilidade externa do serviço.
O fluxo coberto pelo Cypress inclui carregamento da home, busca por artista, seleção, visualização de detalhes, top músicas, álbuns, filtro de álbum, paginação, troca de idioma e persistência do idioma após reload.
Para abrir o Cypress:
```bash
pnpm cy:open
```
Para rodar em modo headless:
```bash
pnpm cy:run
```
Para subir o servidor local e rodar o E2E em sequência:
```bash
pnpm e2e
```
## Internacionalização
A internacionalização usa dicionários tokenizados em:
- `src/i18n/dictionaries/pt-BR.ts`
- `src/i18n/dictionaries/en-US.ts`
O tipo `TranslationKey` é derivado do dicionário base, reduzindo o risco de usar chaves inexistentes.
A preferência de idioma é salva em `localStorage`, então o usuário mantém a escolha ao recarregar a página ou retornar ao app em uma próxima visita.
## Paginação e filtros
A busca de artistas usa filtro por nome com debounce para evitar chamadas excessivas.
A listagem de álbuns usa paginação manual com 20 itens por página. O filtro por nome do álbum reseta a página para `1`, evitando estados inválidos quando o resultado filtrado tem menos páginas.
## Como rodar o projeto
### Requisitos
```bash
Node.js 24.16.0
pnpm 11.5.1
```
Crie `.env.local` a partir de `.env.example`:
```bash
SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=
```
Instale as dependências:
```bash
pnpm install
```
Rode em desenvolvimento:
```bash
pnpm dev
```
Acesse:
```text
http://localhost:3000
```
## Scripts disponíveis
- `pnpm dev`: inicia o servidor de desenvolvimento.
- `pnpm build`: gera a build de produção.
- `pnpm start`: executa a build de produção.
- `pnpm lint`: roda o ESLint.
- `pnpm test`: roda os testes unitários em modo watch.
- `pnpm test:coverage`: roda os testes e gera relatório de cobertura.
- `pnpm cy:open`: abre a interface do Cypress.
- `pnpm cy:run`: executa os testes E2E em modo headless.
- `pnpm e2e`: sobe o app local e executa os testes E2E com mocks.
## Decisões técnicas
- **API Routes para proteger credenciais**: o token do Spotify é obtido no backend do Next.js.
- **Separação por domínio**: artistas e álbuns têm componentes próprios, facilitando manutenção e testes.
- **React Query para dados remotos**: evita duplicação de estado assíncrono e entrega cache por chave.
- **Query keys centralizadas**: reduz inconsistências e facilita invalidar/refatorar queries.
- **Mappers explícitos**: deixam claro onde a resposta da API externa pode ser convertida para modelos internos.
- **Context API enxuto**: usado apenas para estado global de UI, não para cache de dados remotos.
- **Persistência de preferência de UI**: o idioma selecionado é salvo em `localStorage` para melhorar a continuidade da experiência sem envolver estado assíncrono ou backend.
- **Debounce nos filtros**: melhora UX e reduz chamadas desnecessárias.
- **Skeleton loading contextual**: usa placeholders com a mesma estrutura visual da tela final, evitando loaders genéricos em áreas previsíveis.
- **Animações sem biblioteca externa**: transições sutis com Tailwind CSS e CSS nativo, respeitando `prefers-reduced-motion`.
- **Testes focados em contrato e comportamento**: cobrem componentes de domínio, utilitários e mappers sem amarrar os testes a detalhes frágeis de implementação.
- **E2E com mocks da API interna**: Cypress valida o fluxo crítico usando fixtures e `cy.intercept`, evitando dependência da Spotify Web API nos testes automatizados.