mirror of
https://github.com/hanzoai/notify.git
synced 2026-10-30 15:04:32 +00:00
POST /v1/notify/send now defaults to durable async dispatch via
hanzoai/tasks (NotifySendWorkflow, queue notify-send) and returns 202
Accepted with {message_id, task_id, status:"queued"}. ?sync=true keeps
the inline path and returns 200 with the terminal result.
The router fails closed if async is requested but the Dispatcher is
nil or not Started (503) — no silent sync fallback, matching
hanzoai/tasks CONTRACT.md §3 ("production MUST set TASKS_ADDR").
Worker lifecycle moves out of routes/ into cmd/notifyd so the routes
package depends only on the new tasks.Dispatcher interface; tests stub
it directly. Tasks namespace defaults to "default" per CONTRACT.md §6
(single shared worker for all tenants in this PR; per-org namespacing
is the next step once liquidity tenant traffic scales).
A handful of internal helpers narrow from *base.Base to the smaller
core.App interface (Activities, metering.Write/Aggregate, tenant.New,
event.Resolve, template.LoadPublished, mountSend) so tests can drive
them with tests.NewTestApp without booting a full daemon.
Tests:
- internal/tasks/activities_test.go — Deliver idempotency
short-circuits on status=sent and status=failed plus nil-receiver
guard.
- internal/routes/send_test.go — sync 200 / async 202 happy paths +
503-on-missing-dispatcher + 503-on-unstarted-dispatcher +
500-on-dispatch-error + 401-on-missing-X-Org-Id.
References hanzoai/tasks#3.