15 KiB
title, description, published, date, tags, editor, dateCreated
| title | description | published | date | tags | editor | dateCreated |
|---|---|---|---|---|---|---|
| Notificação de Ponto | Sistema de notificação ponto | true | 2026-08-15T01:29:32.722Z | markdown | 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
entrada1esaida1; -
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.
flowchart TD
T["Usuários e administrador<br/>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.
-
Fazer
POSTde autenticação com e-mail e senha. -
Receber
client,tokene validade do token. -
Manter esses valores em memória, associados ao usuário.
-
Fazer
GETdo histórico com token, client e e-mail. -
A resposta contém os últimos oito apontamentos.
-
Se o histórico retornar erro de autenticação, autenticar novamente, atualizar
client,tokene validade e repetir a consulta uma única vez. -
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:
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:
-
Converter horários para
America/Sao_Paulo. -
Manter apenas registros da data atual.
-
Ordenar por hora crescente.
-
Considerar, no máximo, quatro pontos do dia.
-
Interpretar a sequência como:
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.
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.
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:
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:
bruno14082026entrada2
bruno14082026saida2
A garantia técnica deve ser a restrição única:
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
flowchart TD
I["Ciclo do agendador, por usuário"] --> D{"É dia útil?<br/>Segunda a sexta"}
D -->|Não| X["Encerrar ciclo"]
D -->|Sim| A{"Existe agendamento vencido<br/>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:<br/>entrada2 = saida1 + 55 min"]
P -->|3| SA["Calcular saída2 e criar,<br/>se inexistente, o agendamento"]
P -->|4| F["Jornada completa;<br/>não criar lembretes"]
EN --> X
SA --> X
F --> X
8. Estrutura de pastas e arquivos
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
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
-
Criar repositório, estrutura de pastas e projeto Go (
go mod init). -
Implementar configuração, logs e SQLite com migrations.
-
Criar entidades de domínio e testes dos cálculos de 55 minutos e 7h55.
-
Implementar o cliente da API com mocks e teste de reautenticação.
-
Implementar persistência de usuários e agendamentos com a chave única.
-
Construir o ciclo do agendador usando dados simulados.
-
Integrar o Telegram: cadastro, aprovação e mensagens.
-
Fazer testes de ponta a ponta com um único usuário de teste.
-
Criar LXC, instalar o serviço e configurar backup.
-
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
entrada2parasaida1 + 55 min. -
Três pontos: cria apenas um agendamento de
saida2para 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.