From 08cf529a9d78c42f5d669c420c2ca4427eb846b5 Mon Sep 17 00:00:00 2001 From: Bruno OS Date: Sat, 15 Aug 2026 01:00:11 +0000 Subject: [PATCH] docs: create Codigos/notif_ponto --- Codigos/notif_ponto.md | 642 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 642 insertions(+) create mode 100644 Codigos/notif_ponto.md diff --git a/Codigos/notif_ponto.md b/Codigos/notif_ponto.md new file mode 100644 index 0000000..9b34892 --- /dev/null +++ b/Codigos/notif_ponto.md @@ -0,0 +1,642 @@ +--- +title: Notificação de Ponto +description: Sistema de notificação ponto +published: true +date: 2026-08-15T01:00:06.922Z +tags: +editor: markdown +dateCreated: 2026-08-15T01:00:06.922Z +--- + +# Plano do projeto — Bot de lembretes de ponto + +## 1. Objetivo + +Construir uma aplicação em Go que, por mensagens no Telegram, ajude aproximadamente dez usuários a não esquecerem a marcação de ponto. Cada usuário possui sua própria credencial na API de ponto. O sistema consulta o histórico de marcações, calcula os próximos eventos relevantes e envia lembretes de: + +- retorno do almoço (`entrada2`); + +- encerramento do expediente (`saida2`). + +Nesta primeira fase, o Telegram é a única interface. Uma interface web, destinada a um único administrador, será adicionada posteriormente sem duplicar as regras de negócio. + +## 2. Escopo da fase 1 + +Incluído: + +- bot Telegram para usuários e administrador; + +- solicitação e aprovação de cadastro pelo Telegram; + +- armazenamento em SQLite; + +- credencial de API individual por usuário, armazenada de forma criptografada; + +- autenticação na API de ponto e renovação automática do token; + +- leitura dos últimos oito apontamentos; + +- validação de pontos do dia atual; + +- criação persistente e envio único de lembretes; + +- execução em um container LXC Linux no Proxmox; + +- logs, auditoria e backup do banco. + +Fora do escopo inicial: + +- painel web administrativo; + +- regras para feriados municipais, estaduais e nacionais; + +- lembretes de `entrada1` e `saida1`; + +- múltiplos administradores; + +- integrações além de Telegram e API de ponto. + +## 3. Arquitetura + +O projeto será um monólito modular em Go. Para o volume esperado, um único processo, um SQLite e um LXC são suficientes, simples de manter e adequados para estudo. + +```mermaid + +flowchart TD + + T["Usuários e administrador
Telegram"] --> B["Adaptador Telegram"] + + B --> S["Serviços de aplicação"] + + S --> U["Usuários e cadastro"] + + S --> P["Cliente da API de ponto"] + + S --> R["Motor de regras"] + + S --> Q["Agendador de notificações"] + + S --> C["Calendário de dias úteis"] + + U --> DB[("SQLite")] + + R --> DB + + Q --> DB + + P --> API["API externa de ponto"] + + Q --> TG["API do Telegram"] + + W["Fase 2: painel web do administrador"] -. reutiliza os mesmos serviços .-> S + +``` + +### Princípios + +- O bot Telegram não contém cálculo de jornada: ele apenas recebe comandos e envia mensagens. + +- A API de ponto fica isolada em um módulo próprio. + +- As regras de horário ficam em serviços testáveis, sem dependência de Telegram, SQLite ou HTTP. + +- O SQLite registra estado suficiente para evitar mensagens duplicadas após reinício. + +- Tokens de API ficam somente em memória; senha e token nunca são escritos em logs. + +## 4. Integração com a API de ponto + +Cada usuário tem e-mail e senha próprios. + +1. Fazer `POST` de autenticação com e-mail e senha. + +2. Receber `client`, `token` e validade do token. + +3. Manter esses valores em memória, associados ao usuário. + +4. Fazer `GET` do histórico com token, client e e-mail. + +5. A resposta contém os últimos oito apontamentos. + +6. Se o histórico retornar erro de autenticação, autenticar novamente, atualizar `client`, `token` e validade e repetir a consulta uma única vez. + +7. Se o novo teste falhar, registrar erro de auditoria e tentar no próximo ciclo do agendador. + +> As senhas precisam ser criptografadas no SQLite. A chave de criptografia deve ser uma variável de ambiente do LXC, fora do repositório Git. + +## 5. Regras de negócio + +### 5.1 Dia útil + +Antes de consultar agendamentos ou a API, verificar se a data é segunda a sexta-feira. Em sábados e domingos, não consultar nem enviar lembretes. + +Validação de feriados de Belo Horizonte é uma evolução posterior. Desde o início, ela terá uma interface própria (`HolidayProvider`) para que possa ser incluída sem alterar o fluxo central: + +```text + +IsBusinessDay(data, localidade) = segunda a sexta E não é feriado + +``` + +Na fase 1, `não é feriado` será considerado verdadeiro; a localidade padrão será `Belo Horizonte/MG`. + +### 5.2 Pontos válidos + +O histórico vem com até oito registros. A aplicação deve: + +1. Converter horários para `America/Sao_Paulo`. + +2. Manter apenas registros da data atual. + +3. Ordenar por hora crescente. + +4. Considerar, no máximo, quatro pontos do dia. + +5. Interpretar a sequência como: + +```text + +entrada1 → saida1 → entrada2 → saida2 + +``` + +| Pontos no dia | Situação | + +| ---: | --- | + +| 0 | Falta `entrada1` | + +| 1 | Falta `saida1` | + +| 2 | Falta `entrada2` | + +| 3 | Falta `saida2` | + +| 4 | Jornada concluída | + +### 5.3 Lembrete de entrada2 + +Com dois pontos no dia, considerar que eles são `entrada1` e `saida1`. + +```text + +horário do lembrete de entrada2 = saida1 + 55 minutos + +``` + +Exemplo: com saída para almoço às 12:00, o lembrete é agendado para 12:55. + +### 5.4 Lembrete de saida2 + +Com três pontos no dia, considerar que eles são `entrada1`, `saida1` e `entrada2`. O objetivo diário é 7h55 de trabalho efetivo. + +```text + +trabalho_antes_do_almoco = saida1 - entrada1 + +tempo_restante = 7h55 - trabalho_antes_do_almoco + +horario_estimado_saida2 = entrada2 + tempo_restante + +``` + +O lembrete deve ser agendado para o horário calculado menos uma antecedência configurável. Inicialmente, sugerido: cinco minutos. + +Exemplo: + +```text + +entrada1: 08:00 + +saida1: 12:00 + +entrada2: 13:00 + +trabalho antes do almoço: 4h00 + +restante: 3h55 + +saida2 estimada: 16:55 + +lembrete: 16:50 (antecedência de 5 minutos) + +``` + +## 6. Agendamentos e prevenção de duplicidade + +Cada lembrete é persistido no SQLite com uma chave única. Uma chave legível pode seguir o formato: + +```text + +bruno14082026entrada2 + +bruno14082026saida2 + +``` + +A garantia técnica deve ser a restrição única: + +```text + +UNIQUE(user_id, reference_date, notification_type) + +``` + +Isso evita colisões se nome de usuário mudar ou dois nomes forem semelhantes. + +### Estados + +| Status | Significado | + +| --- | --- | + +| `scheduled` | Agendamento criado, ainda não é hora de enviar | + +| `ready_to_send` | O horário chegou; `execute_send = true` | + +| `sent` | Mensagem enviada com sucesso | + +| `cancelled` | Ponto foi detectado antes do lembrete ou o dia deixou de ser aplicável | + +| `failed` | Houve falha de envio; permite retentativa controlada | + +Pela regra aprovada, quando houver um agendamento pendente com `execute_send = true`, o sistema envia a mensagem sem nova consulta à API. Caso não exista agendamento ou ele esteja com `execute_send = false`, o sistema consulta o histórico para decidir se cria/cancela agendamentos. + +> Evolução recomendada: consultar a API uma última vez antes do envio. Isso elimina um falso lembrete quando a pessoa registra o ponto entre a última consulta e o horário agendado. + +## 7. Fluxograma operacional + +```mermaid + +flowchart TD + + I["Ciclo do agendador, por usuário"] --> D{"É dia útil?
Segunda a sexta"} + + D -->|Não| X["Encerrar ciclo"] + + D -->|Sim| A{"Existe agendamento vencido
com execute_send = true?"} + + A -->|Sim| T["Enviar mensagem Telegram"] + + T --> M["Registrar status sent e sent_at"] + + M --> X + + A -->|Não| H["Consultar histórico de pontos"] + + H --> E{"Erro de autenticação?"} + + E -->|Sim| L["Autenticar novamente"] + + L --> R["Atualizar client, token e validade"] + + R --> H + + E -->|Não| V["Filtrar pontos de hoje e ordenar"] + + V --> P{"Quantidade de pontos"} + + P -->|0 ou 1| X + + P -->|2| EN["Criar, se inexistente:
entrada2 = saida1 + 55 min"] + + P -->|3| SA["Calcular saída2 e criar,
se inexistente, o agendamento"] + + P -->|4| F["Jornada completa;
não criar lembretes"] + + EN --> X + + SA --> X + + F --> X + +``` + +## 8. Estrutura de pastas e arquivos + +```text + +bot-pontos/ + +├── cmd/ + +│ └── bot/ + +│ └── main.go + +├── internal/ + +│ ├── app/ + +│ │ └── application.go + +│ ├── config/ + +│ │ └── config.go + +│ ├── domain/ + +│ │ ├── user.go + +│ │ ├── workday.go + +│ │ ├── notification.go + +│ │ └── point.go + +│ ├── pointsapi/ + +│ │ ├── client.go + +│ │ ├── auth.go + +│ │ └── models.go + +│ ├── rules/ + +│ │ ├── point_validator.go + +│ │ ├── schedule_calculator.go + +│ │ └── business_day.go + +│ ├── scheduler/ + +│ │ └── scheduler.go + +│ ├── telegram/ + +│ │ ├── bot.go + +│ │ ├── commands.go + +│ │ └── messages.go + +│ ├── repository/ + +│ │ ├── sqlite.go + +│ │ ├── users.go + +│ │ ├── notifications.go + +│ │ └── audit.go + +│ ├── security/ + +│ │ └── credentials.go + +│ └── audit/ + +│ └── logger.go + +├── migrations/ + +│ ├── 001_initial_schema.sql + +│ └── 002_indexes.sql + +├── configs/ + +│ └── config.example.yaml + +├── deploy/ + +│ ├── bot-pontos.service + +│ └── backup-sqlite.sh + +├── tests/ + +│ ├── rules_test.go + +│ └── scheduler_test.go + +├── .env.example + +├── .gitignore + +├── go.mod + +├── go.sum + +├── README.md + +└── PLANO_PROJETO_BOT_PONTOS.md + +``` + +### Responsabilidade de cada arquivo + +| Arquivo/pasta | Responsabilidade | + +| --- | --- | + +| `cmd/bot/main.go` | Inicializa configuração, banco, bot, agendador e encerra o processo com segurança. | + +| `internal/app/application.go` | Conecta dependências e descreve os casos de uso principais. | + +| `internal/config/config.go` | Lê variáveis de ambiente e parâmetros: Telegram, banco, criptografia, fuso e intervalo do ciclo. | + +| `internal/domain/*.go` | Entidades puras: usuário, ponto, jornada e notificação; sem HTTP ou SQLite. | + +| `internal/pointsapi/client.go` | Requisições HTTP à API; consulta o histórico. | + +| `internal/pointsapi/auth.go` | Login, cache em memória e renovação de token por usuário. | + +| `internal/pointsapi/models.go` | Estruturas de request/response da API externa e conversão para o domínio. | + +| `internal/rules/point_validator.go` | Filtra pontos de hoje, ordena e determina se há 0, 1, 2, 3 ou 4 registros. | + +| `internal/rules/schedule_calculator.go` | Calcula `saida1 + 55 min` e a `saida2` baseada em 7h55. | + +| `internal/rules/business_day.go` | Verifica segunda a sexta; depois receberá o provedor de feriados de Belo Horizonte. | + +| `internal/scheduler/scheduler.go` | Executa o ciclo periódico: envia vencidos ou consulta a API/cria agendamentos. | + +| `internal/telegram/bot.go` | Mantém conexão e atualização do bot Telegram. | + +| `internal/telegram/commands.go` | Trata `/iniciar`, `/status`, `/cadastrar`, `/aprovar` e comandos administrativos. | + +| `internal/telegram/messages.go` | Centraliza textos das notificações e respostas do bot. | + +| `internal/repository/sqlite.go` | Abre SQLite, aplica migrations e configura modo WAL. | + +| `internal/repository/users.go` | CRUD de usuários, pedidos de cadastro e permissões. | + +| `internal/repository/notifications.go` | Cria, busca, atualiza e deduplica agendamentos. | + +| `internal/repository/audit.go` | Persiste erros, ações administrativas e eventos relevantes. | + +| `internal/security/credentials.go` | Criptografa/descriptografa credenciais individuais dos usuários. | + +| `migrations/` | Evolução versionada do esquema SQLite. | + +| `deploy/bot-pontos.service` | Serviço `systemd` para manter o binário ativo no LXC. | + +| `deploy/backup-sqlite.sh` | Backup consistente diário do banco SQLite. | + +| `tests/` | Testes unitários para cálculos e para o fluxo de agendamento. | + +## 9. Modelo inicial de banco + +```text + +users + +- id + +- telegram_chat_id (único) + +- display_name + +- api_email + +- encrypted_api_password + +- role (user | admin) + +- status (pending | active | disabled) + +- created_at + +- updated_at + +work_rules + +- id + +- user_id (único) + +- lunch_reminder_after_minutes (padrão 55) + +- daily_work_minutes (padrão 475 = 7h55) + +- exit_reminder_lead_minutes (padrão 5) + +- timezone (America/Sao_Paulo) + +- active + +scheduled_notifications + +- id + +- notification_key + +- user_id + +- reference_date + +- notification_type (entrada2 | saida2) + +- scheduled_at + +- execute_send + +- status + +- sent_at + +- telegram_message_id + +- created_at + +- updated_at + +audit_logs + +- id + +- user_id (opcional) + +- event_type + +- details + +- created_at + +``` + +## 10. Ambiente LXC no Proxmox + +Recomendação inicial: + +- Debian 12; + +- 1 vCPU; + +- 1 GB de RAM; + +- 8 a 16 GB de disco; + +- fuso horário `America/Sao_Paulo`; + +- saída HTTPS para a API de ponto e para o Telegram; + +- serviço Go controlado por `systemd`; + +- banco em `/var/lib/bot-pontos/app.db`; + +- backup diário do SQLite e backup periódico do próprio LXC pelo Proxmox. + +Em produção, o LXC precisa apenas do binário Go compilado, certificados CA, dados de fuso horário e SQLite. O compilador Go pode ficar apenas no ambiente de desenvolvimento ou CI. + +## 11. Sequência de implementação para estudo + +1. Criar repositório, estrutura de pastas e projeto Go (`go mod init`). + +2. Implementar configuração, logs e SQLite com migrations. + +3. Criar entidades de domínio e testes dos cálculos de 55 minutos e 7h55. + +4. Implementar o cliente da API com mocks e teste de reautenticação. + +5. Implementar persistência de usuários e agendamentos com a chave única. + +6. Construir o ciclo do agendador usando dados simulados. + +7. Integrar o Telegram: cadastro, aprovação e mensagens. + +8. Fazer testes de ponta a ponta com um único usuário de teste. + +9. Criar LXC, instalar o serviço e configurar backup. + +10. Cadastrar os demais usuários gradualmente. + +## 12. Casos de teste mínimos + +- Sábado ou domingo: nenhuma consulta e nenhuma notificação. + +- Dois pontos: cria apenas um agendamento de `entrada2` para `saida1 + 55 min`. + +- Três pontos: cria apenas um agendamento de `saida2` para completar 7h55. + +- Quatro pontos: não cria lembrete. + +- Mesmo ciclo rodado duas vezes: não duplica a mesma chave de agendamento. + +- Reinício da aplicação: agendamento persiste e é enviado uma vez. + +- Token expirado: autentica novamente e repete a consulta. + +- Falha contínua na API ou Telegram: registra auditoria sem travar os demais usuários. + +## 13. Evoluções posteriores + +- Feriados de Belo Horizonte/MG e feriados nacionais por um `HolidayProvider` (API ou calendário local com atualização controlada). + +- Painel web para o administrador com autenticação. + +- Tela de usuários, regras, agendamentos, auditoria e erros. + +- Revalidação da API antes de cada envio para eliminar lembretes obsoletos. + +- Painel de saúde da aplicação e alertas para falhas repetidas. + +- Migração para PostgreSQL apenas se o número de usuários, concorrência ou necessidade de relatórios crescer substancialmente. + +## 14. Resultado esperado + +O projeto é viável para uso diário: o volume é baixo, as regras são objetivas e SQLite atende bem. Também é um bom projeto de estudo porque exercita Go, HTTP, autenticação, persistência, criptografia, agendamento, testes, operações Linux e integração com Telegram, sem introduzir complexidade de microserviços cedo demais. +