App de fitness inteligente: especificação da arquitetura do cliente
ArtefatoEste é o artefato usado no Episódio 3: Dê um cérebro ao seu app e no Episódio 4: O plano de implementação de apps sem código. Use essa especificação como referência para visualizações de front-end, componentes de interface reutilizáveis, gerenciamento de estado do cliente e casos de teste em inglês simples.
Faça login para acessar este artefato
Faça login com seu Perfil do Desenvolvedor do Google para conferir e copiar o artefato completo usado na série Build It!.
O perfil do desenvolvedor é obrigatório
Você não se qualifica para um perfil de desenvolvedor. Peça para o administrador do Workspace ativar esse recurso.
Criar um perfil de desenvolvedor
Crie um Perfil do Desenvolvedor do Google sem custo financeiro para acessar todos os comandos e artefatos do Build It!
Participe do Builder Central para desbloquear
Resgate seu selo de membro Builder sem custo financeiro com um clique para desbloquear todos os comandos e artefatos do Build It!
Status: pronto para a sessão de planejamento (elaboração com o assistente de planejamento do cliente)
Documento complementar: especificação da arquitetura de dados
Meta da arquitetura: reconstrução limpa, sustentável, modular e testável do front-end do protótipo de fitness inteligente do AI Studio.
0. Pilha técnica principal e padrões de engenharia
- Framework de ambiente de execução: Next.js (App Router, React 19) + armazenamento em cache de recursos off-line do App Web Progressivo (PWA).
- Arquitetura de estilo: Tailwind CSS v4 + Tailwind Variants (para estilo de componente determinístico) + Lucide React (ícones).
- Divisão de estado do cliente:
- Zustand (sessão local): gerencia o estado volátil da academia (
useActiveSessionStore), cronômetros, buffers de séries ativas e sequenciamento de passos pré-calculado. Sincronizado comlocalStoragepara recuperação do bloqueio do smartphone. - TanStack Query (estado do servidor): gerencia o armazenamento em cache de documentos do Firestore, a revalidação em segundo plano e as atualizações otimistas para
weekly_plans,user_profiles,prseworkout_logs.
- Zustand (sessão local): gerencia o estado volátil da academia (
- Visualização de gráficos: Recharts (estilizado com tokens personalizados de modo escuro de academia).
- Autenticação: Firebase Authentication com cabeçalho de autenticação de token do portador transmitido para todos os endpoints do servidor.
1. Princípios de design e princípios de front-end
- Ergonomia para academia: projetado para operação tátil com uma mão durante o treino, mesmo com as mãos suadas. Áreas de toque generosas (mínimo de 48 x 48 dp), legibilidade de alto contraste e digitação mínima necessária.
- Interface otimista e resiliência off-line: o registro de séries, o início de timers de descanso e a troca de exercícios precisam responder instantaneamente (<16 ms) na interface. A sincronização em segundo plano processa a persistência do servidor para
POST /api/workouts/logsem bloquear o usuário. - Separação estrita de responsabilidades: os componentes de apresentação/burros recebem dados e emitem eventos usando propriedades. As visualizações de contêiner inteligente gerenciam a lógica de negócios, os armazenamentos de estado e a coordenação de APIs.
- UX de mutação em etapas: as propostas geradas pelo Coach de IA (
POST /api/coach/chat) são renderizadas como cards de visualização interativos em etapas com controles explícitos de [Aceitar plano] e [Modificar] antes de confirmar as mudanças no estado do aplicativo. - Qualidade orientada por comportamento: cada página, componente e interação é associado a casos de teste em linguagem simples que definem claramente o comportamento esperado.
2. Navegação do aplicativo e hierarquia de visualização
| Caminho da rota | Acessar nome | Propósito principal | Componentes principais incluídos |
|---|---|---|---|
/ |
Redirecionamento de raiz | Redirecionamento instantâneo para /today. |
(Redirecionamento do roteador) |
/today |
Prévia do treino de hoje | Visualização padrão. Resolve automaticamente para o dia atual da semana e mostra a prévia do treino de hoje. | <BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workouts/:day |
Prévia do treino diário | Mostra a prévia do treino de um dia específico da semana (por exemplo, /workouts/monday, /workouts/thursday). |
<BackButton />, <WorkoutHeader />, <CoachNoteCard />, <WorkoutExerciseSummary />, <WorkoutBlock />, <ExerciseCard />, <EmptyDayPlaceholder />, <ModifyWithCoachCard /> |
/workout/active |
Monitor de sessões ativas | Tela de execução de treino de alto risco (séries, repetições, timer). A navegação de baixo permanece visível. | <ActiveSessionStickyHeader />, <ActiveExerciseCardHeader />, <CoachTipCard />, <CurrentSetTargetCard />, <SetNavigationRow />, <ExerciseSetsTable />, <ActiveRestTimerDock />, <SessionExerciseOverview />, <ActiveSessionControlsDock />, <SwapExerciseModal />, <FinishConfirmationModal /> |
/week |
Programação de treinamento / Visualização semanal | Visão geral completa da programação de sete dias com agregados semanais de volume/tempo. | <WeekHeader />, <WeeklyStatsSummary />, <DayScheduleCardList />, <DayScheduleCard />, <ModifyWeekWithCoachCard /> |
/coach |
Chat com o Coach de IA | Treinamento conversacional com chips contextuais e propostas de treino em etapas. | <CoachHeader />, <ChatMessageList />, <ChatBubble />, <StagedProposalCard />, <ContextualPromptsBar />, <ChatInputDock />, <ContextBanner />, <ChatInputBar />, <SpeechToTextButton /> |
/progress |
Progresso e análise | Histórico de registros de treino, recordes pessoais e gráficos de volume. | <ProgressHeader />, <PRShowcaseBanner />, <VolumeProgressChartCard />, <AllTimeStatsGrid />, <WorkoutHistorySection />, <HistorySessionCard />, <EmptyHistoryPlaceholder /> |
/settings |
Perfil de usuário e preferências | Perfil do equipamento, notificações e gerenciamento de memória em três níveis. | <SettingsHeader />, <UserProfileCard />, <EquipmentSelectorCard />, <EquipmentToggleChip />, <PreferencesGroup />, <MemoryTierViewerCard />, <MemoryItemCard />, <AccountActionsGroup /> |
/exercises/:exerciseId |
Detalhes da enciclopédia de exercícios | Guia de exercícios com links diretos (por exemplo, /exercises/incline-db-bench-press) com dicas de vídeo e postura. |
<BackButton />, <ExerciseVideoPlayer />, <TargetMusclesCard />, <HowToPerformCard />, <FormTipsCard /> |
3. Especificações de página e visualização
Visualização: DailyWorkoutView (/today e /workouts/:day)
- Finalidade: mostra o regime de treino programado para um dia específico, incluindo o foco, a duração, a distribuição da meta de cardio, as observações do coach, os blocos de séries diretas e os blocos de superséries, com um estado vazio limpo quando nenhum treino está programado.
- Anatomia visual:
- Parte de cima:
<BackButton label="Back to Week" targetRoute="/week" />. - Cabeçalho: título de uma linha (
"Today"ou dia da semana) com selo condicional"✓ Completed", indicador de duração ("⏱ 50 min") e barras de porcentagem de intensidade muscular desejada. - Nota do treinador: card de conselho contextual com ícone e borda verde.
- Corpo: lista rolável de blocos de exercícios usando
<WorkoutExerciseSummary />(séries diretas ou superséries com o seloborder-left: 3px solid #a3e635e🔁 SUPERSET BLOCK). - Estado vazio:
<EmptyDayPlaceholder message="Nothing scheduled for this day" />. - Ação do rodapé inferior:
<ModifyWithCoachCard />(leva a/coach?day=:day).
- Parte de cima:
Visualização: WeekScheduleView (/week)
- Objetivo: mostra uma visão geral completa do cronograma de treino de sete dias, incluindo métricas gerais de volume/tempo semanal, uma lista selecionada de dias de treino ativo (filtrando rigorosamente os dias de descanso/não programados) e um atalho direto para reformular o plano semanal com o Coach de IA.
- Anatomia visual:
<WeekHeader />,<WeeklyStatsSummary />de três colunas (tempo total, volume total, frequência), lista de dias programados usando<DayScheduleCard variant="normal" />(com seloTODAYverde-neon no dia atual) e<ModifyWeekWithCoachCard />(rotas para/coach?context=week).
Visualização: CoachChatView (/coach)
- Objetivo: hub de treinamento de conversação com o agente de treinamento do Gemini. Oferece conselhos de treinamento motivacionais e estratégicos, aceita ditado de conversão de voz em texto e faz ajustes de treino em etapas com human-in-the-loop e controles de aceitação explícitos.
- Anatomia visual:
<CoachHeader />,<ChatMessageList />rolável (<ChatBubble />e<StagedProposalCard />),<ContextualPromptsBar />condicional e<ChatInputDock />fixo (<ContextBanner />com[✕]de dispensar +<ChatInputBar />+<SpeechToTextButton />).
Visualização: ExerciseDetailView (/exercises/:exerciseId)
- Objetivo: entrada de enciclopédia com link direto que oferece uma demonstração em vídeo sem som em loop automático (
<ExerciseVideoPlayer />), selos de músculos-alvo primários e secundários (<TargetMusclesCard />), instruções de desempenho passo a passo ordenadas (<HowToPerformCard />) e dicas de forma (<FormTipsCard />).
Visualização: ActiveWorkoutView (/workout/active)
- Finalidade: tela de registro de séries e execução de treinos de alta intensidade. Gerencia o estado do cronômetro da sessão ao vivo, as metas atuais, as entradas de repetições/peso, a conclusão instantânea da marca de seleção (<16 ms), a alternância automática de superséries, as contagens regressivas do timer de descanso com resposta tátil/áudio, a troca de exercícios e a persistência final para
POST /api/workouts/log. - Anatomia visual:
<ActiveSessionStickyHeader />,<ActiveExerciseCardHeader />,<CoachTipCard />,<CurrentSetTargetCard />,<ActiveRestTimerDock />flutuante (+30s,Skip),<SetNavigationRow />,<ExerciseSetsTable />(+ Add Set),<SessionExerciseOverview />,<ActiveSessionControlsDock />fixo ([⇄ SWAP EXERCISE]+[▶ START WORKOUT]/[⏸ PAUSE]/[▶ RESUME]),<SwapExerciseModal />e<FinishConfirmationModal />.
Visualização: ProgressView (/progress)
- Objetivo: monitorar o progresso atlético ao longo do tempo, celebrar recordes pessoais recentes (
<PRShowcaseBanner />), visualizar tendências de volume semanais/mensais com Recharts interativos (<VolumeProgressChartCard />com alternâncias de4W | 3M | 1Y), exibir<AllTimeStatsGrid />e arquivar sessões de treino concluídas (<WorkoutHistorySection />/<HistorySessionCard />).
Visualização: SettingsView (/settings)
- Finalidade: gerencia as informações do perfil do atleta (
<UserProfileCard />), o inventário de equipamentos (<EquipmentSelectorCard />/<EquipmentToggleChip />), as preferências de treino (<PreferencesGroup />paraLBS / KG, resposta tátil, som) e oferece gerenciamento transparente de usuários e exclusão da Memória de Longo Prazo de 3 Níveis do treinador de IA (<MemoryTierViewerCard />/<MemoryItemCard />).
4. Catálogo e interfaces de componentes reutilizáveis
Principais contratos de propriedades de componentes do TypeScript no aplicativo:
// src/components/workout/WorkoutExerciseSummary.tsx
interface WorkoutExerciseSummaryProps {
blocks: Array<{
label?: string;
category?: string;
exercises: Array<{
exercise_id: string; // Canonical slug (e.g. 'incline-db-bench-press')
name: string; // Denormalized display name (e.g. 'Incline DB Bench Press')
target_sets: number;
target_reps: string | number;
rest_seconds?: number;
}>;
}>;
activeExerciseId?: string;
onSelectExercise?: (exerciseId: string) => void;
}
// src/components/week/DayScheduleCard.tsx
interface DayScheduleCardProps {
dayName: string;
dayShort: string;
subtitleLabel?: string;
isToday?: boolean;
title: string;
focusBadge: string;
durationMin: number;
volumeLbs?: number;
targetMuscles: string[];
variant?: 'normal' | 'condensed';
onPress: (dayName: string) => void;
}
// src/components/coach/StagedProposalCard.tsx
interface StagedProposalCardProps {
proposalId: string;
type: 'UPDATE_DAY' | 'UPDATE_WEEK';
targetDay?: string;
summaryDiff: string;
proposalData: any;
isApplied?: boolean;
onAccept: (proposalId: string, data: any) => void;
onModify: (summaryDiff: string) => void;
}
// src/components/workout/CurrentSetTargetCard.tsx
interface CurrentSetTargetCardProps {
setNumber: number;
targetWeightLbs: number;
targetReps: number;
isCompleted: boolean;
onWeightChange: (weight: number) => void;
onRepsChange: (reps: number) => void;
onToggleComplete: () => void;
}5. Gerenciamento de estado do cliente e matriz de fluxo de dados
5.1 Política de latência e carregamento: o mecanismo de duas velocidades
- Interface otimista para academia (<16 ms): ações táteis na academia, como marcar séries, aumentar pesos/repetições, trocar de guia e alternar equipamentos, atualizam o estado local e renderizam novamente em 16 milissegundos. Os usuários nunca são bloqueados por indicadores de carregamento enquanto seguram pesos.
- Indicadores e ícones de carregamento explícitos para operações assíncronas:
- Conversas com o Coach de IA (
POST /api/coach/chat): ao enviar uma mensagem de chat, um balão animado de carregamento do Coach aparece imediatamente no fluxo do chat até que o Gemini retorne uma resposta ou proposta de treino. - Inicialização a frio e sincronização de rede: os contêineres de visualização mostram carregadores de esqueleto e ícones de carregamento de alto contraste ao buscar
weekly_plansouhistorical_workouts. - Envio de treino (
[Finish]): o modal de confirmação de conclusão renderiza um ícone de carregamento ativo enquanto o payload da sessão é confirmado emPOST /api/workouts/logno Cloud Firestore.
- Conversas com o Coach de IA (
5.2 Arquitetura de armazenamento do cliente e limites de domínio
| Camada de loja | Domínio de estado e propriedades principais | Política de persistência e cache | Contrato de back-end coordenado |
|---|---|---|---|
useActiveSessionStore (Zustand) |
sessionState (unstarted, running, paused), elapsedSeconds, currentStepIndex, steps: WorkoutStep[], loggedExercises. |
Sincronizado com o localStorage a cada segundo para recuperação de bloqueio/atualização do smartphone. |
Envia o payload concluído para POST /api/workouts/log. |
useWeeklyPlanQuery (TanStack Query) |
Programação atual de 7 dias, objetos de treino diário, blocos de supersérie, status de conclusão (scheduled, completed). |
Armazenado em cache na consulta TanStack (staleTime: 5 min); pré-buscado no lançamento. |
Confirmado quando o usuário toca em [Accept Plan] para propostas de POST /api/coach/chat. |
useCoachChatStore (Zustand + TanStack) |
Balões de mensagem cronológicos, activeContext, botões de comando, isCoachTyping: boolean, propostas em etapas. |
Sincronizado com o bucket de chat semanal do Firestore usando a assinatura em tempo real (onSnapshot). |
Envia consultas para POST /api/coach/chat. |
useProgressQuery (TanStack Query) |
Arquivo histórico de treinos, quadro de recordes pessoais (/users/{userId}/prs), agregados de volume de todos os tempos, filtro de período (4W, 3M, 1Y). |
Armazenado em cache na consulta TanStack (staleTime: 10 min). |
Atualizado imediatamente após a conclusão de uma sessão de treino. |
useUserProfileStore (TanStack Query) |
Inventário de equipamentos, unidades (LBS/KG), alternâncias de som/resposta tátil, memória viva de 3 níveis (básica, fisiológica, situacional). |
Armazenado em cache na consulta TanStack com sincronização bidirecional com o Firestore user_profiles. |
Atualizado de forma autônoma usando memory_mutations de POST /api/coach/chat. |
useExerciseLibraryQuery (TanStack Query) |
Entradas estáticas de enciclopédia, URLs de vídeo, músculos primários/secundários, etapas, dicas de forma. | Priorização agressiva de cache com TTL infinito (staleTime: Infinity). |
Somente leitura da coleção imutável exercises do Firestore. |
5.3 Gráfico de etapas de sessão de atividade pré-calculada
export interface WorkoutStep {
stepIndex: number; // 1-based index (e.g. 1 to 13)
totalSteps: number; // Total sets in the session
blockIndex: number; // Index of block in day plan
blockType: 'straight' | 'superset';
exerciseId: string; // Canonical slug
exerciseName: string; // Display name
setNumber: number; // Set index for this exercise (1, 2, 3...)
targetWeightLbs: number; // Target weight in lbs
targetReps: string | number; // Target reps (e.g. "8-10")
restSecondsAfter: number; // Prescribed rest duration
isCompleted: boolean; // Completion checkmark status
actualWeightLbs?: number; // User entered weight
actualRepsCompleted?: number; // User entered reps
}5.4 Fluxo de dados de ponta a ponta e matriz de mutação
| Acionador do usuário | Visualização de origem | Client Store Mutated | Latência da interface / Estado de carregamento | Coordenação de back-end | Reversão / Tratamento de falhas |
|---|---|---|---|---|---|
Toque em [✓] Concluir conjunto |
/workout/active |
useActiveSessionStore |
<16ms (otimista) |
O buffer da sessão local foi atualizado. Não há espera de rede. | Gravação de memória local com persistência local confiável. |
Toque em [Finish Workout]. |
/workout/active |
useActiveSessionStore, useWeeklyPlanStore, useProgressStore |
O botão mostra um ícone de carregamento durante a sincronização | Envia para POST /api/workouts/log. Marca o dia do Firestore como completed. |
Se estiver off-line, coloca o payload em fila no buffer de sincronização local e tenta novamente após a reconexão. |
Toque em [Accept Plan]. |
/coach |
useWeeklyPlanStore, useCoachChatStore |
Selo de interface instantânea ("✓ Plan Applied") |
Confirma proposal.data no Firestore weekly_plans. |
Se a rede falhar, uma notificação de aviso vai alertar o usuário, e os botões vão permanecer ativos para uma nova tentativa. |
| Enviar mensagem no Chat | /coach |
useCoachChatStore, useUserProfileStore |
Adição otimista de balão + indicador de carregamento do Coach | Chama POST /api/coach/chat. As confirmações retornaram memory_mutations. |
Substitui o ícone de carregamento por "Falha ao enviar. Toque para tentar de novo". |
| Alternar ícone de equipamento | /settings |
useUserProfileStore |
Alternância instantânea (<16ms) |
Envia a gravação em segundo plano para o Firestore user_profiles. |
Reverte a seleção de ícones e mostra um aviso de erro se a gravação falhar. |
Excluir item da memória de IA [🗑] |
/settings |
useUserProfileStore |
Exclusão instantânea (<16ms) |
Envia a mutação de exclusão para o Firestore user_profiles. |
Restaura o item da memória e alerta o usuário se a exclusão falhar. |
6. Jornadas completas do usuário e matriz de teste em linguagem simples
- Pacote 1: shell do app, navegação e processamento de rotas (testes 1.1 a 1.6: redirecionamento de inicialização raiz, dock persistente, retorno rápido de sessão de atividade ativa, substituto de dia da semana inválido, substituto de rota desconhecida 404, substituto de link direto de exercício inválido).
- Conjunto 2: visualização do treino diário e renderização de blocos (testes 2.1 a 2.7: resolução dinâmica do título do dia, rota de dia específico e botão "Voltar ", tratamento de blocos únicos x superséries, marcador de posição de dia vazio, carimbo de treino concluído, navegação pura no botão central de reprodução, modificação com anexo de contexto do treinador).
- Conjunto 3: visualização da programação semanal e card da programação diária (testes 3.1 a 3.6: renderização de estatísticas semanais, filtro de dias programados, destaque visual de hoje, navegação no card do dia, modificação da navegação semanal, renderização de variante condensada).
- Conjunto 4: chat com o coach e mutação em etapas (testes 4.1 a 4.7: renderização do fluxo de mensagens de chat, anexação e dispensa do banner de contexto, pré-preenchimento do botão de comando, alternância de ditado de fala, isolamento de mutação em etapas, aceitação e confirmação de proposta, prévia e confirmação de proposta de revisão semanal).
- Conjunto 5: detalhes do exercício e enciclopédia (testes 5.1 a 5.5: renderização de detalhes do exercício, reprodução sem som em loop automático, alternância de vídeo em pausa, tags de músculos primários e secundários, navegação de retorno do histórico e substituto).
- Conjunto 6: rastreamento e registro de treino ativo (testes 6.1 a 6.7: estado inicial não iniciado e início manual, pausa e retomada do cronômetro, registro de séries tátil e alternância de marca de seleção, alternância de etapas de supersérie, modal de troca de exercício e substituição, confirmação de término e sincronização com o servidor, recuperação do estado da sessão ao recarregar).
- Conjunto 7: análise de progresso e histórico (testes 7.1 a 7.5: renderização da visão geral do painel de progresso, exibição do banner de apresentação de RP, alternância do período do gráfico, estado de histórico vazio, toque no histórico de sessões anteriores).
- Conjunto 8: configurações do usuário, equipamento e memória de IA (testes 8.1 a 8.4: renderização da visualização de configurações, atualização do botão de equipamento, troca de unidades, exclusão de itens da memória de IA).