尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗App pessoal para lançar o salário, separar o que fica comigo e o que vai para investir, controlar revendas e acompanhar o patrimônio todo dia.
public/index.html — o app inteiro (uma página).public/relatorio.js — os relatórios em PDF (semana/mês e "Meus gastos"), desenhados no aparelho com o jsPDF.public/extrato.js — leitura do extrato do Itaú em PDF, no próprio aparelho. Veja Controle de gastos.api/ — funções da Vercel:
login — entra com a senha (APP_PASSWORD) e guarda a sessão por um ano;estado / escrever — leem e gravam os dados num arquivo JSON privado do Vercel Blob. Ao gravar um gasto, escrever também confere o aviso de 80%/100% do mês (api/_alertasGastos.js);importar — restaura um backup;mercado — busca dólar PTAX, CDI, Selic e IPCA no Banco Central e guarda o fechamento diário dos índices de mercado. Roda sozinho todo dia útil às 18h (cron em vercel.json) e também quando o app abre com os dados velhos;indices — cotação dos índices de mercado na hora (gráficos, resumo do dia e destaques da semana). Veja Índices de mercado.Nenhum dado pessoal fica neste repositório: tudo mora no Blob privado da conta Vercel.
APP_PASSWORD com a senha do app.Opcionais: APP_SECRET (chave da sessão; sem ela, é derivada da senha) e CRON_SECRET
(protege a chamada do cron).
Para conferir a configuração: https://SEU-DOMINIO/api/estado?diag=1.
Todo dia útil, junto com a atualização do dólar e do CDI, o app grava uma cópia dos dados em
caixa/backups/AAAA-MM.json no Blob (uma por mês, com o último estado do mês). Para restaurar,
baixe o arquivo no painel da Vercel (Storage → Blob) e use Ajustes → Importar backup.
Na aba Mês, o card de índices mostra o gráfico de cada índice, a variação do dia e a do período.
| Índice | O que mede |
|---|---|
| Ibovespa | Principal índice da B3: as ações mais negociadas da bolsa brasileira, com peso pelo valor de mercado. A carteira é revista a cada 4 meses. |
| IFIX | Os fundos imobiliários (FIIs) mais negociados da B3. |
| S&P 500 | As 500 maiores empresas dos EUA, com peso pelo valor de mercado. |
| Nasdaq (Composite) | Todas as ações listadas na Nasdaq, com forte peso de tecnologia. |
| Dow Jones | 30 grandes empresas americanas, com peso pelo preço da ação (não pelo tamanho da empresa). |
| Nikkei 225 | As 225 principais empresas da Bolsa de Tóquio, com peso pelo preço da ação. |
Períodos: 1D (pregão atual, pontos a cada 5 min), 5D (5 pregões, a cada 15 min), 1M, 6M,
YTD (desde 1º de janeiro), 1A, 5A (um ponto por semana) e MAX (um ponto por mês). As datas são
sempre a data local da bolsa (Tóquio está 12h à frente de Brasília).
Atualização ao vivo: os gráficos são buscados na hora, quando o card abre ou o período muda. O servidor
guarda cada resposta por 60 s (1D, 5D e resumo), 5 min (1M) ou 15 min (demais períodos). Durante o
pregão o app atualiza sozinho a cada 60 s. Se a busca ao vivo falhar, o app usa os fechamentos diários que
o cron grava em mercado_hist e mostra o aviso de mercado.atual.indicesErro. Com o pregão aberto,
o cron não grava a barra do dia (ainda não é fechamento); ela entra na passada seguinte.
Destaques da semana: as ações do Ibovespa que mais caíram e mais subiram na semana (até 10 de cada).
A semana vai da segunda até a última cotação e é comparada com o fechamento do pregão anterior à
segunda (normalmente a sexta). No sábado e no domingo aparece a semana que acabou. Na segunda antes da
abertura (sem cotação na semana) aparece a semana anterior, fechada (fechada: true).
Todos exigem login (cookie da sessão). Sem login: 401 { "erro": "login" }. Respostas com
cache-control: private, max-age=30.
GET /api/indices?id=<id>&periodo=<periodo>: gráfico de um índice.
id: ibovespa | ifix | sp500 | nasdaq | dowjones | nikkeiperiodo: 1D | 5D | 1M | 6M | YTD | 1A | 5A | MAX{
"id": "ibovespa", "nome": "Ibovespa", "moeda": "BRL", "periodo": "1D",
"valor": 165405.4, "horario": "2026-11-03T15:50:30.000Z", "pregaoAberto": true,
"fechamentoAnterior": 167921.8, "intradiario": true,
"pontos": [{ "t": 1793710800000, "data": "2026-11-03", "valor": 167917.3 }],
"resumo": { "abertura": 167917.3, "alta": 168005.45, "baixa": 164446.53, "alta52": 209714, "baixa52": 149979 },
"fonte": "Yahoo Finance"
}
moeda: BRL | USD | JPY | null. horario: ISO (UTC) da última cotação.pontos: ordenados por t (epoch em ms). data é a data local da bolsa. intradiario é true em 1D e 5D (pontos com hora).resumo e fechamentoAnterior são sempre da sessão atual (ou da última, com a bolsa fechada). Os campos podem vir null.fonte: Yahoo Finance ou CNBC.400 { "erro": "..." } para id ou período inválido; 502 { "erro": "Não consegui buscar o <nome> agora. Tente de novo em alguns minutos." } quando todas as fontes falharam.GET /api/indices?lista=resumo: último valor e variação do dia de todos os índices.
{
"atualizadoEm": "2026-11-03T16:06:01.412Z",
"indices": [{ "id": "sp500", "nome": "S&P 500", "moeda": "USD", "valor": 7584.87,
"variacaoDia": 43.47, "variacaoDiaPct": 0.5764,
"horario": "2026-11-03T16:06:00.000Z", "pregaoAberto": true }],
"falhas": { "nikkei": "Não consegui buscar o Nikkei 225 agora. Tente de novo em alguns minutos." },
"fonte": "Yahoo Finance"
}
variacaoDia = valor − fechamento anterior; variacaoDiaPct em %. O índice que falhou sai de
indices e aparece em falhas.
GET /api/indices?lista=destaques-semana: maiores quedas e altas da semana entre as ações do Ibovespa.
{
"semana": { "de": "2026-11-02", "ate": "2026-11-03", "base": "2026-10-30" },
"fechada": false, "atualizadoEm": "...",
"quedas": [{ "codigo": "XXXX3", "nome": "...", "preco": 10.5, "variacaoSemana": -1.2,
"variacaoSemanaPct": -10.26, "participacao": 1.8 }],
"altas": [], "total": 84, "semDados": ["YYYY3"], "fonte": "..."
}
semana.base é o pregão usado como referência (fechamento anterior à segunda). Há até 10 ações em
quedas e 10 em altas. total é quantas ações entraram na conta, e semDados lista as que ficaram sem cotação.
Se não der para montar a lista, a resposta é 502 { "erro": "Não consegui montar os destaques da semana agora. Tente de novo em alguns minutos." }.
Campos gravados por /api/mercado em mercado.atual: indices (último valor e variação do dia de
cada índice, para o app usar sem a API ao vivo), indicesAtualizadoEm (ISO da última busca que deu certo)
e indicesErro (mensagem da última falha, ou null quando todos vieram). O retorno de /api/mercado
traz também falhasIndices: { <id>: mensagem }.
Na aba Para mim, os gastos do mês são comparados com o valor que fica com você no mês (Ajustes,
config.main.paraMim), chamado aqui de meta. O mês é o mês da data do gasto, no
horário de Brasília. Gastos fixos e gastos importados do extrato contam como qualquer outro gasto.
/api/escrever), o servidor recalcula o mês atual. Se chegou a
80% ou passou de 100%, manda uma notificação para os aparelhos inscritos. Tocar nela abre a aba Para mim
(/?aba=mim).
enviados de caixa/push.json com a chave
gastos:AAAA-MM:80 ou gastos:AAAA-MM:100. Apagar um gasto e lançar de novo não repete o aviso.fixos (descrição, categoria e valor de cada conta que se repete todo mês).tipo: 'gasto', fixoId) com data do dia 1º do mês, e já desconta da meta desde o começo do mês.fixo-<id do fixo>-<AAAA-MM>. Lançar de novo, por outro aparelho ou outra aba, grava
o mesmo documento, então o fixo não duplica.public/extrato.js). Ele não é enviado para o servidor nem guardado. Só as linhas que você confirma viram gastos.regras e usa essa categoria nas próximas importações.chaveExtrato), e o gasto é gravado
com um id que sai dessa chave. Importar o mesmo extrato de novo, ou um extrato com dias repetidos, não duplica nada.O mês atual até hoje é comparado com o mesmo ponto do mês passado (até o mesmo dia) e com a média dos 3 meses anteriores, no total e por categoria.
O gráfico de barras dos 6 meses fica no card de gastos (ver "Ver gastos de outros meses"), e não mais no card Mês a mês. O card Mês a mês continua sempre sobre o mês atual, e o relatório em PDF não mudou.
O relatório em PDF "Meus gastos" é gerado no aparelho (window.caixaRelatorioGastosPDF(d) em
public/relatorio.js, que devolve um Blob) e traz:
Campos sem valor (null) aparecem como "—".
Dados que a tela passa para o relatório:
{
titulo: 'Meus gastos · nov. de 2026', ate: '2026-11-03', meta: 1100,
meses: [{ mes: '2026-06', nome: 'jun. de 2026', total, fixos, variaveis, sobra /* meta − total */, porCat: [{ id, nome, v }] }], // 6 meses, do mais antigo ao atual
atual: { mes, nome, total, ateDia, mesmoPontoMesPassado /* ou null */, mediaAnteriores3 /* ou null */ },
categorias: [{ id, nome, atual, media3, dif }],
maiores: [{ data, descricao, categoria, valor }],
destaques: ['texto curto']
}
| Onde | O que guarda |
|---|---|
movimentos | Gastos, entradas e ajustes: { tipo: 'gasto' | 'entrada' | 'ajuste', valor (positivo), data 'AAAA-MM-DD', categoria, descricao }. Campos novos: fixoId (gasto lançado por um fixo), origem: 'extrato' e chaveExtrato (gasto importado do extrato). |
fixos | Os gastos fixos do mês e os meses pulados de cada um. |
regras | As regras de categoria aprendidas na importação do extrato (trecho da descrição → categoria). |
caixa/push.json → enviados | As chaves gastos:AAAA-MM:80 e gastos:AAAA-MM:100 dos avisos já enviados. |
Categorias: uber (Uber e 99), ifood (iFood), restaurante, mercado, transporte, combustivel
(Combustível), farmacia (Farmácia), compras, assinaturas, viagem, lazer e outro.
Índices buscados sob demanda, não pelo cron
/api/indices busca na fonte quando o app pede. O cron continua gravando os fechamentos diários em mercado_hist.Yahoo Finance + CNBC como fontes; Stooq removido
IFIX.SA só traz o intradiário).query2), e a CNBC entra como reserva (.BVSP, .IFIX, .SPX, .IXIC, .DJI, .N225). Quando o Yahoo não cobre o período pedido, a CNBC é usada no lugar. Tudo passa pelo módulo api/_indices.js, que converte os formatos das duas fontes para o modelo do app.Composição do Ibovespa pela B3, com cache de 24h
participacao). A carteira muda só a cada 4 meses.Cache em memória, não na CDN
Map dentro da função (60 s a 15 min, conforme o período) e cache-control: private para o navegador. Se a fonte falhar, o servidor devolve o último dado bom com até 6h.Extrato em PDF lido no navegador
public/extrato.js). Para o servidor vão só as linhas confirmadas, já como movimentos, pelo /api/escrever de sempre.public/extrato.js precisa mudar. Cada pedido ao /api/escrever aceita até 100 operações, então importações maiores vão em mais de um pedido.Aviso de gastos disparado na gravação, não no cron
/api/escrever recalcula o mês atual se o pedido mexeu em movimentos (api/_alertasGastos.js, só cálculo). Se a faixa mudou, ele envia pelo api/_push.js e marca a chave em enviados. Tudo fica num try/catch: erro na notificação não muda a resposta.caixa/push.json. Pedidos que não mexem em gastos (como mudar a meta em Ajustes) e o que não passa pelo /api/escrever (importar backup) só disparam o aviso no próximo gasto gravado. Duas gravações no mesmo instante podem mandar o aviso duas vezes, mas a notificação tem a mesma tag e o celular mostra uma só.Ids determinísticos para gastos fixos e importação
fixo-<id>-<AAAA-MM>, e o gasto importado usa um id que sai da chave da linha do extrato (chaveExtrato).