Skip to content

[FEAT] Streaming por seção + skeletons na home do dashboard #169

Description

@RamonFrancisco

User story

Como usuário do dashboard de organização (/[tenant]/dashboard, a home do app pós-login), eu quero que a página apareça em partes — shell primeiro, cada seção depois — para não olhar uma tela branca enquanto a query mais lenta da página termina.

Hoje a home é um único Server Component que dá await em todas as consultas antes de renderizar qualquer coisa: o TTFB da página inteira é o da query mais lenta, e o loading.tsx da rota é um skeleton genérico de página cheia que não corresponde ao layout real (ele desenha 6 hero cards + 4 KPIs + um bloco + um split, e o resto das ~14 seções aparece de uma vez, com salto de layout).

Acceptance criteria

  • A home renderiza o shell (nome da org, contagem de repos, WindowSelector) sem esperar as consultas das seções — o shell aguarda no máximo uma consulta leve, a que a contagem do header e o empty state precisam.
  • Cada seção da home resolve de forma independente, dentro do seu próprio <Suspense>, e não bloqueia as seções abaixo.
  • Cada fallback tem a forma aproximada da seção que substitui (linha de hero cards, grid de KPIs, bloco de gráfico, split de dois blocos), de modo que a seção resolvendo não empurre o conteúdo abaixo mais do que o necessário.
  • Seções que normalmente não têm conteúdo (ex.: alertas de mudança, onde a maioria das orgs tem zero) não exibem skeleton — nada de alerta-fantasma piscando a cada load.
  • loading.tsx da rota cobre apenas o shell, já que a página faz streaming e cada seção carrega o seu próprio fallback.
  • Consultas compartilhadas entre seções são feitas uma vez por request (dedupe), não uma vez por seção.
  • Empty state (org com 0 repos) e a restrição de visibilidade por role (owner/admin) continuam funcionando como hoje.
  • Sem regressão visual no conteúdo já resolvido: as mesmas seções, na mesma ordem, com os mesmos dados da janela de análise selecionada.

Scope / non-goals

Dentro:

  • platform/src/app/[tenant]/dashboard/page.tsx, loading.tsx, extração dos loaders de dados e das seções em módulos próprios.
  • Fallbacks de Suspense reutilizáveis para as formas de seção que se repetem na home.

Fora:

  • Outras rotas (/repos, /compare, /ai-exposure, /team, /settings) — todas já têm loading.tsx; revisar os fallbacks delas é trabalho separado.
  • A landing page pública (src/app/page.tsx) — estática, sem consultas, não precisa de estado de loading.
  • Otimizar as queries em si (índices, novas tabelas pré-agregadas). Aqui o ganho é de ordem de renderização, não de custo de consulta.
  • Skeletons animados customizados / novos componentes de UI além do Skeleton que já existe em @/components/ui/skeleton.

Se encaixa em qual estágio?

Stage 2 (refinamento da plataforma atual)

Implementation notes

  • Rota: platform/src/app/[tenant]/dashboard/page.tsx (~14 seções: org pulse, delivery quality, DORA, AI vs human, AI delivery timeline, tool comparison, AI agent usage, intent distribution, PR health, cycle time, health map, org timeline, hyper engineers, change alerts).
  • Padrão: um módulo por seção em ./panels/*.tsx, cada um dando await só nos loaders que usa; loaders em ./data.ts envolvidos em cache() do React para deduplicar por request (várias seções compartilham o mesmo payload — sem dedupe seriam N round-trips idênticos). Todos os callers precisam passar o mesmo par (orgId, windowDays), já que a memoização é por identidade de argumento.
  • Fallbacks compartilhados em ./panels/skeletons.tsx: linha de hero cards, grid de KPIs (n cards), seção simples (heading + bloco), seção split (heading + dois blocos).
  • <Suspense fallback={null}> para os alertas de mudança.
  • A janela de análise (?window=, issue [FEAT] Janelas de análise selecionáveis (7/15/30/60/90 dias) em todo o produto #80) é resolvida no shell e passada para as seções — nenhuma seção deve reresolver a janela por conta própria.
  • Prior art de fallback por rota: src/app/[tenant]/repos/loading.tsx, src/app/[tenant]/compare/loading.tsx.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions