docs: add BP-10 ntfy notifications blueprint
This commit is contained in:
parent
40adedd82b
commit
9133532ae8
@ -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=
|
||||
|
||||
10
AGENTS.md
10
AGENTS.md
@ -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
|
||||
|
||||
@ -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
|
||||
```
|
||||
|
||||
@ -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/
|
||||
|
||||
116
docs/blueprints/10-ntfy-notifications.md
Normal file
116
docs/blueprints/10-ntfy-notifications.md
Normal 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`.
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user