β‘ Os 4 Estados: Idle, Loading, Success, Error
Todo componente interativo do seu SaaS existe em um de quatro estados a qualquer momento. Pensar nisso como uma state machine muda completamente como voce projeta interfaces. Cada estado tem regras visuais e comportamentais especificas, e em apps de IA o estado "loading" ganha uma importancia que nao existe em apps tradicionais.
π― Conceito Principal
Uma state machine e um modelo mental onde seu componente so pode estar em um estado por vez, e as transicoes entre estados sao explicitas. Isso elimina bugs como "mostrar loading e error ao mesmo tempo" ou "botao clicavel durante processamento".
- β’ Idle: Estado padrao. Input habilitado, botao de enviar ativo, nenhuma animacao rodando. O usuario esta no controle. UI limpa, sem distracao
- β’ Loading: Algo esta sendo processado. Input desabilitado (ou nao, depende do design), indicador visual de progresso, mensagem de contexto ("Analisando seu documento...")
- β’ Success: Operacao concluida. Resposta renderizada, feedback visual positivo (checkmark, cor verde), transicao suave de volta para idle
- β’ Error: Algo falhou. Mensagem clara do que aconteceu, opcao de retry, log do erro para debug. Nunca uma tela em branco
π State Machine para Interacoes de IA
Idle
Input ativo, aguardando acao do usuario
Loading
IA processando, streaming ou aguardando API
Success
Resposta entregue, volta para idle
Error
Falha com retry ou volta para idle
π Por que "Thinking" Importa Mais em Apps de IA
- β’ Apps tradicionais: Requests duram 100-500ms. Um spinner generico resolve. O usuario nem percebe
- β’ Apps de IA: Chamadas duram 5-30 segundos. O "thinking" state precisa ser rico: indicador de progresso, mensagem contextual, animacao sutil. O usuario precisa sentir que algo esta acontecendo
- β’ Tolerancia a espera: Pesquisas mostram que usuarios toleram ate 10s se o feedback visual for bom, mas abandonam em 3s se nao houver nenhum indicador
π‘ Dica Pratica
Use um useReducer (React) ou uma lib como XState para gerenciar estados. Um simples useState('idle') funciona para MVP, mas conforme o app cresce, uma state machine formal evita dezenas de bugs de estado inconsistente.
β O que FAZER
- β Mapear todos os estados possiveis antes de codar a UI
- β Desabilitar inputs durante loading para evitar requests duplicados
- β Transicionar de success para idle automaticamente apos 1-2s
β O que NAO fazer
- β Usar multiplos booleans (isLoading, isError, isSuccess) que podem conflitar
- β Permitir que o usuario envie outra mensagem durante loading
- β Mostrar estado de erro sem opcao de retry ou voltar
β³ Loading States para IA
Em apps tradicionais, um spinner resolve. Em apps de IA, voce precisa de um repertorio inteiro de loading states. Uma chamada de 2 segundos pede um tratamento diferente de uma de 30 segundos. O segredo e gerenciar a expectativa do usuario em tempo real.
π― Conceito Principal
Existem quatro tecnicas principais de loading para apps de IA, e voce vai usar combinacoes delas dependendo da operacao:
- β’ Skeleton Screens: Placeholders cinza na forma do conteudo que vai aparecer. Funcionam melhor que spinners porque dao ao cerebro uma previa da estrutura. Use para carregar listas de conversas, perfis, dashboards
- β’ Typing Indicators: Os tres pontinhos pulsando ("IA esta digitando..."). Classico do chat. Funciona para respostas curtas (2-5s). Para respostas longas, combine com streaming
- β’ Streaming Text: A resposta aparece token por token em tempo real. Padrao de ouro para apps de IA. O usuario le enquanto a IA ainda gera. Reduz percepcao de espera drasticamente
- β’ Progress Estimation: Para operacoes longas (processar PDF de 50 paginas, gerar relatorio), mostre progresso estimado: "Analisando pagina 12 de 47..." ou barra de progresso com percentual
π» Implementando Streaming com OpenAI
π Gerenciando Expectativa em Chamadas de 5-30s
- β’ 0-2 segundos: Typing indicator e suficiente. O usuario nem registra a espera conscientemente
- β’ 2-10 segundos: Streaming e ideal. Se nao for possivel, use typing indicator + mensagem contextual ("Analisando seu pedido...")
- β’ 10-30 segundos: Progress bar ou etapas visiveis ("Etapa 1/3: Lendo documento..."). O usuario precisa sentir que o sistema esta trabalhando, nao travado
- β’ 30+ segundos: Notificacao. Diga ao usuario que ele pode fazer outra coisa e sera avisado quando estiver pronto. Ninguem espera 30s olhando para uma tela
π‘ Dica Pratica
Skeleton screens > spinners. Streaming > typing indicator. Sempre escolha a opcao que da mais informacao ao usuario. Um skeleton mostra onde o conteudo vai aparecer. Um spinner so diz "espere". Streaming mostra progresso real. Typing indicator so diz "algo esta acontecendo".
π¨ Error States e Recuperacao
Erros acontecem. A API cai, o rate limit estoura, o usuario envia algo invalido, a internet oscila. O que define a qualidade do seu SaaS nao e a ausencia de erros, e como voce lida com eles. Um erro bem tratado gera mais confianca do que nenhum erro.
π― Conceito Principal
Existem tres categorias de erros em apps de IA, e cada uma exige tratamento diferente:
- β’ AI Errors (API): Rate limit (429), timeout, modelo indisponivel, resposta truncada, content filter. Sao os mais comuns. Solucao: retry automatico com backoff exponencial, modelo fallback, fila de requests
- β’ System Errors: Banco de dados fora, Supabase down, deploy quebrado, SSL expirado. Sao criticos. Solucao: health checks, monitoring, pagina de manutencao, alertas automaticos
- β’ User Errors: Arquivo grande demais, formato invalido, prompt vazio, caracteres especiais. Sao preveniveis. Solucao: validacao no frontend antes de enviar, mensagens claras de o que corrigir
π» Padroes de Tratamento de Erro
π Mensagens de Erro Amigaveis
Error 429: Too many requests. Rate limit exceeded.
β"Muitas perguntas de uma vez! Aguarde alguns segundos e tente novamente."
Error 500: Internal server error
β"Algo deu errado do nosso lado. Estamos trabalhando nisso. Tente novamente em um minuto."
CORS policy: No 'Access-Control-Allow-Origin'
β"Nao foi possivel conectar ao servidor. Verifique sua conexao e tente novamente."
π‘ Dica Pratica
Implemente fallback responses para quando a API estiver indisponivel. Pode ser uma mensagem pre-gravada, um cache da ultima resposta similar, ou um redirecionamento para um modelo alternativo (ex: cair de GPT-4o para GPT-3.5 quando o 4o estiver sobrecarregado). O usuario prefere uma resposta parcial a nenhuma resposta.
β O que FAZER
- β Retry automatico em erros 429 e 503 (transientes)
- β Botao de "Tentar novamente" visivel em todo erro
- β Detectar offline e avisar antes de tentar enviar
β O que NAO fazer
- β Mostrar stack traces ou codigos HTTP crus ao usuario
- β Engolir erros silenciosamente (console.log e seguir)
- β Fazer retry infinito sem limite (loop de requests)
π¬ Historico de Conversas
Se o usuario fecha o browser e perde tudo que conversou, seu SaaS e descartavel. Historico persistente e o que transforma uma sessao avulsa em um relacionamento continuo. E tambem e o que permite ao usuario voltar, buscar, e continuar de onde parou.
π― Conceito Principal
O modelo de dados para historico de conversas segue uma hierarquia natural: Usuario > Conversas > Mensagens > Anexos. Cada nivel tem suas propriedades e regras.
- β’ Conversations: id, user_id, title (auto-gerado do primeiro prompt), created_at, updated_at, is_archived. Uma conversa agrupa mensagens sobre um mesmo topico
- β’ Messages: id, conversation_id, role (user/assistant/system), content, tokens_used, created_at. Cada mensagem e uma unidade atomica no historico
- β’ Attachments: id, message_id, file_url, file_type, file_size, extracted_text. Arquivos vinculados a mensagens especificas
ποΈ Schema do Banco (Supabase/PostgreSQL)
π Funcionalidades Essenciais do Historico
- β’ Paginacao: Carregar 20 mensagens por vez, com "carregar mais" ou infinite scroll. Conversas com 200+ mensagens nao podem ser carregadas de uma vez
-
β’
Busca: Full-text search no conteudo das mensagens. Supabase tem
to_tsvectornativo para isso. O usuario precisa encontrar aquela conversa de 3 semanas atras - β’ Thread Management: Renomear conversas, arquivar, deletar, fixar favoritas. A sidebar vira inutilizavel com 50+ conversas sem organizacao
- β’ Auto-titulo: Gerar titulo automatico da conversa baseado na primeira mensagem do usuario. Pedir para a IA resumir em 5 palavras custa centavos e economiza cliques
π‘ Dica Pratica
Use Supabase Realtime para sync instantaneo. Se o usuario tem o app aberto em duas abas, uma nova mensagem aparece nas duas automaticamente. E gratis no Supabase e adiciona uma camada profissional que poucos MVPs tem.
πΎ Persistencia de Sessao
O usuario comecou a escrever uma pergunta longa, fechou o notebook para almocar e voltou 2 horas depois. Se o draft desapareceu, voce perdeu confianca. Persistencia de sessao e sobre garantir que nada se perde, nao importa o que o usuario faca.
π― Conceito Principal
Persistencia funciona em duas camadas. LocalStorage para dados temporarios e rapidos (draft da mensagem atual, preferencias de UI, ultimo scroll position). Database para dados permanentes e sincronizados (conversas, mensagens, configuracoes do usuario).
- β’ Resumir conversas: Quando o usuario reabre o app, carregar a ultima conversa ativa automaticamente. Nao forcar a escolher da lista. Lembrar qual conversa estava aberta
- β’ Session timeout: JWT do Supabase dura 1 hora por padrao, com refresh token de 7 dias. Configurar refresh automatico no background. Se expirar, redirecionar para login suavemente
- β’ Multi-device sync: Conversa criada no desktop aparece no celular. Supabase Realtime + polling resolve. Conflitos: last-write-wins e suficiente para MVP
- β’ Draft saving: Auto-save do input a cada 2 segundos no localStorage. Se o browser crashar, o rascunho esta la quando voltar. Custo zero, impacto enorme na UX
βοΈ LocalStorage vs Database: Quando Usar Cada
localStorage
- β’ Draft da mensagem sendo digitada
- β’ Tema (dark/light mode)
- β’ ID da ultima conversa aberta
- β’ Posicao do scroll na sidebar
- β’ Configuracoes de UI (sidebar aberta/fechada)
Database (Supabase)
- β’ Conversas e mensagens completas
- β’ Preferencias do usuario (model, temperature)
- β’ Arquivos enviados (Storage + metadata)
- β’ Usage tracking (tokens, requests)
- β’ System prompts personalizados
π» Auto-save de Draft com localStorage
π‘ Dica Pratica
Regra de ouro: se o dado precisa existir em outro dispositivo, vai para o banco. Se so importa nesta aba, vai para localStorage. Nao complique. Um draft de mensagem nao precisa sincronizar entre dispositivos. Mas as conversas sim.
β O que FAZER
- β Auto-save drafts no localStorage com debounce
- β Reabrir automaticamente a ultima conversa ativa
- β Refresh silencioso do JWT antes de expirar
β O que NAO fazer
- β Guardar conversas inteiras no localStorage (limite de 5MB)
- β Redirecionar bruscamente para login sem salvar estado
- β Ignorar conflitos de sync entre dispositivos
π οΈ Exercicio: Sistema de Estados Completo
Hora de implementar tudo que vimos. Este exercicio integra os 4 estados com UI adequada, historico de conversas com paginacao, e persistencia de sessao. O resultado e um chat funcional com qualidade profissional de UX.
Exercicio: Sistema de Estados + Historico + Persistencia
Tempo estimado: 30-45 minutos
Implementar state machine com 4 estados
Criar um hook ou state manager que controla idle/loading/success/error:
UI para cada estado
Renderizar componentes diferentes para cada estado:
Historico com paginacao
Carregar conversas da sidebar com paginacao (20 por vez). Ao clicar, buscar mensagens daquela conversa tambem paginadas. Implementar infinite scroll ou botao "carregar mais".
Persistencia de sessao
Salvar draft no localStorage, restaurar ultima conversa ao abrir o app, refresh automatico do token de auth.
Testar todos os cenarios
Simular: API lenta (throttle no DevTools), API fora (bloquear request), browser fechado e reaberto, sessao expirada, conversa com 100+ mensagens.
β Criterios de Sucesso
π Bonus
Adicione busca full-text nas conversas usando Supabase text search. Implemente auto-titulo que gera o nome da conversa apos a primeira resposta da IA. E se quiser ir alem, adicione export de conversa em formato Markdown.