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>
240 lines
11 KiB
Markdown
240 lines
11 KiB
Markdown
# 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 auth
|
|
- `CRUD /api/servers` -- Immich server connections
|
|
- `GET /api/servers/{id}/albums` -- Fetch album list from Immich
|
|
- `CRUD /api/trackers` -- Album trackers (album selection, event types, template overrides, targets)
|
|
- `CRUD /api/templates` -- Message templates with preview
|
|
- `CRUD /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**:
|
|
1. **Setup wizard** -- First-run: create admin account, connect Immich server
|
|
2. **Login** -- Username/password
|
|
3. **Dashboard** -- Active trackers overview, recent events timeline, server status
|
|
4. **Servers** -- Add/edit Immich server connections (URL + API key validation)
|
|
5. **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
|
|
6. **Templates** -- Jinja2 template editor:
|
|
- CodeMirror with Jinja2 syntax highlighting
|
|
- Live preview with sample album data
|
|
- Variable reference sidebar
|
|
- Default templates for common use cases
|
|
7. **Targets** -- Manage notification destinations (Telegram chats, webhooks)
|
|
8. **Users** -- User management (admin only)
|
|
9. **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:
|
|
|
|
```python
|
|
# 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>.md` with 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-reviewer` agent 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 `[x]`
|
|
- 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`
|
|
|
|
### Phase 11: Snackbar Notifications `[ ]`
|
|
- Unified toast/snackbar system for action feedback (success, error, info, warning)
|
|
- Replace all `alert()` calls with typed snackbars
|
|
- Auto-dismiss, stacking, accessible, animated
|
|
- **Subplan**: `plans/phase-11-snackbar-notifications.md`
|
|
|
|
---
|
|
|
|
## Verification
|
|
|
|
1. **Core library**: Unit tests for Immich client (mocked HTTP), change detection (pure function), Telegram client (mocked API), template rendering
|
|
2. **HAOS integration**: After refactoring, verify all existing entities, services, and events work identically with a real Immich server
|
|
3. **Server backend**: API integration tests with SQLite in-memory DB, scheduler tests
|
|
4. **Frontend**: Manual testing of all pages, template editor preview, album picker
|
|
5. **End-to-end**: Docker Compose up -> create account -> connect Immich -> create tracker -> trigger album change -> verify notification received
|