Files
wiki/Codigos/notif_ponto.md

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:00:06.922Z 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 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.


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.

  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:


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:


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

  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.