Status Summary
The analytics feature is partially shipped. Backend API endpoints exist and return real data from the database. Frontend pages and components are rendered. Some endpoints have known scoping bugs, and one hook is stubbed. See the specifics below.
Working Backend Endpoints
All analytics endpoints require requireApiSession + requireOrganizationAccess (checked at the guard layer). They read from the signals table (migration 008, range-partitioned by event_timestamp monthly).
Organization Analytics
GET /api/[org]/analytics/overview
Returns aggregate counts for the organization.
Known issue: This route queries the
signalstable without an organization filter — it returns counts aggregated across all organizations, not just the requested one.
Response:
{
"activeContributors": 42,
"pullRequestsOpened": 15,
"commits": 320,
"issues": 8
}Note: the frontend hook (useAnalyticsOverviewQuery) has from/to date-range parameters commented out, so the endpoint is always called without date filters — returning all-time data.
GET /api/[org]/analytics/top-contributors?from=ISO&to=ISO
Returns the top 10 contributors by total activity.
Known issue: Same cross-org scoping bug — no organization filter on the signals query.
Response:
[
{
"userId": 12345,
"userLogin": "octocat",
"avatarUrl": "https://avatars.githubusercontent.com/u/12345",
"commits": 92,
"pullRequests": 12,
"issues": 5,
"totalActivity": 109,
"rank": 1
}
]GET /api/[org]/analytics/trend?from=ISO&to=ISO
Returns daily activity counts grouped by type.
Known issue: Same cross-org scoping bug.
Response:
[
{ "date": "2026-06-01", "commits": 14, "pullRequests": 3, "issues": 2 },
{ "date": "2026-06-02", "commits": 22, "pullRequests": 1, "issues": 0 }
]GET /api/[org]/analytics/activity-feed
Returns the 50 most recent signal events.
Known issue: Same cross-org scoping bug — returns last 50 signals globally.
Response:
[{ "type": "commit", "userLogin": "octocat", "timestamp": "2026-06-27T10:30:00Z" }]Contributor Analytics
GET /api/[org]/contributor/heatmap?contributor=<login>
Returns a 365-day activity heatmap array for a specific GitHub user. Properly scoped (filtered to org repositories). Excludes spam signal type.
contributoris required (GitHub login). Returns 400 if missing.- Fixed window: last 365 days UTC.
- Always returns 365 entries in chronological order.
Response:
[
{ "date": "2025-06-28", "count": 3, "level": 1 },
{ "date": "2025-06-29", "count": 7, "level": 2 },
{ "date": "2025-06-30", "count": 0, "level": 0 }
]Levels: 0 (no activity), 1 (1–2), 2 (3–5), 3 (6–9), 4 (10+).
GET /api/[org]/contributor/profile?contributor=<login>&from=ISO&to=ISO
Returns aggregate activity counts and a daily breakdown for a specific contributor. Properly scoped.
contributoris required. Returns 400 if missing.fromandtoare optional ISO 8601 date strings.
Response:
{
"login": "octocat",
"avatarUrl": "https://avatars.githubusercontent.com/u/12345",
"commits": 92,
"pullRequests": 12,
"issues": 5,
"reviews": 34,
"activity": [{ "date": "2026-06-01", "commits": 5, "pullRequests": 1, "issues": 0, "reviews": 2 }]
}Repository Analytics
All repository routes require repositorySlug as a query parameter (format: owner/repo). Returns 400 if missing. All are properly scoped to the org.
GET /api/[org]/repository/analytics?repositorySlug=owner/repo&from=ISO&to=ISO
Returns per-day commit volume with additions and deletions from signal metadata.
Response:
{
"days": [{ "date": "2026-06-01", "commits": 12, "additions": 340, "deletions": 18 }]
}GET /api/[org]/repository/top-contributors?repositorySlug=owner/repo&from=ISO&to=ISO
Returns the top 10 contributors to a repository. Properly scoped via repository_id.
GET /api/[org]/repository/activity-trend?repositorySlug=owner/repo&from=ISO&to=ISO
Returns daily activity counts for a repository. Properly scoped.
Response:
[{ "date": "2026-06-01", "commits": 5, "pullRequests": 2, "issues": 0 }]GET /api/[org]/repository/metrics?repositorySlug=owner/repo&from=ISO&to=ISO
Returns aggregate metrics for a repository. Properly scoped.
Note: This route currently contains debug
console.logstatements that emit to production logs.
Response:
{
"commits": 120,
"pullRequests": 18,
"issues": 7,
"reviews": 45,
"contributors": 12
}Frontend Hook → Endpoint Mapping
| Hook | Endpoint | Status |
|---|---|---|
useAnalyticsOverviewQuery | GET /api/{org}/analytics/overview | Real; dateRange params disabled |
useOrganizationActivityTrendQuery | GET /api/{org}/analytics/trend | Real; cross-org scoping bug |
useOrganizationTopContributorsQuery | GET /api/{org}/analytics/top-contributors | Real; cross-org scoping bug |
useOrganizationActivityFeedQuery | GET /api/{org}/analytics/activity-feed | Real; cross-org scoping bug |
useContributionHeatmapQuery | GET /api/{org}/contributor/heatmap | Real; properly scoped |
useContributorProfileQuery | GET /api/{org}/contributor/profile | Real; properly scoped |
useRepositoryMetricsQuery | GET /api/{org}/repository/metrics | Real; has debug console.logs |
useRepositoryActivityTrendQuery | GET /api/{org}/repository/activity-trend | Real |
useRepositoryTopContributorsQuery | GET /api/{org}/repository/top-contributors | Real |
useActivityTimelineQuery | (none) | STUB — returns [], no API call |
useSyncStatusQuery | GET /api/sync/status | BROKEN — route does not exist (404) |
Known Limitations
-
Cross-org data leak:
analytics/overview,analytics/top-contributors,analytics/trend, andanalytics/activity-feedall callrequireOrganizationAccessbut then query thesignalstable without an organization filter. Any authenticated org member sees global aggregate data across all organizations. -
Date range disabled: The
useAnalyticsOverviewQueryfrontend hook hasfrom/toparameters commented out. The endpoint is always called without date filters — returning all-time data regardless of the selected date range. -
useSyncStatusQuery broken: This hook attempts
GET /api/sync/status, which does not exist. Always returns 404. There is no standalone sync endpoint — ingestion is handled internally byPOST /api/[org]/leaderboard/score. -
useActivityTimelineQuery stubbed: Returns an empty array immediately with no API call. The
ActivityTimelinepage component renders with zero events regardless of data. -
Debug logging:
GET /api/[org]/repository/metricshasconsole.logstatements (repository ID, date range, row count) visible in production logs. -
lib/analytics/rollups.ts: Contains TypeScript type definitions only. No aggregate queries or computations are implemented in this file. Analytics data is computed directly in route handlers.
Related
- Scoring Overview — how the scoring pipeline generates the data these endpoints read
- Database Schema — the
signalstable structure these endpoints query - API Reference — full route catalog