Commit Graph

105 Commits

Author SHA1 Message Date
aab29e253f Fix [object Object] in Variables button + allow preview of system templates
Some checks failed
Validate / Hassfest (push) Has been cancelled
- Escape {{ }} in Svelte template (use {'{{ }}'} string expression)
- Allow _get() to access system templates (user_id=0) for preview

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:02:35 +03:00
693c157c31 Fix post-login/setup navigation: use hard redirect instead of goto
Some checks failed
Validate / Hassfest (push) Has been cancelled
goto('/') races with layout's onMount auth check, causing redirect
back to /login. Use window.location.href for full page reload which
re-initializes layout with authenticated state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:59:50 +03:00
0bb4d8a949 Simplify templates to pure Jinja2 + CodeMirror editor + variable reference
Some checks failed
Validate / Hassfest (push) Has been cancelled
Major template system overhaul:
- TemplateConfig simplified from 21 fields to 9: removed all sub-templates
  (asset_image, asset_video, assets_format, people_format, etc.)
  Users write full Jinja2 with {% for %}, {% if %} inline.
- Default EN/RU templates seeded on first startup (user_id=0, system-owned)
  with proper Jinja2 loops over added_assets, people, albums.
- build_full_context() simplified: passes raw data directly to Jinja2
  instead of pre-rendering sub-templates.
- CodeMirror editor for template slots (HTML syntax highlighting,
  line wrapping, dark theme support via oneDark).
- Variable reference API: GET /api/template-configs/variables returns
  per-slot variable descriptions + asset_fields for loop contexts.
- Variable reference modal in UI: click "{{ }} Variables" next to any
  slot to see available variables with Jinja2 syntax examples.
- Route ordering fix: /variables registered before /{config_id}.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:57:51 +03:00
bc8fda5984 Add tooltip hints to form fields, fix navigation overlap bug
Some checks failed
Validate / Hassfest (push) Has been cancelled
- Create Hint component with fixed-position floating tooltip
- Add hints to tracking configs (periodic/scheduled/memory modes,
  favorites, times, album mode, rating), template configs (section
  legends), targets (AI captions, media settings, config selectors),
  and trackers (scan interval)
- Add 21 hint i18n keys in EN and RU
- Fix transition:slide → in:slide on all pages to prevent content
  overlap when navigating away mid-animation
- Merge Asset Display into Event Tracking fieldset; use consistent
  "Max Assets" label with hint in each section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:43:30 +03:00
381de98c40 Comprehensive review fixes: security, performance, code quality, and UI polish
Some checks failed
Validate / Hassfest (push) Has been cancelled
Backend: Fix CORS wildcard+credentials, add secret key warning, remove raw
API keys from sync endpoint, fix N+1 queries in watcher/sync, fix
AttributeError on event_types, delete dead scheduled.py/templates.py,
add limit cap on history, re-validate server on URL/key update, apply
tracking/template config IDs in update_target.

HA Integration: Replace datetime.now() with dt_util.now(), fix notification
queue to only remove successfully sent items, use album UUID for entity
unique IDs, add shared links dirty flag and users cache hourly refresh,
deduplicate _is_quiet_hours, add HTTP timeouts, cache albums in config
flow, change iot_class to local_polling.

Frontend: Make i18n reactive via $state (remove window.location.reload),
add Modal transitions/a11y/Escape key, create ConfirmModal replacing all
confirm() calls, add error handling to all pages, replace Unicode nav
icons with MDI SVGs, add card hover effects, dashboard stat icons, global
focus-visible styles, form slide transitions, mobile responsive bottom
nav, fix password error color, add ~20 i18n keys (EN/RU).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:34:31 +03:00
a04d5618d0 Fix icon picker horizontal scroll + finalize Phase 10 plan
Some checks failed
Validate / Hassfest (push) Has been cancelled
IconPicker: replace fixed w-8 h-8 buttons with aspect-square +
overflow-x:hidden to eliminate horizontal scrollbar.

Phase 10 plan updates:
- Add /ocr command (text visible in photos)
- Add /find (text search) separate from /search (CLIP semantic)
- All browsing commands accept [N] count limit (default configurable)
- Response mode configurable per bot (media/text) with --text override
- Rate limiting configurable per command category per chat
- Full EN/RU localized command descriptions (15 commands)
- Descriptions editable per bot in UI
- setMyCommands with language_code for both locales

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:19:31 +03:00
fa829da8b7 Phase 10: scope to tracked albums only, add /search (CLIP) + /find (text)
Some checks failed
Validate / Hassfest (push) Has been cancelled
- IMPORTANT constraint: all asset commands only search within
  tracked albums, never expose untracked content
- /search uses Immich CLIP semantic search (natural language)
- /find uses text search (filename, description)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:09:08 +03:00
a85c557a20 Update Phase 10: remove /trackers, /targets; add /person, /place commands
Some checks failed
Validate / Hassfest (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:08:31 +03:00
69299c055f Add Phase 10 plan: Telegram bot commands
Some checks failed
Validate / Hassfest (push) Has been cancelled
15 commands across 4 categories:
- Informational: /status, /albums, /events
- On-demand: /summary, /latest, /memory, /random
- Asset browsing: /search, /favorites, /people
- Management: /trackers, /targets, /help

Auto-registers commands with Telegram setMyCommands API when
config changes. Per-bot command enable/disable in UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:05:12 +03:00
7ef9cb4326 Fix icon picker grid: use inline grid styles for reliable 8-column layout
Some checks failed
Validate / Hassfest (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:03:49 +03:00
7c8f0f4432 Fix icon picker positioning + match input height + add overlay rule
Some checks failed
Validate / Hassfest (push) Has been cancelled
- IconPicker: use position:fixed with getBoundingClientRect() for
  dropdown (fixes rendering at page footer instead of below button)
- Match icon button height to text input (py-2 same as inputs)
- CLAUDE.md: add rule about overlays requiring position:fixed with
  inline styles (Tailwind v4 classes unreliable in flex containers)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:03:13 +03:00
5a0b0b78f6 Add MDI icon picker to all entity types
Some checks failed
Validate / Hassfest (push) Has been cancelled
- Install @mdi/js (~7000 Material Design Icons)
- IconPicker component: dropdown with search, popular icons grid,
  clear option. Stores icon name as string (e.g. "mdiCamera")
- MdiIcon component: renders SVG from icon name
- Backend: add `icon` field to ImmichServer, TelegramBot,
  TrackingConfig, TemplateConfig, NotificationTarget, AlbumTracker
- All 6 entity pages: icon picker next to name input in create/edit
  forms, icon displayed on entity cards

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:01:22 +03:00
af9bfb7b22 Hide chat selector until bot is selected
Some checks failed
Validate / Hassfest (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:49:57 +03:00
4b01a4b371 Remove manual token input from Telegram targets
Some checks failed
Validate / Hassfest (push) Has been cancelled
Telegram targets now require a registered bot (no manual token
fallback). Shows link to /telegram-bots page when no bots exist.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:48:09 +03:00
cf987cbfb4 Phase 9: Telegram bot management with chat discovery
Some checks failed
Validate / Hassfest (push) Has been cancelled
New entity + API:
- TelegramBot model (name, token, bot_username, bot_id)
- CRUD at /api/telegram-bots with token validation via getMe
- GET /{id}/chats: discover active chats via getUpdates
- GET /{id}/token: retrieve full token (for target config)

Frontend:
- /telegram-bots page: register bots, view discovered chats
  per bot (expandable), refresh on demand
- Targets page: select from registered bots (dropdown) instead
  of raw token input. Chat selector shows discovered chats
  when bot is selected, falls back to manual input.
  Bot token resolved server-side on save.

Nav icon uses monochrome symbol for consistency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:45:58 +03:00
5dee7c55ca Fix i18n: auto-initialize locale on module load
Some checks failed
Validate / Hassfest (push) Has been cancelled
The locale defaulted to 'en' until onMount ran initLocale(), causing
all server-side and initial client renders to show English even when
Russian was saved in localStorage.

Fix: read localStorage synchronously at module import time so t()
returns the correct locale from the first render.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:38:10 +03:00
ca6a9c8830 Fix modal rendering + logout SVG icon
Some checks failed
Validate / Hassfest (push) Has been cancelled
- Modal: use inline styles instead of Tailwind classes for position:fixed
  overlay (Tailwind v4 classes weren't applying correctly inside flex)
- Move password modal outside the flex container to top level
- Replace logout text button with SVG logout icon (16x16, Lucide style)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:34:36 +03:00
7b7ef5fec1 Password change as modal + admin can reset other user passwords
Some checks failed
Validate / Hassfest (push) Has been cancelled
- New Modal.svelte component: overlay with backdrop click to close,
  title bar, reusable via children snippet
- Layout: password change moved from inline sidebar form to modal
  dialog. Clean UX with current + new password fields.
- Users page: 🔑 button per user opens modal for admin to set a
  new password (no current password required for admin reset)
- Backend: PUT /api/users/{id}/password (admin only, min 6 chars)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:32:03 +03:00
0200b9929f Phase 8: Server health, album filter, Jinja2 engine, password change
Some checks failed
Validate / Hassfest (push) Has been cancelled
5 features implemented:

1. Server health indicator: green/red/yellow dot on each server card.
   Pings Immich in background on page load. New GET /api/servers/{id}/ping.

2. Album selector filter: search input above album list in tracker form.
   Filters by name as you type (case-insensitive). Shows total count.

3. Album last update time: each album in the selector shows its
   updatedAt date. Backend now returns updatedAt from Immich API.

4. Full Jinja2 template engine in notifier:
   - build_full_context() assembles all ~40 variables from blueprint
   - Common date/location detection across assets
   - Per-asset date/location when they differ
   - Favorite indicator, people formatting, asset list with truncation
   - Video warning for Telegram
   - All template slots from TemplateConfig used contextually

5. Password change: PUT /api/auth/password endpoint (validates current
   password, min 6 chars). UI in sidebar footer with inline form.

Also: Phase 9 plan (Telegram bot management) added.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:27:00 +03:00
431069fbdb Add Phase 8 plan: UI polish, template engine, password change
Some checks failed
Validate / Hassfest (push) Has been cancelled
5 tasks:
1. Server health indicator on cards
2. Album selector filter-by-name
3. Album last update time display
4. Review/improve template engine (Jinja2 with full variable context)
5. Change user password (self + admin reset)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:16:56 +03:00
5192483fff Add smart combined album asset redistribution + fix locale string
Some checks failed
Validate / Hassfest (push) Has been cancelled
Core library:
- New combine_album_assets() in asset_utils.py: smart redistribution
  of unused quota when albums return fewer assets than their share.
  Two-pass algorithm: even split then redistribute remainder.
- 6 new tests (56 total passing).

Frontend:
- Fix "leave empty to keep current" not localized in server edit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:15:26 +03:00
b708b14f32 Add frontend for TrackingConfig + TemplateConfig, fix locale, simplify trackers
Some checks failed
Validate / Hassfest (push) Has been cancelled
New pages:
- /tracking-configs: Full CRUD with event tracking, asset display,
  periodic summary, scheduled assets, and memory mode sections.
  Collapsible sub-sections that show/hide based on enabled state.
- /template-configs: Full CRUD with all 21 template slots organized
  into 5 fieldsets (event messages, asset formatting, date/location,
  scheduled messages, telegram). Preview support per slot.

Updated pages:
- Targets: added tracking_config_id + template_config_id selectors
  (dropdowns populated from configs). Configs are reusable.
- Trackers: simplified to album selection + scan interval + targets.
  Added Test, Test Periodic, Test Memory buttons per tracker.
- Nav: replaced Templates with Tracking + Templates config links

Other fixes:
- Language button: now triggers window.location.reload() to force
  all child pages to re-evaluate t() calls
- Dark theme buttons: changed primary color to dark gray in dark mode
- Removed old /templates page (replaced by /template-configs)
- Added .gitignore for __pycache__ in server package

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:10:34 +03:00
90b4713d5c Restructure data model: TrackingConfig + TemplateConfig entities
Some checks failed
Validate / Hassfest (push) Has been cancelled
Major model restructuring for clean separation of concerns:

New entities:
- TrackingConfig: What to react to (event types, asset filters,
  periodic/scheduled/memory mode config) - reusable across targets
- TemplateConfig: All ~15 template slots from blueprint (event
  messages, asset formatting, date/location, scheduled messages)
  with full defaults - separate entities per locale

Changed entities:
- AlbumTracker: Simplified to album selection + polling + target_ids
  (removed event_types, template_id, all filter fields)
- NotificationTarget: Extended with tracking_config_id and
  template_config_id FKs (many-to-one, reusable configs)

Removed entities:
- MessageTemplate (replaced by TemplateConfig)
- ScheduledJob (absorbed into TrackingConfig)

Updated services:
- watcher.py: Each target checked against its own tracking_config
  for event filtering before sending notification
- notifier.py: Uses target's template_config to select the right
  template slot based on event type

New API routes:
- /api/tracking-configs/* (CRUD)
- /api/template-configs/* (CRUD + per-slot preview)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 16:57:19 +03:00
fd1ad91fbe Fix UI issues: locale switching, dark theme, loading, edit support
Some checks failed
Validate / Hassfest (push) Has been cancelled
- Fix i18n: remove $state rune (SSR incompatible in .ts files),
  use reactive localeVersion counter in layout to trigger re-render
  on locale change. Language switching now works immediately.
- Fix dark theme: add global CSS rules for input/select/textarea to
  use theme colors, override browser autofill in dark mode, set
  color-scheme for native controls (scrollbars, checkboxes)
- Collapsible sidebar: toggle button (▶/◀) with persistent state,
  icons-only mode when collapsed. Theme/language buttons moved to
  bottom above user info.
- Loading skeletons: all pages show animated pulse placeholders
  while data loads, eliminating content flicker on tab switch
- Edit support: Servers, Trackers, and Targets now have Edit buttons
  that open the form pre-filled with current values. Save calls PUT.
  Sensitive fields (API key, bot token) can be left empty to keep
  current value when editing.
- CLAUDE.md: add dev server restart rules

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 16:15:17 +03:00
42063b7bf6 Mark Phase 7 complete in primary plan
Some checks failed
Validate / Hassfest (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:48:30 +03:00
89cb2bbb70 Add enhanced models, scheduled jobs, per-locale templates (Phase 7b)
Some checks failed
Validate / Hassfest (push) Has been cancelled
Backend changes for full blueprint feature parity:

Database models:
- MessageTemplate: add body_ru (locale variant), event_type field
- AlbumTracker: add track_images, track_videos, notify_favorites_only,
  include_people, include_asset_details, max_assets_to_show,
  assets_order_by, assets_order fields
- New ScheduledJob model: supports periodic_summary, scheduled_assets,
  and memory (On This Day) notification modes with full config
  (times, interval, album_mode, limit, filters, sorting)

API:
- New /api/scheduled/* CRUD endpoints for scheduled jobs
- Tracker create/update accept all new filtering fields
- Tracker response includes new fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:48:01 +03:00
2aa9b8939d Add i18n (RU/EN), dark/light themes, enhanced tracker/target forms (Phase 7a)
Some checks failed
Validate / Hassfest (push) Has been cancelled
Frontend enhancements:
- i18n: Full Russian and English translations (~170 keys each),
  language switcher in sidebar and login page, auto-detect from
  browser, persists to localStorage
- Themes: Light/dark mode with CSS custom properties, system
  preference detection, toggle in sidebar header, smooth transitions
- Dark theme: Full color palette (background, card, muted, border,
  success, warning, error variants)

Enhanced forms:
- Tracker creation: asset type filtering (images/videos), favorites
  only, include people/details toggles, sort by/order selects,
  max assets to show
- Target creation: Telegram media settings (collapsible) with
  max media, group size, chunk delay, max asset size, URL preview
  disable, large photos as documents
- Template creation: event_type selector (all/added/removed/renamed/deleted)

All pages use t() for translations, var(--color-*) for theme-safe
colors, and proper label-for-input associations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:44:32 +03:00
1ad9b8af1d Add Phase 7 plan: Production UI with i18n, themes, OAuth, blueprint parity
Some checks failed
Validate / Hassfest (push) Has been cancelled
Phase 7 covers:
- i18n (RU/EN), dark/light themes, OAuth via Immich
- 4 notification modes matching HAOS blueprint
- Enhanced tracker config (filtering, sorting, telegram media)
- Full template variable system (40+ vars, per-event templates)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:31:02 +03:00
3a516d6d58 Fix runtime issues found during live testing
Some checks failed
Validate / Hassfest (push) Has been cancelled
- Fix jinja2.sandbox import: use `from jinja2.sandbox import
  SandboxedEnvironment` (dotted attribute access doesn't work)
  in templates.py, sync.py, and notifier.py
- Fix greenlet crash in tracker trigger: SQLAlchemy async sessions
  can't survive across aiohttp.ClientSession context managers.
  Eagerly load all tracker/server data before entering HTTP context.
  Split check_tracker into check_tracker (scheduler, own session)
  and check_tracker_with_session (API, reuses route session).
- Fix _check_album to accept pre-loaded params instead of tracker
  object (avoids lazy-load access after greenlet context break)

Tested end-to-end against live Immich server:
- Server connection + album browsing: OK (39 albums)
- Template creation + preview: OK
- Webhook target creation: OK
- Tracker creation + trigger: OK (initialized 4 assets)
- Second trigger: OK (no_changes detected)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:17:12 +03:00
62bf15dce3 Fix Phase 6 review issues: webhook auth, memory bounds, SSTI
Some checks failed
Validate / Hassfest (push) Has been cancelled
Fixes 7 issues identified by code-reviewer agent:

1. (Critical) Webhook endpoint now validates X-Telegram-Bot-Api-
   Secret-Token header against configured secret, and verifies
   bot_token matches a stored NotificationTarget
2. (Critical) register/unregister webhook endpoints now require
   JWT auth via Depends(get_current_user); register passes
   secret_token to Telegram setWebhook
3. (Critical) Conversation dict now uses OrderedDict with LRU
   eviction (max 100 chats); trim happens BEFORE API call
4. (Important) Tool-use responses no longer stored in conversation
   history (avoids corrupted multi-turn state)
5. (Important) Singleton AsyncAnthropic client (module-level,
   lazily initialized once) - no more connection pool leaks
6. (Important) Markdown retry now uses payload.pop("parse_mode")
   instead of setting empty string
7. (Important) All user-controlled data wrapped in <data> tags
   with _sanitize() helper (truncation + newline stripping)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:42:06 +03:00
88ffd5d077 Add Claude AI Telegram bot enhancement (Phase 6)
Some checks failed
Validate / Hassfest (push) Has been cancelled
Integrate Claude AI into the notification system for intelligent
conversational interactions and AI-powered captions.

New modules:
- ai/service.py: Claude API client with conversation history,
  caption generation, and album activity summarization
- ai/telegram_webhook.py: Telegram webhook handler for incoming
  bot messages, routes to AI service for responses

Features:
- Conversational bot: users chat with the bot about albums
- AI captions: intelligent notification messages based on album
  context (people, locations, dates) - enabled per target via
  "ai_captions" config flag
- Album summaries: "what's new?" triggers AI-generated overview
- /start command with welcome message
- Webhook register/unregister endpoints

Architecture:
- Per-chat conversation history (in-memory, capped at 20 messages)
- Graceful degradation: AI features completely disabled without
  IMMICH_WATCHER_ANTHROPIC_API_KEY env var (zero impact)
- AI caption failure falls back to Jinja2 template rendering
- Health endpoint reports ai_enabled status

Config: IMMICH_WATCHER_ANTHROPIC_API_KEY, IMMICH_WATCHER_AI_MODEL,
IMMICH_WATCHER_AI_MAX_TOKENS

Server now has 45 API routes (was 42 after Phase 5).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:38:51 +03:00
43f83acda9 Fix Phase 5 review issues: SSTI, FK violation, sync rebuild
Some checks failed
Validate / Hassfest (push) Has been cancelled
Fixes 5 issues identified by code-reviewer agent:

1. (Critical) EventLog.tracker_id now nullable - use None instead
   of 0 when tracker name doesn't match, avoiding FK constraint
   violations on PostgreSQL
2. (Critical) Replace jinja2.Environment with SandboxedEnvironment
   in all 3 server template rendering locations to prevent SSTI
3. (Important) Rebuild sync_client in _async_update_listener when
   server URL/key options change, propagate to all coordinators
4. (Important) Validate partial server config - require both URL
   and API key or neither, with clear error message
5. (Important) Name fire-and-forget sync task for debugging

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:17:59 +03:00
ab1c7ac0db Add HAOS-Server sync for optional centralized management (Phase 5)
Some checks failed
Validate / Hassfest (push) Has been cancelled
Enable the HAOS integration to optionally connect to the standalone
Immich Watcher server for config sync and event reporting.

Server-side:
- New /api/sync/* endpoints: GET trackers, POST template render,
  POST event report
- API key auth via X-API-Key header (accepts JWT access tokens)

Integration-side:
- New sync.py: ServerSyncClient with graceful error handling
  (all methods return defaults on connection failure)
- Options flow: optional server_url and server_api_key fields
  with connection validation
- Coordinator: fire-and-forget event reporting to server when
  album changes are detected
- Translations: en.json and ru.json updated with new fields

The connection is fully additive -- the integration works identically
without a server URL configured. Server failures never break HA.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:10:29 +03:00
2b487707ce Fix frontend issues found in Phase 4 code review
Some checks failed
Validate / Hassfest (push) Has been cancelled
Fixes 7 issues identified by code-reviewer agent:

1. (Critical) Move JSON.parse inside try/catch in targets page to
   handle malformed webhook headers input gracefully
2. (Low) Add window guard to refreshAccessToken for SSR safety
3. (Important) Show loading indicator instead of page content while
   auth state is being resolved (prevents flash of protected content)
4. (Important) Add try/catch to trackers load() Promise.all
5. (Important) Add error handling to remove() in servers, trackers,
   and templates pages
6. (Important) Track preview per-template with previewId, show
   inline instead of global bottom block
7. (Important) Use finally block for loading state in auth

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:51:39 +03:00
87ce1bc5ec Add SvelteKit frontend with Tailwind CSS (Phase 4)
Some checks failed
Validate / Hassfest (push) Has been cancelled
Build a modern, calm web UI using SvelteKit 5 + Tailwind CSS v4.

Pages:
- Setup wizard (first-run admin account creation)
- Login with JWT token management and auto-refresh
- Dashboard with stats cards and recent events timeline
- Servers: add/delete Immich server connections with validation
- Trackers: create album trackers with album picker, event type
  selection, target assignment, and scan interval config
- Templates: Jinja2 message template editor with live preview
- Targets: Telegram and webhook notification targets with test
- Users: admin-only user management (create/delete)

Architecture:
- Reactive auth state with Svelte 5 runes
- API client with JWT auth, auto-refresh on 401
- Static adapter builds to 153KB for embedding in FastAPI
- Vite proxy config for dev server -> backend API
- Sidebar layout with navigation and user info

Also adds Rule 2 to primary plan: perform detailed code review
after completing each phase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 13:46:55 +03:00
58b2281dc6 Add standalone FastAPI server backend (Phase 3)
Some checks failed
Validate / Hassfest (push) Has been cancelled
Build a complete standalone web server for Immich album change
notifications, independent of Home Assistant. Uses the shared
core library from Phase 1.

Server features:
- FastAPI with async SQLite (SQLModel + aiosqlite)
- Multi-user auth with JWT (admin/user roles, setup wizard)
- CRUD APIs: Immich servers, album trackers, message templates,
  notification targets (Telegram + webhook), user management
- APScheduler background polling per tracker
- Jinja2 template rendering with live preview
- Album browser proxied from Immich API
- Event logging and dashboard status endpoint
- Docker deployment (single container, SQLite in volume)

39 API routes, 14 integration tests passing.

Also adds Phase 6 (Claude AI Telegram bot enhancement) to the
primary plan as an optional future phase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:56:22 +03:00
b107cfe67f Refactor HAOS integration to use shared core library (Phase 2)
Some checks failed
Validate / Hassfest (push) Has been cancelled
Wire the integration to delegate all HA-independent logic to
immich-watcher-core, eliminating ~2300 lines of duplicated code.

Changes:
- const.py: Import shared constants from core, keep HA-specific ones
- storage.py: Create HAStorageBackend adapter wrapping HA's Store,
  use core TelegramFileCache and NotificationQueue via adapter
- coordinator.py: Delegate to core ImmichClient for API calls,
  detect_album_changes() for change detection, and asset_utils
  for filtering/sorting/URL building. Keep HA-specific event firing.
- sensor.py: Replace ~1300 lines of Telegram code with 15-line
  delegation to core TelegramClient. Keep entity classes unchanged.
- __init__.py: Use factory functions for creating core instances
  with HA storage backends
- manifest.json: Add immich-watcher-core dependency

Integration line count: 3600 -> 1295 lines (-64%)
Zero behavior changes for end users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:47:18 +03:00
d0783d0b6a Add shared core library and architecture plans (Phase 1)
Some checks failed
Validate / Hassfest (push) Has been cancelled
Extract HA-independent logic from the integration into packages/core/
as a standalone Python library (immich-watcher-core). This is the first
phase of restructuring the project to support a standalone web app
alongside the existing HAOS integration.

Core library modules:
- models: SharedLinkInfo, AssetInfo, AlbumData, AlbumChange dataclasses
- immich_client: Async Immich API client (aiohttp, session-injected)
- change_detector: Pure function for album change detection
- asset_utils: Filtering, sorting, URL building utilities
- telegram/client: Full Telegram Bot API (text, photo, video, media groups)
- telegram/cache: File ID cache with pluggable storage backend
- telegram/media: Media size checks, URL extraction, group splitting
- notifications/queue: Persistent notification queue
- storage: StorageBackend protocol + JSON file implementation

All modules have zero Home Assistant imports. 50 unit tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:40:08 +03:00
71b79cd919 Move quiet hours from hub config to per-call service params
All checks were successful
Validate / Hassfest (push) Successful in 1m19s
Quiet hours are now specified per send_telegram_notification call via
quiet_hours_start/quiet_hours_end params instead of being a hub-wide
integration option. This allows different automations to use different
quiet hours windows (or none at all).

- Remove quiet_hours_start/end from config options UI and const.py
- Add quiet_hours_start/end as optional HH:MM params on the service
- Remove ignore_quiet_hours param (omit quiet hours params to send immediately)
- Queue stores quiet_hours_end per item; each unique end time gets its
  own async_track_time_change timer for replay
- On startup, items whose quiet hours have passed are sent immediately
- Add async_remove_indices() to NotificationQueue for selective removal
- Timers are cleaned up when no more items need them

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:04:20 +03:00
678e8a6e62 Add quiet hours, fix Telegram bugs, and improve cache performance
All checks were successful
Validate / Hassfest (push) Successful in 5s
- Add quiet hours support to queue notifications during configured time windows
- Fix UnboundLocalError when single-item document chunk exceeds max_asset_data_size
- Fix document-only multi-item chunks being silently dropped (missing skip guard)
- Fix notification queue entity lookup by storing entity_id in queued params
- Fix quiet hours using OS timezone instead of HA-configured timezone (dt_util.now)
- Fix chat_action schema rejecting empty string from "Disabled" selector
- Fix stale thumbhash cache entries not being removed on mismatch
- Fix translation descriptions for send_large_photos_as_documents
- Add batch async_set_many() to TelegramFileCache to reduce disk writes
- Add max-entries eviction (2000) for thumbhash cache to prevent unbounded growth
- Eliminate redundant _is_asset_id/get_asset_thumbhash lookups in media group loop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:45:34 +03:00
dd7032b411 Replace TTL with thumbhash-based cache validation and add Telegram video size limits
Some checks failed
Validate / Hassfest (push) Has been cancelled
- Asset cache now validates entries by comparing stored thumbhash with current
  Immich thumbhash instead of using TTL expiration. This makes cache invalidation
  precise (only when content actually changes) and eliminates unnecessary re-uploads.
  URL-based cache retains TTL for non-Immich URLs.
- Add TELEGRAM_MAX_VIDEO_SIZE (50 MB) check to skip oversized videos in both
  single-video and media-group paths, preventing entire groups from failing.
- Split media groups into sub-groups by cumulative upload size to ensure each
  sendMediaGroup request stays under Telegram's 50 MB upload limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 12:28:33 +03:00
65ca81a3f3 Link to local server repository
All checks were successful
Validate / Hassfest (push) Successful in 5s
2026-02-05 00:17:22 +03:00
3ba33a36cf Minor refactoring to use common const for telegram API url
All checks were successful
Validate / Hassfest (push) Successful in 4s
2026-02-04 17:46:14 +03:00
6ca3cae5df Add document type and content_type support for send_telegram_notification
All checks were successful
Validate / Hassfest (push) Successful in 3s
- Add type: document as default media type (instead of photo)
- Add optional content_type field for explicit MIME type specification
- Documents are sent separately (Telegram API limitation for media groups)
- Default content types: image/jpeg (photo), video/mp4 (video), auto-detect (document)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 01:35:57 +03:00
fde2d0ae31 Bump version to 2.7.1
All checks were successful
Validate / Hassfest (push) Successful in 4s
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
v2.7.1
2026-02-03 02:51:22 +03:00
31663852f9 Fixed link to automation
All checks were successful
Validate / Hassfest (push) Successful in 6s
2026-02-03 02:50:19 +03:00
5cee3ccc79 Add chat_action parameter to send_telegram_notification service
All checks were successful
Validate / Hassfest (push) Successful in 4s
Shows typing/upload indicator while processing media. Supports:
typing, upload_photo, upload_video, upload_document actions.
Set to empty string to disable. Default: typing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 02:48:25 +03:00
3b133dc4bb Exclude archived assets from processing status check
All checks were successful
Validate / Hassfest (push) Successful in 4s
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 15:02:25 +03:00
a8ea9ab46a Rename on_this_day to memory_date with exclude-same-year behavior
All checks were successful
Validate / Hassfest (push) Successful in 2s
Renamed the date filter parameter and changed default behavior to match
Google Photos memories - now excludes assets from the same year as the
reference date, returning only photos from previous years on that day.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
v2.7.0
2026-02-02 14:24:08 +03:00
e88fd0fa3a Add get_assets filtering: offset, on_this_day, city, state, country
All checks were successful
Validate / Hassfest (push) Successful in 3s
- Add offset parameter for pagination support
- Add on_this_day parameter for memories filtering (match month and day)
- Add city, state, country parameters for geolocation filtering
- Update README with new parameters and examples

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 12:25:35 +03:00