Skip to content

PRD: Revenue report by time range

ModuleReports (CORE-11)PRD IDPRD-SLS-002
StatusProposedOwnerReports squad
Date2026-06-05Versionv0.1
Packages@nx/sale · apps/client · apps/boURDSLS · ACC

TL;DR

Enables flexible aggregation and grouping of revenue data by Day, Month, or Year cycles over any selected date range, supporting interactive charts and detailed statistical data tables.

1. Context & Problem

In business operations, store owners and managers need to analyze revenue performance under various time intervals (e.g., monthly or quarterly) rather than just daily flat lists (PRD-SLS-001) in order to make strategic financial and marketing planning decisions.

Currently, the system only supports viewing sales aggregates grouped by individual calendar days within a time range. When users request reports over longer periods (e.g., 6 months, 1 year, or multiple years), rendering detailed daily rows overflows the data table, and chart markers become too dense to read, leading to information overload.

The system needs to provide a flexible database aggregation mechanism and custom interface options (Day, Month, Year grouping) to serve this macro-level analytics requirement.

2. Goals & Non-Goals

Goals

  • Flexible Date Range Filtering: Support quick selection of common periods (Today, Yesterday, This Week, Last Week, This Month, Last Month, This Quarter, This Year, Last Year) or custom date ranges.
  • Selectable Grouping (Group By): Allow users to toggle grouping dynamically between Day, Month, or Year.
  • Interactive Chart Visualization: Display a bar or line chart depicting net revenue and order count trends matching the selected group interval.
  • Detailed Data Table: Display a structured statistical table matching the grouping cycles (e.g., if grouped by Month, each row represents a month in the date range) consisting of gross revenue, deductions/discounts, tax, net revenue, and order count, with a sticky totals row at the bottom.
  • Security & Performance Enforcements: Scoped strictly to the requesting user's Merchant ID (x-merchant-id), aggregate only completed orders (status = 'completed'), and support correct timezone boundaries (GMT+7).

Non-Goals

  • Detailed cost and profit margin breakdowns (owned by advanced analytics ADV).
  • Exporting reports to Excel/PDF formats (owned by advanced analytics ADV).

3. Success Metrics

MetricTarget / signal
Data accuracy100% of revenue figures grouped by Month or Year match the cumulative sum of the daily reports within the same range
Response timeAggregation API resolves in under 500ms for date ranges encompassing up to 2 years of order history
UI ExperienceRecharts dynamically configures X-axis interval spacing to prevent overlapping text markers based on the results count

4. Personas & Use Cases

PersonaGoal in this feature
OwnerView the current year's revenue grouped by Month to analyze high/low seasons and compare monthly performances
ManagerView the current quarter's revenue grouped by Day/Month to reconcile figures and draft periodic reports

Core scenarios: User accesses the Reporting Dashboard -> Selects the filter range (e.g., last 12 months) -> Toggles grouping to Month -> The system sends an API aggregation request -> The client renders a trend chart of the 12 months and a detailed data table showing 12 corresponding rows with a summary row at the bottom.

5. User Stories

  • As an owner, I want to see revenue summaries grouped by month so that I can easily identify seasonal business trends.
  • As a manager, I want to toggle the aggregation grouping interval between day, month, or year depending on the active date range, so that I am not overwhelmed by unnecessary granular details.
  • As a developer, I want the database to perform aggregation directly rather than loading raw orders into memory, to reduce bandwidth consumption and page load latency.

6. Functional Requirements

#RequirementURD ref
FR-1Date range picker on UI supports Quick Presets and Custom RangeURD-ACC-002
FR-2User can toggle the Group By interval (day, month, year) on the UIURD-SLS-006
FR-3API GET /v1/api/sale/reports/revenue-period supports query parameters startDate, endDate, and groupByURD-SLS-006
FR-4API response returns aggregated cumulative summary and period details based on the groupBy parameterURD-SLS-006
FR-5Calculations aggregate only completed orders (status = 'completed') of the requested merchantURD-ACC-001, URD-ACC-003
FR-6Dashboard interface updates charts (bar/line) and data table according to the chosen group intervalURD-SLS-006
FR-7Empty result sets render cumulative zero totals instead of throwing errorsURD-ACC-004

Business Rules

  • BR-01: Revenue is recognized by timestamp/time of completion.
  • BR-02: Only sales orders in completed status are aggregated.
  • BR-03: Cycles with no data must still be displayed with a value of 0.
  • BR-04: Data must be sorted in ascending order of time.

7. Non-Functional Requirements

AreaRequirement
Tenancy & SecurityScope every query strictly to the user's active Merchant ID; enforce cross-merchant isolation at the database layer
PerformanceDatabase queries use indices on merchant_id, status, and completed_at (or created_at) columns to prevent table scans
i18nTime-period labels automatically localize based on the user's active language preference (e.g., "Tháng 01/2026" vs "January 2026")
TimezoneHandle GMT+7 timezone offsets uniformly on the server to ensure correct boundary aggregation

8. UX & Flows

9. Data & Domain

EntityRole
SaleOrderMain order entity used to aggregate revenue totals (grossAmount, discountAmount, taxAmount, netAmount, orderCount) based on the completion date (completedAt)

10. Dependencies & Assumptions

Dependencies

  • Orders (CORE-07) - Completed orders are the single source of truth for revenue calculations.
  • Identity & Authz (CORE-02) - Resolves the active Merchant ID from the Request Context.

Assumptions

  • The system defaults to Vietnam timezone (GMT+7) for daily/monthly/yearly groupings.

11. Risks & Open Questions

Risk / open questionMitigation / status
Query latency over large historical order datasetsEnsure appropriate index configurations are set on merchant_id + status + completed_at to avoid table scans
Overlapping text labels on Recharts graphClient dynamically calculates and offsets tick display intervals on the X-axis based on result density

12. Release Plan & Launch Criteria

AspectKế hoạch
PhaseSLS P2 increment - periodic revenue reports
RolloutAvailable to all merchants
MigrationNo database migrations required (only read-side aggregation queries over existing tables)
Launch criteriaDrizzle queries resolve all groupBy intervals correctly; charts and tables update smoothly; zero lint errors

13. FAQ

Are draft or cancelled orders included in the calculations? No, only sales orders in completed status are aggregated.

What happens if there are no sales in the selected range? The system returns zero totals and renders an empty chart, without throwing errors.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.