From 90bc3ccdc20a069736632bac08c7402445505cb7 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Tue, 21 Apr 2026 19:39:33 +0300 Subject: [PATCH] chore: pre-release cleanup - Skip token clear/redirect on 401 for unauthenticated requests - Fix typo in test secret key in restart-backend script - Remove completed plan documents (entity-relationship-refactor, ux-notification-improvements) --- frontend/src/lib/api.ts | 2 +- plans/entity-relationship-refactor/CONTEXT.md | 53 ----------- plans/entity-relationship-refactor/PLAN.md | 52 ----------- .../phase-1-db-schema.md | 61 ------------- .../phase-2-notification-tracker-rename.md | 60 ------------- .../phase-3-command-entities-api.md | 72 --------------- .../phase-4-command-system-refactor.md | 87 ------------------- .../phase-5-frontend-rename.md | 75 ---------------- .../phase-6-frontend-commands.md | 84 ------------------ .../phase-7-integration-cleanup.md | 73 ---------------- plans/ux-notification-improvements/CONTEXT.md | 19 ---- plans/ux-notification-improvements/PLAN.md | 44 ---------- .../phase-1-entity-icons.md | 44 ---------- .../phase-2-enrich-events.md | 45 ---------- .../phase-3-events-ui.md | 43 --------- .../phase-4-chat-names-test-msg.md | 50 ----------- .../phase-5-link-validation.md | 48 ---------- .../phase-6-no-link-support.md | 47 ---------- scripts/restart-backend.sh | 2 +- 19 files changed, 2 insertions(+), 959 deletions(-) delete mode 100644 plans/entity-relationship-refactor/CONTEXT.md delete mode 100644 plans/entity-relationship-refactor/PLAN.md delete mode 100644 plans/entity-relationship-refactor/phase-1-db-schema.md delete mode 100644 plans/entity-relationship-refactor/phase-2-notification-tracker-rename.md delete mode 100644 plans/entity-relationship-refactor/phase-3-command-entities-api.md delete mode 100644 plans/entity-relationship-refactor/phase-4-command-system-refactor.md delete mode 100644 plans/entity-relationship-refactor/phase-5-frontend-rename.md delete mode 100644 plans/entity-relationship-refactor/phase-6-frontend-commands.md delete mode 100644 plans/entity-relationship-refactor/phase-7-integration-cleanup.md delete mode 100644 plans/ux-notification-improvements/CONTEXT.md delete mode 100644 plans/ux-notification-improvements/PLAN.md delete mode 100644 plans/ux-notification-improvements/phase-1-entity-icons.md delete mode 100644 plans/ux-notification-improvements/phase-2-enrich-events.md delete mode 100644 plans/ux-notification-improvements/phase-3-events-ui.md delete mode 100644 plans/ux-notification-improvements/phase-4-chat-names-test-msg.md delete mode 100644 plans/ux-notification-improvements/phase-5-link-validation.md delete mode 100644 plans/ux-notification-improvements/phase-6-no-link-support.md diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index f0f0cba..9c8e8cf 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -94,7 +94,7 @@ export async function api( } } - if (res.status === 401) { + if (res.status === 401 && token) { clearTokens(); if (typeof window !== 'undefined') { window.location.href = '/login'; diff --git a/plans/entity-relationship-refactor/CONTEXT.md b/plans/entity-relationship-refactor/CONTEXT.md deleted file mode 100644 index f703475..0000000 --- a/plans/entity-relationship-refactor/CONTEXT.md +++ /dev/null @@ -1,53 +0,0 @@ -# Feature Context: Entity Relationship Refactor - -## Current State -Starting — no changes made yet. Branch created from master with all telegram-commands work merged. - -## Key Design Decisions -- Provider capabilities (notifications, commands) inferred from provider type config, not explicit DB flags -- Tracker renamed to NotificationTracker; TrackerTarget renamed to NotificationTrackerTarget -- New entities: CommandConfig, CommandTracker, CommandTrackerListener -- CommandConfig is provider_type-scoped, shareable across multiple CommandTrackers -- CommandTrackerListener is a junction table (command_tracker_id, listener_type, listener_id) for extensibility -- TelegramBot is dual-purpose: notification target backend + commands listener -- TelegramBot polling/webhook lifecycle tied to CommandTrackerListener ref-counting -- Telegram targets gain chat_action field -- commands_config moves from TelegramBot to CommandConfig entity - -## Entity Schema (Target State) -``` -ServiceProvider (type: "immich" → infers has_notifications=true, has_commands=true) - │ - ├─ NotificationTracker (renamed from Tracker) - │ └─ NotificationTrackerTarget (renamed from TrackerTarget) - │ ├─ NotificationTarget (+ chat_action for telegram type) - │ ├─ TrackingConfig (unchanged) - │ └─ TemplateConfig (unchanged) - │ - └─ CommandTracker (new) - ├─ CommandConfig (new, shared, provider_type-scoped) - └─ CommandTrackerListener (junction → listener_type + listener_id) - └─ TelegramBot as "telegram_bot" listener type - -TelegramBot - ├─ Used by NotificationTarget (sending messages) - └─ Used by CommandTrackerListener (receiving commands) - └─ Smart ref-counting: start polling/webhook when first listener added, stop when last removed -``` - -## Temporary Workarounds -None yet. - -## Cross-Phase Dependencies -- Phase 2 depends on Phase 1 (renamed models) -- Phase 3 depends on Phase 1 (new models for CommandConfig, CommandTracker, CommandTrackerListener) -- Phase 4 depends on Phase 3 (command entities exist in DB/API) -- Phase 5 depends on Phase 2 (renamed API endpoints) -- Phase 6 depends on Phase 3 (command entity APIs) -- Phase 7 depends on all prior phases - -## Implementation Notes -- SQLite + async SQLAlchemy via sqlmodel — table renames done via idempotent ALTER TABLE / CREATE TABLE -- No formal test suite — verification via server startup + health check + frontend build -- Migration must handle existing data: rename tables, migrate TelegramBot.commands_config → CommandConfig rows -- Incremental strategy: each phase leaves the codebase fully working diff --git a/plans/entity-relationship-refactor/PLAN.md b/plans/entity-relationship-refactor/PLAN.md deleted file mode 100644 index 8d625b4..0000000 --- a/plans/entity-relationship-refactor/PLAN.md +++ /dev/null @@ -1,52 +0,0 @@ -# Feature: Entity Relationship Refactor - -**Branch:** `feature/entity-relationship-refactor` -**Base branch:** `master` -**Created:** 2026-03-20 -**Status:** ✅ Complete -**Strategy:** Incremental -**Mode:** Automated -**Execution:** Orchestrator - -## Summary - -Rework the entity schema so that ServiceProvider capabilities (notifications, commands) are -inferred from provider type config. Current Trackers become NotificationTrackers. A new -CommandTracker entity links providers to CommandConfigs and CommandsListeners (TelegramBot -as first implementation). TelegramBot becomes dual-purpose: notification target backend + -commands listener with smart ref-counted polling/webhook. CommandConfig is a new shareable -entity scoped to provider type. Telegram targets gain a chat_action setting. - -## Build & Test Commands -- **Build (backend):** `cd packages/server && pip install -e .` -- **Verify (backend):** Server startup + `curl -s http://localhost:8420/api/health` -- **Build (frontend):** `cd frontend && npm install && npx vite build` -- **Test:** No automated test suite yet — verification via server startup and frontend build - -## Phases - -- [x] Phase 1: Database Schema & Migration [domain: backend] → [subplan](./phase-1-db-schema.md) -- [x] Phase 2: Notification Tracker Rename (API) [domain: backend] → [subplan](./phase-2-notification-tracker-rename.md) -- [x] Phase 3: CommandConfig & CommandTracker CRUD [domain: backend] → [subplan](./phase-3-command-entities-api.md) -- [x] Phase 4: Command System Refactor [domain: backend] → [subplan](./phase-4-command-system-refactor.md) -- [x] Phase 5: Frontend Rename & Restructure [domain: frontend] → [subplan](./phase-5-frontend-rename.md) -- [x] Phase 6: Frontend Command Entities [domain: frontend] → [subplan](./phase-6-frontend-commands.md) -- [x] Phase 7: Integration & Cleanup [domain: fullstack] → [subplan](./phase-7-integration-cleanup.md) - -## Phase Progress Log - -| Phase | Domain | Status | Review | Build | Committed | -|-------|--------|--------|--------|-------|-----------| -| Phase 1: DB Schema & Migration | backend | ✅ Complete | ✅ | ✅ | ✅ | -| Phase 2: Notification Tracker Rename | backend | ✅ Complete | ✅ | ✅ | ✅ | -| Phase 3: Command Entities API | backend | ✅ Complete | ✅ | ✅ | ✅ | -| Phase 4: Command System Refactor | backend | ✅ Complete | ✅ | ✅ | ✅ | -| Phase 5: Frontend Rename | frontend | ✅ Complete | ✅ | ✅ | ✅ | -| Phase 6: Frontend Commands | frontend | ✅ Complete | ✅ | ✅ | ✅ | -| Phase 7: Integration & Cleanup | fullstack | ✅ Complete | ✅ | ✅ | ✅ | - -## Final Review -- [x] Comprehensive code review -- [x] Full build passes -- [x] Full test suite passes -- [ ] Merged to `master` diff --git a/plans/entity-relationship-refactor/phase-1-db-schema.md b/plans/entity-relationship-refactor/phase-1-db-schema.md deleted file mode 100644 index e572dad..0000000 --- a/plans/entity-relationship-refactor/phase-1-db-schema.md +++ /dev/null @@ -1,61 +0,0 @@ -# Phase 1: Database Schema & Migration - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective -Add new database models (CommandConfig, CommandTracker, CommandTrackerListener), rename -existing models (Tracker → NotificationTracker, TrackerTarget → NotificationTrackerTarget), -add chat_action to NotificationTarget, and write idempotent migration logic. - -## Tasks - -- [ ] Task 1: Rename `Tracker` model to `NotificationTracker` — update class name, `__tablename__` to `"notification_tracker"`, and all field references. Keep all existing fields (provider_id, collection_ids, scan_interval, batch_duration, enabled, etc.) -- [ ] Task 2: Rename `TrackerTarget` model to `NotificationTrackerTarget` — update class name, `__tablename__` to `"notification_tracker_target"`, rename `tracker_id` FK to `notification_tracker_id` -- [ ] Task 3: Rename `TrackerState` model to `NotificationTrackerState` — update class name, `__tablename__` to `"notification_tracker_state"`, rename `tracker_id` FK to `notification_tracker_id` -- [ ] Task 4: Add `chat_action` optional string field to `NotificationTarget` model (for telegram targets, e.g. "typing", "upload_photo") -- [ ] Task 5: Create `CommandConfig` model — fields: id, user_id (FK→User), provider_type (str), name, icon, enabled_commands (JSON list), locale (str, default "en"), response_mode (str, default "media"), default_count (int, default 5), rate_limits (JSON dict), created_at -- [ ] Task 6: Create `CommandTracker` model — fields: id, user_id (FK→User), provider_id (FK→ServiceProvider), command_config_id (FK→CommandConfig), name, icon, enabled (bool), created_at -- [ ] Task 7: Create `CommandTrackerListener` model — fields: id, command_tracker_id (FK→CommandTracker), listener_type (str, e.g. "telegram_bot"), listener_id (int), created_at. Add unique constraint on (command_tracker_id, listener_type, listener_id) -- [ ] Task 8: Remove `commands_config` field from `TelegramBot` model (will be migrated to CommandConfig) -- [ ] Task 9: Remove `commands_config` field from `TrackerTarget`/`NotificationTrackerTarget` model -- [ ] Task 10: Write idempotent migration in `migrations.py`: - - Rename table `tracker` → `notification_tracker` - - Rename table `tracker_target` → `notification_tracker_target` and rename column `tracker_id` → `notification_tracker_id` - - Rename table `tracker_state` → `notification_tracker_state` and rename column `tracker_id` → `notification_tracker_id` - - Add `chat_action` column to `notification_target` - - Create `command_config` table - - Create `command_tracker` table - - Create `command_tracker_listener` table - - Migrate existing `TelegramBot.commands_config` JSON → `CommandConfig` rows (one per bot that has non-default config) - - Drop `commands_config` column from old telegram_bot table - - Drop `commands_config` column from notification_tracker_target table -- [ ] Task 11: Update all model imports in `models.py` `__init__` / re-exports — ensure other modules can still import the models -- [ ] Task 12: Update `EventLog` model — rename `tracker_id` field to `notification_tracker_id` (nullable FK), add migration for column rename - -## Files to Modify/Create -- `packages/server/src/notify_bridge_server/database/models.py` — rename models, add new models, remove fields -- `packages/server/src/notify_bridge_server/database/migrations.py` — add migration functions - -## Acceptance Criteria -- All new tables are created on startup via migration -- Existing data is preserved and migrated (table renames, column renames, commands_config → CommandConfig) -- Server starts without errors with existing test-data database -- All existing imports still resolve (may need temporary aliases) - -## Notes -- SQLite does not support `ALTER TABLE RENAME COLUMN` in older versions. Use the existing pattern of adding new columns + copying data if needed. -- The migration must be idempotent — safe to run multiple times. -- Other modules (API routes, services) will still reference old model names after this phase. That's OK — Phase 2 will update the API layer. For now, add Python-level aliases (e.g., `Tracker = NotificationTracker`) so existing code continues to work. -- TrackerTarget.commands_config was unused in practice — safe to drop without data loss. - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/entity-relationship-refactor/phase-2-notification-tracker-rename.md b/plans/entity-relationship-refactor/phase-2-notification-tracker-rename.md deleted file mode 100644 index a31a262..0000000 --- a/plans/entity-relationship-refactor/phase-2-notification-tracker-rename.md +++ /dev/null @@ -1,60 +0,0 @@ -# Phase 2: Notification Tracker Rename (API) - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective -Rename all tracker-related API routes, service functions, and internal references to use -"notification_tracker" naming. Add chat_action support to the targets API. Ensure the -watcher, scheduler, and notifier services work with the renamed models. - -## Tasks - -- [ ] Task 1: Rename `api/trackers.py` → `api/notification_trackers.py`. Update all route paths from `/api/trackers` to `/api/notification-trackers`. Update function names (e.g., `list_trackers` → `list_notification_trackers`). Update all model references to use `NotificationTracker`. -- [ ] Task 2: Rename `api/tracker_targets.py` → `api/notification_tracker_targets.py`. Update route paths from `/api/tracker-targets` to `/api/notification-tracker-targets`. Update model references to `NotificationTrackerTarget`, field references to `notification_tracker_id`. -- [ ] Task 3: Update `api/targets.py` — add `chat_action` to create/update request schemas and response serialization for telegram-type targets. -- [ ] Task 4: Update `services/watcher.py` — replace all `Tracker` references with `NotificationTracker`, `TrackerTarget` with `NotificationTrackerTarget`, `TrackerState` with `NotificationTrackerState`, `tracker_id` with `notification_tracker_id` where applicable. -- [ ] Task 5: Update `services/scheduler.py` — rename tracker job references, function parameters, and log messages to use notification_tracker naming. -- [ ] Task 6: Update `services/notifier.py` — update model references and any tracker-related parameter names. -- [ ] Task 7: Update `main.py` — change router imports and registration to use new module names and route prefixes. -- [ ] Task 8: Update `api/status.py` — rename any tracker count queries to use new model names. -- [ ] Task 9: Update `commands/handler.py` — update any tracker model references used for command context resolution. -- [ ] Task 10: Update `commands/webhook.py` — update any tracker model references. -- [ ] Task 11: Update `services/telegram_poller.py` — update any tracker model references. -- [ ] Task 12: Remove backward-compatibility aliases from models.py (if added in Phase 1) — all consumers now use new names. - -## Files to Modify/Create -- `packages/server/src/notify_bridge_server/api/trackers.py` → rename to `notification_trackers.py` -- `packages/server/src/notify_bridge_server/api/tracker_targets.py` → rename to `notification_tracker_targets.py` -- `packages/server/src/notify_bridge_server/api/targets.py` — add chat_action -- `packages/server/src/notify_bridge_server/services/watcher.py` — model name updates -- `packages/server/src/notify_bridge_server/services/scheduler.py` — model name updates -- `packages/server/src/notify_bridge_server/services/notifier.py` — model name updates -- `packages/server/src/notify_bridge_server/main.py` — router registration -- `packages/server/src/notify_bridge_server/api/status.py` — model name updates -- `packages/server/src/notify_bridge_server/commands/handler.py` — model references -- `packages/server/src/notify_bridge_server/commands/webhook.py` — model references -- `packages/server/src/notify_bridge_server/services/telegram_poller.py` — model references - -## Acceptance Criteria -- All API routes work under new `/api/notification-trackers` and `/api/notification-tracker-targets` paths -- Old `/api/trackers` routes no longer exist -- Telegram targets accept and return `chat_action` field -- Server starts and health check passes -- Watcher/scheduler/notifier services function correctly with renamed models - -## Notes -- This is a breaking API change — frontend will need updating in Phase 5. -- The watcher service is the most complex consumer of tracker models — test carefully. -- The EventLog model references notification_tracker_id (renamed in Phase 1). - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/entity-relationship-refactor/phase-3-command-entities-api.md b/plans/entity-relationship-refactor/phase-3-command-entities-api.md deleted file mode 100644 index 93744f5..0000000 --- a/plans/entity-relationship-refactor/phase-3-command-entities-api.md +++ /dev/null @@ -1,72 +0,0 @@ -# Phase 3: CommandConfig & CommandTracker CRUD API - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective -Create full CRUD API routes for CommandConfig, CommandTracker, and CommandTrackerListener -management. These endpoints let users create command configurations (scoped to provider type), -create command trackers that link a provider to a command config, and attach/detach listeners -(telegram bots) to command trackers. - -## Tasks - -- [ ] Task 1: Create `api/command_configs.py` with CRUD routes: - - `GET /api/command-configs` — list all for current user (+ system defaults with user_id=0) - - `POST /api/command-configs` — create new (validate provider_type, enabled_commands against registry) - - `GET /api/command-configs/{id}` — get single - - `PUT /api/command-configs/{id}` — update (validate ownership) - - `DELETE /api/command-configs/{id}` — delete (check not in use by any command tracker) - - Response should include all fields: id, user_id, provider_type, name, icon, enabled_commands, locale, response_mode, default_count, rate_limits, created_at - -- [ ] Task 2: Create `api/command_trackers.py` with CRUD routes: - - `GET /api/command-trackers` — list all for current user, include linked listeners count - - `POST /api/command-trackers` — create new (validate provider_id exists, command_config_id exists, provider_type matches between provider and config) - - `GET /api/command-trackers/{id}` — get single with listeners - - `PUT /api/command-trackers/{id}` — update (name, icon, enabled, command_config_id — validate provider_type match) - - `DELETE /api/command-trackers/{id}` — delete (cascade delete listeners) - - `POST /api/command-trackers/{id}/enable` — enable - - `POST /api/command-trackers/{id}/disable` — disable - -- [ ] Task 3: Add listener management endpoints to command_trackers.py: - - `GET /api/command-trackers/{id}/listeners` — list listeners for a command tracker - - `POST /api/command-trackers/{id}/listeners` — add listener (body: {listener_type, listener_id}). Validate: listener exists (e.g., TelegramBot with that ID), no duplicate (unique constraint), user owns the listener. - - `DELETE /api/command-trackers/{id}/listeners/{listener_id}` — remove listener - -- [ ] Task 4: Add validation helpers: - - Validate `enabled_commands` against `commands/registry.py` known commands for the given provider_type - - Validate `provider_type` match: CommandConfig.provider_type must match ServiceProvider.type of the CommandTracker's provider - - Validate listener ownership: user must own the TelegramBot being attached - -- [ ] Task 5: Register new routers in `main.py` - -- [ ] Task 6: Update `api/telegram_bots.py` — remove the commands config endpoints (POST `/telegram-bots/{id}/commands`, GET `/telegram-bots/{id}/commands`) since commands config now lives in CommandConfig entity. Keep the sync-commands endpoint but update it to accept a command_config_id parameter or read from command trackers. - -## Files to Modify/Create -- `packages/server/src/notify_bridge_server/api/command_configs.py` — new file -- `packages/server/src/notify_bridge_server/api/command_trackers.py` — new file -- `packages/server/src/notify_bridge_server/main.py` — register new routers -- `packages/server/src/notify_bridge_server/api/telegram_bots.py` — remove old commands config endpoints - -## Acceptance Criteria -- Full CRUD for CommandConfig with provider_type validation -- Full CRUD for CommandTracker with provider↔config type matching -- Listener add/remove with ownership validation and uniqueness -- Old telegram bot commands config endpoints removed -- Server starts and all new endpoints respond correctly - -## Notes -- The command registry currently defines commands globally. In future, commands could be provider-scoped. For now, validate enabled_commands against the flat registry list. -- CommandConfig with user_id=0 could serve as system defaults (like TemplateConfig), but this is optional for Phase 3. -- The sync-commands endpoint on TelegramBot may need to resolve which commands to sync from attached CommandTrackers — this is wired up in Phase 4. - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/entity-relationship-refactor/phase-4-command-system-refactor.md b/plans/entity-relationship-refactor/phase-4-command-system-refactor.md deleted file mode 100644 index f021a05..0000000 --- a/plans/entity-relationship-refactor/phase-4-command-system-refactor.md +++ /dev/null @@ -1,87 +0,0 @@ -# Phase 4: Command System Refactor - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective -Refactor the command handling system to resolve commands through CommandTracker → CommandConfig -instead of TelegramBot.commands_config. Implement smart ref-counted polling/webhook management -for TelegramBot when used as a commands listener. Handle multi-tracker routing (one bot serving -multiple command trackers for different providers). - -## Tasks - -- [ ] Task 1: Refactor `commands/handler.py` — `handle_command()`: - - Instead of reading `bot.commands_config`, resolve command config through CommandTrackerListeners: - 1. Find all CommandTrackerListener rows where listener_type="telegram_bot" AND listener_id=bot.id - 2. Load the associated CommandTracker for each (filter enabled=True) - 3. Load CommandConfig for each tracker - 4. Load ServiceProvider for each tracker - - For each incoming command, check which CommandConfig(s) have it enabled - - If multiple trackers enable the same command (e.g., two Immich providers with /latest), use the first match or let the user disambiguate (future enhancement — for now, use first enabled match) - - Pass the resolved provider config to command execution functions - -- [ ] Task 2: Update `_get_bot_context()` in handler.py: - - Currently finds trackers/providers by matching bot_token in notification target configs - - New approach: resolve through CommandTracker → provider_id → ServiceProvider - - Return a list of (command_tracker, command_config, provider) tuples - -- [ ] Task 3: Implement smart ref-counted polling/webhook in `services/telegram_poller.py`: - - Track active listener count per bot: when a CommandTrackerListener is added for a bot, increment ref count; when removed, decrement - - `start_bot_if_needed(bot_id)` — start polling/webhook only if not already running - - `stop_bot_if_unused(bot_id)` — stop polling/webhook only if ref count reaches 0 - - Export these functions for use by the command_trackers API (when adding/removing listeners) - -- [ ] Task 4: Update `commands/webhook.py`: - - Webhook handler already receives messages for a specific bot (by webhook_path_id) - - Update to use the new command resolution flow from Task 1 - - Ensure chat auto-discovery still works - -- [ ] Task 5: Update `services/scheduler.py`: - - On startup, instead of starting polling for all bots with update_mode="polling", start polling only for bots that have active CommandTrackerListeners - - Use ref-counting logic from Task 3 - -- [ ] Task 6: Update telegram bot sync-commands endpoint: - - `POST /api/telegram-bots/{id}/sync-commands` should now: - 1. Find all CommandTrackerListeners for this bot - 2. Collect all enabled commands across all linked CommandConfigs - 3. Merge command lists (union of enabled commands) - 4. Call setMyCommands with the merged list - 5. Use locale from the first CommandConfig (or a bot-level default) - -- [ ] Task 7: Update `services/__init__.py` startup logic: - - On startup, enumerate all enabled CommandTrackers with listeners - - For each unique bot referenced, call `start_bot_if_needed(bot_id)` - -## Files to Modify/Create -- `packages/server/src/notify_bridge_server/commands/handler.py` — new command resolution flow -- `packages/server/src/notify_bridge_server/commands/webhook.py` — updated handler -- `packages/server/src/notify_bridge_server/services/telegram_poller.py` — ref-counted polling -- `packages/server/src/notify_bridge_server/services/scheduler.py` — startup logic -- `packages/server/src/notify_bridge_server/services/__init__.py` — startup logic -- `packages/server/src/notify_bridge_server/api/telegram_bots.py` — sync-commands update - -## Acceptance Criteria -- Commands resolve through CommandTracker → CommandConfig instead of TelegramBot.commands_config -- Bot polling/webhook starts only when at least one CommandTrackerListener references the bot -- Bot polling/webhook stops when last listener is removed -- Multiple command trackers can share the same bot — commands are merged -- Telegram bot sync-commands syncs the merged command set -- Existing command functionality (search, latest, random, etc.) still works end-to-end - -## Notes -- Rate limiting can stay in-memory per (bot_id, chat_id, category) — no schema change needed. -- The handler currently uses `_get_bot_context()` to find providers via notification targets. The new flow resolves providers via CommandTracker.provider_id — this is cleaner and decouples commands from notification targets. -- Edge case: a bot with no CommandTrackerListeners should not poll/webhook. If a user deletes all command trackers referencing a bot, polling should stop. -- Edge case: a command tracker can be disabled (enabled=False) — disabled trackers don't count for ref-counting. - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/entity-relationship-refactor/phase-5-frontend-rename.md b/plans/entity-relationship-refactor/phase-5-frontend-rename.md deleted file mode 100644 index b787d94..0000000 --- a/plans/entity-relationship-refactor/phase-5-frontend-rename.md +++ /dev/null @@ -1,75 +0,0 @@ -# Phase 5: Frontend — Rename & Restructure - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** frontend - -## Objective -Rename all tracker-related frontend pages, routes, API calls, and i18n keys to use -"notification tracker" naming. Add chat_action dropdown to telegram target form. -Update navigation. - -## Tasks - -- [ ] Task 1: Rename route directory `frontend/src/routes/trackers/` → `frontend/src/routes/notification-trackers/`. Update `+page.svelte` to use new API endpoints (`/api/notification-trackers`, `/api/notification-tracker-targets`). - -- [ ] Task 2: Update `+layout.svelte` navigation: - - Change "Trackers" nav item to "Notification Trackers" (or shorter "Notif. Trackers") with route `/notification-trackers` - - Keep icon the same - -- [ ] Task 3: Update `frontend/src/lib/i18n/en.json`: - - Rename `tracker.*` keys to `notificationTracker.*` - - Rename `trackerTarget.*` keys to `notificationTrackerTarget.*` - - Add nav key: `nav.notificationTrackers` - - Add `targets.chatAction`, `targets.chatActionHelp` keys - - Remove old `tracker.*` keys - -- [ ] Task 4: Update `frontend/src/lib/i18n/ru.json` — same key renames as en.json with Russian translations - -- [ ] Task 5: Update `frontend/src/routes/targets/+page.svelte`: - - Add `chat_action` dropdown to telegram target form (options: none/typing/upload_photo/upload_video/upload_document/record_video/record_voice) - - Include chat_action in create/update API calls - - Display chat_action in target list if set - -- [ ] Task 6: Update `frontend/src/routes/notification-trackers/+page.svelte` (renamed from trackers): - - All API calls point to `/api/notification-trackers` and `/api/notification-tracker-targets` - - All variable names reflect "notificationTracker" naming - - i18n keys updated to new prefixes - -- [ ] Task 7: Update `frontend/src/routes/+page.svelte` (dashboard): - - Update any tracker references/stats to use new API endpoints and naming - -- [ ] Task 8: Update any other pages that reference trackers: - - `tracking-configs/+page.svelte` — update if it links to trackers - - `template-configs/+page.svelte` — update if it references trackers - -## Files to Modify/Create -- `frontend/src/routes/trackers/+page.svelte` → move to `frontend/src/routes/notification-trackers/+page.svelte` -- `frontend/src/routes/+layout.svelte` — nav updates -- `frontend/src/lib/i18n/en.json` — key renames -- `frontend/src/lib/i18n/ru.json` — key renames -- `frontend/src/routes/targets/+page.svelte` — chat_action -- `frontend/src/routes/+page.svelte` — dashboard updates - -## Acceptance Criteria -- Navigation shows "Notification Trackers" linking to `/notification-trackers` -- Notification trackers page works with renamed API endpoints -- Telegram targets have chat_action dropdown -- All i18n keys updated in both en and ru -- Frontend builds without errors -- No references to old `/api/trackers` endpoints remain - -## Notes -- The old `/trackers` route should be removed entirely (no redirect needed — this is an admin tool). -- chat_action values map to Telegram's sendChatAction API parameter. -- Keep the UI structure the same — this is a rename, not a redesign. - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/entity-relationship-refactor/phase-6-frontend-commands.md b/plans/entity-relationship-refactor/phase-6-frontend-commands.md deleted file mode 100644 index cfd02dc..0000000 --- a/plans/entity-relationship-refactor/phase-6-frontend-commands.md +++ /dev/null @@ -1,84 +0,0 @@ -# Phase 6: Frontend — Command Entities - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** frontend - -## Objective -Create new frontend pages for CommandConfig and CommandTracker management. Update the -Telegram Bots page to remove inline commands config (now managed via CommandConfig entity) -and show listener status instead. - -## Tasks - -- [ ] Task 1: Create `frontend/src/routes/command-configs/+page.svelte`: - - List view showing all command configs with name, provider_type badge, enabled command count, locale - - Create form: name, icon, provider_type selector, enabled_commands checkboxes (from registry), locale dropdown, response_mode dropdown, default_count slider, rate_limits inputs - - Edit/delete functionality - - Follow existing page patterns (show/hide form toggle, icon picker, confirm modal for delete) - -- [ ] Task 2: Create `frontend/src/routes/command-trackers/+page.svelte`: - - List view showing command trackers: name, provider name, command config name, listener count, enabled status - - Create form: name, icon, provider selector, command_config selector (filtered by matching provider_type), enabled toggle - - Edit/delete functionality - - Expandable section per tracker showing: - - Linked listeners with type badge and name - - "Add Listener" dropdown (select from user's telegram bots) - - Remove listener button per listener - -- [ ] Task 3: Update `frontend/src/routes/telegram-bots/+page.svelte`: - - Remove the "Commands" expandable section (command enable/disable checkboxes, locale, response_mode, default_count, rate_limits) - - Replace with "Listener Status" section showing: - - List of command trackers using this bot as a listener - - Each showing: tracker name, provider name, command config name, enabled status - - Link to command tracker page - - Keep: Chats section, Webhook section, Settings section (update_mode) - -- [ ] Task 4: Update `frontend/src/routes/+layout.svelte` navigation: - - Add "Command Configs" nav item (route `/command-configs`, icon: settings/cog) - - Add "Command Trackers" nav item (route `/command-trackers`, icon: terminal/command) - - Group navigation logically: Providers, Notification Trackers, Tracking, Templates, Targets, Bots | Command Trackers, Command Configs - -- [ ] Task 5: Update `frontend/src/lib/i18n/en.json`: - - Add `commandConfig.*` keys (title, form labels, validation messages) - - Add `commandTracker.*` keys (title, form labels, listener management) - - Add `nav.commandConfigs`, `nav.commandTrackers` keys - - Remove `telegramBot.commands*` keys (moved to commandConfig) - -- [ ] Task 6: Update `frontend/src/lib/i18n/ru.json` — same additions/removals as en.json with Russian translations - -- [ ] Task 7: Update `frontend/src/routes/+page.svelte` (dashboard): - - Add command tracker count/status to dashboard stats - -## Files to Modify/Create -- `frontend/src/routes/command-configs/+page.svelte` — new page -- `frontend/src/routes/command-trackers/+page.svelte` — new page -- `frontend/src/routes/telegram-bots/+page.svelte` — remove commands section, add listener status -- `frontend/src/routes/+layout.svelte` — navigation -- `frontend/src/lib/i18n/en.json` — new keys -- `frontend/src/lib/i18n/ru.json` — new keys -- `frontend/src/routes/+page.svelte` — dashboard - -## Acceptance Criteria -- CommandConfig page: full CRUD with provider_type filtering and command checkboxes -- CommandTracker page: full CRUD with provider/config selection and listener management -- Telegram Bots page: no more inline commands config, shows listener status instead -- Navigation includes new pages in logical grouping -- Both i18n languages updated -- Frontend builds without errors - -## Notes -- Command checkboxes should show all 13 commands from the registry (help, status, albums, events, summary, latest, memory, random, search, find, person, place, favorites, people). -- Provider_type filtering: when user selects a provider in CommandTracker form, only show CommandConfigs with matching provider_type. -- The telegram bot "Sync with Telegram" button should remain — it now syncs commands from all linked command trackers. -- Follow existing UI patterns closely (ConfirmModal, icon picker, collapsible sections, snackbar notifications). - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/entity-relationship-refactor/phase-7-integration-cleanup.md b/plans/entity-relationship-refactor/phase-7-integration-cleanup.md deleted file mode 100644 index 39ef34d..0000000 --- a/plans/entity-relationship-refactor/phase-7-integration-cleanup.md +++ /dev/null @@ -1,73 +0,0 @@ -# Phase 7: Integration & Cleanup - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective -Final integration pass: verify end-to-end flows, clean up deprecated code paths, -update CLAUDE.md entity relationship documentation, and ensure everything works -together. - -## Tasks - -- [ ] Task 1: Verify notification flow end-to-end: - - ServiceProvider → NotificationTracker → NotificationTrackerTarget → NotificationTarget - - Watcher detects changes → dispatches through renamed entities - - Scheduled/periodic/memory notifications still work - -- [ ] Task 2: Verify command flow end-to-end: - - CommandTracker → CommandConfig + CommandTrackerListener (TelegramBot) - - Incoming command via webhook/polling → resolved through command tracker - - Bot ref-counting: start/stop polling based on listener count - -- [ ] Task 3: Clean up deprecated code: - - Remove any remaining backward-compatibility aliases in models.py - - Remove any old route files that were renamed (trackers.py, tracker_targets.py) - - Remove any unused imports - - Ensure no references to old model names remain anywhere - -- [ ] Task 4: Update CLAUDE.md "Entity Relationships" section: - - Document new schema: ServiceProvider capabilities, NotificationTracker, CommandTracker, CommandConfig, CommandTrackerListener - - Update the entity relationship diagram - - Update Template System Sync Rules if affected - -- [ ] Task 5: Verify migration idempotency: - - Fresh database: all tables created correctly - - Existing database with old schema: migration runs without errors, data preserved - - Running migration twice: no errors - -- [ ] Task 6: Clean up any TODO markers left by previous phases - -- [ ] Task 7: Verify frontend-backend integration: - - All frontend pages load and display data correctly - - CRUD operations work for all entities - - Command tracker listener add/remove triggers bot polling start/stop - -## Files to Modify/Create -- `packages/server/src/notify_bridge_server/database/models.py` — cleanup aliases -- `CLAUDE.md` — update entity relationships documentation -- Various files — cleanup TODOs and unused code - -## Acceptance Criteria -- Full notification flow works: provider → notification tracker → target -- Full command flow works: command tracker → command config → listener → bot -- No references to old model/route names remain -- CLAUDE.md accurately documents new entity schema -- Server starts cleanly with both fresh and migrated databases -- Frontend builds and all pages functional - -## Notes -- This phase is primarily verification and cleanup — no major new features. -- If integration issues are found, fix them in this phase rather than going back. -- The old plans/entity-relationship-refactor/ files from previous attempts can be kept as historical record. - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/ux-notification-improvements/CONTEXT.md b/plans/ux-notification-improvements/CONTEXT.md deleted file mode 100644 index 5ba07b7..0000000 --- a/plans/ux-notification-improvements/CONTEXT.md +++ /dev/null @@ -1,19 +0,0 @@ -# Feature Context: UX & Notification Improvements - -## Current State -Starting implementation. All entity models already have `icon: str` fields. EventLog exists with basic fields. Immich client already has shared link CRUD methods. Frontend uses Svelte 5 + Tailwind v4 with inline form/card pattern on all CRUD pages. - -## Temporary Workarounds -- None yet - -## Cross-Phase Dependencies -- Phase 3 depends on Phase 2 (enriched event data from API) -- Phase 6 logically follows Phase 5 (link validation informs no-link handling) -- Phases 1, 4 are fully independent - -## Implementation Notes -- All overlays MUST use `position: fixed` with inline styles and `z-index: 9999` -- SQLAlchemy async + aiohttp: eager load DB data before aiohttp context -- Jinja2 templates use SandboxedEnvironment -- Icons stored as MDI icon path names (e.g., `mdiCamera`) from `@mdi/js` -- Frontend uses MdiIcon component to render SVG icons diff --git a/plans/ux-notification-improvements/PLAN.md b/plans/ux-notification-improvements/PLAN.md deleted file mode 100644 index 030c326..0000000 --- a/plans/ux-notification-improvements/PLAN.md +++ /dev/null @@ -1,44 +0,0 @@ -# Feature: UX & Notification Improvements - -**Branch:** `feature/ux-notification-improvements` -**Base branch:** `feature/entity-relationship-refactor` -**Created:** 2026-03-20 -**Status:** 🟡 In Progress -**Strategy:** Incremental -**Mode:** Automated -**Execution:** Orchestrator - -## Summary -Seven UX and notification improvements: show entity icons, enrich event data, dashboard filtering/sorting, friendly Telegram chat names, bot test messages, album public link validation, and graceful degradation for albums without public links. - -## Build & Test Commands -- **Build (backend):** `cd packages/server && pip install -e .` -- **Build (frontend):** `cd frontend && npx vite build` -- **Test (backend):** `cd packages/server && python -m pytest` (if tests exist) -- **Lint:** N/A - -## Phases - -- [ ] Phase 1: Show Entity Icons on Cards [domain: frontend] → [subplan](./phase-1-entity-icons.md) -- [ ] Phase 2: Enrich Event Data [domain: backend] → [subplan](./phase-2-enrich-events.md) -- [ ] Phase 3: Richer Events Display + Filtering & Sorting [domain: frontend] → [subplan](./phase-3-events-ui.md) -- [ ] Phase 4: Friendly Chat Names + Test Message for Bots [domain: fullstack] → [subplan](./phase-4-chat-names-test-msg.md) -- [ ] Phase 5: Album Public Link Validation [domain: fullstack] → [subplan](./phase-5-link-validation.md) -- [ ] Phase 6: Support Albums Without Public Links [domain: backend] → [subplan](./phase-6-no-link-support.md) - -## Phase Progress Log - -| Phase | Domain | Status | Review | Build | Committed | -|-------|--------|--------|--------|-------|-----------| -| Phase 1: Entity Icons | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 2: Enrich Events | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 3: Events UI | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 4: Chat Names + Test | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 5: Link Validation | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 6: No-Link Support | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | - -## Final Review -- [ ] Comprehensive code review -- [ ] Full build passes -- [ ] Full test suite passes -- [ ] Merged to `feature/entity-relationship-refactor` diff --git a/plans/ux-notification-improvements/phase-1-entity-icons.md b/plans/ux-notification-improvements/phase-1-entity-icons.md deleted file mode 100644 index 82102c2..0000000 --- a/plans/ux-notification-improvements/phase-1-entity-icons.md +++ /dev/null @@ -1,44 +0,0 @@ -# Phase 1: Show Entity Icons on Cards - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** frontend - -## Objective -Display the user-selected icon on every entity card (Providers, Trackers, Targets, Telegram Bots). Currently the IconPicker saves the icon but cards use hardcoded default icons. - -## Tasks - -- [ ] Task 1: Update provider cards in `frontend/src/routes/providers/+page.svelte` to show `provider.icon` (fallback to default server/cloud icon) -- [ ] Task 2: Update tracker cards in `frontend/src/routes/trackers/+page.svelte` to show `tracker.icon` (fallback to default radar icon) -- [ ] Task 3: Update target cards in `frontend/src/routes/targets/+page.svelte` to show `target.icon` (fallback to type-based default) -- [ ] Task 4: Update bot cards in `frontend/src/routes/telegram-bots/+page.svelte` to show `bot.icon` (fallback to robot icon) -- [ ] Task 5: Ensure icon rendering uses MdiIcon component with proper sizing consistent with existing card headers - -## Files to Modify/Create -- `frontend/src/routes/providers/+page.svelte` — card header icon -- `frontend/src/routes/trackers/+page.svelte` — card header icon -- `frontend/src/routes/targets/+page.svelte` — card header icon -- `frontend/src/routes/telegram-bots/+page.svelte` — card header icon - -## Acceptance Criteria -- Each entity card displays the saved icon if set -- Falls back to a sensible default icon per entity type when no icon is saved -- Icon styling is consistent across all card types -- No regressions in existing card layout or functionality - -## Notes -- Icons are stored as MDI path constant names (e.g., the string key from `@mdi/js`) -- The MdiIcon component already exists in `frontend/src/lib/components/MdiIcon.svelte` -- IconPicker component already handles icon selection and stores the value -- Need to check exactly how icon values are stored (full path data vs key name) to render correctly - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/ux-notification-improvements/phase-2-enrich-events.md b/plans/ux-notification-improvements/phase-2-enrich-events.md deleted file mode 100644 index 99565ec..0000000 --- a/plans/ux-notification-improvements/phase-2-enrich-events.md +++ /dev/null @@ -1,45 +0,0 @@ -# Phase 2: Enrich Event Data - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective -Enrich EventLog with provider name, tracker name, and asset counts so the dashboard can display richer event details. Update the status API to return these fields. - -## Tasks - -- [ ] Task 1: Add `provider_name`, `tracker_name`, `provider_id` columns to EventLog model (or store in details JSON to avoid migration complexity) -- [ ] Task 2: Update watcher.py event logging to populate provider_name, tracker_name, and assets_count when creating EventLog entries -- [ ] Task 3: Update status.py GET /api/status endpoint to return enriched event fields (provider_name, tracker_name, event_type, collection_name, assets_count, details) -- [ ] Task 4: Add pagination/limit support to the events endpoint (query param `limit`, default 20) -- [ ] Task 5: Add optional filtering query params: `event_type`, `provider_id`, `search` (name match) -- [ ] Task 6: Handle migration for existing EventLog rows (backfill from tracker/provider if possible, or leave empty for old rows) - -## Files to Modify/Create -- `packages/server/src/notify_bridge_server/database/models.py` — EventLog model changes -- `packages/server/src/notify_bridge_server/services/watcher.py` — populate new fields on event creation -- `packages/server/src/notify_bridge_server/api/status.py` — enrich response, add filtering/pagination -- `packages/server/src/notify_bridge_server/database/migrations.py` — add columns if using real columns - -## Acceptance Criteria -- EventLog entries created after this phase include provider_name, tracker_name, assets_count -- GET /api/status returns enriched event data -- Filtering by event_type, provider_id, and text search works -- Old events without new fields still render (graceful degradation) -- No breaking changes to existing API consumers - -## Notes -- Storing provider_name/tracker_name as denormalized strings is intentional — the event log should be a historical record even if the tracker/provider is later deleted -- The `details` JSON field already exists and could hold extra data, but explicit columns are better for filtering -- EventLog.tracker_id already exists as FK — can join for backfill but also store name directly - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/ux-notification-improvements/phase-3-events-ui.md b/plans/ux-notification-improvements/phase-3-events-ui.md deleted file mode 100644 index b06164e..0000000 --- a/plans/ux-notification-improvements/phase-3-events-ui.md +++ /dev/null @@ -1,43 +0,0 @@ -# Phase 3: Richer Events Display + Filtering & Sorting - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** frontend - -## Objective -Update the dashboard to display richer event details (provider name, tracker name, album name, event type, assets count) and add filtering/sorting controls. - -## Tasks - -- [ ] Task 1: Update event timeline items in `+page.svelte` to show: provider name, tracker name, album name, event type badge, and assets count -- [ ] Task 2: Add filter controls above the events list: text search input, event type dropdown (all/assets_added/assets_removed/collection_renamed/collection_deleted/sharing_changed), provider dropdown (populated from providers list) -- [ ] Task 3: Add sort control: newest first / oldest first toggle -- [ ] Task 4: Wire filters to API query params (event_type, provider_id, search) from Phase 2 -- [ ] Task 5: Add "load more" button or increase default limit for events -- [ ] Task 6: Ensure graceful display when enriched fields are empty (old events before Phase 2) - -## Files to Modify/Create -- `frontend/src/routes/+page.svelte` — event display, filter/sort controls, API calls - -## Acceptance Criteria -- Each event shows: provider name, tracker name, album name, event type (badge), assets count -- Filtering by text search, event type, and provider works -- Sort by time (newest/oldest) works -- Old events without enriched data display gracefully (show what's available) -- Filter/sort state resets on page load (no persistence needed) -- UI is responsive and consistent with existing design - -## Notes -- Depends on Phase 2's enriched API response -- Provider list for the dropdown can come from existing /api/providers endpoint -- Event type badges already have color mapping in the current dashboard code - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/ux-notification-improvements/phase-4-chat-names-test-msg.md b/plans/ux-notification-improvements/phase-4-chat-names-test-msg.md deleted file mode 100644 index 6f095ed..0000000 --- a/plans/ux-notification-improvements/phase-4-chat-names-test-msg.md +++ /dev/null @@ -1,50 +0,0 @@ -# Phase 4: Friendly Chat Names + Test Message for Bots - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective -Two Telegram UX improvements: (a) show friendly chat names instead of raw IDs on target cards, (b) add a "Send Test Message" button to each chat item on the bots page. - -## Tasks - -### 4a: Friendly Chat Names on Target Cards -- [ ] Task 1: Update GET /api/targets in targets.py to resolve chat_id → friendly name by looking up TelegramChat table (match on bot token's bot_id + chat_id) -- [ ] Task 2: Include `chat_name` field in target API response alongside chat_id -- [ ] Task 3: Update target cards in targets/+page.svelte to display "Chat Name (chat_id)" instead of raw chat_id - -### 4b: Test Message Button for Bot Chats -- [ ] Task 4: Add POST /api/telegram-bots/{bot_id}/chats/{chat_id}/test endpoint in telegram_bots.py that sends a simple test message via the bot -- [ ] Task 5: Add "Send Test" button to each chat item in telegram-bots/+page.svelte with loading/success/error feedback -- [ ] Task 6: Handle edge cases (bot can't reach chat, chat deleted, etc.) with proper error messages - -## Files to Modify/Create -- `packages/server/src/notify_bridge_server/api/targets.py` — resolve chat names -- `packages/server/src/notify_bridge_server/api/telegram_bots.py` — test message endpoint -- `frontend/src/routes/targets/+page.svelte` — display friendly names -- `frontend/src/routes/telegram-bots/+page.svelte` — test message button - -## Acceptance Criteria -- Target cards show "Chat Title (chat_id)" for telegram targets where chat name is known -- Falls back to just chat_id when no matching TelegramChat record exists -- Test message button sends a simple "Test message from Notify Bridge" to the chat -- Button shows loading state, then success/error feedback -- Error messages are user-friendly (not raw API errors) - -## Notes -- TelegramChat stores: chat_id (string), title, chat_type, username, bot_id (FK) -- NotificationTarget.config stores: bot_token, chat_id -- To resolve: need to find TelegramBot by token → get bot_id → lookup TelegramChat by (bot_id, chat_id) -- For test message: use TelegramClient directly with bot token from TelegramBot record -- The test endpoint on targets already exists (POST /api/targets/{id}/test) — this is a NEW endpoint specifically for bot chat items - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/ux-notification-improvements/phase-5-link-validation.md b/plans/ux-notification-improvements/phase-5-link-validation.md deleted file mode 100644 index dfb8973..0000000 --- a/plans/ux-notification-improvements/phase-5-link-validation.md +++ /dev/null @@ -1,48 +0,0 @@ -# Phase 5: Album Public Link Validation - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective -When saving/updating a tracker with album selections, check if the selected albums have valid public shared links. Warn the user about missing links and offer to auto-create them. - -## Tasks - -- [ ] Task 1: Add GET /api/providers/{id}/albums/{album_id}/shared-links endpoint that wraps ImmichClient.get_shared_links() -- [ ] Task 2: Add POST /api/providers/{id}/albums/{album_id}/shared-links endpoint that wraps ImmichClient.create_shared_link() -- [ ] Task 3: In trackers/+page.svelte, after album selection changes (on save), call shared-links endpoint for each newly selected album -- [ ] Task 4: Show a warning dialog/section listing albums without valid public links (expired, password-protected, or missing) -- [ ] Task 5: Add "Auto-create public links" button in the warning dialog that calls the create endpoint for each missing album -- [ ] Task 6: Add hints explaining implications: "Public links allow anyone with the URL to view album contents" and "Albums without public links will have limited notification features (no clickable links in messages)" -- [ ] Task 7: Allow user to proceed without creating links (dismiss warning and save anyway) - -## Files to Modify/Create -- `packages/server/src/notify_bridge_server/api/trackers.py` or new `providers.py` routes — shared link endpoints -- `frontend/src/routes/trackers/+page.svelte` — validation UI, warning dialog, auto-create flow - -## Acceptance Criteria -- On tracker save with new albums, shared links are checked -- Albums without valid links are highlighted with a warning -- User can auto-create links with one click -- User can dismiss and proceed without links -- Hints explain security/privacy implications -- Already-valid links are not re-created -- Expired or password-protected links are flagged as problematic - -## Notes -- ImmichClient already has: get_shared_links(album_id), create_shared_link(album_id, ...), delete_shared_link(), set_shared_link_password() -- SharedLinkInfo model has: id, key, has_password, is_expired, is_accessible -- A "valid" link = exists AND not expired AND is_accessible (has_password is a warning, not a blocker) -- The check should only run for NEWLY selected albums (not all albums on every save) -- Use a modal/dialog for the warning — follows project convention of fixed-position overlays - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/plans/ux-notification-improvements/phase-6-no-link-support.md b/plans/ux-notification-improvements/phase-6-no-link-support.md deleted file mode 100644 index 0ab2e88..0000000 --- a/plans/ux-notification-improvements/phase-6-no-link-support.md +++ /dev/null @@ -1,47 +0,0 @@ -# Phase 6: Support Albums Without Public Links - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective -Allow tracking albums even without public links. Templates should conditionally wrap items in `` when public URLs exist, otherwise show plain text names. Telegram should still send assets to chats regardless of public link status. - -## Tasks - -- [ ] Task 1: In template context building (context.py), include `has_public_url` / `album_url` / per-asset `public_url` flags so templates can conditionally render links -- [ ] Task 2: Update default system templates (EN/RU seeds) to use `{% if album_url %}` / `{% if asset.public_url %}` conditionals — wrap in `` when URL exists, plain text otherwise -- [ ] Task 3: Verify that Telegram notification sending (notifier.py + telegram client) sends assets via direct API download regardless of public link status (it should already work since it uses internal API URLs with api_key headers, not public links) -- [ ] Task 4: Ensure the template context correctly distinguishes between internal API URLs (for media download) and public URLs (for user-facing links in messages) -- [ ] Task 5: Test that events from albums without public links still generate notifications with asset media but no clickable links in the message text - -## Files to Modify/Create -- `packages/core/src/notify_bridge_core/templates/context.py` — add public_url flags to context -- `packages/core/src/notify_bridge_core/providers/immich/provider.py` — ensure shared link info flows through events -- `packages/server/src/notify_bridge_server/services/notifier.py` — verify asset sending works without public links -- Default template seeds (wherever EN/RU templates are defined) — conditional link rendering - -## Acceptance Criteria -- Albums without public links can be tracked without errors -- Notifications are sent with media assets regardless of public link status -- Message text includes clickable links only when public URLs exist -- Message text shows plain album/asset names when no public URL -- Default EN/RU templates handle both cases -- No regressions for albums that DO have public links - -## Notes -- Internal asset URLs use format: `{provider_url}/api/assets/{id}/original` with x-api-key header -- Public URLs use format: `{external_domain}/share/{key}` (no auth needed) -- Telegram client downloads via internal URLs (with headers) — this is independent of public links -- The public URL is only relevant for the message text (human-readable links) -- Template context already has `album_url` from event.extra — need to make it None/empty when no shared link - -## Review Checklist -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - diff --git a/scripts/restart-backend.sh b/scripts/restart-backend.sh index ed6a4d6..a5c6ea9 100644 --- a/scripts/restart-backend.sh +++ b/scripts/restart-backend.sh @@ -24,7 +24,7 @@ fi # Start backend export NOTIFY_BRIDGE_DATA_DIR=./test-data -export NOTIFY_BRIDGE_SECRET_KEY=test-secret-key-minimum-32chars +export NOTIFY_BRIDGE_SECRET_KEY=test-secret-key-minimum-32-chars nohup "$PYTHON" -m uvicorn notify_bridge_server.main:app \ --host 0.0.0.0 --port 8420 > .backend.log 2>&1 &