Skip to content

[WIP] Add article analytics dashboard for writers#124

Closed
Copilot wants to merge 1 commit intomainfrom
copilot/add-article-analytics-dashboard
Closed

[WIP] Add article analytics dashboard for writers#124
Copilot wants to merge 1 commit intomainfrom
copilot/add-article-analytics-dashboard

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 5, 2026

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.


This section details on the original issue you should resolve

<issue_title>Article analytics dashboard for writers</issue_title>
<issue_description>Writers want to know their reach. Add a per-article analytics view visible to the author showing views, estimated reads, reactions, and bookmarks over time.

Context: Part of the TechDiary comeback strategy — writers choose platforms where they can see their impact.

Acceptance criteria:

  • View count per article
  • Reaction and bookmark counts
  • Basic time-series chart (views over last 30 days)
  • Accessible from the article editor or dashboard</issue_description>

Comments on the Issue (you are @copilot in this section)

@kingRayhan ## Implementation Plan: ClickHouse for Article Analytics

Why ClickHouse?

PostgreSQL (current DB) is not suited for analytics — counting millions of page view events with time-series aggregation is slow and pollutes the main DB. ClickHouse is purpose-built for this:

  • Columnar storage — aggregations over millions of rows are instant
  • Append-only inserts — perfect for event streams (page views)
  • Time-series queries — built-in date functions, fast GROUP BY toDate(timestamp)
  • Free tier available — ClickHouse Cloud has a generous free tier, or self-host via Docker
  • No impact on the main PostgreSQL DB

Architecture

Browser
  └── POST /api/analytics/pageview   (lightweight API route)
        └── ClickHouse: INSERT INTO article_views
              └── (batch insert via @clickhouse/client)

Dashboard page
  └── Server Action: getArticleAnalytics(articleId)
        └── ClickHouse: SELECT toDate(viewed_at), count() GROUP BY 1

ClickHouse Schema

CREATE TABLE article_views (
  article_id   UUID,
  viewer_id    Nullable(UUID),   -- NULL for anonymous
  session_id   String,           -- fingerprint / session token hash
  referrer     Nullable(String),
  country_code Nullable(String), -- from IP geo (optional)
  viewed_at    DateTime DEFAULT now()
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(viewed_at)
ORDER BY (article_id, viewed_at);

Use MergeTree — fast inserts, efficient range scans by article_id + viewed_at.


New Files

src/backend/persistence/
  clickhouse.client.ts          # ClickHouse client singleton

src/backend/services/
  analytics.actions.ts          # Server actions for querying analytics

src/app/api/analytics/
  pageview/route.ts             # POST endpoint — receives view events

src/components/
  ArticleAnalyticsChart.tsx     # Recharts time-series chart (client component)

src/app/(dashboard-editor)/dashboard/
  analytics/[articleId]/page.tsx

Environment Variables to Add

CLICKHOUSE_HOST=
CLICKHOUSE_DATABASE=
CLICKHOUSE_USERNAME=
CLICKHOUSE_PASSWORD=

Tracking Logic

Client-side — fire-and-forget fetch on article page load:

// src/app/[username]/[articleHandle]/page.tsx (or a client component)
useEffect(() => {
  fetch('/api/analytics/pageview', {
    method: 'POST',
    body: JSON.stringify({ article_id, session_id: getSessionId() }),
  });
}, []);

API route — inserts into ClickHouse, returns 200 immediately (no await needed by client):

// POST /api/analytics/pageview
export async function POST(req: Request) {
  const { article_id, session_id } = await req.json();
  await clickhouseClient.insert({
    table: 'article_views',
    values: [{ article_id, session_id, viewed_at: new Date() }],
    format: 'JSONEachRow',
  });
  return new Response(null, { status: 200 });
}

Deduplication — count unique session_id per article per day to avoid reload inflation:

SELECT toDate(viewed_at) as date, uniq(session_id) as views
FROM article_views
WHERE article_id = {articleId}
  AND viewed_at >= now() - INTERVAL 30 DAY
GROUP BY date
ORDER BY date

Analytics Server Action

// src/backend/services/analytics.actions.ts
export async function getArticleAnalytics(articleId: string) {
  const userId = await authID();
  // verify ownership before returning data

  const rows = await clickhouseClient.query({
    query: `
      SELECT toDate(viewed_at) as date, uniq(session_id) as views
      FROM article_views
      WHERE article_id = {articleId: UUID}
        AND viewed_at >= now() - INTERVAL 30 DAY
      GROUP BY date ORDER BY date
    `,
    query_params: { articleId },
    format: 'JSONEachRow',
  });

  return rows.json();
}

Dashboard UI

  • Time-series line chart using Recharts (already likely in deps via shadcn)
  • Summary cards: total views (all time), views this month, reactions, bookmarks
  • Reactions + bookmarks still queried from PostgreSQL via existing repositories
  • Date range picker (7d / 30d / 90d / all time)

Package

bun add @clickhouse/client

Rollout Order

  1. Set up ClickHouse Cloud instance + create table
  2. Add clickhouse.client.ts
  3. Build POST /api/analytics/pageview route
  4. Add tracking call to article detail page
  5. Build analytics.actions.ts query
  6. Build dashboard UI page + chart component
  7. Add env vars to production</comment_new>

Copilot AI linked an issue Apr 5, 2026 that may be closed by this pull request
Copilot stopped work on behalf of shoaibsharif due to an error April 5, 2026 05:31
Copilot AI requested a review from shoaibsharif April 5, 2026 05:31
@kingRayhan kingRayhan marked this pull request as ready for review April 5, 2026 17:47
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 19b92d38-d8eb-4888-b087-94ea10cb934c

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 copilot/add-article-analytics-dashboard

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

@kingRayhan kingRayhan closed this Apr 5, 2026
@kingRayhan
Copy link
Copy Markdown
Member

Closing this cause I have done this in #125

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.

Article analytics dashboard for writers

3 participants