Insights de IA — Fluida¶
Atualizado: 2026-06-22
Status: implementado e ativado em produção (mobile + web + backend)
Handoff de entrega: .context/handoffs/2026-06-22-cartoes-fatura-insights.md
Handoff de design: design_handoff_insights_ia/design_handoff_insights/
Esta página é a referência canônica da feature Insights Fluida. Para padrões gerais de frontend, ver Frontend Architecture. Para o motor de insights por dimensão que a antecede, ver MVP-3 — Hub de Cartões + Insights Globais e MVP-2 — AI Insights v2.
1. Visão¶
"Fluida" é o redesenho da tela de Insights de IA: troca o dump de JSON por uma leitura editorial — uma retrospectiva guiada, com textos curtos intercalados a comparativos e gráficos, de densidade baixa e tom analítico. Mesmo conceito em mobile e web.
Os insights são gerados diário ou semanalmente: a IA lê transações, metas, orçamentos, cartões e carteira e produz um insight geral + insights detalhados por tema. A tela Fluida é a leitura desse conteúdo, organizada como uma matéria:
- Masthead — logo + seletor de cadência (Diário/Semanal) + abas de tema (Geral · Transações · Metas · Orçamentos · Cartões) + alternador claro/escuro.
- Lead editorial — kicker (tema) + selo de severidade + tempo de leitura; headline serifada (Newsreader) + parágrafo de abertura.
- Beats intercalados (o coração do "fluido"):
- Comparativos ("Como se compara") — mini-cards ontem · anteontem · vs. semana.
- Texto curto (capitular no primeiro parágrafo).
- Gráfico ("O ritmo de saídas") — barras dos últimos 7 dias / 6 semanas, com o pico destacado.
- Texto curto + pull-stat (destaque numérico, ex.: "55% das despesas").
- Pontos de atenção (lista de alertas por severidade).
- "Para onde seguir agora" — bloco teal com a recomendação de fechamento.
- Procedência da IA — modelo, data de geração, nota de privacidade.
No web, alguns beats ficam lado a lado (texto + número/visual), com largura de leitura ~740px; no mobile, empilham.
Recorte por feature¶
Cada página de feature (Transações, Metas, Orçamentos, Cartões, Carteira) exibe uma section "Insights de IA" compacta com apenas o recorte daquela dimensão (lead + destaques + "ler na íntegra" → leva à tela principal). O mesmo conteúdo, recortado por dimensão.
2. Decisão de dados (princípio central)¶
A IA gera o TEXTO; o backend CALCULA os números.
- O summary/parágrafos vêm da geração de IA já existente (motor de insights por dimensão — MVP-3).
- Os blocos
retro(comparativos),series(gráfico) ehighlights(destaques numéricos) são derivados das transações pelo backend — determinísticos, auditáveis, sem alucinação. - O lead (
severity,title,lead,next_step,read_min) é derivado deterministicamente dosummary, sem nova chamada ao LLM (ver §4).
Vantagem: números sempre corretos e baratos; texto rico onde a IA agrega valor. O cliente (app/web) não calcula — só renderiza o payload.
3. Arquitetura¶
3.1 Backend (auraxis-api, Flask)¶
A geração de insight existente é enriquecida com os campos Fluida, on-the-fly, na serialização (REST + GraphQL).
| Arquivo | Papel |
|---|---|
app/services/insight_fluida_builder.py |
enrich_insight_payload(payload, *, user_id, anchor) — injeta paragraphs, retro, series, highlights, lead. Reusa weekly_summary._aggregate_range para os agregados. |
app/services/insight_lead_builder.py |
build_lead(...) + helpers derive_severity / derive_title_and_lead / derive_next_step / resolve_read_min. Tudo string/número — sem LLM. |
app/services/weekly_summary.py |
_aggregate_range(*, user_id, start, end) -> (income, expense, count) para transações PAGAS (exclui soft-deleted e impact_policy == CARDS_ONLY). Fonte única dos agregados. |
PRs: #1502 (payload estruturado) e #1508 (lead editorial). Exposto em REST e na mutation GraphQL generateAiInsight.
3.2 Mobile (auraxis-app, React Native + Expo + Tamagui)¶
- Tela:
features/insights/screens/insights-fluida-screen.tsx(Fluida) vs.features/insights/screens/ai-insights-screen.tsx(legada). O switch por flag está emapp/(private)/insights.tsx. - Mapper:
features/insights/fluida/insight-to-fluida-vm.ts—UserInsight(payload real) →InsightFluidaVM, com fallback mock-safe: se o insight énull, não tem corpo, ou é payload legado, cai para o recorte mock (selectFluidaVM); lead e corpo caem independentemente. - Recorte por feature:
shared/insights/insight-section.tsx(InsightSection) — section compacta plugada nas 5 páginas de feature; renderizanullquando não hávm; gated pela flag. - Beats/charts: barras em RN puro com animação de crescimento a partir da baseline (hook de bar-grow); sem lib de chart pesada.
- Fonte serifada:
@expo-google-fonts/newsreader(^0.4.1) — JS-only, carregada viaexpo-font, por isso OTA-friendly (não exige rebuild nativo).
3.3 Web (auraxis-web, Nuxt 4 + TypeScript + Naive UI + ECharts)¶
- Feature:
app/features/ai-insights/fluida/— 15 componentes Vue emcomponents/:InsightsFluida.vue(raiz),FluidaMasthead,FluidaCadenceToggle,FluidaThemeTabs,FluidaLead,FluidaSevChip,FluidaReadTime,FluidaCompareBeat,FluidaChartBeat,FluidaTextBeat,FluidaPullStat,FluidaStatTiles,FluidaAlertList,FluidaSeguir,FluidaAiMeta. - Mapper:
app/features/ai-insights/fluida/model/insight-to-fluida-vm.ts— converte o DTO REST para o view model. FunçãooverlayLead()mapeia oleaddo backend:readMin: lead.read_min,nextStep: lead.next_step(corrige o naming snake_case do REST); quando oleadfalta, o recorte mock sobrevive verbatim. - Switch legado:
app/pages/insights.vue—<InsightsFluida v-if="isFluidaEnabled" />vs.<div v-else>(relatório legado), comuseFeatureFlag("web.insights.fluida"). - Gráfico: ECharts (stack já presente na web).
- Fonte serifada:
@nuxtjs/google-fonts(3.2.0) comNewsreader: [500, 600]— só na headline; corpo segue Inter.
Paridade app ↔ web: mesmo contrato de dados e mesma lógica de view model (ambos os mappers se chamam
insight-to-fluida-vm.tse implementam o mesmo overlay com fallback mock-safe).
4. Lead determinístico (sem custo extra de LLM)¶
build_lead(...) deriva o lead a partir do summary já gerado:
severity— heurística sobre a variação de saídas semana-a-semana + concentração do gasto dominante (thresholds: ~+30% →atencao; ~+100% →alerta; ou ~55% de concentração). Níveis:ok(verde) ·atencao(âmbar) ·alerta(vermelho).read_min— tabela fixa por cadência × escopo: Diário ~15 min (geral) / ~3 min (tema); Semanal ~30 min (geral) / ~5 min (tema).title/lead— extraídos do texto dosummary(primeira frase / corpo).next_step— extraído dosummary(preferência pela última frase de recomendação).
Nenhuma dessas operações chama o LLM — são string/número. É o ponto exato do follow-up (§6).
5. Feature flags¶
| Flag | Repo | Arquivo | Valor | Janela |
|---|---|---|---|---|
app.insights.fluida |
auraxis-app |
config/feature-flags.json |
enabled-prod |
criada 2026-06-21; remover até 2026-12-31 |
web.insights.fluida |
auraxis-web |
config/feature-flags.json |
enabled-prod |
criada 2026-06-21; remover até 2027-12-31 |
- O default era OFF; toda a feature foi construída atrás da flag, sem tocar produção até o flip (app #618, web #1076).
- Tela legada preservada em ambos (app: switch por flag; web:
v-if/v-else) → rollback imediato desligando a flag.
6. Contrato de dados (payload Fluida)¶
Por cadência (diario | semanal) e por dimensão (geral + temas transacoes/metas/orcamentos/cartoes):
| Campo | Tipo | Origem | Onde aparece |
|---|---|---|---|
severity |
ok | atencao | alerta |
backend (heurística) | selo do lead |
title (REST: derivado) |
string | backend (do summary) | headline serifada |
lead |
string | backend (do summary) | parágrafo de abertura |
paragraphs |
string[] | IA (summary) | beats de texto |
read_min |
number | backend (tabela) | badge de tempo de leitura |
next_step |
string | backend (do summary) | bloco "para onde seguir" |
retro[] |
{ quando, valor, txt }[] |
backend (agregados) | comparativos (só no geral) |
series |
{ diaSerie[7], semanaSerie[6] } |
backend (agregados) | gráfico "ritmo de saídas" |
highlights[] (temas) |
{ k, v, s }[] |
backend (agregados) | pull-stats / tiles numéricos |
alertas[] (geral) |
lista por severidade | backend | pontos de atenção |
Atenção ao naming REST: o backend serializa em snake_case (
read_min,next_step); o mapper web converte para camelCase (readMin,nextStep) nooverlayLead(). Foi a correção da PR web #1073.
Referência de formato e tom (mock ancorado em dados reais de Junho/2026): design_handoff_insights_ia/design_handoff_insights/insights-data.js.
7. Tokens de design (referência do handoff)¶
Escopo .axi, claro/escuro. Atenção: o protótipo usa brand #0E6376; em produção vale a paleta semântica de cada frontend (ver Frontend Architecture e o design system vigente).
- Tipografia: UI Plus Jakarta Sans (web vigente: Inter); headline serifada Newsreader (peso 500–600); valores em mono tabular (IBM Plex Mono / JetBrains Mono,
tabular-nums). - Severidade:
ok=verde ·atencao=âmbar ·alerta=vermelho. - Sinais:
pos#11a36b,neg#e5484d,warn#c77d1a. Raios: cards 14–18, chips 999.
8. Entrega (rastreabilidade)¶
| Camada | PRs |
|---|---|
Backend (auraxis-api) |
#1502 payload, #1508 lead |
Mobile (auraxis-app) |
#600, #602, #604, #606, #608, #618 (flip) |
Web (auraxis-web) |
#1071, #1073, #1076 (flip) |
Estado: ativada em produção — app por OTA (#618); web e backend deployados. Lead+corpo reais com fallback mock-safe; app↔web em paridade.
Os campos Fluida no app são JS-only (inclusive a fonte Newsreader via
@expo-google-fonts/newsreader), por isso a entrega mobile foi OTA-safe. Contraste com o incidente de Cartões, em que libs nativas foram (erroneamente) enviadas por OTA — ver a lição2026-06-22-licao-deps-nativas-exigem-build.
9. Follow-up aberto¶
- Lead 100% gerado pela IA por dimensão. Hoje o lead (
title/lead/next_step) é derivado deterministicamente dosummary(§4). Para tê-lo gerado pela IA por dimensão, estender oinsight_fluida_builderreusando a geração de texto já existente — pedir os campos do lead no mesmo ciclo do summary, para não somar custo de LLM (não abrir nova chamada). - Limpeza das flags quando a tela legada for aposentada (janelas na §5).