{"id":50700219,"url":"https://github.com/raphaigor/kanastra-spotify-challenge","last_synced_at":"2026-06-09T09:01:36.679Z","repository":{"id":362169931,"uuid":"1257697490","full_name":"raphaigor/kanastra-spotify-challenge","owner":"raphaigor","description":"Desafio técnico para Front End, utilizando React + Next","archived":false,"fork":false,"pushed_at":"2026-06-03T01:09:22.000Z","size":244,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T02:07:59.562Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/raphaigor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-02T23:36:16.000Z","updated_at":"2026-06-03T01:09:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/raphaigor/kanastra-spotify-challenge","commit_stats":null,"previous_names":["raphaigor/kanastra-spotify-challenge"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/raphaigor/kanastra-spotify-challenge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphaigor%2Fkanastra-spotify-challenge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphaigor%2Fkanastra-spotify-challenge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphaigor%2Fkanastra-spotify-challenge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphaigor%2Fkanastra-spotify-challenge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/raphaigor","download_url":"https://codeload.github.com/raphaigor/kanastra-spotify-challenge/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphaigor%2Fkanastra-spotify-challenge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34098952,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-09T09:01:35.432Z","updated_at":"2026-06-09T09:01:36.674Z","avatar_url":"https://github.com/raphaigor.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spotify Artist Explorer\n\n## Sobre o projeto\n\nEste 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.\n\nA 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.\n\n## Funcionalidades\n\n- Busca de artistas por nome.\n- Seleção de artista com destaque visual.\n- Exibição de nome, popularidade, seguidores, gêneros e link para o Spotify.\n- Listagem das principais músicas do artista.\n- Listagem de álbuns com 20 itens por página.\n- Paginação manual de álbuns.\n- Filtro de álbuns por nome.\n- Estados de loading, erro e lista vazia.\n- Skeleton loading para artistas, detalhes e álbuns.\n- Animações suaves de interação em cards, inputs e seleção de artista.\n- Transições entre estados de carregamento e conteúdo.\n- Interface responsiva para mobile e desktop.\n- Tradução tokenizada em `pt-BR` e `en-US`.\n- Persistência do idioma em `localStorage` para manter a preferência em futuras entradas na tela.\n- Consumo seguro da API do Spotify via API Routes do Next.js.\n- Testes unitários mínimos com Vitest e React Testing Library.\n- Testes E2E com Cypress usando mocks da API interna.\n\n## Tecnologias utilizadas\n\n- **Next.js**: usado com App Router para compor UI, rotas server-side e API Routes na mesma aplicação.\n- **React**: base da componentização e da composição da interface.\n- **TypeScript**: garante tipagem para modelos de domínio, responses da API, hooks e services.\n- **Tailwind CSS**: acelera a criação de uma UI responsiva e consistente sem sair do componente.\n- **Axios**: centraliza requests HTTP tanto para a API interna quanto para a Spotify Web API.\n- **TanStack React Query**: gerencia cache, loading, erro, refetch e evita requests desnecessárias.\n- **Context API**: mantém estado global de UI, como idioma e artista selecionado, sem prop drilling.\n- **Spotify Web API**: fonte dos dados de artistas, músicas e álbuns.\n- **Tradução tokenizada**: dicionários tipados em `pt-BR` e `en-US` para textos de interface.\n- **Vitest + React Testing Library**: validam componentes, formatadores e mappers com testes unitários rápidos.\n- **Cypress**: valida o fluxo principal da aplicação com testes E2E e mocks da API interna.\n\n## Arquitetura do projeto\n\n```text\ncypress/\n  e2e/                  # Testes E2E do fluxo principal\n  fixtures/             # Mocks usados pelo Cypress\n  support/              # Configurações e comandos de suporte\n\nsrc/\n  app/\n    api/                  # API Routes seguras do Next.js\n    layout.tsx            # Layout global e providers\n    page.tsx              # Orquestra a experiência principal\n    providers.tsx         # React Query Provider e UIProvider\n  components/\n    common/               # Componentes reutilizáveis e sem regra de domínio\n    artists/              # Componentes do domínio de artistas\n    albums/               # Componentes do domínio de álbuns\n    layout/               # Composição visual da página\n  constants/              # Query keys, rotas e paginação\n  contexts/               # Estado global de UI\n  hooks/                  # Hooks de dados e debounce\n  i18n/                   # Dicionários tokenizados\n  services/               # Comunicação HTTP interna e externa\n  types/                  # Tipos separados por domínio\n  utils/                  # Formatadores e mappers\n```\n\nEssa 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`.\n\nOs 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.\n\n## Padrões de componentização\n\n- **common**: componentes genéricos como `Button`, `Input`, `Skeleton`, `ErrorState`, `EmptyState`, `LanguageSwitcher` e `Stat`.\n- **artists**: componentes ligados à busca, listagem, card, detalhes e top tracks de artistas.\n- **albums**: componentes ligados à busca, grid, card e paginação de álbuns.\n- **layout**: composição da tela principal, como hero/header e grid responsivo.\n\nComponentes usam PascalCase, hooks começam com `use`, services descrevem a operação externa e tipos ficam separados por domínio.\n\n## Fluxo de dados\n\nO fluxo de dados segue a cadeia:\n\n```text\nUI -\u003e Hook -\u003e Service/API Route -\u003e Spotify API -\u003e Mapper -\u003e UI\n```\n\nExemplo:\n\n```text\nArtistList -\u003e useArtists -\u003e spotifyApi -\u003e /api/spotify/artists -\u003e spotifyClient -\u003e Spotify Web API -\u003e mapArtist -\u003e ArtistCard\n```\n\nOs 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.\n\n## Segurança no consumo da API\n\nAs credenciais do Spotify ficam exclusivamente no servidor, em `.env.local`:\n\n```bash\nSPOTIFY_CLIENT_ID=\nSPOTIFY_CLIENT_SECRET=\n```\n\nO 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.\n\n## Gerenciamento de estado\n\n- **React Query**: estado assíncrono, cache, loading, erro e refetch de artistas, detalhes e álbuns.\n- **Context API**: estado global de UI, como idioma e artista selecionado.\n- **Estado local**: filtros e página atual ficam próximos dos componentes que os usam.\n\nEssa separação evita prop drilling, reduz acoplamento e facilita explicar onde cada estado vive.\n\nNa 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.\n\n## Testes unitários\n\nOs 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.\n\nForam cobertos pontos críticos para apresentação técnica:\n\n- `ArtistCard`: renderização de nome, popularidade, seguidores e ação de seleção.\n- `AlbumCard`: renderização de nome, imagem, ano e total de faixas.\n- Formatadores: duração, imagem fallback e número compacto.\n- Mappers: garantia de que a UI recebe um contrato próprio e não depende do payload bruto do Spotify.\n\nPara rodar os testes:\n\n```bash\npnpm test\n```\n\nPara rodar cobertura:\n\n```bash\npnpm test:coverage\n```\n\n## Testes E2E com Cypress\n\nOs 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.\n\nO 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.\n\nPara abrir o Cypress:\n\n```bash\npnpm cy:open\n```\n\nPara rodar em modo headless:\n\n```bash\npnpm cy:run\n```\n\nPara subir o servidor local e rodar o E2E em sequência:\n\n```bash\npnpm e2e\n```\n\n## Internacionalização\n\nA internacionalização usa dicionários tokenizados em:\n\n- `src/i18n/dictionaries/pt-BR.ts`\n- `src/i18n/dictionaries/en-US.ts`\n\nO tipo `TranslationKey` é derivado do dicionário base, reduzindo o risco de usar chaves inexistentes.\n\nA 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.\n\n## Paginação e filtros\n\nA busca de artistas usa filtro por nome com debounce para evitar chamadas excessivas.\n\nA 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.\n\n## Como rodar o projeto\n\n### Requisitos\n\n```bash\nNode.js 24.16.0\npnpm 11.5.1\n```\n\nCrie `.env.local` a partir de `.env.example`:\n\n```bash\nSPOTIFY_CLIENT_ID=\nSPOTIFY_CLIENT_SECRET=\n```\n\nInstale as dependências:\n\n```bash\npnpm install\n```\n\nRode em desenvolvimento:\n\n```bash\npnpm dev\n```\n\nAcesse:\n\n```text\nhttp://localhost:3000\n```\n\n## Scripts disponíveis\n\n- `pnpm dev`: inicia o servidor de desenvolvimento.\n- `pnpm build`: gera a build de produção.\n- `pnpm start`: executa a build de produção.\n- `pnpm lint`: roda o ESLint.\n- `pnpm test`: roda os testes unitários em modo watch.\n- `pnpm test:coverage`: roda os testes e gera relatório de cobertura.\n- `pnpm cy:open`: abre a interface do Cypress.\n- `pnpm cy:run`: executa os testes E2E em modo headless.\n- `pnpm e2e`: sobe o app local e executa os testes E2E com mocks.\n\n## Decisões técnicas\n\n- **API Routes para proteger credenciais**: o token do Spotify é obtido no backend do Next.js.\n- **Separação por domínio**: artistas e álbuns têm componentes próprios, facilitando manutenção e testes.\n- **React Query para dados remotos**: evita duplicação de estado assíncrono e entrega cache por chave.\n- **Query keys centralizadas**: reduz inconsistências e facilita invalidar/refatorar queries.\n- **Mappers explícitos**: deixam claro onde a resposta da API externa pode ser convertida para modelos internos.\n- **Context API enxuto**: usado apenas para estado global de UI, não para cache de dados remotos.\n- **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.\n- **Debounce nos filtros**: melhora UX e reduz chamadas desnecessárias.\n- **Skeleton loading contextual**: usa placeholders com a mesma estrutura visual da tela final, evitando loaders genéricos em áreas previsíveis.\n- **Animações sem biblioteca externa**: transições sutis com Tailwind CSS e CSS nativo, respeitando `prefers-reduced-motion`.\n- **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.\n- **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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraphaigor%2Fkanastra-spotify-challenge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fraphaigor%2Fkanastra-spotify-challenge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraphaigor%2Fkanastra-spotify-challenge/lists"}