Files

6.9 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
17-telegram-scheduler 04 execute 2
17-01
17-02
pkg/bot/subscribe.go
pkg/bot/notify.go
pkg/bot/subscribe_test.go
true
TELE-05
TELE-07
SCHED-03
truths artifacts key_links
/subscribe adds user to subscribers table
/unsubscribe removes user from subscribers table
New key findings trigger Telegram notification to all subscribers
Scheduled scan completion with findings triggers auto-notify
path provides exports
pkg/bot/subscribe.go /subscribe and /unsubscribe handler implementations
handleSubscribe
handleUnsubscribe
path provides exports
pkg/bot/notify.go Notification dispatcher sending findings to all subscribers
NotifyNewFindings
path provides
pkg/bot/subscribe_test.go Tests for subscribe/unsubscribe and notification
from to via pattern
pkg/bot/notify.go pkg/storage db.ListSubscribers to get all chat IDs db.ListSubscribers
from to via pattern
pkg/bot/notify.go telego bot.SendMessage to each subscriber bot.SendMessage
from to via pattern
pkg/scheduler/scheduler.go pkg/bot/notify.go OnComplete callback calls NotifyNewFindings NotifyNewFindings
Implement /subscribe, /unsubscribe handlers and the notification dispatcher that bridges scheduler job completions to Telegram messages.

Purpose: Completes the auto-notification pipeline (TELE-05, TELE-07, SCHED-03). When scheduled scans find new keys, all subscribers get notified automatically. Output: pkg/bot/subscribe.go, pkg/bot/notify.go, pkg/bot/subscribe_test.go.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/17-telegram-scheduler/17-CONTEXT.md @.planning/phases/17-telegram-scheduler/17-01-SUMMARY.md @.planning/phases/17-telegram-scheduler/17-02-SUMMARY.md @pkg/storage/subscribers.go @pkg/bot/bot.go From pkg/storage/subscribers.go: ```go type Subscriber struct { ChatID int64; Username string; SubscribedAt time.Time } func (db *DB) AddSubscriber(chatID int64, username string) error func (db *DB) RemoveSubscriber(chatID int64) (int64, error) func (db *DB) ListSubscribers() ([]Subscriber, error) func (db *DB) IsSubscribed(chatID int64) (bool, error) ```

From pkg/scheduler/scheduler.go:

type JobResult struct { JobName string; FindingCount int; Duration time.Duration; Error error }
type Config struct { ...; OnComplete func(result JobResult) }
Task 1: Implement /subscribe, /unsubscribe handlers pkg/bot/subscribe.go Create pkg/bot/subscribe.go with methods on *Bot:

*handleSubscribe(bot telego.Bot, msg telego.Message):

  • Check if already subscribed via b.cfg.DB.IsSubscribed(msg.Chat.ID)
  • If already subscribed, reply "You are already subscribed to notifications."
  • Otherwise call b.cfg.DB.AddSubscriber(msg.Chat.ID, msg.From.Username)
  • Reply "Subscribed! You will receive notifications when new API keys are found."

*handleUnsubscribe(bot telego.Bot, msg telego.Message):

  • Call b.cfg.DB.RemoveSubscriber(msg.Chat.ID)
  • If rows affected == 0, reply "You are not subscribed."
  • Otherwise reply "Unsubscribed. You will no longer receive notifications."

Both handlers have no rate limit (instant operations). cd /home/salva/Documents/apikey && go build ./pkg/bot/... /subscribe and /unsubscribe handlers compile and use storage layer.

Task 2: Notification dispatcher and tests pkg/bot/notify.go, pkg/bot/subscribe_test.go - Test 1: NotifyNewFindings with 0 subscribers sends no messages - Test 2: NotifyNewFindings with 2 subscribers formats and sends to both - Test 3: Subscribe/unsubscribe updates DB correctly - Test 4: Notification message contains job name, finding count, and duration 1. Create pkg/bot/notify.go:

*NotifyNewFindings(result scheduler.JobResult) method on Bot:

  • If result.FindingCount == 0, do nothing (no notification for empty scans)
  • If result.Error != nil, notify with error message instead
  • Load all subscribers via b.cfg.DB.ListSubscribers()
  • If no subscribers, return (no-op)
  • Format message:
    New findings from scheduled scan!
    
    Job: {result.JobName}
    New keys found: {result.FindingCount}
    Duration: {result.Duration}
    
    Use /stats for details.
    
  • Send to each subscriber's chat ID via b.bot.SendMessage
  • Log errors for individual send failures but continue to next subscriber (don't fail on one bad chat ID)
  • Return total sent count and any errors

*NotifyFinding(finding engine.Finding) method on Bot:

  • Simpler variant for real-time notification of individual findings (called from scan pipeline if notification enabled)
  • Format: "New key detected!\nProvider: {provider}\nKey: {masked}\nSource: {source_path}:{line}\nConfidence: {confidence}"
  • Send to all subscribers
  • Always use masked key
  1. Create pkg/bot/subscribe_test.go:
  • TestSubscribeUnsubscribe: Open :memory: DB, add subscriber, verify IsSubscribed==true, remove, verify IsSubscribed==false
  • TestNotifyNewFindings_NoSubscribers: Create Bot with :memory: DB (no subscribers), call NotifyNewFindings, verify no panic and returns 0 sent
  • TestNotifyMessage_Format: Verify the formatted notification string contains job name, finding count, duration text
  • TestNotifyNewFindings_ZeroFindings: Verify no notification sent when FindingCount==0

For tests that need to verify SendMessage calls, create a mockTelegoBot interface or use the Bot struct with a nil telego.Bot and verify the notification message format via a helper function (separate formatting from sending). cd /home/salva/Documents/apikey && go test ./pkg/bot/... -v -count=1 -run "Subscribe|Notify" Notification dispatcher sends to all subscribers on new findings. Subscribe/unsubscribe persists to DB. All tests pass.

- `go build ./pkg/bot/...` compiles - `go test ./pkg/bot/... -v -run "Subscribe|Notify"` passes - NotifyNewFindings sends to all subscribers in DB - /subscribe and /unsubscribe modify subscribers table

<success_criteria>

  • /subscribe adds chat to subscribers table, /unsubscribe removes it
  • NotifyNewFindings sends formatted message to all subscribers
  • Zero findings produces no notification
  • Notification always uses masked keys </success_criteria>
After completion, create `.planning/phases/17-telegram-scheduler/17-04-SUMMARY.md`