22127e2a59
Adds Home Assistant as a service provider with two coordinated surfaces: Notifications (subscription): - Long-lived WebSocket client (aiohttp ws_connect) with auth handshake, exponential-backoff reconnect, bounded event queue, and area-registry enrichment cached per (re)connect - ServiceProvider ABC gains an optional `subscribe()` method for push-style providers; HomeAssistantServiceProvider uses it via a per-provider supervisor task started in the FastAPI lifespan - 4 event types (state_changed, automation_triggered, call_service, event_fired), 4 default Jinja templates (en + ru), HA-specific tracker filters (entity_glob, domain_allowlist, exact entity ids) - Extracted shared dispatch pipeline (api/webhooks.py → services/ event_dispatch.py) so subscription and webhook ingest share the same event_log + deferred-dispatch + quiet-hours code path Bot commands: - /status, /entities [glob], /state <entity_id>, /areas - Multi-command WS session so /status and /areas cost one handshake - Sensitive-attribute blocklist (camera access_token, entity_picture, etc.) and 30-attribute cap to keep /state output safe and within Telegram's message size - Error-message redaction strips URL userinfo before surfacing to chat Frontend: - HA descriptor with toggle ConfigField type (new) and tag-input filter mode for free-text glob/domain lists (new TagInput component) - 15 command slots + 4 notification slots wired into the existing template-config UI
178 lines
7.9 KiB
Markdown
178 lines
7.9 KiB
Markdown
# Feature Backlog
|
|
|
|
Curated feature ideas, narrowed from a brainstorming pass on 2026-05-13.
|
|
Order is **rough sequencing preference**, not strict priority — adjust as we go.
|
|
|
|
---
|
|
|
|
## 1. Quiet Hours — close the gaps in the existing system
|
|
|
|
**Reality check (verified 2026-05-13).** Quiet hours are already shipped under
|
|
the "deferred dispatch" name in v0.8.0. The pipeline lives at
|
|
`packages/server/src/notify_bridge_server/services/deferred_dispatch.py` with
|
|
helpers in `dispatch_helpers.py` and tests in
|
|
`tests/test_deferred_dispatch.py`. What exists:
|
|
|
|
- Per-tracking-config window: `tracking_config.quiet_hours_enabled`,
|
|
`quiet_hours_start`, `quiet_hours_end`.
|
|
- Per-link override: `notification_tracker_target.quiet_hours_start`,
|
|
`quiet_hours_end`.
|
|
- Smart coalescing (asset add + asset remove during a window cancels each
|
|
other out, set-union merge for repeated adds).
|
|
- Post-window drain via APScheduler one-shot date jobs.
|
|
- Wall-clock event types (`scheduled_message`) drop instead of deferring.
|
|
- Frontend status surface: `deferred`, `deferred_then_dropped`,
|
|
`deferred_then_failed`, with `deferred_until` and `deferred_for_seconds`
|
|
fields exposed in the event log.
|
|
|
|
**What's NOT there (the actual gaps):**
|
|
|
|
| Gap | Sketch |
|
|
| --- | --- |
|
|
| **Target-level windows** | Today, hours bind to the *watcher* (tracking config / link). Users naturally think of DND at the *destination* ("don't ping my phone at night, regardless of source"). New column on `notification_target` + dispatcher gate. |
|
|
| **Multiple windows per row** | Today is a single HH:MM range. Real schedules want weekday-evening + weekend-all-day. JSON list of windows. |
|
|
| **Days-of-week** | Same window every day. Need `days: ["mon", "tue", ...]` filter per window. |
|
|
| **Per-window timezone** | Uses the global app TZ. Multi-traveller / multi-target setups want per-window TZ. |
|
|
| **Silent mode** | Modes today are defer-or-drop. Telegram `disable_notification=true` ("send but don't ring") is a third useful mode. |
|
|
| **Per-receiver windows** | One bot → multiple chats, each potentially with its own DND. Today it's all-or-nothing per target. |
|
|
|
|
**Recommended cut for v1 of "extend quiet hours":**
|
|
|
|
- Add target-level quiet hours (new column `notification_target.quiet_hours_json`
|
|
= list of `{days, start, end, mode, tz}`).
|
|
- Modes: `drop`, `defer`, `silent`. `defer` reuses the existing
|
|
deferred-dispatch pipeline (just changes who decides). `silent` maps to
|
|
`disable_notification=true` for Telegram; other targets fall through to
|
|
normal send (or we treat `silent` as `defer` for non-Telegram targets — TBD).
|
|
- Dispatcher precedence: target window wins over link/tracking-config window
|
|
when both are configured. Document this explicitly.
|
|
- Frontend: new "Quiet hours" fieldset in the target editor (Aurora cassette
|
|
style). Reuses Timezone picker; new day-picker chip row.
|
|
- Skip days-of-week + multi-window in v1 if scope grows — ship the target-level
|
|
cut first, then iterate.
|
|
|
|
**Open questions.**
|
|
|
|
- How exactly do target / link / tracking-config windows combine? Proposal:
|
|
any window covering "now" wins (drop > defer > silent precedence).
|
|
- Should `silent` for non-Telegram targets degrade to normal send or to
|
|
defer? Defer is the safer default.
|
|
- Does the event log need a new status (`silenced` / `dropped_by_target_qh`)
|
|
to make precedence visible?
|
|
|
|
---
|
|
|
|
## 2. Immich Smart Actions (expand beyond Auto-Organize)
|
|
|
|
**What.** Extend the existing Smart Actions pattern (currently:
|
|
**Immich Auto-Organize**) with more rule-driven actions against the Immich API.
|
|
|
|
**Why.** Auto-Organize already proves the descriptor → rule editor → executor
|
|
pipeline. Adding actions is mostly authoring new executors + small UI rule
|
|
shapes, not new infra.
|
|
|
|
**Candidates (pick in this order).**
|
|
|
|
1. **Auto-favorite by person** — when an asset is detected containing person
|
|
X (or any of a set), mark it favorite.
|
|
2. **Auto-archive by age / album** — assets older than N days in a given
|
|
album get archived. Pair with a "dry-run shows count" UX like
|
|
Auto-Organize already has.
|
|
3. **Duplicate cluster nudge** — periodically run Immich's duplicate API and
|
|
send a digest notification with inline buttons ("review", "ignore for 30d").
|
|
Depends on inline-button work (see backlog item 4 dependencies).
|
|
4. **Share-link rotation** — for an album, regenerate the share link every N
|
|
days; notify with the new URL.
|
|
5. **Pending-delete review** — push a weekly digest of trash contents before
|
|
Immich's auto-purge fires.
|
|
|
|
**Shape.**
|
|
|
|
- Reuse the existing **action descriptor** layer
|
|
(`packages/core/src/notify_bridge_core/providers/actions.py`,
|
|
`action_executor.py`) and the frontend rule editor used by Auto-Organize.
|
|
- Each new action = (a) executor in core, (b) rule schema in the descriptor,
|
|
(c) frontend descriptor extension for the rule editor fields.
|
|
- Persist as `provider_actions` rows (already exists for Auto-Organize) with
|
|
a discriminator + JSON config.
|
|
|
|
**Open questions.**
|
|
|
|
- Does "auto-favorite by person" need a confirmation queue or run silently?
|
|
Default to silent + event_log entry.
|
|
- How do we surface "this action moved/changed X assets" in the dashboard?
|
|
Probably a per-action stat tile on the provider detail page.
|
|
|
|
---
|
|
|
|
## 3. Home Assistant Provider
|
|
|
|
**Full plan:** [feature-home-assistant.md](feature-home-assistant.md).
|
|
|
|
**One-line summary.** New WebSocket-based service provider with a 3-phase
|
|
ship: subscribe + dispatch (Phase 1), bot commands (Phase 2), HA service
|
|
calls as Smart Actions (Phase 3). Chosen over webhook ingest because
|
|
Phases 2 + 3 force a long-lived API connection anyway; consolidating on WS
|
|
avoids a refactor.
|
|
|
|
**Status:** planned, not started.
|
|
|
|
---
|
|
|
|
## 4. Block-Based Template Builder
|
|
|
|
**What.** A visual, drag-and-drop builder for notification and command
|
|
templates that compiles down to Jinja2. Lives alongside (not instead of) the
|
|
current `JinjaEditor`. Author can flip between views.
|
|
|
|
**Why.** The current Jinja editor is powerful but unforgiving. A block UI
|
|
lowers the floor for new users and provides a discovery surface for the
|
|
variables documented in `template_configs.py`.
|
|
|
|
**Shape.**
|
|
|
|
- Frontend-only feature for v1 — compiles to the same Jinja strings the
|
|
backend already accepts.
|
|
- Blocks: `Text`, `Variable`, `If`, `For`, `Link`, `Image`, `Icon`, `Caption`,
|
|
`Group` (HTML span/group). Each block knows its serialized Jinja
|
|
representation.
|
|
- Round-trip: variables, simple `{% if %}` / `{% for %}` blocks, and string
|
|
literals parse back to blocks; arbitrary Jinja stays in a "Raw" block that
|
|
the user can edit as text.
|
|
- Variable picker reads `get_template_variables(provider_type, slot)`. This is
|
|
the same data already shown in the template-help panel.
|
|
- Preview pane unchanged — reuses `services/sample_context.py` server
|
|
rendering.
|
|
- Toggle in the template editor: **Visual / Code**.
|
|
|
|
**Open questions.**
|
|
|
|
- Round-tripping arbitrary Jinja is hard. v1: parseable subset → blocks,
|
|
anything else → single Raw block. Show a banner explaining.
|
|
- Locale handling: same compiled Jinja, just authored per locale tab.
|
|
- Do we want a marketplace of pre-built block compositions? Out of scope for
|
|
v1 — bundle import/export is a separate backlog item.
|
|
|
|
---
|
|
|
|
## Recommended Sequencing
|
|
|
|
1. **Quiet Hours per Target** — small, isolated, immediate user value.
|
|
2. **Immich Smart Actions** — incremental on existing pattern; ship one
|
|
action at a time (start with auto-favorite by person).
|
|
3. **Home Assistant Provider** — multi-file, follows new-provider checklist;
|
|
biggest user-base expansion.
|
|
4. **Block-Based Template Builder** — largest frontend lift; benefits from
|
|
the variable-doc work that the other features will exercise.
|
|
|
|
Dependencies are loose — 1 and 2 are independent of 3 and 4. The block
|
|
builder pairs nicely with Home Assistant because HA's rich context surfaces
|
|
the value of an easier authoring UX.
|
|
|
|
---
|
|
|
|
## Decision log
|
|
|
|
- **2026-05-13** — Backlog seeded with these four items selected from a
|
|
broader brainstorm. Not started.
|