Skip to content

AdminStatsService returns a hardcoded zero snapshot: the admin dashboard always shows zeros #522

Description

@Xhristin3

Problem

GET /admin/stats always returns zeros. AdminStatsService.compute() (api/src/admin/admin-stats.service.ts) does not query the database at all — it returns a hardcoded snapshot:

export class AdminStatsService {
  async compute(): Promise<AdminStats> {
    // Placeholder zero snapshot. The query above replaces this body
    // once the DB module is wired.
    return {
      totalUsers: 0,
      totalStreams: 0,
      activeStreams: 0,
      eventsLast24h: 0,
      generatedAt: new Date().toISOString(),
    }
  }
}

The comment's premise is stale: the DB module is wired, and the repository layer for every table it would count already exists (UsersRepository, StreamsDbRepository, stream_events queries in streams-db.repository.ts). The documented replacement query — four aggregate subqueries over users, streams, and stream_events — is written in the file's JSDoc but never executed. The admin dashboard (app/src/app/admin/admin-dashboard.tsx) therefore renders "0" for total users, total streams, active streams, and events last 24h, with a plausible-looking generatedAt timestamp, in every deployment.

Root cause

// api/src/admin/admin-stats.service.ts — compute()
return { totalUsers: 0, totalStreams: 0, activeStreams: 0, eventsLast24h: 0, ... }

The service injects nothing (no PG_POOL, no repository), so there is no path to real data.

Why this is architecturally hard

  1. The service is constructed with no dependencies, and AdminController already wraps it in a 60s cache (CacheInterceptor plus an explicit cache.set). The fix must add a data source without breaking the caching contract — the aggregate queries are cheap and index-friendly (the JSDoc cites idx_streams_user_id and idx_stream_events_created_at), so the design question is which layer owns the query: a new admin repository, or direct PG_POOL access consistent with the codebase's repository pattern.
  2. AdminStats (the wire shape) is consumed by the app (app/lib/api/admin-stats.ts) and the contract is stable; the change is internal. But the definition of "active streams" and "events last 24h" must be pinned (status = 'active' at query time; stream_events.created_at > NOW() - interval '24 hours') so the dashboard's labels match the query.
  3. This is a trust boundary: admin dashboards showing plausible zeros can mask a dead system (e.g. a failing pipeline that produces no events). The acceptance criteria should treat "non-zero when data exists" as the observable outcome, not just "the query runs".

Acceptance criteria

Service

  • compute() returns real counts: totalUsers = row count of users, totalStreams = row count of streams, activeStreams = streams with status = 'active', eventsLast24h = stream_events rows with created_at within the last 24 hours.
  • The implementation follows the repository pattern used elsewhere in api/src (parameterized queries, handleDbError-style error handling) and keeps the 60-second cache behaviour of AdminController intact.
  • The placeholder comment and JSDoc in admin-stats.service.ts are removed or rewritten to describe the implemented queries.

Tests

  • An integration test against the test database (see api/src/database.integration.spec.ts) seeds users/streams/events and asserts the returned counts match, including a stream with status = 'inactive' that must not count toward activeStreams.
  • The existing admin controller spec still passes with the cached behaviour.

Documentation

  • The Swagger description of GET /admin/stats matches the implemented definitions (which counters, which time windows).

Out of scope

New admin metrics beyond the four existing fields, and the admin role/access story (separate issue).

Getting started

Real files in scope: api/src/admin/admin-stats.service.ts, api/src/admin/admin.controller.ts, api/src/database/database.module.ts (PG_POOL token), api/src/auth/users.repository.ts (pattern), api/src/database.integration.spec.ts (test harness), app/src/app/admin/admin-dashboard.tsx (consumer).

Verify with:

cd api && npm run typecheck && npm test

Good first files to read: api/src/admin/admin-stats.service.ts, api/src/streams/repository/streams-db.repository.ts (query style), api/src/database.integration.spec.ts.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignapiREST API design and endpointsbugSomething isn't workingobservability

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions