Skip to content

Comment analytics overview#27684

Draft
prschulz wants to merge 2 commits intomainfrom
comment-analytics-overview
Draft

Comment analytics overview#27684
prschulz wants to merge 2 commits intomainfrom
comment-analytics-overview

Conversation

@prschulz
Copy link
Copy Markdown
Contributor

@prschulz prschulz commented May 5, 2026

Summary

Adds a comment analytics overview rail to the moderation page in the posts app, behind a new commentAnalytics private labs flag. The rail summarizes commenting activity for a chosen date range and lets moderators drill in by clicking through to filtered views of the comment list.

CleanShot 2026-05-05 at 16 06 45@2x

What's new:

  • New commentAnalytics private labs flag (ghost/core/core/shared/labs.js) plus a toggle in private features settings.
  • New GET /stats/comments admin endpoint (api/endpoints/stats.js). Returns 404 when the flag is off. Accepts date_from, date_to, timezone. Permissions: comments.browse (matches the moderation page).
  • New CommentsStatsService.getOverview() that aggregates from comments + comment_reports:
    • totals — total comments, distinct commenters, distinct reported comments
    • previousTotals — same shape for the length-matched window immediately preceding the selected range (used for trend badges; null when the range is unbounded)
    • series — per-day buckets of comments / commenters / reported (used by the bar chart)
    • topPosts / topMembers — top 25 by comment count in range
    • All bounds are computed in the caller-supplied IANA timezone via the shared getDateBoundaries / applyDateFilter utilities — same pattern every other stats endpoint already uses.
  • React analytics rail (apps/posts/src/views/comments/) consumed via a new useCommentsOverview hook in admin-x-framework:
    • KPI tabs (Comments / Commenters / Reported) with a bar chart per tab.
    • Icon-only colored up/down badge next to each KPI value, with a Radix tooltip explaining the period-over-period comparison (e.g. "You're trending up 12% from 79 compared to the previous 30 days"). "Unchanged" hides the badge entirely; "All time" suppresses comparison since there's no preceding period.
    • Top posts and top commenters cards (preview top 5, sheet for the full top 25).
    • Date range picker reusing the existing STATS_RANGES.
  • Filtering integration: clicking a chart bar filters the moderation list to that day (and adds reported=true on the Reported tab). Top-post and top-commenter rows filter by post= / author=. Bar clicks are only enabled on daily-bucket ranges (< 91 days) since weekly/monthly buckets would mislead.
  • Layout: the rail is sticky on lg+ so the moderation list scrolls underneath without scrolling the analytics out of view.
  • Shade KpiTabValue gained two optional props to support this view: diffTooltip (renders the diff badge inside a Radix TooltipProvider so it portals to body and escapes ancestor overflow/stacking) and diffIconOnly (renders the badge as an icon-only circle instead of the default percent-and-icon pill).

⚠️ Do not merge yet

Opening as a draft so the team can review the API shape and UI before this leaves the private flag.

Test plan

  • Unit: ghost/core/test/unit/server/services/comments/comments-stats-service.test.js — 7 tests covering empty data, full payload shape, reports-only days, DateYYYY-MM-DD formatting, previousTotals returned for bounded ranges, previousTotals = null for unbounded ranges, and a timezone case verifying PST→UTC bound conversion.
  • E2E: ghost/core/test/e2e-api/admin/stats.test.js "Comments overview" — 2 tests covering the response shape and the date-range query params.
  • Linted: pnpm --filter posts run lint:code, pnpm --filter shade run lint:code, pnpm --filter @tryghost/admin-x-framework run lint, cd ghost/core && pnpm lint:server.
  • Typechecked: apps/posts, apps/shade, ghost/core all clean.
  • Manual smoke: enable the commentAnalytics labs flag and exercise the rail across all STATS_RANGES values (Today, Last 7/30/90 days, YTD, Last 12 months, All time). Verify the KPI tabs, trend badges + tooltips, sticky scroll behavior, bar-click filtering on daily ranges, and top-posts / top-commenters drill-throughs. Also verify the 404 when the flag is off.
  • Manual smoke from a non-UTC timezone (e.g. PST) confirming "Today" returns the expected day's comments.

prschulz and others added 2 commits May 1, 2026 10:04
- introduces a `commentAnalytics` private flag that exposes a new `GET /stats/comments` admin endpoint and an analytics rail alongside the moderation list in the posts app
- backend aggregates totals, daily series, and top posts/members from `comments` + `comment_reports`; controller gates on `labs.isSet('commentAnalytics')` so it 404s when the flag is off
- ships behind a private flag so we can iterate on the analytics shape and UI without committing to an API surface or exposing an unfinished view to users

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- backend `getOverview` now returns `previousTotals` for the length-matched
  window immediately preceding the requested range, computed in the
  caller-supplied IANA timezone via the shared `getDateBoundaries` /
  `applyDateFilter` utilities (matches how every other stats endpoint
  handles `date_from` / `date_to` / `timezone`)
- frontend renders an icon-only colored up/down badge next to each KPI
  value with a Radix tooltip explaining the comparison; "unchanged" hides
  the badge entirely and "All time" suppresses comparison since there is
  no preceding period
- analytics rail is now sticky on `lg+` so the moderation list scrolls
  underneath without scrolling the analytics out of view
- still gated behind the `commentAnalytics` private labs flag
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 19c89d5c-ffe2-4468-b4f1-d89d955b18b1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch comment-analytics-overview

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@prschulz prschulz requested a review from jonatansberg May 5, 2026 20:20
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.

1 participant