- 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
19 KiB
✅ 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
- 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
- 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
- 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`);
}
- 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
- 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
- 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"), });
- 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", }
- 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(), });
- 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)
- Importação Automática de Extratos 🔄
Prioridade: Alta | Complexidade: Alta
Métodos:
- Upload de OFX/CSV - Parser para formatos bancários
- API Open Banking - Integração com Pluggy/Belvo
- Email parsing - Ler extratos enviados por email
- OCR de PDFs - Extrair dados de PDFs bancários
Fluxo sugerido: // app/(dashboard)/importacao/page.tsx
- Selecionar conta bancária de destino
- Upload de arquivo ou conectar via API
- Pré-visualização das transações
- Matching automático com categorias (ML)
- Revisão e confirmação
- Importação em lote
🎨 Melhorias de UI/UX
- 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:
- 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}
- 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
- 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)
- 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
- 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
- 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)
- 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>
);
}
- 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>
);
}
- 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 (
{title}
{description && ({description}
)}// 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
- 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- 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 });
- 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)
- ✅ Breadcrumbs e Page Headers consistentes
- ✅ Command Palette (⌘K)
- ✅ Indicadores visuais de status
- ✅ Modo card para tabelas em mobile
- ✅ Relatórios PDF básicos
🚀 Fase 2 - Value Boost (1 mês)
- 🎯 Metas Financeiras
- 🔮 Análise Preditiva
- 🔔 Sistema de Notificações
- 📊 Gráficos interativos com drill-down
- 🎓 Onboarding interativo
💎 Fase 3 - Diferenciais (2-3 meses)
- 🔄 Importação automática de extratos (OFX/CSV)
- 📎 Anexos e comprovantes com OCR
- 🎨 Temas personalizáveis
- 🏆 Gamificação e conquistas
- 💹 Tracking de investimentos
🎯 Métricas de Sucesso
Para medir o impacto das melhorias:
-
Engajamento:
- Tempo médio na aplicação
- Frequência de uso (DAU/MAU)
- Transações criadas por usuário/mês
-
Usabilidade:
- Taxa de conclusão de onboarding
- Tempo para criar primeira transação
- Taxa de erro em formulários
-
Performance:
- LCP (Largest Contentful Paint) < 2.5s
- FID (First Input Delay) < 100ms
- CLS (Cumulative Layout Shift) < 0.1
-
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:
- Melhorar a experiência mobile (responsividade avançada)
- Adicionar inteligência (previsões, notificações, insights)
- Aumentar a eficiência (command palette, importação automática)
- Personalização (temas, dashboard, densidade)
- Gamificação (metas, conquistas) para engajamento
Próximos Passos Recomendados:
- Validar com usuários quais features têm maior demanda
- Implementar quick wins da Fase 1
- A/B testing de novos designs
- Iteração baseada em feedback