Skip to content

[Feature] Build Data Aggregation Endpoints for Dashboard Analytics (Daily/Monthly Summaries) #21

Description

@KarenZita01

Description

The EquipChain platform requires data aggregation endpoints to power dashboards, analytics portals, and reporting tools. These endpoints will summarize meter reading data, contract interactions, and system metrics into meaningful time-series aggregates: daily summaries, monthly summaries, and custom date-range rollups.

The aggregation system must support: Daily Summaries — total readings per meter per day, average/min/max values, number of readings, and total active time; Monthly Summaries — same aggregations rolled up to monthly granularity; Custom Date Range — user-specified start and end dates with configurable interval grouping (hourly, daily, weekly, monthly); Cross-Meter Aggregations — fleet-wide summaries (total readings across all meters, average across fleet, top/bottom performers); Comparison Periods — ability to compare current period vs previous period (e.g., this month vs last month, this month vs same month last year).

Each aggregation endpoint should support filtering by meter ID, device group, timezone (for correct day boundaries), and aggregation type (count, sum, avg, min, max, p50, p95). Results should be cached (using Issue #12's Redis cache) with a TTL appropriate to the aggregation granularity (daily: 1 hour, monthly: 1 day). The aggregation engine should be efficient, processing data in-memory for MVP and designed to swap in database aggregation queries later.

Technical Context & Impact

Step-by-Step Implementation Guide

  1. Create Aggregation Service: Write src/services/aggregator.js exporting functions: aggregateReadings(readings, { startDate, endDate, granularity, meters, aggregationType }). Implement grouping by time buckets (using date-fns or manual date math). Support count, sum, avg, min, max, p50, p95 aggregation types.
  2. Create Comparison Logic: Extend aggregator with comparePeriods(currentPeriodData, previousPeriodData) returning delta and percentage change for each metric. Support previous period and year-over-year comparison modes.
  3. Create Analytics Routes: Write src/routes/analytics.js with GET /api/analytics/daily-summary (query params: startDate, endDate, meterIds, timezone), GET /api/analytics/monthly-summary, GET /api/analytics/custom-range, GET /api/analytics/fleet-summary. Apply Zod validation schemas. Apply caching middleware with appropriate TTL.
  4. Create Validation Schemas: Write src/schemas/analytics.schema.js with schemas for each analytics endpoint: validate dates are valid ISO strings, meterIds is an optional array of strings, granularity is one of ['hour', 'day', 'week', 'month'], timezone is a valid IANA timezone string.
  5. Populate Sample Data: Create a seed script scripts/seed-readings.js that generates sample meter reading data for testing analytics. Store in the in-memory store.
  6. Write Tests: Create tests/unit/aggregator.test.js testing aggregation logic with synthetic data: verify daily summaries match expected values, test empty periods, test meter filtering. Create tests/integration/analytics.test.js testing the full request/response cycle.

Verification & Testing Steps

  1. Run the seed script to populate sample readings data spanning 90 days across 3 meters.
  2. Call GET /api/analytics/daily-summary?startDate=2026-01-01&endDate=2026-01-31 — verify the response contains 31 daily entries with correct counts, sums, and averages.
  3. Call GET /api/analytics/monthly-summary?startDate=2026-01-01&endDate=2026-06-01 — verify 6 monthly entries with correct rollups.
  4. Call GET /api/analytics/fleet-summary — verify fleet-wide totals and averages across all meters.
  5. Call GET /api/analytics/custom-range?startDate=2026-01-01&endDate=2026-01-07&granularity=hour — verify hourly breakdown within the date range.
  6. Add comparison: GET /api/analytics/daily-summary?compareWith=previous_period — verify response includes current and previous period data with delta/percentage fields.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions