Files
openmonetis/PLAN.md
Felipe Coutinho 95d6a45a95 feat(plan): adicionar análise e sugestões para OpenSheets
- Criação do documento PLAN.md com análise da aplicação
- Identificação de pontos fortes e sugestões de novas features
- Inclusão de melhorias técnicas e métricas de sucesso
2025-12-09 17:24:07 +00:00

19 KiB

📊 Análise e Sugestões para OpenSheets 🎯 Resumo Executivo O OpenSheets é uma aplicação financeira bem estruturada com 184 componentes, 15 widgets de dashboard, e um design system coeso baseado em cores terracota. A análise identificou pontos fortes significativos e oportunidades estratégicas para melhorias.

Pontos Fortes Identificados

Arquitetura

  • Server-first com Next.js 15 App Router
  • 🚀 Fetching paralelo otimizado (18+ requests simultâneos)
  • 🔒 Modo privacidade bem implementado
  • 🎨 Design system consistente (OKLCH color space)

Componentes

  • 📦 40+ componentes shadcn/ui bem organizados
  • ♻️ Alta reutilização de componentes
  • 🎭 Sistema de skeletons completo
  • 🌙 Suporte total a tema dark/light

🚀 Sugestões de Novas Features

  1. Análise Preditiva e Forecasting 🔮

Prioridade: Alta | Complexidade: Média

// Nova página: app/(dashboard)/previsoes/

Features:

  • Previsão de gastos mensais baseada em histórico
  • Alerta de contas a vencer na próxima semana
  • Projeção de saldo futuro considerando despesas recorrentes
  • Machine learning simples para detectar padrões de gasto

Componentes sugeridos:

  • ForecastChart - Gráfico de linha com projeções
  • UpcomingBillsWidget - Widget de contas a vencer
  • SavingsGoalTracker - Acompanhamento de metas de economia

  1. Metas Financeiras (Goals) 🎯

Prioridade: Alta | Complexidade: Média

// Nova tabela no schema: export const metas = pgTable("metas", { id: uuid("id").primaryKey().defaultRandom(), userId: uuid("user_id").notNull().references(() => user.id), nome: text("nome").notNull(), valorAlvo: numeric("valor_alvo", { precision: 12, scale: 2 }).notNull(), valorAtual: numeric("valor_atual", { precision: 12, scale: 2 }).default("0"), prazo: timestamp("prazo"), categoriaId: uuid("categoria_id").references(() => categorias.id), tipo: text("tipo").notNull(), // 'economia', 'quitacao_divida', 'compra' });

Features:

  • Criar metas de economia (ex: "Viagem para Europa - R$ 10.000")
  • Vincular transações às metas
  • Dashboard de progresso visual
  • Sugestões automáticas de quanto economizar mensalmente

  1. Relatórios Exportáveis 📄

Prioridade: Média | Complexidade: Baixa

Formatos:

  • PDF com gráficos (usando jsPDF + html2canvas)
  • Excel/CSV detalhado (usando xlsx)
  • JSON para backup completo

Tipos de relatório:

  • Extrato mensal consolidado
  • Análise de gastos por categoria
  • Comparativo período a período
  • Resumo anual (imposto de renda)

Código sugerido: // lib/reports/generate-pdf-report.ts import { jsPDF } from 'jspdf';

export async function generateMonthlyReport(userId: string, period: string) { const data = await fetchMonthlyData(userId, period); const doc = new jsPDF();

// Adicionar logo, gráficos, tabelas
doc.save(`relatorio-${period}.pdf`);

}


  1. Modo Comparativo de Períodos 📊

Prioridade: Média | Complexidade: Baixa

UI sugerida: <MonthPicker mode="comparison" periods={[currentPeriod, comparePeriod]} />

Features:

  • Comparar dois meses lado a lado
  • Ver variação percentual por categoria
  • Identificar onde economizou/gastou mais
  • Gráficos de delta de gastos

  1. Tags/Etiquetas para Transações 🏷️

Prioridade: Baixa | Complexidade: Baixa

export const tags = pgTable("tags", { id: uuid("id").primaryKey(), userId: uuid("user_id").notNull(), nome: text("nome").notNull(), cor: text("cor").notNull(), // hex color });

export const lancamento_tags = pgTable("lancamento_tags", { lancamentoId: uuid("lancamento_id").references(() => lancamentos.id), tagId: uuid("tag_id").references(() => tags.id), });

Use cases:

  • Tag "Trabalho" para despesas dedutíveis
  • Tag "Emergência" para gastos não planejados
  • Tag "Investimento" para rastrear aplicações
  • Filtrar dashboard por tags

  1. Anexos e Comprovantes 📎

Prioridade: Média | Complexidade: Alta

Implementação:

  • Upload de imagens/PDFs de notas fiscais
  • Armazenamento em storage (S3-compatible ou local)
  • OCR para extrair dados automaticamente (Tesseract.js)
  • Galeria de comprovantes por transação

export const anexos = pgTable("anexos", { id: uuid("id").primaryKey(), lancamentoId: uuid("lancamento_id").references(() => lancamentos.id), arquivo: text("arquivo_url").notNull(), tipo: text("tipo").notNull(), // 'imagem', 'pdf' tamanho: integer("tamanho_bytes"), });


  1. Investimentos Tracking 💹

Prioridade: Baixa | Complexidade: Alta

Escopo:

  • Registrar compra/venda de ações, FIIs, criptomoedas
  • Importação de extratos de corretoras
  • Gráfico de evolução patrimonial
  • Cálculo de rentabilidade

Nova seção no sidebar: { title: "Investimentos", icon: RiLineChartLine, href: "/investimentos", }


  1. Gamificação e Conquistas 🏆

Prioridade: Baixa | Complexidade: Média

Conquistas sugeridas:

  • "Primeiro Mês no Azul" - Receitas > Despesas
  • "Economista" - Gastou menos que orçamento 3 meses seguidos
  • "Organizado" - Todas transações categorizadas
  • "Disciplinado" - 30 dias sem gastos em categoria específica

Implementação: export const conquistas = pgTable("conquistas", { id: uuid("id").primaryKey(), codigo: text("codigo").notNull(), // 'primeiro_mes_azul' nome: text("nome").notNull(), descricao: text("descricao"), icone: text("icone"), });

export const usuario_conquistas = pgTable("usuario_conquistas", { userId: uuid("user_id").references(() => user.id), conquistaId: uuid("conquista_id").references(() => conquistas.id), desbloqueadaEm: timestamp("desbloqueada_em").defaultNow(), });


  1. Notificações e Lembretes 🔔

Prioridade: Alta | Complexidade: Média

Tipos de notificação:

  • Lembrete de fatura vencendo em 3 dias
  • Orçamento atingindo 80% do limite
  • Despesa incomum detectada (> 2x média da categoria)
  • Cobrança recorrente não registrada este mês

Implementação:

  • Cron job diário verificando condições
  • Sistema de notificações in-app
  • Opcional: Email notifications (Resend/Nodemailer)
  • Web Push Notifications (service worker)

  1. Importação Automática de Extratos 🔄

Prioridade: Alta | Complexidade: Alta

Métodos:

  1. Upload de OFX/CSV - Parser para formatos bancários
  2. API Open Banking - Integração com Pluggy/Belvo
  3. Email parsing - Ler extratos enviados por email
  4. OCR de PDFs - Extrair dados de PDFs bancários

Fluxo sugerido: // app/(dashboard)/importacao/page.tsx

  1. Selecionar conta bancária de destino
  2. Upload de arquivo ou conectar via API
  3. Pré-visualização das transações
  4. Matching automático com categorias (ML)
  5. Revisão e confirmação
  6. Importação em lote

🎨 Melhorias de UI/UX

  1. Redesign do Diálogo de Transação 💳

Problema: Diálogo com muitos campos condicionais pode confundir usuários

Solução: // Wizard multi-step com progresso visual {/_ Nome, valor, data /} {/ Método, conta, condição /} {/ Categoria, pagador, notas _/}

Indicador de progresso:

1}>1 2}>2 3

  1. Tabela Responsiva com Card View 📱

Problema: Tabelas complexas em mobile têm scroll horizontal

Solução: // components/lancamentos/table/lancamentos-responsive-view.tsx export function LancamentosResponsiveView() { const isMobile = useIsMobile();

if (isMobile) {
  return <LancamentosCardList items={data} />;
}

return <LancamentosTable items={data} />;

}

// Card view para mobile function LancamentoCard({ lancamento }) { return (

{lancamento.nome}

{lancamento.categoria}

{lancamento.condicao} {lancamento.formaPagamento}
); }
  1. Dashboard Personalizável 🔧

Problema: Todos veem os mesmos 15 widgets

Solução: // lib/dashboard/widgets/user-widget-preferences.ts export const widgetPreferences = pgTable("widget_preferences", { userId: uuid("user_id").references(() => user.id), widgetId: text("widget_id").notNull(), ordem: integer("ordem").notNull(), visivel: boolean("visivel").default(true), tamanho: text("tamanho"), // 'small', 'medium', 'large' });

// Drag-and-drop com dnd-kit import { DndContext, closestCenter } from '@dnd-kit/core';

{widgets.map(widget => ( ))}

Features:

  • Reordenar widgets via drag-and-drop
  • Ocultar/mostrar widgets
  • Redimensionar widgets (grid responsivo)
  • Salvar preferências no banco

  1. Busca Global (Command Palette) ⌘K

Problema: Navegar entre muitas páginas é lento

Solução: // components/command-palette.tsx import { RiSearchLine } from '@remixicon/react';

export function CommandPalette() { const [open, setOpen] = useState(false);

useEffect(() => {
  const down = (e: KeyboardEvent) => {
    if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
      e.preventDefault();
      setOpen(true);
    }
  };
  document.addEventListener('keydown', down);
  return () => document.removeEventListener('keydown', down);
}, []);

return (
  <CommandDialog open={open} onOpenChange={setOpen}>
    <CommandInput placeholder="Buscar transações, categorias, contas..." />
    <CommandList>
      <CommandGroup heading="Ações Rápidas">
        <CommandItem onSelect={openNewTransaction}>
          <RiAddLine className="mr-2" />
          Nova Transação
        </CommandItem>
      </CommandGroup>
      <CommandGroup heading="Transações Recentes">
        {recentTransactions.map(t => (
          <CommandItem key={t.id}>{t.nome}</CommandItem>
        ))}
      </CommandGroup>
      <CommandGroup heading="Navegação">
        <CommandItem onSelect={() => router.push('/dashboard')}>
          Dashboard
        </CommandItem>
      </CommandGroup>
    </CommandList>
  </CommandDialog>
);

}

Ações rápidas:

  • Nova transação (Ctrl+K → "nova")
  • Ver conta específica
  • Buscar transação por nome/valor
  • Navegar para qualquer página
  • Executar ações (marcar como pago, editar, excluir)

  1. Onboarding Interativo 🎓

Problema: Novos usuários podem se sentir perdidos

Solução: // components/onboarding/onboarding-tour.tsx import { Joyride } from 'react-joyride';

const steps = [ { target: '.sidebar-nav', content: 'Aqui você navega entre as diferentes seções', }, { target: '[data-tour="new-transaction"]', content: 'Clique aqui para adicionar sua primeira transação', }, { target: '.month-picker', content: 'Use isto para navegar entre meses', }, ];

export function OnboardingTour() { const { tourCompleted } = useUserPreferences();

return (
  <Joyride
    steps={steps}
    run={!tourCompleted}
    continuous
    showSkipButton
  />
);

}

Checklist inicial:

  • Criar primeira conta bancária
  • Adicionar um cartão de crédito
  • Registrar primeira transação
  • Definir orçamento mensal
  • Explorar dashboard

  1. Modo Compacto / Densidade Ajustável 📏

Problema: Algumas páginas têm muito espaço em branco

Solução: // Adicionar ao contexto de preferências export const densitySettings = { comfortable: { gap: 6, padding: 6, fontSize: 'text-base' }, normal: { gap: 4, padding: 4, fontSize: 'text-sm' }, compact: { gap: 2, padding: 2, fontSize: 'text-xs' }, };

// Aplicar dinamicamente

Controle: // Em ajustes/page.tsx Compacto Normal Confortável


  1. Indicadores Visuais de Status 🚦

Problema: Difícil ver rapidamente status de contas/faturas

Solução: // components/status-indicator.tsx export function StatusIndicator({ status }: { status: string }) { const config = { 'em-dia': { color: 'green', icon: RiCheckLine, label: 'Em dia' }, 'vencendo': { color: 'yellow', icon: RiTimeLine, label: 'Vencendo' }, 'atrasado': { color: 'red', icon: RiAlertLine, label: 'Atrasado' }, };

const { color, icon: Icon, label } = config[status];

return (
  <Badge variant={color} className="gap-1">
    <Icon className="h-3 w-3" />
    {label}
  </Badge>
);

}

Aplicar em:

  • Cards de faturas (verde = paga, amarelo = próxima, vermelho = vencida)
  • Boletos (status de pagamento)
  • Orçamentos (verde = dentro, amarelo = 80%, vermelho = estourou)

  1. Gráficos Interativos com Drill-Down 📊

Problema: Gráficos mostram dados mas não permitem explorar

Solução: // components/dashboard/interactive-category-chart.tsx <Pie data={categoryData} onClick={(data, index) => { // Ao clicar em fatia, abrir modal com transações daquela categoria showCategoryDetails(data.categoryId); }} />

// Modal de drill-down function CategoryDetailsModal({ categoryId, period }) { const transactions = useCategoryTransactions(categoryId, period);

return (
  <Dialog>
    <DialogHeader>
      <DialogTitle>Detalhes - {categoryName}</DialogTitle>
    </DialogHeader>
    <DialogContent>
      <LancamentosTable
        data={transactions}
        filters={{ categoryId }}
      />
    </DialogContent>
  </Dialog>
);

}


  1. Tema de Cores Personalizável 🎨

Problema: Apenas uma cor primária (terracota)

Solução: // lib/theme/color-themes.ts export const colorThemes = { terracotta: { primary: 'oklch(69.18% 0.18855 38.353)' }, ocean: { primary: 'oklch(69.18% 0.18855 220)' }, forest: { primary: 'oklch(69.18% 0.18855 140)' }, sunset: { primary: 'oklch(69.18% 0.18855 25)' }, lavender: { primary: 'oklch(69.18% 0.18855 280)' }, };

// Em ajustes/page.tsx export function ThemeColorPicker() { const { colorTheme, setColorTheme } = useTheme();

return (
  <div className="flex gap-2">
    {Object.entries(colorThemes).map(([name, colors]) => (
      <button
        key={name}
        onClick={() => setColorTheme(name)}
        className="w-8 h-8 rounded-full border-2"
        style={{ backgroundColor: colors.primary }}
      />
    ))}
  </div>
);

}


  1. Breadcrumbs e Page Headers Consistentes 🗺️

Problema: Inconsistência em headers entre páginas

Solução: // components/page-header.tsx interface PageHeaderProps { title: string; description?: string; breadcrumbs?: { label: string; href?: string }[]; actions?: React.ReactNode; }

export function PageHeader({ title, description, breadcrumbs, actions }: PageHeaderProps) { return (

{breadcrumbs && ( {breadcrumbs.map((crumb, i) => ( {crumb.href ? ( {crumb.label} ) : ( {crumb.label} )} ))} )}

{title}

{description && (

{description}

)}
{actions &&
{actions}
}
); }

// Uso: <PageHeader title="Transações" description="Gerencie suas receitas e despesas" breadcrumbs={[ { label: 'Dashboard', href: '/dashboard' }, { label: 'Transações' }, ]} actions={ Nova Transação } />


🔧 Melhorias Técnicas

  1. Error Boundary Global

// app/error.tsx 'use client';

export default function Error({ error, reset, }: { error: Error & { digest?: string }; reset: () => void; }) { return (

Algo deu errado!

Tentar novamente
); }
  1. Analytics e Telemetria

// lib/analytics.ts export function trackEvent(event: string, properties?: Record<string, any>) { // Posthog, Mixpanel, ou custom console.log('[Analytics]', event, properties); }

// Uso: trackEvent('transaction_created', { type: 'despesa', amount: 100 });

  1. Rate Limiting para Actions

// lib/rate-limit.ts import { Ratelimit } from '@upstash/ratelimit';

const ratelimit = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow(10, '10 s'), });

export async function checkRateLimit(userId: string) { const { success } = await ratelimit.limit(userId); if (!success) throw new Error('Rate limit exceeded'); }


📊 Priorização Sugerida

🔥 Fase 1 - Quick Wins (1-2 semanas)

  1. Breadcrumbs e Page Headers consistentes
  2. Command Palette (⌘K)
  3. Indicadores visuais de status
  4. Modo card para tabelas em mobile
  5. Relatórios PDF básicos

🚀 Fase 2 - Value Boost (1 mês)

  1. 🎯 Metas Financeiras
  2. 🔮 Análise Preditiva
  3. 🔔 Sistema de Notificações
  4. 📊 Gráficos interativos com drill-down
  5. 🎓 Onboarding interativo

💎 Fase 3 - Diferenciais (2-3 meses)

  1. 🔄 Importação automática de extratos (OFX/CSV)
  2. 📎 Anexos e comprovantes com OCR
  3. 🎨 Temas personalizáveis
  4. 🏆 Gamificação e conquistas
  5. 💹 Tracking de investimentos

🎯 Métricas de Sucesso

Para medir o impacto das melhorias:

  1. Engajamento:

    • Tempo médio na aplicação
    • Frequência de uso (DAU/MAU)
    • Transações criadas por usuário/mês
  2. Usabilidade:

    • Taxa de conclusão de onboarding
    • Tempo para criar primeira transação
    • Taxa de erro em formulários
  3. Performance:

    • LCP (Largest Contentful Paint) < 2.5s
    • FID (First Input Delay) < 100ms
    • CLS (Cumulative Layout Shift) < 0.1
  4. Adoção de Features:

    • % de usuários usando metas
    • % de usuários que personalizam dashboard
    • Taxa de uso do command palette

📝 Conclusão

O OpenSheets já possui uma base sólida com excelente arquitetura e design. As sugestões focam em:

  1. Melhorar a experiência mobile (responsividade avançada)
  2. Adicionar inteligência (previsões, notificações, insights)
  3. Aumentar a eficiência (command palette, importação automática)
  4. Personalização (temas, dashboard, densidade)
  5. Gamificação (metas, conquistas) para engajamento

Próximos Passos Recomendados:

  1. Validar com usuários quais features têm maior demanda
  2. Implementar quick wins da Fase 1
  3. A/B testing de novos designs
  4. Iteração baseada em feedback