• Notify Bridge 0.10.0
    Release / test-backend (push) Successful in 2m17s
    Release / release (push) Successful in 1m0s
    Stable

    alexei.dolgolyov released this 2026-06-05 21:04:57 +03:00 | 0 commits to master since this release

    v0.10.0 (2026-06-05)

    Multi-time-point scheduling for Immich. The single comma-separated "times" text box is replaced with an add/remove list of native HH:MM pickers for the scheduled assets, periodic summary, and memory slots — entering several fire times per day is now discoverable, and the read/write path is hardened end to end. This release also pins aiohttp<3.14 in the backend test environment so the suite stays green against the current aioresponses. No breaking changes; no migrations required.

    User-facing changes

    Features

    • Immich multi-time scheduling UI. A new TimeListEditor replaces the comma-separated text box with an add/remove list of native HH:MM pickers for the scheduled-assets, periodic-summary, and memory slots. It dedupes and sorts on save, enforces a per-day cap, collapses on-screen duplicates, and gives each row an aria-label. Keyboard entry is no longer clobbered mid-edit — it syncs from the value prop only on external changes via an untrack guard (8065e6e)
    • Per-section save guard. An enabled feature section (scheduled / periodic / memory) must now have at least one time before it can be saved, enforced in the provider descriptor (8065e6e)
    • Refreshed copy. New en/ru i18n keys and updated help text for the editor; the dead invalidTimeList string was removed (8065e6e)

    Bug Fixes

    • Server-side *_times normalization. The tracking_configs API now normalizes scheduled_times / periodic_times / memory_times on every write (validate, dedup, sort, cap at 24), returns 422 on malformed input, and refuses to enable a slot whose times list is empty (8065e6e)
    • Restored scheduler observability. The scheduler now warns when an enabled slot has zero or dropped fire times, restoring the visibility that was lost when the old per-call warning was removed (8065e6e)

    Development / Internal

    CI/Build

    • Pin aiohttp<3.14 in the backend test install. aioresponses 0.7.8 (latest) does not pass the stream_writer keyword argument that aiohttp 3.14 made required on ClientResponse, so every aioresponses-mocked HTTP test failed to construct a response. notify-bridge-core declares aiohttp>=3.9 with no upper bound, so CI floated to 3.14.0 — the pin keeps the test environment reproducible in both build.yml and release.yml until aioresponses ships an aiohttp-3.14-compatible release (11593ea)

    Refactoring

    • Shared time-list service. A new services/time_list.py exposes normalize_time_list (raising TimeListError) and a lenient parse_hhmm_list; the scheduler drops its private parser copy in favour of the shared one (8065e6e)

    Tests

    • Time-list coverage. New tests for time-list normalization and parsing (including non-ASCII and odd-shaped input) and for the "enabled implies at least one time" validation (8065e6e)

    Chores

    • Checked-in vex config. A .vex.toml enabling semantic embeddings, call-graph, BM25, and auto-update for the vex code-search index (d01e519)

    All Commits
    • 8065e6efeat(immich): multi-time-point scheduling for scheduled/periodic/memory (alexei.dolgolyov)
    • 11593eafix(ci): pin aiohttp<3.14 in backend test deps (alexei.dolgolyov)
    • d01e519chore: add vex semantic-search config (alexei.dolgolyov)

    Changelog

    6877c4d chore: release v0.10.0
    d01e519 chore: add vex semantic-search config
    11593ea fix(ci): pin aiohttp<3.14 in backend test deps
    8065e6e feat(immich): multi-time-point scheduling for scheduled/periodic/memory

    Downloads
  • v0.9.0 e2c17dd343

    Notify Bridge 0.9.0
    Release / test-backend (push) Successful in 2m16s
    Release / release (push) Successful in 1m3s
    Stable

    alexei.dolgolyov released this 2026-05-28 15:33:00 +03:00 | 4 commits to master since this release

    v0.9.0 (2026-05-28)

    A feature + observability release. The headline additions are per-receiver Telegram options (silent send and forum-topic routing), an oversized-video fallback that bypasses Telegram's 50 MB sendVideo cap by switching to sendDocument, partial-failure visibility on the dashboard via a new dispatch_summary block on every EventLog row, and an admin diagnostic-mode panel for temporary per-module DEBUG logging with auto-revert. End-to-end correlation IDs (dispatch_id, X-Request-Id) now tie log lines to the database rows they produced. No breaking changes; no migrations required.

    User-facing changes

    Features

    • Per-receiver Telegram options. Each Telegram chat receiver can now be configured to send silently (disable_notification — no sound or vibration on the recipient) and to route into a specific forum topic (message_thread_id) on supergroups with topics enabled. A new cog-icon button on the receiver row opens an inline editor; active options surface as a bell-off icon and a #thread-id chip on the receiver header. The plumbing uses a ContextVar bound at the public send entry points, so every internal payload builder (sendMessage, sendPhoto/Video/Document, sendMediaGroup, cache-hit POST) picks them up without a signature change (6a8f374)
    • Send oversized videos as documents. A new per-target toggle, send_large_videos_as_documents, falls back to sendDocument when a video would exceed Telegram's 50 MB sendVideo limit. Useful for archival use cases (Immich library shares with users on free Telegram accounts) where the video would otherwise be silently dropped or noisily 413'd. Pairs with the existing send_large_photos_as_documents toggle. Translated copy lives under targets.sendLargeVideosAsDocuments (6a8f374)
    • Diagnostic mode for temporary DEBUG logging. A new Diagnostics cassette on the Settings page lets an admin flip one module to DEBUG for a bounded window (1 minute to 4 hours) with an automatic revert. Useful for investigating a specific dispatch failure without flooding stderr; the revert reads the current DB-configured log_levels at expiry so a setting change made during the window is honored. State is in-memory only — a restart wipes overrides, and setup_logging() re-applies the DB baseline at boot, so a forgotten override cannot silently survive a deploy (6a8f374)
    • Partial-delivery visibility in the dashboard. Every event-, watcher-, scheduled-, deferred-, action-, and command-dispatch path now writes a dispatch_summary block onto EventLog.details: per-target succeeded/failed counts, Telegram media delivered_count / skipped_count / failed_count, and a truncated list of error strings. Partial outcomes (one target out of three failed, two of ten assets dropped) are no longer indistinguishable from a clean success (6a8f374)
    • Inbound request correlation IDs. A new middleware accepts X-Request-Id from the inbound request (so an upstream proxy with its own correlation system can propagate its id) and echoes the value back on the response. Values are sanitised to a bounded charset to prevent CR/LF injection into log lines. The id is bound into log context for every request and copied onto any EventLog row written during the same request, so the SPA can surface it for bug reports (6a8f374)

    Bug Fixes

    • sendMediaGroup byte-budget enforcement. Telegram's sendMediaGroup envelope tops out near 50 MB total (multipart bytes including form overhead). Previously the per-item budget admitted items that, when summed, busted Telegram's request cap and 413'd. A new 45 MB total-bytes budget (TELEGRAM_MAX_GROUP_TOTAL_BYTES) splits groups before the overhead pushes us over, with safety margin (6a8f374)
    • Per-item fallback inside sendMediaGroup. A stale file_id reference (cache poisoning by Telegram's GC, or a video that's no longer downloadable from the cached URL) used to silently lose the cached asset because the failed chunk had no re-download path. Each cached item now retains its source_url + download_headers so the per-item fallback can re-fetch and retry as a single send when its file_id POST returns transient errors (6a8f374)

    Development / Internal

    Observability

    • Shared dispatch_id across log lines and EventLog rows. A disp:<12 hex> correlation id is bound at the top of every dispatch entry point (dispatch_provider_event, check_tracker, dispatch_scheduled_for_tracker, _process_row in deferred dispatch, run_action, command handler, HA status logger) via ContextVar. Nested dispatcher calls reuse the bound id instead of generating their own, so a single dispatch's log lines and the EventLog.details.dispatch_id field share one searchable id (6a8f374)
    • enrich_details_with_correlation() helper. New helper in notify_bridge_core.log_context merges the bound dispatch_id and request_id onto EventLog.details dicts at write time without overwriting caller-provided keys. Every EventLog insertion site has been migrated to use it (6a8f374)

    Architecture

    • split_media_by_upload_size retired. Per-item upload accounting moved onto the new _MediaItem dataclass (upload_bytes property) and the splitter logic moved into _send_media_group, where the byte budget and per-item fallback live (6a8f374)
    • API endpoints for diagnostic mode. New routes under /api/app-settings/diagnostic-mode (GET list, POST activate, DELETE /{module:path} revert) with admin-auth requirement and a curated module allowlist that blocks the root logger (6a8f374)

    Tests

    • New suites: test_diagnostic_mode.py, test_dispatch_summary.py, test_request_correlation.py, test_telegram_media_group_partial.py, test_telegram_per_send_options.py. Total: 294 tests passing (up from 283 in v0.8.2) (6a8f374)
    • Test scaffolding fix: _reset_state() in test_diagnostic_mode.py now also clears the _bg_tasks set so a long-window schedule from one test doesn't pollute len(_bg_tasks) in the next test's assertion. Cross-loop .cancel() is intentionally skipped — the prior test's loop is closed and cancelling there raises RuntimeError on the next test's setup (9aada75)

    Documentation

    • Six-axis production-readiness review (/.claude/reviews/) covering backend, frontend, security, performance/DB, UI/UX, and bugs+features. Snapshots the v0.8.1 codebase; informed several items shipped in v0.8.2 and this release (6a8f374)
    • Functional review of Telegram / Immich / Logging subsystems (.claude/docs/functional-review-2026-05-28.md). Captures what's in place, in-flight work, and ranked gaps for each subsystem; pairs with the existing feature backlog (6a8f374)

    All Commits
    • 6a8f374feat: observability, per-receiver Telegram options, oversized-video fallback (alexei.dolgolyov)
    • 9aada75fix(tests): clear diagnostic_mode _bg_tasks between cases (alexei.dolgolyov)

    Changelog

    e2c17dd chore: release v0.9.0
    9aada75 fix(tests): clear diagnostic_mode _bg_tasks between cases
    6a8f374 feat: observability, per-receiver Telegram options, oversized-video fallback

    Downloads
  • v0.8.2 85a8f1e71c

    Notify Bridge 0.8.2
    Release / test-backend (push) Successful in 2m20s
    Release / release (push) Successful in 1m40s
    Stable

    alexei.dolgolyov released this 2026-05-22 22:54:00 +03:00 | 7 commits to master since this release

    v0.8.2 (2026-05-22)

    A production-readiness hardening release that follows up on v0.8.1 with six isolated, low-risk fixes surfaced by a parallel full-codebase review (backend, frontend, security, performance, UI/UX, bugs+features). No breaking changes; no migrations required.

    User-facing changes

    Security

    • Provider access_token masked in API responses. The provider GET endpoints were leaking plaintext credentials — most importantly Home Assistant long-lived tokens — in their JSON payloads. The field is now masked on read and dropped on edit when the *** placeholder is sent back, so the UI can show "set" / "unset" without ever round-tripping the secret. Centralized through PROVIDER_SECRET_FIELDS so every call site stays in sync (2d59a5b)
    • Pre-auth resource-exhaustion amplifier closed on webhook ingest. The Gitea provider used to read the 1 MiB request body before checking whether a secret was even configured or whether the request had a signature header — an unauthenticated client could force a body read on every hit. The generic-webhook bearer-token path had the same shape: body read before Authorization check. Both now bail out before consuming the body when the auth precondition fails (2d59a5b)

    Bug Fixes

    • Home Assistant status-change events no longer silently lost. ha_status_changed rows are written from asyncio.create_task(...), but create_task only keeps a weak reference — the task was being garbage-collected before the row landed, so connection-flap events disappeared. The task handles are now held in a module-level set with a done_callback to release them on completion (2d59a5b)
    • Telegram-webhook handler exceptions can no longer leak writes. The catch-all error path in the Telegram inbound endpoint now rolls back the request's SQLAlchemy session before returning, so a handler crash mid-transaction cannot bleed uncommitted state into the next request on the same connection (2d59a5b)

    Accessibility

    • Toast notifications now announced by screen readers. Added role="region" on the snackbar container plus per-toast role / aria-live / aria-atomic attributes, with a localized region name (snackbar.region) in both en and ru (2d59a5b)
    • Active sidebar link now has an accessible state. aria-current="page" is now set on the matching nav item, so assistive tech can announce the active route (2d59a5b)

    Development / Internal

    Refactoring

    • Last provider.type === 'immich' check removed from components. The action-rule editor's "Auto-organize" affordance now consumes a supportsAutoOrganize capability on ProviderDescriptor instead of branching on the provider type — bringing the rule editor under CLAUDE.md rule 8 (no provider-specific hardcoding in components) (2d59a5b)

    Chores

    • Synced .facts-sync.json with claude-code-facts@cfdafa9. Both previously pending suggestions (venv install for monorepos + hatchling METADATA workaround) were applied upstream; the local queue is empty (a20635a)

    Known gaps (tracked for follow-up)

    The full-codebase review surfaced more ship-blockers than this release fixes. Each of the items below needs more than a mechanical edit and is tracked in .claude/reviews/README.md:

    • Secret encryption at rest
    • JWT moved into an HTTP-only cookie
    • Alembic adoption (currently create_all)
    • Webhook delivery idempotency
    • Deferred-dispatch crash window
    • Persisted Telegram update watermark
    • bridge_self counter lock

    All Commits
    • 2d59a5bfix: production-readiness hardening from full-codebase review (alexei.dolgolyov)
    • a20635achore: sync .facts-sync.json with claude-code-facts@cfdafa9 (alexei.dolgolyov)

    Changelog

    85a8f1e chore: release v0.8.2
    2d59a5b fix: production-readiness hardening from full-codebase review
    a20635a chore: sync .facts-sync.json with claude-code-facts@cfdafa9

    Downloads
  • v0.8.1 d7c48b06ee

    Notify Bridge 0.8.1
    Release / test-backend (push) Successful in 2m1s
    Release / release (push) Successful in 2m3s
    Stable

    alexei.dolgolyov released this 2026-05-16 18:33:41 +03:00 | 10 commits to master since this release

    v0.8.1 (2026-05-16)

    ⚠️ Breaking Changes

    • Telegram webhook secret is now mandatory. NOTIFY_BRIDGE_TELEGRAM_WEBHOOK_SECRET must be set when running Telegram bots in webhook mode — the inbound endpoint returns 401 without it. Polling-mode bots are unaffected (10d30fc)
    • Generic webhooks with auth_mode="none" require explicit opt-in. Existing unauthenticated webhook providers must set acknowledge_unauthenticated=true in their config or they will be rejected. Generic webhook ingest is also rate-limited to 60 requests/min per source IP (10d30fc)
    • Every user now gets a bridge_self provider auto-seeded. It is internal-only and excluded from the "create provider" wizard, but appears in the provider list. Wire it to a Telegram/Email/Matrix target to receive bridge health alerts (10d30fc)

    User-facing changes

    Features

    • Home Assistant provider. New service provider that subscribes to a Home Assistant instance over WebSocket (long-lived connection with auth handshake, exponential-backoff reconnect, area-registry enrichment) and emits 4 event types: state_changed, automation_triggered, call_service, event_fired. Trackers support entity-glob, domain-allowlist, and exact-id filters via the new TagInput UI control (22127e2)
    • Home Assistant bot commands. /status, /entities [glob], /state <entity_id>, /areas — query your HA instance from chat. Multi-command WS sessions reuse a single handshake; sensitive attributes (camera access tokens, entity pictures, etc.) are blocklisted and /state output is capped at 30 attributes to stay within Telegram message limits (22127e2)
    • Bridge self-monitoring (bridge_self provider). A new internal provider type emits health events from the bridge itself: bridge_self_poll_failures (consecutive tracker poll failures), bridge_self_deferred_backlog (pending defers above threshold), bridge_self_target_failures (consecutive 5xx/network failures per target). Per-user thresholds default to 3 / 100 / 5 and are configurable. Self-loop guard ensures bridge_self failures never count toward target-failure thresholds (10d30fc)
    • bridge_self bot commands. /status, /thresholds, /reset, /health let operators inspect bridge health and reset counters from chat. Includes Jinja2 templates for both locales (8651767)
    • On-watch stats scope selector. New icon toggle on the "On watch" provider deck switches between page-scoped stats (legacy) and full-corpus stats that aggregate across every event matching the active filters (dec0839)

    Bug Fixes

    • Immich periodic summary now honors periodic_interval_days. A configured 3-day interval was firing every day because the dispatch path never consulted the interval or start date. The scheduler now gates on (today - start_date).days % interval == 0 and logs interval_not_due skips so operators can distinguish suppressed-by-interval from other skip causes (90f958b)
    • Planka webhook crash fixed. The handler had a NameError on every call when reading the request body — webhook ingest from Planka now works (10d30fc)
    • HA quiet-hours dropped events. ha_state_changed, automation_triggered, service_called, and event_fired were missing from the deferrable set and were silently dropped during quiet windows. They now defer like every other event type (10d30fc)
    • Notifier no longer cancels peer sends on a single failure. Switched the per-receiver fan-out to asyncio.gather(return_exceptions=True); one bad chat won't cancel sends to the rest (10d30fc)
    • Quiet-hours gate now respects event-type-disabled. When a tracker has the event type disabled, that wins over the deferral path — events are dropped, not stored to be drained later (10d30fc)
    • NUT first poll seeds silently. No more spurious ups_on_battery notification on the very first poll after adding a NUT provider (10d30fc)
    • HA disconnect/reconnect now logged. Status changes write ha_status_* rows to the EventLog so operators can see WS supervisor health in the UI (10d30fc)

    Performance

    • Jinja2 template compilation cached with lru_cache(maxsize=512) — repeated renders of the same template no longer reparse the source (10d30fc)
    • Per-locale render cache in NotificationDispatcher skips re-rendering identical content for receivers sharing a locale (10d30fc)
    • Tracker list cached per provider_id with a 5s TTL plus explicit invalidation on tracker CRUD — relieves the HA chat-bus rate-query pressure (10d30fc)
    • Nav-counts collapsed from 16 round-trips to a single UNION ALL (10d30fc)
    • HA event_log skips empty eventsassets_added/assets_removed events with empty payloads are no longer persisted (10d30fc)

    Security

    • DNS-rebinding SSRF protection. PinnedResolver is now wired into the shared aiohttp session — outbound URL validation pins the resolved IP for the lifetime of the request (10d30fc)
    • Mass-assignment guards added on Action create/update; cron expressions with sub-minute granularity are rejected (10d30fc)
    • Backup import hardening. JSON depth capped at 10, node count at 100k; _sanitize_config now extends to all JSON-typed fields on import (10d30fc)
    • Telegram _safe_get walks redirects manually with SSRF revalidation at every hop (10d30fc)
    • Bcrypt 72-byte password length cap with a clear 422 response (was silently truncating before) (10d30fc)
    • Webhook payload body redaction. Sensitive substring set extended with oauth, client_secret, webhook_secret, csrf in both header filter and template-extras filter (10d30fc)

    Operations

    • Deep healthcheck at /api/ready — checks DB SELECT 1, scheduler running, HA supervisor presence; returns {ready, checks, errors, version} (10d30fc)
    • Prometheus metrics at /api/metricsdeferred_pending, event_log_total, dispatch_duration, poll_failures, send_failures (10d30fc)
    • New OPERATIONS.md covering deploy, healthchecks, metrics, backup/restore procedures, log handling, common scenarios, and upgrade flow (10d30fc)

    Development / Internal

    Architecture

    • Shared dispatch pipeline. Extracted webhook ingest's event-log + deferred-dispatch + quiet-hours code path from api/webhooks.py into services/event_dispatch.py so HA subscription and webhook ingest now share the same pipeline (22127e2)
    • ServiceProvider ABC gains optional subscribe() for push-style providers; HomeAssistantServiceProvider uses it via a per-provider supervisor task started in the FastAPI lifespan (22127e2)
    • Provider construction switched from if/elif ladder to factory registry (10d30fc)
    • Provider credential resolution unified across all 5 dispatch sites (10d30fc)
    • NotificationDispatcher hoisted out of the per-tracker loop (10d30fc)

    Database

    • New UNIQUE indexes: service_provider.webhook_token, telegram_bot.webhook_path_id, partial UNIQUE on telegram_bot.bot_id, telegram_chat(bot_id, chat_id), notification_tracker_target unique link, partial UNIQUE on bridge_self provider per user (10d30fc)
    • Composite ix_event_log_user_event_type_created index (10d30fc)
    • save_chat_from_webhook switched to ON CONFLICT DO UPDATE (was racy under concurrent webhook delivery) (10d30fc)
    • ondelete=CASCADE on user-id FKs (model annotation; app-side cascade delete added for existing data) (10d30fc)
    • delete_notification_tracker converted from N+1 to bulk DELETE/UPDATE (10d30fc)
    • Module-level asyncio.Lock replaced with lazy _get_lock() pattern (avoids cross-event-loop binding) (10d30fc)
    • VACUUM INTO snapshot now PRAGMA integrity_check-verified before being returned (10d30fc)
    • Batched receivers/chats/bots in load_link_data (was per-target N+1) (10d30fc)
    • flag_modified on JSON column reassignments in deferred_dispatch (10d30fc)

    Frontend

    • 76 catch (err: any) sites converted to errMsg(err) helper (10d30fc)
    • globalProviderFilter made a pure getter; reconciliation moved to a one-time $effect in +layout (10d30fc)
    • Provider-filter binding simplified — paired $effects and the _syncingFilter flag removed; now a one-way derived value (10d30fc)
    • entity-cache got a separate _refreshing flag for background re-fetches so loading spinners don't appear on revalidation (10d30fc)
    • api.ts 401 handling rewritten: AuthRedirectError class + dedup _redirecting flag, goto() instead of window.location.href (10d30fc)
    • Accessibility: aria-expanded on mobile More menu, role=switch + aria-checked on Telegram bot toggles (10d30fc)
    • Provider-specific hardcoding removed: Immich-only block extracted to descriptor featureDiscoveryHint (10d30fc)
    • 5 svelte-check null-narrowing errors fixed in EventDetailModal (10d30fc)
    • New TagInput component for free-text glob/domain lists; new toggle ConfigField type for HA descriptor (22127e2)

    CI/Build

    • CI pytest gate added to .gitea/workflows/build.yml and release.yml (wheel-built install to dodge editable-install slowness on the hosted runner) (10d30fc)

    Tests

    • New test suites: test_bridge_self (11), test_gitea_parser (9), test_planka_parser (6), test_immich_change_detector (6), test_backup_roundtrip (1) (10d30fc)

    Other

    • command_sync snapshot+expunge bot before exiting AsyncSession (was raising on detached-instance access) (10d30fc)
    • HA asyncio.shield now drains inner task on cancellation (was leaking tasks on supervisor restart) (10d30fc)
    • APScheduler drain job ID resolution upgraded to seconds (was minute-bucketed; collisions possible) (10d30fc)
    • Webhook payload rollback failures now logged (were swallowed) (10d30fc)

    All Commits
    Hash Message Author
    8651767 feat: bridge_self bot commands — status, thresholds, reset, health alexei.dolgolyov
    10d30fc feat: production readiness — security, perf, bug fixes, bridge self-monitoring alexei.dolgolyov
    22127e2 feat: Home Assistant provider — WebSocket subscription + bot commands alexei.dolgolyov
    90f958b fix(server): honor periodic_interval_days for Immich periodic summary alexei.dolgolyov
    dec0839 feat: on-watch stats scope selector (page vs all) alexei.dolgolyov

    Changelog

    d7c48b0 ci: isolate test backend install in venv
    66f152e fix(tests): green pytest gate for v0.8.1
    faaaa39 chore: release v0.8.1
    8651767 feat: bridge_self bot commands — status, thresholds, reset, health
    10d30fc feat: production readiness — security, perf, bug fixes, bridge self-monitoring
    22127e2 feat: Home Assistant provider — WebSocket subscription + bot commands
    90f958b fix(server): honor periodic_interval_days for Immich periodic summary
    dec0839 feat: on-watch stats scope selector (page vs all)

    Downloads
  • v0.8.0 dfd7329177

    Notify Bridge 0.8.0
    Release / release (push) Successful in 1m55s
    Stable

    alexei.dolgolyov released this 2026-05-12 03:01:06 +03:00 | 18 commits to master since this release

    v0.8.0 (2026-05-12)

    User-facing changes

    Features

    • Quiet hours now defer notifications instead of dropping them. Events that arrive during a tracker's quiet window are stored on disk and re-fired at the window end. Asset events for the same (link, event_type, collection) coalesce so a flurry of adds/removes during the night collapses into a single morning notification (ba199f2)
    • Upstream release check. New "Release Cassette" in Settings polls a configurable Gitea or GitHub repo on a schedule and surfaces the latest tag in the UI so you know when a newer Notify Bridge is available. Pre-release filtering and interval are operator-configurable; the install ships pointed at this repo's own upstream (ba199f2)
    • Frontend polish across the board. New MetaStrip component, expanded EventDetailModal, and i18n additions land alongside cohesive Aurora-glass styling tweaks on most management pages — providers, targets, bots, trackers, command and notification templates, users, actions, layout, and dashboard (ba199f2)

    Documentation

    • README rewritten to cover every supported provider, target type, bot command, and smart action — including the deploy / env-var matrix (bb5afcc, 4335036)

    Development / Internal

    Architecture

    • New deferred_dispatch table with two migrations: an ON DELETE SET NULL FK rebuild on event_log_id (so the daily event-log retention sweep no longer deadlocks against pending defers), and a partial unique index on (link_id, collection_id, event_type) WHERE status='pending' to make coalescing race-safe under SQLite's serializable writes (ba199f2)
    • Drain scheduler with three layers: a one-shot APScheduler date job per window-end (idempotent, minute-bucketed), a 5-minute periodic catch-up scan as safety net for misfire-grace overflow and process-restart gaps, and load_pending_drain_jobs to re-arm scheduled drains on boot (ba199f2)
    • Release-check provider abstraction (packages/core/.../release/) with Gitea and GitHub adapters, SSRF-safe outbound URL validation, a registry/factory, and a server-side scheduler probe with cached state and on-settings-change cache invalidation (ba199f2)
    • Version resolution helper (packages/server/.../version.py) that returns the max of installed-package metadata vs source pyproject.toml — fixes the long-running editable-install bug where bumping the version without reinstalling kept the old number visible in the UI (ba199f2)

    Tests

    • New test suites: test_deferred_dispatch.py (drain + coalescing + retention interaction), test_release_provider.py (Gitea and GitHub adapter parsing and error paths), and test_release_service.py (scheduler-level caching and settings invalidation) (ba199f2)

    All Commits
    Hash Message Author
    ba199f2 feat: deferred dispatch, release-check provider, settings polish alexei.dolgolyov
    bb5afcc docs: expand README with all providers, targets, bot commands, and smart actions alexei.dolgolyov
    4335036 docs: sync README deploy section with actual env vars alexei.dolgolyov

    Changelog

    dfd7329 chore: release v0.8.0
    ba199f2 feat: deferred dispatch, release-check provider, settings polish
    bb5afcc docs: expand README with all providers, targets, bot commands, and smart actions
    4335036 docs: sync README deploy section with actual env vars

    Downloads
  • v0.7.2 5d41a39406

    Notify Bridge 0.7.2
    Release / release (push) Successful in 1m10s
    Stable

    alexei.dolgolyov released this 2026-05-11 00:39:06 +03:00 | 22 commits to master since this release

    v0.7.2 (2026-05-11)

    Features

    • Redesign settings/common with Aurora cassettes — refreshed identity, logging, Telegram, and cache-ledger sections with the new glass/cassette UI (6229bf9)
    • Group targets by bot in the targets view and redesign backup settings (a666bad)
    • Add /status command handler for webhook providers (bede928)

    Bug Fixes

    • Stop event-log flicker on pagination (87cb33c)

    All Commits
    Hash Message Author
    6229bf9 feat(frontend): redesign settings/common with Aurora cassettes alexei.dolgolyov
    a666bad feat(frontend): group targets by bot, redesign backup settings alexei.dolgolyov
    bede928 feat(server): add /status command handler for webhook providers alexei.dolgolyov
    87cb33c fix(frontend): stop event-log flicker on pagination alexei.dolgolyov

    Changelog

    5d41a39 chore: release v0.7.2
    6229bf9 feat(frontend): redesign settings/common with Aurora cassettes
    a666bad feat(frontend): group targets by bot, redesign backup settings
    bede928 feat(server): add /status command handler for webhook providers
    87cb33c fix(frontend): stop event-log flicker on pagination

    Downloads
  • v0.7.1 757271dadf

    Notify Bridge 0.7.1
    Release / release (push) Successful in 2m11s
    Stable

    alexei.dolgolyov released this 2026-05-07 23:33:09 +03:00 | 27 commits to master since this release

    v0.7.1 (2026-05-07)

    Features

    • Bot command invocations now appear in the dashboard event stream with command_handled, command_rate_limited, and command_failed rows — closing the last user-initiated path that was invisible to the dashboard (35a3008)
    • Click any event row to open a detail modal with full provenance (bot → chat → issuer → provider), raw details JSON, and per-entity action buttons that deep-link into the relevant list page with the card scrolled into view and pulsing (35a3008)
    • Configurable event auto-refresh dropdown (Off / 10s / 30s / 1m / 5m), persisted in localStorage; ticker pauses while the tab is hidden (35a3008)
    • Smoother event refresh — no more loading-placeholder flicker on auto-refresh; unchanged rows reuse their DOM nodes and identical pages skip re-rendering entirely (b170c2b)
    • Page header breadcrumbs are now translated (new crumbs.* i18n namespace covering all 15 call sites), so Routing · Notification, Operators · Bots, etc. switch with the active language (b170c2b)
    • Tracker form's Immich feature-discovery banner now offers an Open Template Config shortcut alongside Open Tracking Config, and /template-configs?edit=<id> auto-opens the editor on landing (b170c2b)
    • Event-type filter, dashboard verb labels, and gradients extended for the three new command_* types; filled in previously missing i18n keys (common.hide, common.show, commandConfig.noCommandsForProvider) (35a3008)
    • Telegram issuer info (from) captured in both poller and webhook paths and persisted under details.issuer, whitelisted to identity fields only by _normalize_issuer so language_code and any future PII fields are dropped (35a3008)

    Bug Fixes

    • Cyrillic glyphs in sidebar nav links, section labels, and monospace badges now render in Geist instead of falling back to Segoe UI / Cascadia / Consolas. Switched to @fontsource-variable/geist (latin + latin-ext + cyrillic) and added @fontsource/geist-mono cyrillic subsets for weights 400/500/600 (73b046f)

    Development / Internal

    Database

    • EventLog gains nullable command_tracker_id / telegram_bot_id FKs plus deletion-snapshot name columns; idempotent migration (35a3008)
    • /api/status resolves live CommandTracker / TelegramBot names (mirroring the action pattern) and exposes tracker_id, command_tracker_id, telegram_bot_id so the frontend can deep-link (35a3008)

    Tests

    • New test_command_event_logging.py covers subject formatting, issuer normalization, the three event branches, and graceful failure when the DB is unreachable; full server suite passing 96/96 (35a3008)

    All Commits
    Hash Message Author
    73b046f fix(frontend): cyrillic glyphs for nav and section labels alexei.dolgolyov
    b170c2b feat(frontend): smoother event refresh, localized crumbs, template config deep-link alexei.dolgolyov
    35a3008 feat: log bot command invocations to the event stream alexei.dolgolyov

    Changelog

    757271d chore: release v0.7.1
    73b046f fix(frontend): cyrillic glyphs for nav and section labels
    b170c2b feat(frontend): smoother event refresh, localized crumbs, template config deep-link
    35a3008 feat: log bot command invocations to the event stream

    Downloads
  • v0.7.0 632e4c1aa3

    Notify Bridge 0.7.0
    Release / release (push) Successful in 1m19s
    Stable

    alexei.dolgolyov released this 2026-05-07 14:03:48 +03:00 | 31 commits to master since this release

    v0.7.0 (2026-05-07)

    Hardened notification stack with shared HTTP base, SSRF protections, secret redaction, and a bounded queue across every provider client; Settings logging selectors switched to icon grids; entity names autogenerate from the chosen type or provider across bots, targets, trackers, actions, and configs.

    User-facing changes

    Features

    • Settings: replace log level and log format dropdowns with icon-grid selectors carrying per-option icons and i18n descriptions (0eb899a)
    • Forms: auto-generate entity names from the selected type/provider across bots, targets, notification trackers, command trackers, actions, and tracking/template/command/command-template configs — names update live until you manually edit, then your edit is preserved (5bd63a2)

    Reliability & Security

    • Notification stack hardening: shared HTTP base, SSRF protections, secret redaction in error logs, and a bounded delivery queue across the dispatcher, receiver, and all provider clients (telegram, discord, email, matrix, ntfy, slack, webhook) (0eb899a)

    Development / Internal

    Refactoring

    • Notifications: extract shared http_base, redact, and SSRF helpers; refactor dispatcher, queue, receiver, and every provider client onto the new base (0eb899a)

    Tests

    • New coverage: SSRF hardening, secret redaction, HTTP base, bounded queue, dispatcher aggregation, Telegram media partitioning, email and matrix clients (0eb899a)

    Tooling

    • Document code-review-graph MCP usage in CLAUDE.md, register .mcp.json, and gitignore .code-review-graph/ (0eb899a)

    All Commits

    Click to expand
    Hash Message Author
    0eb899a feat: harden notification stack and switch logging selectors to icon grid alexei.dolgolyov
    5bd63a2 feat(frontend): autogenerate entity names from type/provider alexei.dolgolyov

    Changelog

    632e4c1 chore: release v0.7.0
    0eb899a feat: harden notification stack and switch logging selectors to icon grid
    5bd63a2 feat(frontend): autogenerate entity names from type/provider

    Downloads
  • v0.6.5 349e9136a4

    Notify Bridge 0.6.5
    Release / release (push) Successful in 1m36s
    Stable

    alexei.dolgolyov released this 2026-04-28 19:10:49 +03:00 | 34 commits to master since this release

    v0.6.5 (2026-04-28)

    UI polish across the redesign: command-template editing now groups slots into four labelled fieldsets that mirror the notification-template page, modal/popup scrolling no longer drags the page underneath, and Telegram's Discover Chats keeps the existing list visible with a smooth shimmer instead of blanking it to "Loading…".

    User-facing changes

    Features

    • Command template slots grouped into 4 fieldsets: the command-template configs page now mirrors the notification-template layout, splitting slots by name prefix into Command Responses, Error Messages (rate_limited / no_results), Command Descriptions (desc_*), and Usage Examples (usage_*). The language picker, reset-all button, and slot filter are hoisted above the groups so they apply across all fieldsets, and empty groups are hidden so providers without usage_* slots don't render an empty header (04c8e3c)

    Bug Fixes

    • Modal scroll chaining contained: scrolling past the inner boundary of a modal or popup no longer scrolls the page underneath. overscroll-behavior: contain was added to every in-modal/popup scroll container — Modal body, EntitySelect, MultiEntitySelect, IconPicker, IconGridSelect, SearchPalette, and TimezoneSelector (9afd38e)
    • Smoother Telegram Discover Chats refresh: Discover Chats no longer collapses the existing chat list into a "Loading…" placeholder. The initial-load state (chatsLoading) is now split from the refresh state (chatsRefreshing); rows are keyed by chat.id with flip+fade animations, the list dims with a sweeping shimmer while the Discover button shows a spinning icon and a "Discovering chats…" label. Honors prefers-reduced-motion (9afd38e)

    Development / Internal

    i18n

    • Drop orphan cmdTemplateConfig.commandResponsesHint key — hints.commandResponses replaces it (04c8e3c)

    All Commits
    Hash Message Author
    04c8e3c feat(frontend): group command template slots into 4 logical fieldsets alexei.dolgolyov
    9afd38e fix(redesign): contain modal scroll chaining and smooth Telegram chat refresh alexei.dolgolyov

    Changelog

    349e913 chore: release v0.6.5
    04c8e3c feat(frontend): group command template slots into 4 logical fieldsets
    9afd38e fix(redesign): contain modal scroll chaining and smooth Telegram chat refresh

    Downloads
  • v0.6.4 aa9548d884

    Notify Bridge 0.6.4
    Release / release (push) Successful in 1m41s
    Stable

    alexei.dolgolyov released this 2026-04-27 18:27:09 +03:00 | 37 commits to master since this release

    v0.6.4 (2026-04-27)

    Fixes Telegram chat actions: the indicator the user picks in the UI is now actually sent, and the phantom "typing…" bubble that lingered for ~5s after a notification arrived is gone.

    User-facing changes

    Bug Fixes

    • Telegram chat action UI choice now respected: chat_action was stored in two places — the model column and the config JSON — and dispatch unconditionally overrode the config value with the column. The frontend only ever wrote the JSON path, so picking "upload_photo" / "record_voice" / etc. in the UI silently had no effect on outgoing chat actions. The column is now the single source of truth: the frontend sends chat_action top-level, dispatch reads from the column, and a one-time migration backfills existing config values into the column and strips the legacy key (72dd611)
    • Phantom Telegram chat-action indicator: a long-standing race in the keepalive loop (bare sleep(4) + finally cancel) could fire one last sendChatAction after the response had already arrived, leaving a "typing…" / "uploading…" bubble in the chat for ~5 seconds. Replaced with a stop event + wait_for so callers signal stop cleanly via the new stop_keepalive helper (72dd611)

    Development / Internal

    Database

    • Migration: new one-shot migration moves chat_action from notification_target.config JSON into the dedicated column on existing rows, then deletes the legacy key from config. No action required — runs automatically on backend start (72dd611)

    All Commits
    Hash Message Author
    72dd611 fix(telegram): respect chat_action UI choice, drop phantom indicator alexei.dolgolyov

    Changelog

    aa9548d chore: release v0.6.4
    72dd611 fix(telegram): respect chat_action UI choice, drop phantom indicator

    Downloads