Skip to content

Add Telegram rich report rendering#184

Merged
dzarlax merged 2 commits into
mainfrom
codex/183-telegram-rich-messages
Jun 14, 2026
Merged

Add Telegram rich report rendering#184
dzarlax merged 2 commits into
mainfrom
codex/183-telegram-rich-messages

Conversation

@dzarlax

@dzarlax dzarlax commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add Telegram Bot API sendRichMessage support with legacy sendMessage fallback
  • render morning and evening reports as opt-in Rich Messages
  • add TELEGRAM_RICH_MESSAGES / telegram_rich_messages rollout flag and update docs
  • add focused tests for rich payloads, fallback behavior, and report structure

Closes #183.

Verification

  • go test ./internal/notify -run "Telegram|Morning|Rich|SendReport" -count=1
  • go test ./...
  • go vet ./...
  • git diff --check

Notes

  • Rich messages are disabled by default until TELEGRAM_RICH_MESSAGES=true or telegram_rich_messages=true is set.
  • No live Telegram send or deploy was performed in this branch.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added optional Telegram Rich Messages support for morning and evening reports (disabled by default, enabled via TELEGRAM_RICH_MESSAGES environment variable) with automatic fallback to standard HTML if rich sending fails.
    • Added support for Apple Exercise Time metric displayed as "Exercise" in weekly digest.
  • Documentation

    • Updated environment variable documentation to include TELEGRAM_RICH_MESSAGES setting.
  • Tests

    • Added test coverage for rich message functionality and fallback behavior.

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dzarlax, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 47 minutes and 55 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 13d4ab79-a7c0-414a-969a-248af48e0e0f

📥 Commits

Reviewing files that changed from the base of the PR and between f357f49 and bc22fd6.

📒 Files selected for processing (3)
  • internal/notify/report_rich.go
  • internal/notify/report_test.go
  • internal/notify/telegram.go
📝 Walkthrough

Walkthrough

Adds opt-in Telegram Bot API rich message sending (TELEGRAM_RICH_MESSAGES=true) for morning and evening health reports. A new SendRichHTML method posts to /sendRichMessage; a sendReportHTML helper attempts the rich path first and falls back to legacy sendMessage HTML on failure. New formatMorningRich/formatEveningRich renderers produce structured rich HTML with tables, blockquotes, and details. The flag is wired through storage.NotifyConfignotify.Config from an environment variable via a new getEnvBool helper.

Changes

Telegram Rich Messages Feature

Layer / File(s) Summary
Telegram Bot API transport: URL helper and SendRichHTML
internal/notify/telegram.go, internal/notify/telegram_test.go
Introduces telegramAPIBase variable and botAPIURL helper; refactors existing Send/SendInlineKeyboard/AnswerCallbackQuery to use it; adds buildRichMessagePayload and (*Bot).SendRichHTML targeting /sendRichMessage with ok/description response validation. Tests validate payload JSON shape and ok:false error handling via httptest stub server.
Rich HTML content renderers
internal/notify/report_rich.go
New file with formatMorningRich and formatEveningRich top-level builders and all supporting helpers: HTML escaping, headline/summary table, today dashboard table with vs-yesterday trends, sections/details, AI blockquotes, energy bank, readiness, alerts, sleep sources, freshness details, and utilities (sectionSummary, energyVerdictLabel, stripSimpleTags).
Report send orchestration
internal/notify/report.go, internal/notify/report_test.go
Adds TelegramRichMessages bool to notify.Config; introduces htmlReportSender interface and sendReportHTML helper (tries SendRichHTML, logs failure, falls back to Send); updates SendMorningSmartOpts and SendEvening to compute rich payloads and route through sendReportHTML. Tests cover fallback dispatch, morning rich HTML structure/escaping, and evening rich today table via sampleBriefing().
Config, storage, and server wiring
internal/storage/settings.go, cmd/server/main.go
Adds TelegramRichMessages to storage.NotifyConfig and populates it in GetNotifyConfig. In main.go, envNotifyDefaults reads TELEGRAM_RICH_MESSAGES via a new getEnvBool helper; buildNotifyCfg propagates the flag into notify.Config.
digest.go addition, env docs, and implementation plan
internal/notify/digest.go, AGENTS.md, CLAUDE.md, docs/ai-plans/2026-06-14-telegram-rich-messages.html
Extends prettyMetric with apple_exercise_time"Exercise". Documents TELEGRAM_RICH_MESSAGES in both agent docs. Adds full implementation plan and post-implementation status doc under docs/ai-plans/.

Sequence Diagram(s)

sequenceDiagram
  participant Server as cmd/server/main.go
  participant Report as report.go<br/>SendMorningSmartOpts
  participant Renderer as report_rich.go
  participant Helper as sendReportHTML
  participant Bot as telegram.go Bot
  participant TG as Telegram API

  rect rgba(100, 149, 237, 0.5)
    Note over Server: startup
    Server->>Server: getEnvBool("TELEGRAM_RICH_MESSAGES", false)
    Server->>Report: notify.Config{TelegramRichMessages: true}
  end

  rect rgba(144, 238, 144, 0.5)
    Note over Report: morning report send
    Report->>Renderer: formatMorningRich(briefing)
    Renderer-->>Report: richHTML
    Report->>Helper: sendReportHTML(bot, fallbackHTML, richHTML, true)
    Helper->>Bot: SendRichHTML(richHTML)
    Bot->>TG: POST /sendRichMessage
    alt ok:true
      TG-->>Bot: success
      Bot-->>Helper: nil
    else ok:false or HTTP error
      TG-->>Bot: error
      Bot-->>Helper: error
      Helper->>Helper: log.Printf rich failure
      Helper->>Bot: Send(fallbackHTML)
      Bot->>TG: POST /sendMessage
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • Dzarlax-AI/health_dashboard#121: Modifies the same internal/notify/telegram.go Telegram bot client plumbing (SendInlineKeyboard, AnswerCallbackQuery) that this PR refactors to use botAPIURL.

Poem

🐇 Hop, hop, the messages grow rich,
With tables and blockquotes sewn stitch by stitch!
A fallback in place when the API is cross,
No health report vanished, no morning data lost.
The rabbit delivers each dawn—HTML or bright—
One env var to toggle, the future feels right! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add Telegram rich report rendering' clearly and concisely summarizes the main change—implementing Telegram Rich Messages support for report delivery.
Description check ✅ Passed The PR description covers the key changes, references the linked issue (#183), includes a verification plan with test commands, and notes the disabled-by-default rollout strategy.
Linked Issues check ✅ Passed The implementation fully addresses issue #183 objectives: adds sendRichMessage support with HTML fallback [#183], upgrades morning/evening reports with rich formatting [#183], implements rollout flags [#183], includes fallback behavior [#183], and provides focused unit tests [#183].
Out of Scope Changes check ✅ Passed All changes are within scope: Telegram rich message transport, morning/evening report rendering, rollout flags, documentation, and tests. Only incidental doc update for apple_exercise_time metric is outside core objective but is minor and uncontroversial.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/183-telegram-rich-messages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f357f4957f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/notify/report_rich.go Outdated
Comment on lines +176 to +177
fmt.Fprintf(sb, "<tr><td>😴 Sleep</td><td>%s</td><td>%s</td></tr>\n", richEsc(sleepValue), richText(stripSimpleTags(sleepRead)))
fmt.Fprintf(sb, "<tr><td>❤️ Recovery</td><td>%d%%</td><td>%s</td></tr>\n", b.RecoveryPct, richText(stripSimpleTags(recoveryRead)))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Suppress stale metrics in rich summary

When f.sleepStale() or f.watchOff() is true, the detailed Sleep/Recovery sections below are replaced by freshness banners, but these summary rows still print sleepValue from b.Sleep.TotalAvg and b.RecoveryPct. For rich-message users with a 36h+ sensor sync gap, the top table can show days-old sleep/recovery numbers before warning that the section is stale, which undermines the freshness-banner contract; gate these rows on the same freshness checks or show the banner/placeholder instead.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/notify/telegram.go (1)

82-109: 💤 Low value

Consider checking io.ReadAll error for completeness.

Line 94 ignores the error from io.ReadAll(resp.Body). While unlikely to fail in practice (reading from an already-closed or fully-buffered HTTP response body), checking the error would make the code more defensive and consistent with robust error handling.

🛡️ Proposed defensive improvement
-	body, _ := io.ReadAll(resp.Body)
+	body, readErr := io.ReadAll(resp.Body)
+	if readErr != nil {
+		return fmt.Errorf("telegram sendRichMessage: read body: %w", readErr)
+	}
 	if resp.StatusCode != http.StatusOK {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/notify/telegram.go` around lines 82 - 109, In the SendRichHTML
method, the error returned from io.ReadAll(resp.Body) is currently ignored by
assigning it to the blank identifier. Check this error explicitly and return a
formatted error if it occurs, similar to how other errors in this function are
handled (e.g., using fmt.Errorf with appropriate context). This improves
defensive programming and ensures any unexpected issues reading the response
body are properly surfaced.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/notify/telegram.go`:
- Around line 82-109: In the SendRichHTML method, the error returned from
io.ReadAll(resp.Body) is currently ignored by assigning it to the blank
identifier. Check this error explicitly and return a formatted error if it
occurs, similar to how other errors in this function are handled (e.g., using
fmt.Errorf with appropriate context). This improves defensive programming and
ensures any unexpected issues reading the response body are properly surfaced.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fb39e13e-1dac-4072-9891-c01c743282ab

📥 Commits

Reviewing files that changed from the base of the PR and between d142513 and f357f49.

📒 Files selected for processing (11)
  • AGENTS.md
  • CLAUDE.md
  • cmd/server/main.go
  • docs/ai-plans/2026-06-14-telegram-rich-messages.html
  • internal/notify/digest.go
  • internal/notify/report.go
  • internal/notify/report_rich.go
  • internal/notify/report_test.go
  • internal/notify/telegram.go
  • internal/notify/telegram_test.go
  • internal/storage/settings.go

@dzarlax dzarlax merged commit 566c1dc into main Jun 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade Telegram reports to Rich Messages

1 participant