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>
10 KiB
Immich Watcher: Standalone Web App + Shared Core Architecture
Status: Planning Created: 2026-03-19
Context
The current immich_album_watcher HA integration contains ~3,600 lines of tightly coupled code: Immich API client, change detection, Telegram notifications, and HA entities/services. A separate HA Blueprint (~2,000 lines) adds message templating, filtering, scheduled notifications, and memory mode.
Goal: Enable Immich album change notifications without Home Assistant via a standalone web application, while keeping the HAOS integration functional and sharing as much logic as possible.
Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Architecture | Hybrid (Option C) | HAOS standalone with shared core lib, optional server sync. No breaking changes for HA-only users. |
| Frontend | SvelteKit + Shadcn-svelte | Small bundle, fast, calm UI aesthetic. Good fit for self-hosted. |
| Notifications | Telegram + Generic webhook | Telegram from existing code. Webhook enables Discord/Slack/ntfy/custom. |
| Auth | Multi-user (admin/user roles) | Supports shared Immich servers. Admin manages servers/users, users manage own trackers. |
| Backend | FastAPI + SQLite + APScheduler | Async-native Python, zero external DB deps, proven scheduler. |
Repository Structure
immich-watcher/
packages/
core/ # Shared Python library
pyproject.toml
src/immich_watcher_core/
immich_client.py # Immich API (from coordinator.py)
models.py # AssetInfo, AlbumData, AlbumChange, SharedLinkInfo
change_detector.py # Change detection (from coordinator.py)
telegram/
client.py # Telegram Bot API (from sensor.py)
cache.py # File cache with pluggable backend
media.py # Media download, size checks, group splitting
webhook/
client.py # Generic webhook notification provider
templates.py # Jinja2 template engine
storage.py # Abstract storage protocol + SQLite impl
constants.py # Shared constants (from const.py)
tests/
server/ # Standalone FastAPI app
pyproject.toml
src/immich_watcher_server/
main.py # FastAPI entry point
database/models.py # SQLModel ORM
database/migrations/ # Alembic
api/ # REST endpoints
services/
scheduler.py # APScheduler background polling
watcher.py # Album polling orchestrator
notifier.py # Notification dispatch
Dockerfile
docker-compose.yml
haos/ # Home Assistant integration (moved)
custom_components/immich_album_watcher/
... (refactored to use core library)
hacs.json
frontend/ # SvelteKit web UI source
package.json
src/
dist/ # Built static files served by FastAPI
plans/ # This folder
README.md
LICENSE
Shared Core Library Extractions
| Core Module | Source File | What Gets Extracted |
|---|---|---|
immich_client.py |
coordinator.py | All /api/ calls, session injection via constructor |
models.py |
coordinator.py L66-326 | Dataclasses (already HA-independent) |
change_detector.py |
coordinator.py L979-1066 | detect_album_changes() pure function |
telegram/client.py |
sensor.py (~1200 lines) | Full Telegram Bot API: send_message/photo/video/media_group |
telegram/cache.py |
storage.py | TelegramFileCache with CacheBackend protocol |
templates.py |
NEW (from blueprint logic) | Jinja2 renderer with ~40 variables matching blueprint |
storage.py |
storage.py | Abstract protocol + SQLite implementation |
webhook/client.py |
NEW | Generic webhook POST JSON with event data |
The ImmichClient accepts an aiohttp.ClientSession in constructor -- HA provides its managed session, standalone creates its own.
Standalone Server Design
Backend: FastAPI + SQLite + APScheduler
Database tables: users, immich_servers, notification_targets, message_templates, album_trackers, album_states, telegram_cache, notification_queue
Key API endpoints:
POST /api/auth/setup/POST /api/auth/login-- JWT authCRUD /api/servers-- Immich server connectionsGET /api/servers/{id}/albums-- Fetch album list from ImmichCRUD /api/trackers-- Album trackers (album selection, event types, template overrides, targets)CRUD /api/templates-- Message templates with previewCRUD /api/targets-- Notification targets (Telegram chats, webhooks)CRUD /api/users-- User management (admin only)GET /api/status-- Dashboard data
Background: APScheduler runs one job per tracker at its scan interval. Each job: fetch album -> detect changes -> render template -> dispatch notification.
Frontend: SvelteKit + Shadcn-svelte
Pages:
- Setup wizard -- First-run: create admin account, connect Immich server
- Login -- Username/password
- Dashboard -- Active trackers overview, recent events timeline, server status
- Servers -- Add/edit Immich server connections (URL + API key validation)
- Trackers -- Create/edit album trackers:
- Album picker (multi-select, fetched from Immich)
- Event type toggles (assets added/removed, renamed, sharing changed, deleted)
- Notification target selection
- Template selection or per-tracker override
- Scan interval, quiet hours
- Templates -- Jinja2 template editor:
- CodeMirror with Jinja2 syntax highlighting
- Live preview with sample album data
- Variable reference sidebar
- Default templates for common use cases
- Targets -- Manage notification destinations (Telegram chats, webhooks)
- Users -- User management (admin only)
- Settings -- Global defaults
Auth: Multi-user, bcrypt + JWT
- Multiple user accounts with admin/user roles
- Admin: full access (user management, server configuration)
- User: manage own trackers, templates, and targets
- First-run setup creates initial admin account
Deployment: Single Docker container, SQLite in mounted volume
HAOS Integration Changes
The integration gets refactored to delegate to core:
# coordinator.py becomes thin wrapper
class ImmichAlbumWatcherCoordinator(DataUpdateCoordinator):
def __init__(self, ...):
self._client = ImmichClient(session, url, api_key) # from core
async def _async_update_data(self):
album = await self._client.get_album(self._album_id)
change = detect_album_changes(old, album, pending) # from core
if change: self._fire_events(change, album) # HA-specific
return album
# sensor.py Telegram methods delegate to core
async def _execute_telegram_notification(self, ...):
telegram = TelegramClient(session, token, cache) # from core
return await telegram.send_notification(...)
Phases
Rule 1: Before starting work on any phase, create a detailed trackable subplan at
plans/phase-N-<name>.mdwith granular tasks, specific files to create/modify, and acceptance criteria. Do not begin implementation until the subplan is reviewed.Rule 2: After completing each phase, perform a detailed code review of all changes. Use the
code-revieweragent to check for bugs, logic errors, security vulnerabilities, code quality issues, and adherence to project conventions. Document review findings in the phase subplan under a "## Review" section and fix any issues before committing.
Phase 1: Extract Core Library [x]
- Extract models, Immich client, change detection, Telegram client, cache into
packages/core/ - Write unit tests for all extracted modules
- Subplan:
plans/phase-1-core-library.md
Phase 2: Wire Core into HAOS Integration [x]
- Move integration to
packages/haos/ - Refactor coordinator.py, sensor.py, storage.py to use core library
- Update manifest.json, hacs.json for new structure
- Verify identical behavior with real Immich server
- Subplan:
plans/phase-2-haos-refactor.md
Phase 3: Build Server Backend [x]
- FastAPI app with database, scheduler, API endpoints
- Telegram + webhook notification providers
- Jinja2 template engine with variable system matching blueprint
- Subplan:
plans/phase-3-server-backend.md
Phase 4: Build Frontend [x]
- SvelteKit app with all pages (setup, dashboard, trackers, templates, targets, users)
- Template editor with live preview
- Album picker connected to Immich API
- Subplan:
plans/phase-4-frontend.md
Phase 5: HAOS-Server Sync (Optional) [x]
- Add optional server URL to HA config flow
- Implement tracker/template config sync
- Subplan:
plans/phase-5-haos-server-sync.md
Phase 6: Claude AI Telegram Bot Enhancement (Optional) [x]
- Conversational bot, AI captions, album summaries
- Subplan:
plans/phase-6-claude-ai-bot.md
Phase 7: Production UI & Full Blueprint Parity [ ]
- i18n (RU/EN), dark/light themes, OAuth via Immich
- 4 notification modes: event-driven, periodic summary, scheduled assets, memory
- Enhanced tracker config (filtering, sorting, telegram media)
- Full template variable system (40+ vars, per-event templates)
- Subplan:
plans/phase-7-production-ui.md - Integrate Claude AI to enhance the Telegram notification bot
- Enable conversational interactions: users can ask questions about their albums, get summaries, request specific photos
- AI-powered message formatting: intelligent caption generation, album descriptions
- Smart notification filtering: AI decides notification importance/relevance
- Natural language tracker configuration via Telegram chat
- Subplan:
plans/phase-6-claude-ai-bot.md
Verification
- Core library: Unit tests for Immich client (mocked HTTP), change detection (pure function), Telegram client (mocked API), template rendering
- HAOS integration: After refactoring, verify all existing entities, services, and events work identically with a real Immich server
- Server backend: API integration tests with SQLite in-memory DB, scheduler tests
- Frontend: Manual testing of all pages, template editor preview, album picker
- End-to-end: Docker Compose up -> create account -> connect Immich -> create tracker -> trigger album change -> verify notification received