From e6603f2cb9a4ba605b80508fbff6e4522e01d2d6 Mon Sep 17 00:00:00 2001 From: Bruno Santos Date: Thu, 5 Nov 2026 22:31:13 -0300 Subject: [PATCH] docs --- README.md | 2 +- docs/ARQUITETURA.md | 80 +++++++++++++++++++++++++++++++++++++++++- docs/MANUAL_USUARIO.md | 10 +++--- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5bded98..3df3969 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Documentação: - [docs/MANUAL_USUARIO.md](docs/MANUAL_USUARIO.md): manual do usuário do Telegram e do administrador do painel; - [docs/DEPLOY.md](docs/DEPLOY.md): passo a passo de implantação e atualização no servidor; -- [docs/ARQUITETURA.md](docs/ARQUITETURA.md): arquitetura, regras de negócio e decisões; +- [docs/ARQUITETURA.md](docs/ARQUITETURA.md): arquitetura, regras de negócio e decisões, com referência de variáveis de ambiente (seção 17) e eventos de auditoria (seção 18); - [secrets/README.md](secrets/README.md): segredos e troca da chave de criptografia; - [backend/api/openapi.yaml](backend/api/openapi.yaml): contrato da API REST. diff --git a/docs/ARQUITETURA.md b/docs/ARQUITETURA.md index 1c399b1..4b69237 100644 --- a/docs/ARQUITETURA.md +++ b/docs/ARQUITETURA.md @@ -643,7 +643,7 @@ Um lembrete `failed` pode ser reenviado **manualmente** pelo painel, num botão | --- | --- | | Quem pode | Papel `admin` ou `owner` | | O que pode ser reenviado | Só status `failed` e `reference_date` = dia atual (no fuso do usuário). `expired`, `cancelled` e `sent` não podem. | -| Pré-condições | Usuário `active` e com lembretes ligados. Se o ponto seguinte já tiver sido batido (ex.: `entrada2` já registrada), o painel avisa e bloqueia o reenvio. | +| Pré-condições | Usuário `active` e com lembretes ligados. Antes de reenviar, a API consulta a PontoMais ao vivo: se o ponto seguinte já tiver sido batido (ex.: `entrada2` já registrada), o reenvio é bloqueado; se a PontoMais não responder, o reenvio também é recusado (`409`) e pode ser tentado de novo depois. | | Confirmação | O diálogo avisa que, se a falha foi um *crash* durante o envio (`sending` → `failed`), o usuário **pode já ter recebido** a mensagem original. | | Execução | `UPDATE notifications SET status='sending', attempts=attempts+1 WHERE id=$1 AND status='failed' RETURNING *`. A troca de status é atômica, então um duplo clique ou dois admins ao mesmo tempo resultam em um único envio. O envio acontece na hora, sem esperar o próximo despacho. | | Tolerância de 10 min | **Não se aplica**: o reenvio é uma decisão consciente do admin. A mensagem informa o horário previsto ("estava previsto para 13:02" se já tiver passado). | @@ -1148,3 +1148,81 @@ Os comandos para rodar os testes em containers estão no `README.md` ("Desenvolv - medir no piloto o atraso do `last_cached` da PontoMais (8.2). **Pendências de código:** testes de integração com Postgres real, testes de contrato e testes web (13); endpoint `/metrics`, se um dia houver Prometheus (12). + +## 17. Referência: variáveis de ambiente + +Todas são lidas por `backend/internal/config/config.go`. Segredos aceitam a variante `_FILE`, que aponta para um arquivo (é assim que o Compose passa os Docker secrets). Na prática só as do `.env.example` precisam ser ajustadas; as demais têm padrão. + +**Usadas só pelo Compose** (`.env`): `BP_HOST_LAN_IP` (IP onde o painel é publicado, obrigatória), `BP_WEB_PORT` (porta do painel no host, padrão `3000`) e `BP_NPM_IP` (somado a `BP_TRUSTED_PROXIES`). + +| Variável | Padrão | Uso | +| --- | --- | --- | +| `BP_LOG_LEVEL` | `info` | `debug`, `info`, `warn` ou `error` | +| `BP_DEFAULT_TIMEZONE` | `America/Sao_Paulo` | Fuso padrão: novos usuários, hora da retenção e o "hoje" das rotinas globais | +| `BP_DB_HOST` · `BP_DB_PORT` · `BP_DB_NAME` | `postgres` · `5432` · `botpontos` | Conexão com o banco | +| `BP_DB_USER` · `BP_DB_PASSWORD(_FILE)` | — (obrigatórias) | `botpontos_app` na `api`/`worker`; `botpontos` no `migrate` | +| `BP_DB_MAX_CONNS` | `10` | Pool (o Compose usa 10 na `api` e 5 no `worker`) | +| `BP_HTTP_ADDR` | `:8080` | Endereço da API | +| `BP_WORKER_HEALTH_ADDR` | `:8081` | Health do worker | +| `BP_WORKER_LEADER_RETRY` | `10s` | Intervalo entre tentativas de obter a liderança (4.3) | +| `BP_RECONCILIATION_INTERVAL` | `15m` | Tick da reconciliação (8.2) | +| `BP_RECONCILIATION_DEADLINE` | `5m` | Prazo total de um ciclo de reconciliação | +| `BP_RECONCILIATION_WORKERS` | `4` | Usuários consultados em paralelo | +| `BP_DISPATCH_INTERVAL` | `2m` | Tick do despacho | +| `BP_MAINTENANCE_INTERVAL` | `5m` | Tick da manutenção | +| `BP_LATE_TOLERANCE` | `10m` | Atraso máximo para ainda enviar (9.3) | +| `BP_SENDING_TIMEOUT` | `5m` | `sending` parado vira `failed` (6.3) | +| `BP_SLOW_CHECK_INTERVAL` | `60m` | Consultas lentas (9.12) | +| `BP_EXIT_CONFIRM_WINDOW` | `20m..5m` | Janela da consulta de confirmação antes do `saida2` | +| `BP_API_FAILURE_THRESHOLD` | `3` | Falhas seguidas até pausar (9.4) | +| `BP_RETENTION_AUDIT` · `BP_RETENTION_NOTIFICATIONS` · `BP_RETENTION_SESSIONS` | `8760h` · `2160h` · `168h` | Retenção (9.10) | +| `BP_RETENTION_HOUR` | `3` | Hora da limpeza diária | +| `BP_QUERY_WINDOW_START` · `BP_DAY_CHECK_DEADLINE` · `BP_NO_POINTS_RECHECK_UNTIL` · `BP_QUERY_WINDOW_END` | `11:30` · `11:45` · `15:00` · `19:00` | Só os padrões gravados na 1ª subida (9.13) | +| `BP_PONTOMAIS_AUTH_URL` · `BP_PONTOMAIS_HISTORY_URL` | URLs de `api.pontomais.com.br` | Login e histórico (`last_cached`) | +| `BP_PONTOMAIS_TIMEOUT` | `10s` | Timeout por chamada à PontoMais | +| `BP_ENCRYPTION_KEY(_FILE)` | — (obrigatória, ≥ 32 caracteres) | Chave AES-256 das senhas da PontoMais | +| `BP_ENCRYPTION_KEY_VERSION` | `1` | Versão da chave atual | +| `BP_ENCRYPTION_PREVIOUS_KEY(_FILE)` · `BP_ENCRYPTION_PREVIOUS_KEY_VERSION` | vazio · `0` | Só durante a troca de chave (`secrets/README.md`) | +| `BP_TELEGRAM_TOKEN(_FILE)` | — (obrigatória no `worker`) | Token do @BotFather | +| `BP_TELEGRAM_POLL_TIMEOUT` | `25` | Segundos do *long polling* | +| `BP_HOLIDAY_API_BASE_URL` | `https://feriadosapi.com/api/v1` | Base da API de feriados | +| `BP_HOLIDAY_API_KEY(_FILE)` | vazio | Chave da feriadosapi.com (vazio = fallback seg–sex) | +| `BP_HOLIDAY_LOCATION` | `3106200` | Código IBGE da cidade (9.9) | +| `BP_PUBLIC_URL` | vazio | URL pública do painel, usada na checagem de `Origin` (vazio só em desenvolvimento) | +| `BP_COOKIE_SECURE` | `true` | Cookies `Secure` (use `false` só em `http://` local) | +| `BP_SESSION_DURATION` · `BP_SESSION_IDLE` | `8h` · `30m` | Sessão absoluta e ociosa | +| `BP_LOGIN_MAX_FAILURES` · `BP_LOGIN_LOCK` | `5` · `15m` | Bloqueio de login | +| `BP_TRUSTED_PROXIES` | `127.0.0.0/8,172.16.0.0/12` | Proxies cujo `X-Forwarded-For` é aceito (11.4) | + +## 18. Referência: eventos de auditoria + +O filtro **Evento** da tela Auditoria compara o nome exato (ex.: `user_activated`). Origem: `telegram`, `web` (painel), `worker` ou `cli`. + +| Evento | Quando é gravado | +| --- | --- | +| `user_registered` | `/cadastrar` | +| `user_activated` · `user_disabled` | Ativação ou desativação do usuário (painel ou Telegram) | +| `bot_admin_changed` | Liga/desliga o admin do bot | +| `schedule_changed` · `user_window_changed` | Jornada alterada; janela personalizada criada, alterada ou removida (9.14) | +| `schedule_window_violation` | Na subida do worker, jornada fora da regra de 9.8 | +| `credentials_changed` · `credentials_tested` | Credencial PontoMais salva; teste da credencial | +| `notifications_enabled` · `notifications_disabled` | Lembretes ligados ou pausados (usuário ou painel) | +| `notifications_paused_api_failure` | Pausa automática após 3 falhas (9.4) | +| `point_api_failure` | Falha individual na consulta à PontoMais | +| `point_api_outage_started` · `point_api_outage_ended` | Início e fim de queda geral da PontoMais | +| `invalid_point_history` · `invalid_workday_calculation` | Pontos fora de ordem ou cálculo impossível | +| `day_no_points` · `day_not_worked` · `day_resumed` | Situação do dia (9.12) | +| `notification_scheduled` · `notification_sent` · `notification_failed` | Lembrete agendado, enviado ou com erro no Telegram | +| `notification_expired` | Atraso acima da tolerância (9.3) | +| `notification_cancelled` | Cancelado (ponto seguinte batido, pausa ou painel) | +| `notification_interrupted` | `sending` parado, marcado como `failed` pela manutenção | +| `notification_resent` | Reenvio manual (9.5) | +| `holiday_synced` · `holiday_sync_failed` | Sincronização de feriados com sucesso ou falha (fallback) | +| `holiday_added` · `holiday_removed` | Feriado manual cadastrado ou removido | +| `settings_changed` | Janela global alterada (9.13) | +| `web_login` · `web_login_failed` · `web_logout` | Acesso ao painel | +| `web_account_created` · `web_account_changed` · `web_account_deleted` · `web_password_reset` | Gestão de contas do painel | +| `retention_applied` | Limpeza diária (9.10) | +| `encryption_key_rotated` | `botpontos admin rotate-key` | + +A constante `telegram_failure` existe no código (`domain/audit.go`), mas hoje nenhum ponto grava esse evento: falhas ao avisar os admins pelo Telegram ficam só no log. diff --git a/docs/MANUAL_USUARIO.md b/docs/MANUAL_USUARIO.md index ce91a75..defa18f 100644 --- a/docs/MANUAL_USUARIO.md +++ b/docs/MANUAL_USUARIO.md @@ -242,7 +242,7 @@ Faixas de alerta aparecem no topo quando: - **a PontoMais está fora do ar:** ninguém é pausado; aguarde; - **os feriados do ano não foram obtidos:** segunda a sexta estão valendo como dias úteis. Cadastre os feriados manualmente se precisar. -Os números são clicáveis e levam à lista filtrada. +A maioria dos números é clicável e leva à lista filtrada. Uma conta de leitura ligada a um usuário não vê esses contadores, só os avisos e os próprios lembretes de hoje. ## Aprovar um novo usuário @@ -265,9 +265,9 @@ Quando alguém envia `/cadastrar`, os admins do bot recebem um aviso no Telegram | Botão | O que faz | | --- | --- | | **Ativar** | Aprova o cadastro (exige credencial validada) | -| **Desativar** | Bloqueia o uso do bot e cancela os lembretes agendados. Não apaga o histórico | +| **Desativar** | Bloqueia o uso do bot e cancela os lembretes agendados. A pessoa recebe no Telegram o aviso de que o acesso foi desativado. Não apaga o histórico | | **Ligar lembretes** | Liga os lembretes, zera o contador de falhas e retoma o dia, se ele estava "sem pontos" | -| **Pausar lembretes** | Desliga os lembretes e cancela os agendados. O `/status` do usuário mostra "pausado pelo painel" | +| **Pausar lembretes** | Desliga os lembretes e cancela os agendados. O `/status` do usuário mostra "pausados (por um administrador)" | | **Tornar admin do bot** / **Remover admin do bot** | Define quem recebe os avisos operacionais no Telegram | | **Retomar consultas de hoje** | Aparece quando o dia está "sem pontos". Volta a consultar até o fim da janela | @@ -325,7 +325,7 @@ Ações: - **Cancelar:** só para lembretes **agendados**. - **Reenviar:** só para lembretes que **falharam** e são **do dia de hoje**. - O usuário precisa estar ativo e com os lembretes ligados. - - Se o ponto seguinte já foi batido, o reenvio é bloqueado. + - Antes de reenviar, o sistema consulta a PontoMais. Se o ponto seguinte já foi batido, o reenvio é bloqueado; se a PontoMais não responder, tente de novo em alguns minutos. - Atenção: se a falha foi um travamento no meio do envio, a pessoa **pode já ter recebido** a mensagem original. O painel pergunta antes de reenviar. Lembretes **expirados** não podem ser reenviados. @@ -334,7 +334,7 @@ Lembretes **expirados** não podem ser reenviados. Registra quem fez o quê e quando: cadastros, ativações, mudanças de jornada e de credencial, envios, falhas, pausas, logins, alterações de configuração etc. -Filtre por período, origem (Telegram, painel, worker, terminal), tipo de evento e resultado. A partir da tela de um usuário, o link **Auditoria deste usuário** já abre filtrado. Use **Mais antigos →** para paginar. +Filtre por período, origem (Telegram, painel, worker, terminal), tipo de evento e resultado. O campo **Evento** precisa do nome exato, como aparece na coluna (ex.: `user_activated`, `notification_expired`, `web_login_failed`); a lista completa está na seção 18 do [documento de arquitetura](ARQUITETURA.md#18-referência-eventos-de-auditoria). A partir da tela de um usuário, o link **Auditoria deste usuário** já abre filtrado. Use **Mais antigos →** para paginar. Senhas e tokens nunca aparecem na auditoria.