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)
This commit is contained in:
@@ -94,7 +94,7 @@ export async function api<T = any>(
|
||||
}
|
||||
}
|
||||
|
||||
if (res.status === 401) {
|
||||
if (res.status === 401 && token) {
|
||||
clearTokens();
|
||||
if (typeof window !== 'undefined') {
|
||||
window.location.href = '/login';
|
||||
|
||||
@@ -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
|
||||
@@ -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`
|
||||
@@ -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
|
||||
<!-- Filled in by the implementation agent after completing this phase. -->
|
||||
@@ -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
|
||||
<!-- Filled in by the implementation agent after completing this phase. -->
|
||||
@@ -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
|
||||
<!-- Filled in by the implementation agent after completing this phase. -->
|
||||
@@ -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
|
||||
<!-- Filled in by the implementation agent after completing this phase. -->
|
||||
@@ -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
|
||||
<!-- Filled in by the implementation agent after completing this phase. -->
|
||||
@@ -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
|
||||
<!-- Filled in by the implementation agent after completing this phase. -->
|
||||
@@ -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
|
||||
<!-- This is the final phase — no handoff needed. -->
|
||||
@@ -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
|
||||
@@ -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`
|
||||
@@ -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
|
||||
<!-- Filled in after completion -->
|
||||
@@ -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
|
||||
<!-- Filled in after completion -->
|
||||
@@ -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
|
||||
<!-- Filled in after completion -->
|
||||
@@ -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
|
||||
<!-- Filled in after completion -->
|
||||
@@ -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
|
||||
<!-- Filled in after completion -->
|
||||
@@ -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 `<a href>` 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 `<a href>` 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
|
||||
<!-- Filled in after completion -->
|
||||
@@ -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 &
|
||||
|
||||
|
||||
Reference in New Issue
Block a user