docs: update GEMINI.md and MEMORY.md and fix decimal places formatting in finance
Build and Deploy (Gitea) / build-and-deploy (push) Successful in 2m3s Details

This commit is contained in:
Sidney 2026-07-18 20:13:59 -03:00
parent eefcbcc671
commit 3277f81ce7
5 changed files with 36 additions and 30 deletions

View File

@ -89,4 +89,6 @@
55. **Migração Automática de Chaves de IA**: O sistema deve migrar automaticamente as configurações e chaves de IA legadas salvas no arquivo JSON para a tabela relacional `configuracoes_ia` do PostgreSQL para centralizar as credenciais.
56. **Geração Híbrida de Imagens Gemini/Imagen**: O backend deve suportar chamadas de imagem nativas (endpoint `:generateImages` do Imagen 3) para modelos `imagen-` e chamadas multimodais para modelos Gemini (`responseModalities`), aplicando fallbacks automáticos em cascata caso o modelo primário selecionado falhe.
57. **Correção de Autofill no Chrome**: Modais de IA devem desativar ou evitar elementos de formulário que induzam o Chrome a preencher incorretamente campos de texto irrelevantes (como busca de provas) com dados armazenados de login (ex: 'admin').
58. **Limitação de Decimais em Formatação Financeira**: Todos os valores financeiros renderizados na tela (especialmente parcelas, multas e juros de atraso) devem ser limitados a exatamente duas casas decimais utilizando `toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })` para garantir conformidade visual e evitar o arredondamento incorreto do navegador com 3 ou mais dígitos.
59. **Resiliência do Modelo de IA**: O backend em `server.selfhosted.js` implementa um filtro ativo contra modelos descontinuados da API Gemini (como `gemini-1.5-flash` e `gemini-2.5-flash-lite`) salvos no banco. O fallback forçado sob o capô deve ser sempre `gemini-2.0-flash`.

View File

@ -107,3 +107,7 @@ Nesta sessão de trabalho, realizamos o "core" da transição do sistema EduMana
- **Migração de Chaves de IA para o PostgreSQL**: Adicionada rotina de migração transparente que move as credenciais e configurações de IA do antigo cache JSON de configurações para a tabela relacional `configuracoes_ia`.
- **Correção de Autofill no Chrome**: Corrigido bug onde o recurso de preenchimento automático do Chrome inseria o usuário 'admin' na barra de busca de provas ao carregar o modal de configuração de IA.
### Fase 14: Correção de Precisão Financeira e Fallback do Módulo de IA (Julho de 2026)
- **Exibição Estrita de Duas Casas Decimais**: Adicionado o parâmetro `maximumFractionDigits: 2` em todos os locais onde valores financeiros são formatados no painel Manager (arquivos `Finance.tsx`, `Students.tsx` e `Courses.tsx`). Isso corrige de forma definitiva a exibição de parcelas vencidas com 3 casas decimais (ex: R$ 175,871), aplicando o formato monetário padrão brasileiro de exatamente 2 casas decimais.
- **Fallback e Filtro de Modelos Gemini Descontinuados**: Atualizado o modelo padrão de IA nas camadas de banco (`database.js`), backend (`server.selfhosted.js`) e frontend (`Exams.tsx`) de `gemini-1.5-flash` para `gemini-2.0-flash`. Além disso, foi adicionado um filtro que intercepta modelos inexistentes ou inválidos configurados no banco (como `gemini-2.5-flash-lite`) e faz o redirecionamento automático sob o capô para o modelo estável `gemini-2.0-flash`, evitando erros 404.

View File

@ -222,7 +222,7 @@ const Courses: React.FC<CoursesProps> = ({ data, updateData }) => {
<DollarSign size={18} className="text-emerald-500" />
<div>
<p className="text-[10px] uppercase font-bold text-slate-400">Investimento Mensal</p>
<p className="font-semibold text-slate-800">R$ {course.monthlyFee.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}</p>
<p className="font-semibold text-slate-800">R$ {course.monthlyFee.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</p>
</div>
</div>
</div>

View File

@ -1130,9 +1130,9 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
)}
</td>
<td className="px-6 py-5">
<div className="font-black text-slate-900">R$ {group.totalAmount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}</div>
<div className="font-black text-slate-900">R$ {group.totalAmount.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</div>
{group.totalReceived > 0 && (
<div className="text-[10px] text-blue-600 font-black">PAGO: R$ {group.totalReceived.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}</div>
<div className="text-[10px] text-blue-600 font-black">PAGO: R$ {group.totalReceived.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</div>
)}
<div className="text-[10px] text-slate-500 font-medium">Total do Carnê</div>
</td>
@ -1229,28 +1229,28 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
const displayValue = valorPago > 0 ? valorPago : (payment.amount - discount);
return (
<div className="font-bold text-slate-700 text-sm">
R$ {displayValue.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
R$ {displayValue.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
);
} else {
return (
<>
<div className="font-bold text-slate-700 text-sm">
R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
{activeDiscount > 0 && (
<div className="text-[10px] text-emerald-600 font-bold">
- R$ {activeDiscount.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
);
} else {
return (
<>
<div className="font-bold text-slate-700 text-sm">
R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
</div>
{activeDiscount > 0 && (
<div className="text-[10px] text-emerald-600 font-bold">
- R$ {activeDiscount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
</div>
)}
{additions > 0 && (
<div className="text-[10px] text-red-500 font-bold">
+ R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} (Juros/Multa)
</div>
)}
</>
);
}
)}
{additions > 0 && (
<div className="text-[10px] text-red-500 font-bold">
+ R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (Juros/Multa)
</div>
)}
</>
);
}
})()}
</td>
<td className="px-4 py-4">{getStatusBadge(payment)}</td>
@ -1368,23 +1368,23 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
const displayValue = valorPago > 0 ? valorPago : (payment.amount - discount);
return (
<div className="font-black text-slate-900 text-sm">
R$ {displayValue.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
R$ {displayValue.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
);
} else {
return (
<>
<div className="font-black text-slate-900 text-sm">
R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
R$ {(payment.amount + additions).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
{activeDiscount > 0 && (
<div className="text-[10px] text-emerald-600 font-bold">
- R$ {activeDiscount.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
- R$ {activeDiscount.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
)}
{additions > 0 && (
<div className="text-[10px] text-red-500 font-bold mt-0.5">
+ R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} (Multa/Juros)
+ R$ {additions.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (Multa/Juros)
</div>
)}
</>
@ -1701,7 +1701,7 @@ const Finance: React.FC<FinanceProps> = ({ data, updateData }) => {
<div className="flex justify-between items-start">
<div>
<div className="text-xs font-black text-indigo-500 uppercase tracking-wider">Parcela {parcela.numero}</div>
<div className="text-lg font-bold text-slate-800 mt-0.5">R$ {parcela.valor.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}</div>
<div className="text-lg font-bold text-slate-800 mt-0.5">R$ {parcela.valor.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</div>
</div>
<div className="text-right">
<div className="text-xs text-slate-400 font-medium">Vencimento</div>

View File

@ -2540,7 +2540,7 @@ const Students: React.FC<StudentsProps> = ({ data, updateData, deepLinkStudentId
<div className="flex justify-between items-start">
<div>
<div className="text-xs font-black text-indigo-500 uppercase tracking-wider">Parcela {parcela.numero}</div>
<div className="text-lg font-bold text-slate-800 mt-0.5">R$ {parcela.valor.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}</div>
<div className="text-lg font-bold text-slate-800 mt-0.5">R$ {parcela.valor.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</div>
</div>
<div className="text-right">
<div className="text-xs text-slate-400 font-medium">Vencimento</div>