# 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.