# Project Guidelines ## Version Management Update the integration version in `custom_components/immich_album_watcher/manifest.json` only when changes are made to the **integration content** (files inside `custom_components/immich_album_watcher/`). **IMPORTANT** ALWAYS ask for version bump before doing it. Do NOT bump version for: - Repository setup (hacs.json, root README.md, LICENSE, CLAUDE.md) - CI/CD configuration - Other repository-level changes Use semantic versioning: - **MAJOR** (x.0.0): Breaking changes - **MINOR** (0.x.0): New features, backward compatible - **PATCH** (0.0.x): Bug fixes, integration documentation updates ## Documentation Updates **IMPORTANT**: Always keep the README.md synchronized with integration changes. When modifying the integration interface, you MUST update the corresponding documentation: - **Service parameters**: Update parameter tables and examples in README.md - **New events**: Add event documentation with examples and field descriptions - **New entities**: Document entity types, attributes, and usage - **Configuration options**: Update configuration documentation - **Translation files**: Add translations for new parameters/entities in `en.json` and `ru.json` - **services.yaml**: Keep service definitions in sync with implementation The README is the primary user-facing documentation and must accurately reflect the current state of the integration. ## Development Servers **IMPORTANT**: When the user requests it OR when backend code changes are made (files in `packages/server/`), you MUST restart the standalone server using this one-liner: ```bash PID=$(netstat -ano 2>/dev/null | grep ':8420.*LISTENING' | awk '{print $5}' | head -1) && [ -n "$PID" ] && taskkill //F //PID $PID 2>/dev/null; sleep 1 && cd packages/server && pip install -e . 2>&1 | tail -1 && cd ../.. && IMMICH_WATCHER_DATA_DIR=./test-data IMMICH_WATCHER_SECRET_KEY=test-secret-key-minimum-32chars nohup python -m uvicorn immich_watcher_server.main:app --host 0.0.0.0 --port 8420 > /dev/null 2>&1 & sleep 3 && curl -s http://localhost:8420/api/health ``` **IMPORTANT**: Overlays (modals, dropdowns, pickers) MUST use `position: fixed` with inline styles and `z-index: 9999`. Tailwind CSS v4 `fixed`/`absolute` classes do NOT work reliably inside flex/overflow containers in this project. Always calculate position from `getBoundingClientRect()` for dropdowns, or use `top:0;left:0;right:0;bottom:0` for full-screen backdrops. **IMPORTANT**: When the user requests it, restart the frontend dev server using this one-liner: ```bash PID=$(netstat -ano 2>/dev/null | grep ':5173.*LISTENING' | awk '{print $5}' | head -1) && [ -n "$PID" ] && taskkill //F //PID $PID 2>/dev/null; sleep 1 && cd frontend && npx vite dev --port 5173 --host > /dev/null 2>&1 & sleep 4 && curl -s -o /dev/null -w "Frontend: %{http_code}" http://localhost:5173/ ``` ## Frontend Architecture Notes - **i18n**: Uses `$state` rune in `.svelte.ts` file (`lib/i18n/index.svelte.ts` or `index.ts` with auto-detect). Locale auto-detects from localStorage at module load time. `t()` is reactive via `$state`. `setLocale()` updates immediately without page reload. - **Svelte 5 runes**: `$state` only works in `.svelte` and `.svelte.ts` files. Regular `.ts` files cannot use runes -- use plain variables instead. - **Static adapter**: Frontend uses `@sveltejs/adapter-static` with SPA fallback. API calls proxied via Vite dev server config. - **Auth flow**: After login/setup, use `window.location.href = '/'` (hard redirect), NOT `goto('/')` (races with layout auth check). - **Tailwind CSS v4**: Uses `@theme` directive in `app.css` for CSS variables. Grid/flex classes work but `fixed`/`absolute` positioning requires inline styles in overlay components. ## Backend Architecture Notes - **SQLAlchemy async + aiohttp**: Cannot nest `async with aiohttp.ClientSession()` inside a route that has an active SQLAlchemy async session -- greenlet context breaks. Eagerly load all DB data before entering aiohttp context, or use `check_tracker_with_session()` pattern. - **Jinja2 SandboxedEnvironment**: All template rendering MUST use `from jinja2.sandbox import SandboxedEnvironment` (not `jinja2.sandbox.SandboxedEnvironment` -- dotted access doesn't work). - **System-owned entities**: `user_id=0` means system-owned (e.g. default templates). Access checks must allow `user_id == 0` in `_get()` helpers. - **Default templates**: Stored as `.jinja2` files in `packages/server/src/immich_watcher_server/templates/{en,ru}/`. Loaded by `load_default_templates(locale)` and seeded to DB on first startup if no templates exist. - **FastAPI route ordering**: Static path routes (e.g. `/variables`) MUST be registered BEFORE parameterized routes (e.g. `/{config_id}`) to avoid path conflicts. - **`__pycache__`**: Add to `.gitignore`. Never commit.