79 lines
3.1 KiB
Plaintext
79 lines
3.1 KiB
Plaintext
Evidence — Todo 15: NtfyPublisher + ntfy access snippet
|
|
=======================================================
|
|
|
|
Files created:
|
|
- crates/news-server/src/notify/mod.rs
|
|
- crates/news-server/src/notify/ntfy.rs
|
|
- deploy/ntfy-access-snippet.md
|
|
|
|
Files modified:
|
|
- crates/news-server/src/lib.rs (added `pub mod notify;`)
|
|
- crates/news-server/Cargo.toml (reqwest, url, tokio time feature, wiremock dev-dep)
|
|
- Cargo.toml (workspace `url = "2"`)
|
|
|
|
Verification commands
|
|
---------------------
|
|
|
|
1) cargo fmt --all --check
|
|
Output: (no output) → exit 0
|
|
|
|
2) cargo clippy --workspace --all-targets -- -D warnings
|
|
Output tail:
|
|
Checking news-server v0.1.0 (...)
|
|
Finished `dev` profile [unoptimized + debuginfo] target(s) in 5.34s
|
|
→ exit 0
|
|
|
|
3) cargo test -p news-server
|
|
Output tail:
|
|
running 20 tests
|
|
test notify::ntfy::tests::normal_lane_sends_priority_three ... ok
|
|
test notify::ntfy::tests::bypass_lane_sends_priority_five ... ok
|
|
test notify::ntfy::tests::request_has_required_headers ... ok
|
|
test notify::ntfy::tests::retries_once_on_server_error_then_err ... ok
|
|
...
|
|
test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
|
|
|
Ntfy tests added:
|
|
- notify::ntfy::tests::request_has_required_headers
|
|
- notify::ntfy::tests::bypass_lane_sends_priority_five
|
|
- notify::ntfy::tests::normal_lane_sends_priority_three
|
|
- notify::ntfy::tests::retries_once_on_server_error_then_err
|
|
|
|
Key implementation notes
|
|
------------------------
|
|
- Header shape mirrors movie_recs_notify: `Title`, `Tags`, `Priority`, `Markdown: yes`, `Content-Type: text/plain; charset=utf-8`, plus ntfy-specific `Click` and `Actions`.
|
|
- Actions format follows ntfy docs short form with `; ` separators:
|
|
`view, Open article, <link>; http, Interested, <api>/api/feedback, method=POST, body='{"story_cluster_id":"...","kind":"interested"}'; http, Not interested, ...`
|
|
- JSON bodies are wrapped in single quotes so the comma/colon-rich payload does not break ntfy's simple action parser.
|
|
- Auth: `NTFY_TOKEN` → `Authorization: Bearer ...`; `NTFY_USER`+`NTFY_PASS` → reqwest `.basic_auth(...)` (Basic base64); otherwise none.
|
|
- Retry: transport errors and 5xx sleep 500 ms and retry exactly once; 4xx returns `Err` immediately. No unwrap/expect/panic.
|
|
- `feedback_base_url` is read from `NEWS_API_BASE_URL` with default `http://localhost:3000`.
|
|
|
|
--- deploy/ntfy-access-snippet.md full content ---
|
|
|
|
# ntfy access provisioning for `news-triage`
|
|
|
|
The ntfy server is configured with a deny-by-default posture:
|
|
|
|
```yaml
|
|
# /home/connor/data/ntfy/etc/server.yml
|
|
auth-default-access: "deny-all"
|
|
```
|
|
|
|
Because of that posture, the `news-bot` user must be created and granted
|
|
read/write access to the `news-triage` topic before `news-server` can publish
|
|
notifications. These are one-time operator actions.
|
|
|
|
Run from the host that owns the `ntfy` container:
|
|
|
|
```bash
|
|
# Create the publishing user (interactive password prompt).
|
|
sudo podman exec -it ntfy ntfy user add news-bot
|
|
|
|
# Grant read/write access to the news-triage topic.
|
|
sudo podman exec ntfy ntfy access news-bot news-triage rw
|
|
```
|
|
|
|
Store the resulting password in the deployment secret path (`~/.env` for the
|
|
`news-backend` compose block) as `NTFY_USER` and `NTFY_PASS`.
|