docs: add BP-10 ntfy notifications blueprint

This commit is contained in:
Rodrigo Verdiani 2026-07-06 22:00:07 -03:00
parent 40adedd82b
commit 9133532ae8
7 changed files with 168 additions and 3 deletions

View File

@ -24,3 +24,9 @@ WORK_WINDOW_END=18:00
LIDARR_URL=
LIDARR_API_KEY=
WEBHOOK_SECRET=
# Ntfy notifications (optional, leave disabled if not using).
NTFY_ENABLED=false
NTFY_URL=
NTFY_TOPIC=
NTFY_TOKEN=

View File

@ -38,6 +38,7 @@ internal/
models/ # tipos compartilhados (Job, Log, Config)
store/ # repositórios SQLite + migrations
scanner/ # library scanner (navegação + scan recursivo)
ntfy/ # cliente de notificações ntfy
web/
styles/ # input.css + bundles DaisyUI (fonte)
@ -77,6 +78,10 @@ Variáveis de ambiente (defaults). Sobrescritas por overrides no SQLite via `/se
| `WORK_WINDOW_ENABLED` | `false` | Habilita janela de trabalho |
| `WORK_WINDOW_START` | `08:00` | Início da janela (HH:MM) |
| `WORK_WINDOW_END` | `18:00` | Fim da janela (HH:MM) |
| `NTFY_ENABLED` | `false` | Habilita notificações ntfy |
| `NTFY_URL` | — | URL base do servidor ntfy |
| `NTFY_TOPIC` | — | Tópico para publicar notificações |
| `NTFY_TOKEN` | — | Token de autenticação (opcional) |
## Componentes Principais
@ -104,6 +109,11 @@ Gate que libera ou retém tarefas conforme a janela de trabalho.
- Scan recursivo: detecta FLACs, agrupa por diretório (álbum), retorna lista.
- Endpoints REST usados pela página `/library`.
### Ntfy (`internal/ntfy/`)
- Cliente de notificações para servidor ntfy (self-hosted ou público).
- Envia notificação de sucesso/falha ao final de cada job.
- Respeita `DRY_RUN`; token opcional via `Authorization: Bearer`.
### Web UI (`internal/web/`)
Páginas:
- `/` — dashboard: status, fila, workers, janela de trabalho

View File

@ -14,6 +14,7 @@ Em ambos os fluxos, o Coda converte os arquivos, valida o resultado, remove os F
- Interface web: dashboard, tarefas, logs, navegação/scan de FLACs e configurações.
- Persistência em **SQLite** (jobs, logs e configurações).
- Modo **dry run** para simular sem converter nem apagar.
- Notificações via **ntfy** (self-hosted ou público) ao final de cada job.
## Stack
@ -100,14 +101,18 @@ Definida por variáveis de ambiente (defaults) e sobrescrita pela interface web
| `WORK_WINDOW_ENABLED` | `false` | Habilita a janela de trabalho |
| `WORK_WINDOW_START` | `08:00` | Início da janela (HH:MM) |
| `WORK_WINDOW_END` | `18:00` | Fim da janela (HH:MM) |
| `NTFY_ENABLED` | `false` | Habilita notificações ntfy |
| `NTFY_URL` | — | URL base do servidor ntfy |
| `NTFY_TOPIC` | — | Tópico para publicar notificações |
| `NTFY_TOKEN` | — | Token de autenticação (opcional) |
## Estrutura do Projeto
```
cmd/server/ # entrypoint
internal/ # config, scheduler, webhook, queue, worker,
# transcoder, validator, lidarr, logger, web,
# models, store, scanner
# transcoder, validator, lidarr, logger, web,
# models, store, scanner, ntfy
web/ # styles/ (fonte CSS), static/ (gerado), templates/
data/ # volume local do SQLite
```

View File

@ -166,6 +166,14 @@ Responsável por:
- exposição dos resultados via API REST para a interface web;
- enfileiramento dos álbuns selecionados para conversão.
### Ntfy Client
Cliente HTTP responsável por:
- envio de notificações de sucesso/falha ao final de cada job;
- suporte a servidor self-hosted ou público;
- autenticação opcional via token (`Authorization: Bearer`).
### Web UI
Interface para operação e monitoramento do serviço.
@ -203,6 +211,7 @@ internal/
models/
store/
scanner/
ntfy/
web/
styles/

View File

@ -0,0 +1,116 @@
# Blueprint 10 — Ntfy Notifications
- **ID:** BP-10
- **Feature:** Notificações via ntfy sobre sucesso/falha de jobs
- **Requisitos:** RF-017
- **Depende de:** BP-05 (Worker Pool)
- **Status:** pendente
## Objetivo
Implementar um cliente HTTP que envia notificações para um servidor [ntfy](https://ntfy.sh) (self-hosted ou público) ao final de cada job, informando se a conversão foi concluída com sucesso ou falhou. Respeitar `DRY_RUN`.
## Contexto
- BP-05 definiu o worker pool com um fluxo de `process` que termina chamando `finishJob` (status `done` ou `error`). O notificador será chamado antes do finish.
- `config.Service` fornecerá `NtfyEnabled`, `NtfyURL`, `NtfyTopic`, `NtfyToken`.
- O padrão segue a mesma abordagem do `Rescanner`: interface injetada no `worker.Pool`, substituível para testes.
## Restrições e Convenções
- Sem comentários; erros com `%w`; logs com `slog.With("job_id", id)`.
- **Resiliência:** falha ao enviar notificação **não** deve interromper o pipeline. Logar o erro e seguir.
- `DRY_RUN=true`: **não** enviar notificação; logar a intenção.
- Se `NTFY_ENABLED=false` ou `NtfyURL`/`NtfyTopic` vazios: pular (log debug).
- Token (`NTFY_TOKEN`) é opcional; se presente, enviar como `Authorization: Bearer <token>`.
- Timeout de 10s no HTTP client.
- Mensagens em inglês.
## Design
### `internal/ntfy/client.go`
```go
type Client struct {
cfg *config.Service
hc *http.Client
}
func New(cfg *config.Service) *Client
// Notify envia uma notificação com o resultado do job.
// Implementa worker.Notifier.
func (c *Client) Notify(ctx context.Context, job *models.Job) error
```
- Endpoint: `POST {NtfyURL}/{NtfyTopic}`
- Prioridade: `high` para erro, `default` para sucesso.
- Tags: `white_check_mark` (done), `x` (error).
- Corpo: `json.Marshal(ntfyMessage{...})` com title, message, priority, tags.
- Header `Authorization: Bearer <NtfyToken>` apenas se token != "".
### `internal/worker/notifier.go`
```go
type Notifier interface {
Notify(ctx context.Context, job *models.Job) error
}
type NoopNotifier struct{}
func (NoopNotifier) Notify(ctx context.Context, job *models.Job) error {
return nil
}
```
Adicionar campo `Notifier` ao `worker.Pool` e chamar `p.Notifier.Notify(ctx, job)` antes de `finishJob`.
### Wiring em `cmd/server/main.go`
- `notifier := ntfy.New(cfgSvc)` (ou `NoopNotifier{}` se `NtfyEnabled=false`).
- Passar `notifier` ao `worker.New(..., notifier)`.
### Config (novas chaves editáveis)
| Key | Default | Descrição |
|-----|---------|-----------|
| `NTFY_ENABLED` | `false` | Habilita notificações ntfy |
| `NTFY_URL` | — | URL base do servidor ntfy |
| `NTFY_TOPIC` | — | Tópico para publicar |
| `NTFY_TOKEN` | — | Token de autenticação (opcional) |
## Tarefas
- [ ] Adicionar `Notifier` interface em `internal/worker/`.
- [ ] Criar `internal/ntfy/client.go` (`New`, `Notify`).
- [ ] Adicionar keys ntfy ao `config` (Key + validação + editableKeys + Config struct + buildConfig).
- [ ] Chamar `Notifier.Notify` no `worker.process` antes de `finishJob`.
- [ ] Wiring no `main.go`: `ntfy.New(cfgSvc)``worker.New(...)`.
- [ ] Atualizar documentos: `README.md`, `AGENTS.md`, `requirements.md`, `architecture.md`.
## Testes
`internal/ntfy/client_test.go` (httptest.Server):
- [ ] `Notify` envia `POST /<topic>` com prioridade/título/tags corretos para job concluído.
- [ ] `Notify` envia prioridade `high` e tag `x` para job com erro.
- [ ] `DRY_RUN=true` → nenhum request é feito.
- [ ] `NtfyEnabled=false` → nenhum request, retorna nil.
- [ ] Token presente → header `Authorization: Bearer <token>`.
- [ ] Timeout/erro de rede → erro logado, não interrompe.
`internal/worker/worker_test.go` (atualizar):
- [ ] Verificar que `Notifier` fake é chamado antes do `finishJob` tanto em sucesso quanto em erro.
- [ ] Verificar que `NoopNotifier` não causa efeitos colaterais.
## Definição de Pronto
- DoD comum atendido.
- `go test ./internal/ntfy/... ./internal/worker/...` verde.
- `make run-prod`: notificações enviadas ao final de cada job (se habilitado).
## Arquivos
- **Criar:** `internal/ntfy/client.go` (+ `_test.go`), `internal/worker/notifier.go`.
- **Modificar:** `internal/config/config.go`, `internal/worker/worker.go`, `cmd/server/main.go`.

View File

@ -33,6 +33,7 @@ O que **falta** está coberto pelos blueprints abaixo.
| 07 | [Webhook Trigger](07-webhook-trigger.md) ~~~✅~~~ | Endpoint de webhook | RF-001, RF-012 | 05, 06 |
| 08 | [Library Scan & Convert](08-library-scan-and-convert.md) ~~~✅~~~ | Scan/navegação + conversão manual | RF-015 | 05 |
| 09 | [Web Interface](09-web-interface.md) ~~~✅~~~ | UI completa | RF-009, RF-010, RF-016 | 02, 03, 05, 08 |
| 10 | [Ntfy Notifications](10-ntfy-notifications.md) | Notificações via ntfy | RF-017 | 05 |
Recomenda-se executá-los em ordem numérica. Cada blueprint assume que os anteriores dos quais depende já foram concluídos e integrados.

View File

@ -99,7 +99,8 @@ A aplicação deverá registrar:
- duração;
- arquivos convertidos;
- erros;
- chamadas ao Lidarr.
- chamadas ao Lidarr;
- notificações enviadas.
Os logs deverão ser persistidos em SQLite e permanecer disponíveis para consulta via interface web.
@ -190,6 +191,10 @@ TIMEZONE=America/Sao_Paulo
WORK_WINDOW_ENABLED=false
WORK_WINDOW_START=08:00
WORK_WINDOW_END=18:00
NTFY_ENABLED=false
NTFY_URL=
NTFY_TOPIC=
NTFY_TOKEN=
```
---
@ -256,6 +261,19 @@ Alterações têm efeito imediato (não exigem reinicialização do container).
---
### RF-017 Notificações via ntfy
A aplicação deverá enviar notificações para um servidor [ntfy](https://ntfy.sh) (self-hosted ou público) ao final de cada job, informando o resultado da conversão.
- Notificação de **sucesso**: prioridade `default`, tag `white_check_mark`, título com artista/álbum.
- Notificação de **falha**: prioridade `high`, tag `x`, título com artista/álbum e mensagem de erro.
- Falha ao enviar notificação **não** interrompe o pipeline — o job não é revertido.
- Respeita o modo `DRY_RUN`: nenhuma notificação é enviada.
- Desabilitada por padrão (`NTFY_ENABLED=false`).
- Suporte a token de autenticação (`Authorization: Bearer`).
---
## 2. Requisitos Não Funcionais
### RNF-001