Commit Graph

120 Commits

Author SHA1 Message Date
482f54d620 Persist Telegram chats in DB, auto-save from webhooks, click-to-copy
All checks were successful
Validate / Hassfest (push) Successful in 4s
- Add TelegramChat model (bot_id, chat_id, title, type, username)
- Chats auto-saved when bot receives webhook messages
- New API: GET/DELETE chats, POST discover (merges from getUpdates)
- Cascade delete chats when bot is deleted
- Frontend: click chat row to copy chat ID to clipboard
- Frontend: delete button per chat, "Discover chats" sync button
- Add 4 i18n keys (EN/RU) for chat management

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:45:20 +03:00
e6ff0a423a Phase 10: Telegram bot commands + Phase 11: Snackbar notifications
All checks were successful
Validate / Hassfest (push) Successful in 3s
Phase 10 — Telegram Bot Commands:
- Add commands_config JSON field to TelegramBot model (enabled cmds,
  default count, response mode, rate limits, locale)
- Create command handler with 14 commands: /status, /albums, /events,
  /summary, /latest, /memory, /random, /search, /find, /person,
  /place, /favorites, /people, /help
- Add search_smart, search_metadata, search_by_person, get_random,
  download_asset, get_asset_thumbnail to ImmichClient
- Auto-register commands with Telegram setMyCommands API (EN+RU)
- Rate limiting per chat per command category
- Media mode: download thumbnails and send as photos to Telegram
- Webhook handler routes /commands before falling through to AI chat
- Frontend: expandable Commands section per bot with checkboxes,
  count/mode/locale settings, rate limit inputs, sync button

Phase 11 — Snackbar Notifications:
- Create snackbar store (snackbar.svelte.ts) with $state rune
- Create Snackbar component with fly/fade transitions, typed colors
- Mount globally in +layout.svelte
- Replace all alert() calls with typed snackbar notifications
- Add success snacks to all CRUD operations across all pages
- 4 types: success (3s), error (5s), info (3s), warning (4s)
- Max 3 visible, auto-dismiss, manual dismiss via X button

Both: Add ~30 i18n keys (EN+RU) for commands UI and snack messages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:39:05 +03:00
ffce3ee337 Show template previews by default, remove Preview toggle button
All checks were successful
Validate / Hassfest (push) Successful in 3s
Previews now always visible below each template editor when content
is valid. Populated automatically via the debounced validation call.
When editing an existing config, all slots are previewed immediately
on form open. Preview hidden when there are errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:17:22 +03:00
c5a3521b14 Use combobox for target type selector, refresh previews on change
All checks were successful
Validate / Hassfest (push) Successful in 3s
- Replace toggle buttons with <select> dropdown for target type
- Add refreshAllPreviews() that immediately re-renders all open
  previews when target type changes (no 800ms debounce)
- validateSlot() now accepts optional immediate flag

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:13:53 +03:00
4babaddd87 Replace video_warning with target_type + has_videos/has_photos
All checks were successful
Validate / Hassfest (push) Successful in 2s
Major template system improvements:
- Remove video_warning field from TemplateConfig model
- Add target_type, has_videos, has_photos to template context
- Templates use {% if target_type == "telegram" and has_videos %}
  for conditional Telegram warnings instead of a separate field
- date_format moved from "Telegram" to "Settings" group
- Add target type selector (Telegram/Webhook) in template editor
  to preview how templates render for each target type
- All template slots now use JinjaEditor (not plain <input>)
- Preview endpoint accepts target_type parameter
- Clean up TemplateConfigCreate schema (remove stale fields)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:11:38 +03:00
510463cba6 Move preview button to per-slot in edit form, remove card dropdown
All checks were successful
Validate / Hassfest (push) Successful in 3s
- Preview button always visible next to Variables for each template slot
- Remove \n\n prefix from video_warning default value
- Use conditional {% if video_warning %} with blank line in templates
- Fix all .jinja2 files and inline defaults to match
- Add SVG favicon (camera + notification dot)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:03:35 +03:00
b87b5b2c87 Fix template variable docs to match actual notifier output
All checks were successful
Validate / Hassfest (push) Successful in 3s
Audit and fix all template variable references:
- template_vars.py: Add missing fields (album_id, old_shared,
  new_shared, latitude, longitude, owner_id, people per asset)
- _SAMPLE_CONTEXT: Use proper structured data matching
  build_asset_detail() output (id, owner_id, latitude, longitude,
  people per asset, playback_url for videos)
- i18n: Fix all variable descriptions for accuracy, add missing
  fields, mark scheduler-dependent slots as "not yet implemented"
- Variables modal: Add album_fields section for periodic_summary
- Shared _ASSET_FIELDS and _ALBUM_FIELDS dicts in template_vars.py
  to keep scheduled/memory slots DRY

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:58:21 +03:00
3c893d6dbf Add live template preview (auto-updates as you type)
All checks were successful
Validate / Hassfest (push) Successful in 4s
Preview now piggybacks on the validation debounce call — when the
template renders successfully, the result is shown in a collapsible
<details> section below the editor. Removes the manual Preview button
since it's now automatic. Preview hides when there are errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:51:04 +03:00
afb8be8101 Jinja2 syntax validation with debounced API check
All checks were successful
Validate / Hassfest (push) Successful in 3s
Two-pass validation in preview-raw endpoint:
1. Syntax check (catches {% if %}, unclosed tags)
2. StrictUndefined render (catches {{ asset.a }}, {{ bad_var }})

Frontend shows:
- Red error for syntax errors with line number
- Amber warning for undefined variables
- Error line highlighted in editor

Sample context now uses proper structured data (lists of dicts
for assets/albums) so valid field access like {{ asset.filename }}
renders correctly during preview.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:49:58 +03:00
59108a834c Jinja2 syntax highlighting + description field + preview toggle
All checks were successful
Validate / Hassfest (push) Successful in 32s
- Error line highlighting in JinjaEditor (red background on error line)
- Backend returns error_line from TemplateSyntaxError
- Localized syntax error messages with line number
- Renamed {{ }} button to "Variables" (localized)
- Localized all template variable descriptions (EN/RU)
- Added t() fallback parameter for graceful degradation
- Page transition animation (fade) to prevent content stacking
- Added syntaxError/line i18n keys

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 20:44:57 +03:00
31873a8ffd Add real-time Jinja2 syntax validation with debounced API check
All checks were successful
Validate / Hassfest (push) Successful in 3s
Validates template syntax as user types (800ms debounce). Calls
preview-raw API and shows red error text below the editor if
Jinja2 parsing fails. Clears error when template is valid.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:29:52 +03:00
ce21733ae6 Jinja2 syntax highlighting + description field + preview toggle
Some checks failed
Validate / Hassfest (push) Has been cancelled
JinjaEditor:
- Custom StreamLanguage parser for Jinja2 syntax highlighting:
  {{ variables }} in blue, {% statements %} in purple, {# comments #} in gray
- Replaced HTML mode (didn't understand Jinja2 syntax)
- Proper monospace font (Consolas/Monaco)

TemplateConfig:
- Added `description` field to model + seed defaults with descriptions
- Description shown on template cards instead of raw template text
- Description input in create/edit form

Preview:
- Toggle behavior: clicking Preview again hides the preview
- Per-slot preview uses preview-raw API (renders current editor content)

i18n: added common.description, templateConfig.descriptionPlaceholder

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:28:00 +03:00
68b104ed40 Move preview button to per-slot in edit form, remove card dropdown
Some checks failed
Validate / Hassfest (push) Has been cancelled
Each template slot now has its own Preview button next to the label.
Clicking it renders the current editor content via preview-raw API
and shows the result inline below the editor. Removed the old
per-card preview dropdown since preview is now part of editing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:20:48 +03:00
6076e6d8ca Fix Modal overlay + per-slot template preview dropdown
Some checks failed
Validate / Hassfest (push) Has been cancelled
- Modal: revert to inline styles (Tailwind fixed class broken).
  Added max-height: 80vh with overflow-y: auto for scrollable content.
- Template configs: preview is now per message slot via dropdown
  (assets added/removed/renamed/deleted, periodic, scheduled, memory)
  instead of hardcoded to assets_added only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:15:33 +03:00
5870ebd216 Move default templates to .jinja2 files + add live preview + update CLAUDE.md
Some checks failed
Validate / Hassfest (push) Has been cancelled
Templates:
- Default EN/RU templates moved from inline Python strings to
  14 .jinja2 files in templates/{en,ru}/ directory
- Properly formatted with readable indentation and Jinja2
  whitespace control ({%- -%})
- load_default_templates(locale) loads from files on first access
- Seed function uses file loader instead of inline dicts

Preview:
- New POST /api/template-configs/preview-raw endpoint: renders
  arbitrary Jinja2 text with sample data (for live editing preview)
- Route ordering fixed: /variables before /{config_id}

CLAUDE.md:
- Added Frontend Architecture Notes (i18n, Svelte 5 runes, auth
  flow, Tailwind v4 quirks)
- Added Backend Architecture Notes (SQLAlchemy+aiohttp greenlet
  issue, SandboxedEnvironment import, system-owned entities,
  FastAPI route ordering, __pycache__)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:12:46 +03:00
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