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();
|
clearTokens();
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
window.location.href = '/login';
|
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
|
# Start backend
|
||||||
export NOTIFY_BRIDGE_DATA_DIR=./test-data
|
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 \
|
nohup "$PYTHON" -m uvicorn notify_bridge_server.main:app \
|
||||||
--host 0.0.0.0 --port 8420 > .backend.log 2>&1 &
|
--host 0.0.0.0 --port 8420 > .backend.log 2>&1 &
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user