Files
notify-bridge/plans/entity-relationship-refactor/phase-4-command-system-refactor.md
T
alexei.dolgolyov 1d445f3980 feat: entity relationship refactor — notification trackers, command system, chat actions
Rework entity schema: rename Tracker→NotificationTracker, add CommandConfig/
CommandTracker/CommandTrackerListener entities for decoupled command handling.
Commands now resolve through CommandTracker→CommandConfig instead of
TelegramBot.commands_config. Smart ref-counted bot polling based on active
listeners. Add chat_action to telegram targets. Full frontend CRUD pages
for command configs and command trackers. Idempotent SQLite migrations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 01:27:20 +03:00

5.0 KiB

Phase 4: Command System Refactor

Status: Not Started Parent plan: 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.pyhandle_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