{
  "id": "notificacoes",
  "title": "Notificações",
  "description": "Alertas persistidos no banco, filtráveis no painel e distribuídos opcionalmente por Telegram e e-mail.",
  "type": "feature",
  "status": "observed",
  "visibility": "public",
  "tags": [
    "notificações",
    "telegram",
    "e-mail",
    "filas"
  ],
  "related": [
    "automacoes",
    "financas",
    "nfce",
    "auditoria",
    "dashboard"
  ],
  "sourceRefs": [
    "https://github.com/james-suite/james/blob/master/routes/web.php",
    "https://github.com/james-suite/james/blob/master/app/Http/Controllers/NotificationController.php",
    "https://github.com/james-suite/james/blob/master/app/Notifications/GeneralNotification.php",
    "https://github.com/james-suite/james/blob/master/app/Notifications/DueTodayNotification.php",
    "https://github.com/james-suite/james/blob/master/app/Notifications/FinancialSummaryNotification.php",
    "https://github.com/james-suite/james/blob/master/app/Console/Commands/SendDueTodayAlerts.php",
    "https://github.com/james-suite/james/blob/master/app/Console/Commands/SendMonthlyFinancialDigest.php",
    "https://github.com/james-suite/james/blob/master/app/Jobs/ScrapeNfceInvoiceJob.php"
  ],
  "authors": [],
  "updated": null,
  "diagram": null,
  "body": "## O que o módulo entrega\n\nNotificações é a camada de comunicação do James. Ela transforma eventos de finanças, automações, importações e rotinas em mensagens com título, nível, detalhes e uma ação que leva de volta ao sistema.\n\nOs fluxos automáticos persistem suas notificações no banco de dados. `GeneralNotification` faz isso quando `database` está presente em `channels`; Telegram e e-mail são canais complementares e podem estar desabilitados sem impedir o registro interno quando ele foi solicitado.\n\n{{diagram:notifications-flow}}\n\n## Contrato de uma notificação\n\n`GeneralNotification` recebe um payload estável:\n\n```php\nnew GeneralNotification(\n    title: 'Título curto',\n    message: 'Explicação do que aconteceu.',\n    actionUrl: route('financial.dashboard'),\n    level: NotificationLevel::Warning,\n    details: ['Valor' => 'R$ 150,00'],\n    channels: ['database', 'telegram', 'mail'],\n    actionLabel: 'Abrir painel',\n    items: [],\n)\n```\n\n| Campo | Uso |\n| --- | --- |\n| `title` | Título exibido no painel, e-mail e Telegram. |\n| `message` | Texto principal da ocorrência. |\n| `action_url` | Link opcional para a tela relacionada. |\n| `action_label` | Texto do botão da ação. |\n| `level` | `info`, `success`, `warning` ou `danger`. |\n| `details` | Mapa chave/valor para metadados legíveis. |\n| `items` | Lista de itens com descrição, quantidade, preço unitário e total. |\n| `channels` | Canais desejados para `GeneralNotification`. |\n\nAs notificações específicas de vencimentos e resumo financeiro usam payloads adicionais (`due_alert` e `financial_summary`) para renderizar blocos estruturados na interface e nas mensagens externas.\n\n## Níveis\n\n| Case | Valor | Uso visual |\n| --- | --- | --- |\n| `NotificationLevel::Info` | `info` | Informação ou conclusão sem alerta. |\n| `NotificationLevel::Success` | `success` | Operação concluída com êxito. |\n| `NotificationLevel::Warning` | `warning` | Prazo, pendência ou atenção necessária. |\n| `NotificationLevel::Danger` | `danger` | Erro, falha ou risco financeiro. |\n\nCada nível fornece rótulo, cor e ícone Heroicon. No e-mail, o nível `Danger` usa o estilo de erro do Laravel Mail; no Telegram, o nível aparece em caixa alta no cabeçalho.\n\n## De onde as notificações vêm\n\n### Alertas de vencimentos\n\nO comando `finance:due-today-alerts` procura itens para hoje e amanhã em três fontes:\n\n- transações pendentes ou efetivadas que se enquadram no período;\n- faturas de cartão não pagas com vencimento no período;\n- recorrências ativas ainda não materializadas, sem duplicar as recorrências já representadas pela fatura do cartão.\n\nO alerta consolida quantidade, receitas, despesas, impacto líquido e a lista de dias/itens. Ele não é enviado quando não há itens. Um cache por usuário impede reenvio do mesmo dia; `--force` permite reenviar manualmente.\n\n### Resumo financeiro mensal\n\nO comando `finance:monthly-digest` calcula o mês anterior e compara receitas, despesas e resultado com o mês anterior a ele. O resumo inclui:\n\n- receitas, despesas e resultado do período;\n- variações em relação ao período comparado;\n- saldo atual das contas;\n- compromissos pendentes;\n- saldo líquido;\n- distribuição por categorias de receita e despesa.\n\nO envio mensal também usa uma chave de cache por usuário e período. `--force` permite repetir o resumo quando necessário.\n\n### Rotinas e importação de NFC-e\n\nO processamento de recorrências, a rolagem de faturas e outras automações usam `GeneralNotification` para informar sucesso ou falha. A importação assíncrona de NFC-e envia uma notificação com ação para abrir o rascunho ou tentar novamente. Consulte [Rotinas automáticas](doc:automacoes) e [Importação de NFC-e](doc:nfce).\n\n## Canais de entrega\n\n### Banco de dados\n\nÉ o canal interno e alimenta `/notifications`. O JSON persistido contém o payload da notificação e permite renderizar detalhes, itens, nível e ação sem depender do canal externo.\n\n### Telegram\n\nO canal é usado somente quando `TELEGRAM_BOT_TOKEN` e `TELEGRAM_CHAT_ID` estão preenchidos. A mensagem inclui título, texto, detalhes, itens e botão de ação quando a URL é externa.\n\nSe a URL aponta para `localhost` ou `127.0.0.1`, o James não cria um botão inline inválido para a API do Telegram; ele coloca o endereço como texto seguro na mensagem.\n\n### E-mail\n\nO e-mail exige destinatário com endereço preenchido e `NOTIFICATIONS_MAIL_ENABLED=true`. A mensagem usa os templates transacionais do Laravel, inclui detalhes e itens e adiciona um botão quando existe `actionUrl`.\n\n### Filas\n\n`GeneralNotification`, `DueTodayNotification` e `FinancialSummaryNotification` implementam `ShouldQueue`. Em produção, o worker precisa estar ativo para que as notificações queued sejam processadas. O registro no banco, o envio externo e a disponibilidade da fila devem ser tratados como partes distintas do fluxo.\n\n## Central `/notifications`\n\nO painel autenticado permite:\n\n- pesquisar no payload JSON da notificação;\n- filtrar por `unread` ou `read`;\n- filtrar por data inicial e final;\n- ordenar do mais novo para o mais antigo ou vice-versa;\n- navegar por páginas de 20 registros;\n- abrir uma notificação, marcando-a como lida;\n- marcar todas as notificações como lidas;\n- excluir uma notificação individual.\n\nO contador da sidebar e o cartão do Dashboard usam somente notificações não lidas. A tela de detalhes verifica se a notificação pertence ao usuário autenticado antes de exibi-la ou alterá-la.\n\n## Exemplos para desenvolvimento\n\n### Notificação somente interna\n\n```php\nuse App\\Notifications\\GeneralNotification;\n\n$user->notify(new GeneralNotification(\n    title: 'Rascunho pronto',\n    message: 'A NFC-e foi importada e aguarda revisão.',\n    actionUrl: route('financial.transactions.edit', $transaction),\n    channels: ['database'],\n));\n```\n\n### Notificação com itens\n\n```php\n$user->notify(new GeneralNotification(\n    title: 'Importação concluída',\n    message: 'Revise os itens antes de efetivar a transação.',\n    details: ['Emitente' => 'Comércio exemplo', 'Total' => 'R$ 120,00'],\n    items: [\n        ['description' => 'Produto', 'quantity' => '2', 'unit_price' => 'R$ 60,00', 'total' => 'R$ 120,00'],\n    ],\n));\n```\n\nNos testes, use `Notification::fake()` e faça asserções por destinatário, classe, nível, título e payload. O projeto mantém testes de unidade para os três formatos de notificação e testes de feature para a central web.\n\n### Referências\n\n- [Rotinas automáticas](doc:automacoes) — comandos que produzem alertas.\n- [Finanças](doc:financas) — origem de vencimentos e resumos.\n- [Auditoria e logs](doc:auditoria) — rastreia as mutações que deram origem a parte dos avisos.",
  "sections": [
    {
      "id": "o-que-o-modulo-entrega",
      "level": 2,
      "title": "O que o módulo entrega",
      "text": "Notificações é a camada de comunicação do James. Ela transforma eventos de finanças, automações, importações e rotinas em mensagens com título, nível, detalhes e uma ação que leva de volta ao sistema.  Os fluxos automáticos persistem suas notificações no banco de dados. `GeneralNotification` faz isso quando `database` está presente em `channels`; Telegram e e-mail são canais complementares e podem estar desabilitados sem impedir o registro interno quando ele foi solicitado.",
      "line": 1
    },
    {
      "id": "contrato-de-uma-notificacao",
      "level": 2,
      "title": "Contrato de uma notificação",
      "text": "`GeneralNotification` recebe um payload estável:   | Campo | Uso | | --- | --- | | `title` | Título exibido no painel, e-mail e Telegram. | | `message` | Texto principal da ocorrência. | | `action_url` | Link opcional para a tela relacionada. | | `action_label` | Texto do botão da ação. | | `level` | `info`, `success`, `warning` ou `danger`. | | `details` | Mapa chave/valor para metadados legíveis. | | `items` | Lista de itens com descrição, quantidade, preço unitário e total. | | `channels` | Canais desejados para `GeneralNotification`. |  As notificações específicas de vencimentos e resumo financeiro usam payloads adicionais (`due_alert` e `financial_summary`) para renderizar blocos estruturados na interface e nas mensagens externas.",
      "line": 9
    },
    {
      "id": "niveis",
      "level": 2,
      "title": "Níveis",
      "text": "| Case | Valor | Uso visual | | --- | --- | --- | | `NotificationLevel::Info` | `info` | Informação ou conclusão sem alerta. | | `NotificationLevel::Success` | `success` | Operação concluída com êxito. | | `NotificationLevel::Warning` | `warning` | Prazo, pendência ou atenção necessária. | | `NotificationLevel::Danger` | `danger` | Erro, falha ou risco financeiro. |  Cada nível fornece rótulo, cor e ícone Heroicon. No e-mail, o nível `Danger` usa o estilo de erro do Laravel Mail; no Telegram, o nível aparece em caixa alta no cabeçalho.",
      "line": 39
    },
    {
      "id": "de-onde-as-notificacoes-vem",
      "level": 2,
      "title": "De onde as notificações vêm",
      "text": "",
      "line": 50
    },
    {
      "id": "alertas-de-vencimentos",
      "level": 3,
      "title": "Alertas de vencimentos",
      "text": "O comando `finance:due-today-alerts` procura itens para hoje e amanhã em três fontes:  - transações pendentes ou efetivadas que se enquadram no período; - faturas de cartão não pagas com vencimento no período; - recorrências ativas ainda não materializadas, sem duplicar as recorrências já representadas pela fatura do cartão.  O alerta consolida quantidade, receitas, despesas, impacto líquido e a lista de dias/itens. Ele não é enviado quando não há itens. Um cache por usuário impede reenvio do mesmo dia; `--force` permite reenviar manualmente.",
      "line": 52
    },
    {
      "id": "resumo-financeiro-mensal",
      "level": 3,
      "title": "Resumo financeiro mensal",
      "text": "O comando `finance:monthly-digest` calcula o mês anterior e compara receitas, despesas e resultado com o mês anterior a ele. O resumo inclui:  - receitas, despesas e resultado do período; - variações em relação ao período comparado; - saldo atual das contas; - compromissos pendentes; - saldo líquido; - distribuição por categorias de receita e despesa.  O envio mensal também usa uma chave de cache por usuário e período. `--force` permite repetir o resumo quando necessário.",
      "line": 62
    },
    {
      "id": "rotinas-e-importacao-de-nfc-e",
      "level": 3,
      "title": "Rotinas e importação de NFC-e",
      "text": "O processamento de recorrências, a rolagem de faturas e outras automações usam `GeneralNotification` para informar sucesso ou falha. A importação assíncrona de NFC-e envia uma notificação com ação para abrir o rascunho ou tentar novamente. Consulte [Rotinas automáticas](doc:automacoes) e [Importação de NFC-e](doc:nfce).",
      "line": 75
    },
    {
      "id": "canais-de-entrega",
      "level": 2,
      "title": "Canais de entrega",
      "text": "",
      "line": 79
    },
    {
      "id": "banco-de-dados",
      "level": 3,
      "title": "Banco de dados",
      "text": "É o canal interno e alimenta `/notifications`. O JSON persistido contém o payload da notificação e permite renderizar detalhes, itens, nível e ação sem depender do canal externo.",
      "line": 81
    },
    {
      "id": "telegram",
      "level": 3,
      "title": "Telegram",
      "text": "O canal é usado somente quando `TELEGRAM_BOT_TOKEN` e `TELEGRAM_CHAT_ID` estão preenchidos. A mensagem inclui título, texto, detalhes, itens e botão de ação quando a URL é externa.  Se a URL aponta para `localhost` ou `127.0.0.1`, o James não cria um botão inline inválido para a API do Telegram; ele coloca o endereço como texto seguro na mensagem.",
      "line": 85
    },
    {
      "id": "e-mail",
      "level": 3,
      "title": "E-mail",
      "text": "O e-mail exige destinatário com endereço preenchido e `NOTIFICATIONS_MAIL_ENABLED=true`. A mensagem usa os templates transacionais do Laravel, inclui detalhes e itens e adiciona um botão quando existe `actionUrl`.",
      "line": 91
    },
    {
      "id": "filas",
      "level": 3,
      "title": "Filas",
      "text": "`GeneralNotification`, `DueTodayNotification` e `FinancialSummaryNotification` implementam `ShouldQueue`. Em produção, o worker precisa estar ativo para que as notificações queued sejam processadas. O registro no banco, o envio externo e a disponibilidade da fila devem ser tratados como partes distintas do fluxo.",
      "line": 95
    },
    {
      "id": "central-notifications",
      "level": 2,
      "title": "Central /notifications",
      "text": "O painel autenticado permite:  - pesquisar no payload JSON da notificação; - filtrar por `unread` ou `read`; - filtrar por data inicial e final; - ordenar do mais novo para o mais antigo ou vice-versa; - navegar por páginas de 20 registros; - abrir uma notificação, marcando-a como lida; - marcar todas as notificações como lidas; - excluir uma notificação individual.  O contador da sidebar e o cartão do Dashboard usam somente notificações não lidas. A tela de detalhes verifica se a notificação pertence ao usuário autenticado antes de exibi-la ou alterá-la.",
      "line": 99
    },
    {
      "id": "exemplos-para-desenvolvimento",
      "level": 2,
      "title": "Exemplos para desenvolvimento",
      "text": "",
      "line": 114
    },
    {
      "id": "notificacao-somente-interna",
      "level": 3,
      "title": "Notificação somente interna",
      "text": "",
      "line": 116
    },
    {
      "id": "notificacao-com-itens",
      "level": 3,
      "title": "Notificação com itens",
      "text": "Nos testes, use `Notification::fake()` e faça asserções por destinatário, classe, nível, título e payload. O projeto mantém testes de unidade para os três formatos de notificação e testes de feature para a central web.",
      "line": 129
    },
    {
      "id": "referencias",
      "level": 3,
      "title": "Referências",
      "text": "- [Rotinas automáticas](doc:automacoes) — comandos que produzem alertas. - [Finanças](doc:financas) — origem de vencimentos e resumos. - [Auditoria e logs](doc:auditoria) — rastreia as mutações que deram origem a parte dos avisos.",
      "line": 144
    }
  ],
  "sourcePath": "content/notificacoes.md",
  "visuals": [
    {
      "id": "notifications-flow",
      "kind": "flowchart",
      "title": "Fluxo de notificações",
      "description": "Uma notificação é persistida e pode ser distribuída por canais externos configurados.",
      "summary": "Eventos do sistema passam por GeneralNotification e pelo pipeline de canais. O banco é o canal interno; Telegram e e-mail são opcionais conforme a configuração.",
      "renderMode": "mermaid",
      "api": "api/diagrams/notifications-flow.json",
      "human": "diagrams/notifications-flow.html"
    }
  ],
  "apiVersion": 1
}
