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 |
|
|
true |
|
|
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) }
*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
- 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.
<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>