Adiciona mecanismo de expiração periódica para jobs que ficam presos
nos status received ou processing além de um threshold configurável.
- models: novo status StatusTimeout
- store: migration v2 com índice em jobs(status); método ExpireStuck
que faz UPDATE atômico para os status alvo anteriores ao threshold
- expirer: novo pacote com goroutine periódica que chama ExpireStuck
e loga WARN quando algum job é expirado
- config: campos JobTimeoutMinutes (default 120) e
ExpirerIntervalMinutes (default 10), lidos via env vars
JOB_TIMEOUT_MINUTES e EXPIRER_INTERVAL_MINUTES
- main: instancia e inicia o Expirer no startup
- dashboard: card Timeout com contagem; badge neutral na tabela de jobs
- Enriquecer logger com artist e album após carregar o job do banco
- Logar início do job com path e contagem de FLACs encontrados
- Logar cada arquivo antes de chamar o ffmpeg
- Emitir Error('job failed') ou Info('job completed') em finishJob,
garantindo que todo encerramento gere entrada na tabela de logs
O contexto da requisição HTTP era passado para o Enqueue, causando
'context canceled' quando a conexão encerrava antes do INSERT no
SQLite completar. Jobs devem ser persistidos independentemente do
ciclo de vida da requisição.
Store attributes as key=value pairs in the SQLite log message
so they are visible in the web UI. job_id is extracted into the
dedicated column and excluded from the message text.
Simplify the webhook endpoint path to match the URL documented
in the Lidarr integration guide.
Also add a Lidarr integration section to README covering Coda
environment variables, Lidarr webhook configuration, and the
full end-to-end flow.
The ntfy API requires JSON payloads to be sent to the root URL (/)
with the topic field in the body. Posting to /<topic> with a JSON
body causes ntfy to treat it as plain text, rendering the raw JSON
as the notification content.
- Add Topic field to message struct
- Pass topic into buildMessage and include it in the payload
- Replace notificationURL with rootURL that resolves to base URL root
- Remove unused strings import
- Fix tests: add DRY_RUN=false override to prevent .env interference
Add SQLite persistence layer with domain types for jobs, logs, and config.
- internal/models: Job, LogEntry, JobStatus, JobSource types
- internal/store: Store with WAL pragmas, idempotent migrations
- JobRepository, LogRepository, ConfigRepository with full CRUD
- Wire store.New into main.go server startup
- 15 passing tests covering all repositories
Add the initial foundation for Coda, a Go/Docker service that converts
FLAC albums to MP3 320 kbps CBR, triggered by Lidarr webhooks or manually
from the web UI.
- docs: requirements and architecture (SQLite persistence, media volume,
work window, manual FLAC search, env + web config)
- config: .env loader with env precedence
- web: embed/dev asset split, chi server, index template (DaisyUI + htmx)
- build: Makefile (setup/css/run/build/test/lint), Dockerfile (Tailwind
standalone CLI + DaisyUI, no Node), .env.example, ignore rules
- docs: AGENTS.md and README for the project