Backend
- Per-chat album scope for Immich commands (search/latest/memory/...): new
allowed_album_ids on CommandTrackerListener, threaded listener/page kwargs
through ProviderCommandHandler.handle; PATCH listener-scope endpoint.
- /search and /find accept a trailing page number; Immich client search_smart
/ search_metadata take a page param.
- Immich person-asset lookup switched from removed GET /api/people/{id}/assets
to POST /api/search/metadata with personIds (fixes /person command and
auto_organize rules silently returning zero candidates on Immich 1.106+).
- Auto_organize rule now sets the target album's thumbnail to the first added
image when missing (falls back to any asset type); failures do not fail the
rule. add_assets_to_album surfaces the Immich error body on non-2xx.
- EventLog.user_id / action_id / action_name columns with defensive migration
+ backfill. Status query filters by user_id directly; Immich/webhook paths
emit user_id explicitly. action_runner writes an action_success/partial/
failed event on each non-dry-run.
- Dashboard DELETE /api/status/events (scoped to user_id) + rendering live
tracker/provider/action names via FK join with snapshot fallback.
- PATCH /api/users/{id} for username/role change with last-admin guard.
- Deletion protection returns structured {message, entity, blocked_by}
(ApiError carries .blockedBy; frontend opens BlockedByModal).
- Backup prepare-restore → AppSetting markers + atomic write of
pending_restore.json; lifespan hook applies on next startup and archives
under data/applied_restores/. apply-restart sends SIGTERM so the lifespan
shutdown runs; NOTIFY_BRIDGE_SUPERVISED env override gates the button.
Manual POST /api/backup/files (same format as scheduled).
- New periodic-summary test path reuses shared collect_scheduled_assets
(limit=0) so test and future production code go through one primitive.
- Per-receiver locale for Telegram test messages (resolves
TelegramChat.language_override per chat instead of applying the first
receiver's locale to everyone).
- Bounded concurrency (semaphores) in NotificationDispatcher._preload_asset_data
and _refresh_telegram_chat_titles; chat title sweep extended to 24h since
save_chat_from_webhook covers active chats opportunistically.
- Telegram poller detects the \"webhook is active\" 409 and auto-calls
deleteWebhook for bots whose DB update_mode is polling (throttled per bot).
- TelegramClient.get_chat added (CLAUDE.md rule 6); set_album_thumbnail added.
- Seeds: rename \"Default Commands\" → \"Default Immich Commands\";
track_assets_removed default False.
Frontend
- Global provider selector visible when there is only one provider.
- Clear-events button + i18n + ConfirmModal on the dashboard; new icons/
labels/filters/colors for action_success / action_partial / action_failed.
- Auto-select first available tracking/template/command/config + bot on
create forms (trackers, command-trackers, targets, template/command
configs).
- Telegram target disable_url_preview defaults to true.
- BlockedByModal wired into 8 deletion flows; fetchAuth helper for
multipart/binary calls (reuses api()'s refresh + ApiError mapping).
- Immich tracker 'Checking links' parallelised (concurrency cap 6).
- Backup page: pending-restore banner + Apply-now / Apply-later modal,
restarting overlay polling /api/health, manual 'Create backup' button.
- Command-trackers listener row gets an 'Edit album scope' modal with
inherit/explicit multiselect.
- Users page: Edit user modal (username + role).
- parseDate helper for consistent UTC date rendering.
Migrations / schema
- event_log: + user_id, action_id, action_name (+ backfill user_id from
notification_tracker).
- command_tracker_listener: + allowed_album_ids.
- Remove top paginator from dashboard events, keep only bottom
- Fix test message locale: pass UI locale to email/matrix bot tests
- Convert webhook auth mode from text input to icon grid selector
- Generate secure UUID tokens for webhook URLs instead of sequential IDs
- Move Recent Payloads into per-provider expandable container (lazy-loaded)
- Make template config languages dynamic via app settings instead of hardcoded
- Change default dev port to 5175
Replace all if/else chains keyed on provider type strings with a
descriptor-driven architecture. Each provider type (immich, gitea,
planka, scheduler, nut, google_photos) has a descriptor in
frontend/src/lib/providers/ that declares config fields, event
tracking fields, collection metadata, validation, and hooks.
Components now use getDescriptor(type) and render dynamically.
Dashboard provider card shows provider name + type when global
filter is active. Grid-items derived from registry.
- Dashboard providers card now shows count of providers matching the
global provider type filter instead of special name/type display
- Fix provider update sending empty config when only name/icon changed,
causing 400 validation error (api_key required)
- Add locale support to notification templates (matching command template
pattern): TemplateSlot now has locale field with (config_id, slot_name,
locale) uniqueness, nested API format {slot: {locale: template}}
- Migration merges separate EN/RU system configs into unified per-provider
configs; seeds create one config per provider with multi-locale slots
- Locale-aware dispatch with EN fallback in NotificationDispatcher
- Frontend locale tabs (EN/RU) on template config editor
- Fix tracking config cards not showing default provider icons
- Global provider filter, search palette, and various UX polish
- Added desc text to all 40+ grid items (EN + RU)
- compact prop on all IconGridSelect in compact form sections
- Fixed compact width to fill grid cells (removed width:auto)
- Replaced <select> filter dropdowns with IconGridSelect on config pages
- Replaced <select> provider filters with EntitySelect on tracker pages
- Dashboard filters constrained to fixed widths (not full row)
- Added filtering to command-template-configs and providers pages
- providerTypeFilterItems() with "All" option for filter contexts
Scheduler provider:
- Virtual provider (no external service) that emits SCHEDULED_MESSAGE
events on user-defined intervals or cron expressions
- Custom variables stored in tracker filters, flattened into template context
- fire_count persists across triggers via tracker state
- APScheduler CronTrigger support for cron-mode schedules
- Default templates (EN+RU), seeded on startup
Multi-provider UX fixes:
- Tracking config hides Immich-specific sections (periodic, scheduled,
memory, asset display) for non-Immich providers
- Command config driven by provider capabilities — hides commands/settings
for providers without bot commands
- Template config hides empty "Scheduled Messages" group
- Test menu on tracker targets is provider-aware (Immich shows all 4 test
types, others show only basic)
- Removed redundant Test button from tracker card
- System-owned tracking configs (user_id=0) seeded for Gitea + Scheduler
- Fixed ownership checks to allow system configs in tracker-target links
- Capabilities cache shared across template-configs and command-configs
- Command tracker bot selector uses EntitySelect instead of raw select
- Sample context includes Gitea + Scheduler variables for template preview
First webhook-based provider integration (Immich uses polling).
Gitea pushes events via POST /api/webhooks/gitea/{provider_id} with
HMAC-SHA256 signature validation.
- 9 event types: push, issue opened/closed/commented, PR opened/closed/merged/commented, release published
- Generic filters system on NotificationTracker (collections, senders, exclude_senders)
- Provider capabilities include supported_filters and webhook_based flag
- Gitea API client for connection testing and repository listing
- 18 default Jinja2 notification templates (EN + RU)
- Frontend: conditional provider forms, Gitea event toggles in tracking config
- Auto-migration for filters column and Gitea tracking flags
When clicking a CrossLink, the target entity ID is passed as
?highlight=<id> in the URL. The destination page:
1. Shows a semi-transparent dim overlay (z-index: 10)
2. Finds the card with data-entity-id matching the ID
3. Scrolls to it smoothly (block: center)
4. Applies a pulsing primary-color box-shadow animation (z-index: 11)
5. Cleans up overlay + animation after 2 seconds
If the card isn't in DOM yet (data still loading), a MutationObserver
waits up to 5 seconds for it to appear.
Changes:
- New highlight.ts utility with highlightFromUrl(), MutationObserver,
dim overlay management
- Card component accepts entityId prop → data-entity-id attribute
- CrossLink accepts entityId prop → appends ?highlight=<id> to href
- All 9 entity pages: Card elements have entityId, highlightFromUrl()
called after data loads
- CSS: cardHighlight keyframe animation + nav-dim-overlay styles
- Add $state-based entity cache layer with 30s TTL, request deduplication,
and local mutation helpers (entity-cache.svelte.ts + caches.svelte.ts)
- Wire all 10 page components to use shared caches for cross-page data
- Add slide animation for nav tree expand/collapse with rotating chevron
- Remove aggregate count badges from container nav nodes (keep on leaves)
- Convert Targets from flat leaf to group with per-type children
(Telegram, Webhook, Email, Discord, Slack, ntfy, Matrix)
- Add URL-based type filtering on Targets page with per-type descriptions
- Add Bots group children for Email and Matrix alongside Telegram
- Tab-based routing for bots page (?tab=telegram/email/matrix)
- Add per-type target counts and email/matrix bot counts to /status/counts
- Split CLAUDE.md into focused context files under .claude/docs/
- Fix .gitignore: scope lib/ to root, allow .claude/docs/ tracking
- Clear all caches on logout
- Reset form state when switching target type tabs
Adds telegram bot command system with 13 commands (search, latest, random, etc.),
webhook/polling handlers, rate limiting, app settings page, and various UI/UX
improvements across all entity pages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace 3 test buttons with unified dropdown menu (basic/periodic/scheduled/memory)
- Send text message first, then assets as reply (not combined caption+media)
- Pass all target config settings to Telegram client (disable_url_preview, max_media, chunk_delay, etc.)
- Real data test notifications for periodic/scheduled/memory (fetch from Immich)
- Provider card URL is now a clickable hyperlink
- Localized test type labels (EN/RU)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show entity icons on all cards with fallback defaults (providers, trackers, targets, bots)
- Enrich EventLog with provider_name, tracker_name, assets_count; add DB migration
- Dashboard events: filtering (type, provider, search), sorting, pagination, dynamic page size
- Friendly chat names on telegram target cards (resolve from TelegramChat table)
- Test message button on bot chat items with locale-aware messages
- Album public link validation on tracker save with auto-create dialog
- Support albums without public links: conditional <a href> in templates
- Fetch shared links during poll, enrich events with public_url/protected_url
- Per-asset public_url in template context ({share_url}/photos/{asset_id})
- Common date/location detection: common_date + common_location context vars
- Dual date formats: date_format (datetime) + date_only_format (date only)
- Template clone button, HTML link rendering in template preview
- Fix Telegram asset download 401: pass x-api-key headers through client
- Fix provider external_url matching for API key scoping
- Fix event timestamp timezone (append Z suffix for UTC)
- Localize event filter controls, test messages (EN/RU)
- Template variable UI helpers updated with all new fields
- CLAUDE.md: template system sync rules documentation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- Scheduler lifecycle sync: create/update/delete tracker now syncs APScheduler jobs
- Test-periodic/test-memory endpoints render actual Jinja2 templates with sample data
- Cascade cleanup on tracker delete (TrackerState removed, EventLog nullified)
- Fix user_id=0 FK violation for system-owned TemplateConfig (removed FK constraint)
- Fix API key leak: only attach x-api-key header for internal provider URLs
- Validate config ownership in tracker_targets create/update
- Fix _response() double-emit of created_at in template/tracking configs
- Add per-target-link test endpoints (test, test-periodic, test-memory)
Frontend:
- Fix orphaned provider on test exception in providers/new
- Add submitting guard + disabled state to targets save button
- Move test buttons from tracker card to per-target-link rows
- Fix Svelte 5 async $state reactivity (spread reassignment for all Record mutations)
- i18n for dashboard timeAgo and event type badges (EN + RU)
- Add required attribute to chat select dropdown in targets
- Fix font CSS vars to prioritize imported DM Sans / JetBrains Mono
- Standardize empty states with centered icon + text across all 6 list pages
- Add stagger-children animation class to all list containers
- Fix slide transition duration consistency (200ms everywhere)
- Standardize border-radius to rounded-md across all form inputs
- Fix providers/new page structure (h2 + mb-8 spacing)
- Fix tracker card action row overflow (flex-wrap justify-end)
- JinjaEditor dark mode reactivity (recreate editor on theme change)
- Add aria-labels to mobile nav items
- Make ConfirmModal confirm button label/icon configurable
- Remove double error reporting on providers page
- Add telegram bot edit functionality (name editing via PUT)
- i18n for External Domain label on provider forms
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend API (38 routes):
- providers: full CRUD + test connection + list collections + API key masking
- trackers: full CRUD + trigger + history + test-periodic/memory
- tracking-configs: full CRUD with Pydantic models, provider_type filter
- template-configs: full CRUD + preview + preview-raw with two-pass validation
- targets: full CRUD + test notification + config masking
- telegram-bots: full CRUD + chat discovery + token endpoint
- users: full admin CRUD + password reset + self-delete protection
- status: dashboard endpoint with providers/trackers/targets/events counts
Frontend pages updated:
- Dashboard with animated stat cards and event timeline
- Providers with proper components, delete confirm, snackbar
- Trackers/targets/tracking-configs/template-configs/telegram-bots/users
all use PageHeader, Card, Loading, MdiIcon with correct i18n keys
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>