Specification: Scheduled Report Parity
TLDR (Solution Summary)
- Build scheduled-report parity so every executable BetterFleet report can be configured for recurring email delivery using the same report-module rules that govern the Reports page.
Scheduled Reports editor + add report-specific fields for Site Power Report, Daily EV Load Report, Charger Network Connectivity Log, Charger OCPP Logs, Sensor Reads, Circuit Capacity Allocation, User Access Log Report, Charging Sessions, Vehicle Charging Summary, and Charger Performance + each schedule captures the same business-significant filters as the matching on-demand report.
Report catalog + define shared schedulable metadata for labels, availability, scope, lookback limits, and required selectors + the Reports page and Scheduled Reports use one source of truth for report rules.
Scheduled report configuration + persist rolling lookback and typed report parameters + schedules no longer rely on generic schedule-only logic that diverges from report behavior.
Scheduled report scope model + support depot-scoped schedules and account-scoped schedules + User Access Log Report fits the product model cleanly instead of being forced into depot-only behavior.
Scheduled run execution + add a backend execution registry that mirrors report-module rules + scheduled runs reject invalid configurations and generate output that matches on-demand output for the same report and filters.
Delivery plan + ship CSV-backed reports first and table-driven reports second + the business gets early value without sacrificing the end-state parity model.
1. Summary
- Problem statement:
- Scheduled Reports currently allows only Site Power Report and Daily EV Load Report, while the Reports page exposes a broader set of executable reports with report-specific constraints and filters.
- The existing Scheduled Reports flow uses a mostly generic configuration model, so adding more reports by one-off wiring would create variance between on-demand and scheduled behavior.
- Goal and success criteria:
- Define one capability where all executable user-facing reports can be scheduled for recurring delivery using the same report rules as the Reports page.
- Success is measured by:
- every executable user-facing report, except the hidden Charge Point Report, being represented in the scheduled-report capability;
- no scheduled report being able to bypass an existing report-specific rule such as maximum lookback or required selectors;
- scheduled output matching on-demand output for the same report and filters;
- User Access Log Report being schedulable without distorting the scheduled-report scope model.
- What will be built in this phase:
Scheduled Reports catalog + include all executable user-facing reports except Charge Point Report + users can configure recurring delivery from the same report set they can run on demand.
Shared report-module rules + define schedulable metadata for each report + labels, availability, scope, lookback caps, and required selectors stay aligned across on-demand and scheduled surfaces.
Scheduled report configuration + store rolling lookback, recipients, cadence, scope, and typed report parameters + every schedule retains the same business-significant filter meaning as its report.
Scheduled report execution registry + validate and run schedules using report-type-specific rules + invalid runs fail explicitly and valid runs generate report output consistently.
Scope model + distinguish depot-scoped schedules from account-scoped schedules + User Access Log Report is supported without a depot-only workaround.
Phased delivery + deliver CSV-backed reports before table-driven reports + parity advances safely without blocking the entire initiative on the hardest exports.
- Scope (in/out) for this phase:
- In:
- the whole scheduled-report parity capability, including its phased delivery model;
- all executable user-facing reports currently available from the Reports page;
- full filter parity for business-significant report filters;
- depot-scoped and account-scoped scheduled report ownership;
- conceptual end-state behavior for scheduled execution and delivery.
- Out:
- backlog-ready story slicing;
- database schema design details;
- infrastructure implementation details;
- non-CSV delivery formats;
- new recurrence patterns beyond the current daily schedule.
- Current baseline (as of March 17, 2026):
- Scheduled Reports currently supports Site Power Report and Daily EV Load Report only.
- The Reports page already has a report-module layer that defines labels, availability, lookback limits, and some per-report validation.
- Several reports already map cleanly to backend CSV generation, while Charging Sessions, Vehicle Charging Summary, and Charger Performance rely on on-demand flows that include web-side shaping or table-driven export behavior.
- User Access Log Report is executable today but does not fit the current depot-scoped scheduled-report model.
- Future evolution guardrails:
- This phase must make weekly or monthly recurrence easier later, not harder.
- This phase must keep adding a new schedulable report a catalog-and-execution extension, not a fresh UX and validation rewrite.
- This phase must preserve the ability to support non-CSV delivery or downstream report subscriptions later without reworking the scope and configuration model.
- Not in scope:
- Technical design specifics such as storage schema, migration steps, or low-level API contracts unless they are needed later in implementation planning.
2. Users and Use Cases
- Primary personas:
- Depot Admin or Manager configuring depot-scoped operational reports.
- System Admin configuring account-scoped security reports.
- Stakeholder recipients who rely on scheduled CSV delivery rather than interactive report runs.
- Support and product teams diagnosing why a schedule is valid, invalid, delivered, or rejected.
- High-level user stories:
- As a Depot Admin or Manager, I want to schedule the same operational reports I can run on demand so recurring reporting does not require manual exports.
- As a System Admin, I want to schedule User Access Log Report with the right scope and guardrails so security reporting is part of the same capability without being constrained by depot ownership.
- As a stakeholder recipient, I want the scheduled report data to match what the product shows for the same filters so I can trust the emailed CSV.
- As support or product, I want a schedule to fail for an explicit rule reason instead of drifting into inconsistent behavior so troubleshooting is fast and predictable.
- Edge cases and failure modes:
- A report is executable in one context but unavailable in another because of permissions or feature flags.
- A user configures a lookback longer than the report allows.
- A user omits a required selector such as a circuit, charger, or user.
- A report is account-scoped but is being configured from a depot-centered workflow.
- A scheduled run produces no data for the selected period.
- A report module changes later; Scheduled Reports must inherit the rule change without separate business-rule edits.
3. Conceptual Model Terms and Decisions
Key Terms
| Term |
Definition |
Notes |
| Report Module |
The canonical definition of a report's label, availability, limits, filters, and execution contract |
Source of truth for user-facing report behavior |
| Schedulable Report |
A report that may be configured for recurring delivery |
Hidden Charge Point Report is excluded in this capability |
| Scheduled Report Configuration |
The saved object that defines report type, scope, cadence, recipients, lookback, and report parameters |
The main managed business object |
| Scheduled Report Scope |
The authorization and ownership boundary for a schedule |
Depot scope and account scope both exist in this capability |
| Rolling Lookback |
The relative time window used at run time, such as last 1, 14, 30, or 92 days |
Used instead of absolute scheduled start and end dates |
| Report Parameters |
Report-specific selectors such as circuits, chargers, users, vehicles, vehicle groups, cost centres, or depots |
Must be typed and validated by report |
| Scheduled Run |
One concrete execution attempt of a saved scheduled report configuration |
Produces output, rejection, or delivery failure |
| Output Parity |
The requirement that scheduled output matches on-demand output for the same report and filters |
Protects trust and maintainability |
Decision Ledger
| ID |
Decision |
Rationale |
Alternatives Rejected |
Implications |
| D-001 |
Write one specification for the whole capability and express delivery in phases |
Keeps the end state coherent while still allowing incremental rollout |
Separate disconnected specs for each phase |
Later phases remain aligned to one capability model |
| D-002 |
Use shared report modules as the source of truth for report behavior and maintain a matching backend execution registry |
Preserves consistency without forcing one-off scheduled logic for each report |
Duplicate scheduled-report rules or incremental local wiring |
Requires explicit alignment between configuration and execution contracts |
| D-003 |
Preserve full filter parity for executable reports |
Avoids scheduled output differing from on-demand output in business-significant ways |
Schedule only minimal selectors |
Makes charging-session and performance reports a larger phase-2 effort |
| D-004 |
Allow scheduled reports to be depot-scoped or account-scoped |
User Access Log Report does not fit a depot-only ownership model |
Anchor every schedule to a depot |
Scope becomes part of the core capability |
| D-005 |
Exclude Charge Point Report from parity scope |
It is currently hidden and unavailable to end users |
Include every declared report type regardless of user visibility |
"All existing reports" means all executable user-facing reports |
| D-006 |
Keep daily cadence only in this phase |
Matches current behavior and limits scope while the report-parity model is established |
Introduce weekly or monthly recurrence now |
Cadence expansion remains future work on top of the same schedule model |
| D-007 |
Deliver CSV-backed reports before table-driven reports |
Reduces delivery risk and allows earlier business value |
Single release with every report enabled at once |
Phase 2 must focus on export unification and parity for table-driven reports |
4. Domain Model and Eventstorming (Conceptual)
- Bounded context and ubiquitous language:
Report Catalog defines what reports exist, who can access them, and what rules govern them.
Scheduled Report Management governs how users configure, validate, save, and edit recurring report definitions.
Scheduled Report Execution governs how a saved definition becomes a concrete run.
Report Delivery governs formatting, recipient delivery, and observable run outcomes.
- Aggregates and entities:
Report Definition aggregate: report type, label, availability, scope, lookback rules, parameter rules.
Scheduled Report Configuration aggregate: chosen report, recipients, cadence, scope, lookback, parameters.
Scheduled Run aggregate: execution attempt, validation outcome, output status, delivery status.
- Value objects:
RollingLookbackWindow
ScheduledRecipientList
ReportParameterSet
ScheduledReportScope
- Domain events and their triggers:
ScheduledReportConfigured when a valid schedule is created or updated.
ScheduledReportConfigurationRejected when the proposed schedule violates report rules.
ScheduledRunTriggered when the scheduler starts a run.
ScheduledRunRejected when the run fails rule validation or context resolution.
ScheduledReportGenerated when report output is produced.
ScheduledReportDelivered when delivery succeeds.
ScheduledReportDeliveryFailed when output exists but delivery does not complete.
- Commands, actors, and policies:
CreateScheduledReport and UpdateScheduledReport are issued by Depot Admin, Manager, or System Admin depending on scope.
ValidateScheduledReportAgainstModuleRules is a system policy applied during create, edit, and run.
TriggerScheduledRun is a system command from the scheduler.
DeliverScheduledReport is a system policy applied only after successful generation.
- Invariants and business rules enforced:
- Only executable user-facing reports marked schedulable may be configured.
- A schedule must use the lookback limit, required selectors, and scope policy of its report definition.
- A scheduled run must not generate output using rules that differ from the report's on-demand semantics.
- User Access Log Report must be account-scoped in this capability.
- Charge Point Report remains excluded until it becomes a user-facing executable report.
- External systems and integrations:
- Existing report data providers remain the source of report data.
- Existing scheduling infrastructure remains the source of run triggers.
- Existing email delivery remains the delivery mechanism in this phase.
Interaction Flow
flowchart LR
Admin["Depot Admin / Manager / System Admin"] --> Cmd["Create or Update Scheduled Report"]
Cmd --> Validate["Validate Against Report Module Rules"]
Validate -->|Valid| Saved["Scheduled Report Configuration Saved"]
Validate -->|Invalid| Rejected["Configuration Rejected"]
Saved --> Trigger["Scheduled Run Triggered"]
Trigger --> Resolve["Resolve Report Type and Scope"]
Resolve --> Policy{"Rules satisfied?"}
Policy -->|No| RunRejected["Scheduled Run Rejected"]
Policy -->|Yes| Execute["Generate Report Data"]
Execute --> Format["Format Scheduled CSV Output"]
Format --> Deliver["Deliver Email to Recipients"]
Deliver --> Recorded["Run Outcome Recorded"]
Event Timeline
timeline
title Scheduled Report Parity Timeline
ScheduledReportConfigured: Valid schedule saved
ScheduledRunTriggered: Scheduler starts a run
ScheduledRunRejected: Run blocked by rule or context failure
ScheduledReportGenerated: Report output created
ScheduledReportDelivered: Recipients receive CSV
Event Dictionary
ScheduledReportConfigured: a schedule is created or updated successfully | establishes the recurring delivery contract | scheduledReportId, reportType, scope, lookback, reportParams, recipientCount | enables future runs.
ScheduledReportConfigurationRejected: a proposed schedule fails validation | protects parity and rule enforcement | reportType, scope, rejectionReason | requires user correction before save.
ScheduledRunTriggered: the scheduler starts one execution attempt | creates a concrete run context | scheduledReportId, runAt | moves configuration into execution.
ScheduledRunRejected: the triggered run cannot execute | keeps invalid runs observable | scheduledReportId, reportType, rejectionReason | prevents misleading or partial output.
ScheduledReportGenerated: report data is produced | allows formatting and delivery | scheduledReportId, reportType, rowCount | starts delivery processing.
ScheduledReportDelivered: recipients receive the report output | completes the primary user outcome | scheduledReportId, recipientCount, deliveredAt | records a successful run.
ScheduledReportDeliveryFailed: generation succeeded but delivery did not | separates data issues from delivery issues | scheduledReportId, failureReason | enables operational follow-up.
5. Requirements and Constraints
- Functional requirements:
FR-001: The capability shall include every executable user-facing report currently available from the Reports page except Charge Point Report.
FR-002: The capability shall represent Site Power Report, Daily EV Load Report, Charger Network Connectivity Log, Charger OCPP Logs, Sensor Reads, Circuit Capacity Allocation, User Access Log Report, Charging Sessions, Vehicle Charging Summary, and Charger Performance as schedulable reports.
FR-003: A shared report definition shall govern report label, availability, scope, lookback limits, required selectors, and report-specific parameters for both on-demand and scheduled experiences.
FR-004: The scheduled-report editor shall validate lookback limits and required selectors using the same business rules as the matching report definition.
FR-005: The scheduled-report configuration shall persist rolling lookback and typed report parameters for each report.
FR-006: The capability shall support depot-scoped schedules and account-scoped schedules.
FR-007: User Access Log Report shall be configured and executed as an account-scoped schedule.
FR-008: The capability shall keep daily cadence and scheduled run time as the supported recurrence model in this phase.
FR-009: Scheduled runs shall reject invalid or unavailable configurations with an explicit reason.
FR-010: Scheduled runs for Site Power Report, Daily EV Load Report, Charger Network Connectivity Log, Charger OCPP Logs, Sensor Reads, Circuit Capacity Allocation, and User Access Log Report shall be delivered in the first phase.
FR-011: Scheduled runs for Charging Sessions, Vehicle Charging Summary, and Charger Performance shall be delivered in the second phase with full filter parity.
FR-012: Scheduled output for a report and filter set shall match the on-demand output semantics for that same report and filter set.
FR-013: A scheduled run with no data shall still produce a user-visible delivery outcome consistent with current scheduled-report behavior.
FR-014: Existing valid Site Power Report and Daily EV Load Report schedules shall remain supported through the transition into the shared parity model.
- Non-functional requirements:
NFR-001: A change to a report's user-facing rule shall be defined once in the shared report definition and reused by both Reports and Scheduled Reports.
NFR-002: Rejected configurations and rejected runs shall be observable with a reason that support and product teams can interpret without source-code investigation.
NFR-003: Adding a new schedulable report after this phase shall require extension of the shared report catalog and execution mapping rather than bespoke scheduled-report UX and validation logic.
NFR-004: The phased rollout shall allow phase-1 reports to ship without forcing temporary behavior that must later be discarded to reach output parity.
- Constraints and assumptions:
- Daily cadence only.
- CSV email delivery only.
- Full filter parity includes filters that materially affect exported rows, even if those filters are currently applied in on-demand processing rather than at the earliest data query boundary.
- "All existing reports" means all executable user-facing reports, not hidden or unavailable report types.
- Charge Point Report remains excluded until it becomes a user-facing executable report.
- Build item coverage mapping:
Scheduled Reports editor build item -> FR-004, FR-005, FR-008, FR-009, FR-013, NFR-002.
Report catalog build item -> FR-001, FR-002, FR-003, FR-006, FR-007, NFR-001, NFR-003.
Scheduled report configuration build item -> FR-004, FR-005, FR-006, FR-007, FR-014.
Scheduled run execution build item -> FR-009, FR-010, FR-011, FR-012, FR-013, NFR-002, NFR-004.
Delivery plan build item -> FR-010, FR-011, FR-014, NFR-004.
- Verification notes:
FR-001-FR-007: validate by catalog, scope, and editor behavior reviews against the existing executable report set.
FR-008-FR-009: validate through scheduled configuration and execution-path checks using invalid and valid inputs.
FR-010-FR-011: validate by phase-based delivery review against the named report list.
FR-012-FR-013: validate through parity comparisons between on-demand and scheduled output and through no-data delivery checks.
FR-014: validate through migration and backward-compatibility checks for existing Site Power Report and Daily EV Load Report schedules.
NFR-001-NFR-004: validate through architecture review, support-observability review, and post-phase onboarding checks for new reports.
6. Interaction and Flow
- User journey or process steps:
- An authorized user opens Scheduled Reports and selects a report from the same user-facing report catalog used by the Reports page.
- The system reveals the report's required fields, scope, and lookback rules.
- The user configures recipients, time, lookback, and report parameters and saves the schedule.
- The system validates the configuration against the shared report definition and either saves it or rejects it with a rule-specific reason.
- The scheduler triggers a run at the chosen time.
- The system resolves report type, scope, and parameters, validates the current context, generates output, and delivers a CSV or records an explicit rejection or delivery failure.
flowchart TD
Start["User opens Scheduled Reports"] --> Choose["Choose report type"]
Choose --> Show["Show report-specific fields and rules"]
Show --> Save["Save schedule"]
Save --> Check{"Valid against report definition?"}
Check -->|No| Reject["Show explicit validation reason"]
Check -->|Yes| Persist["Persist scheduled report configuration"]
Persist --> Trigger["Scheduled run time arrives"]
Trigger --> RunCheck{"Valid at run time?"}
RunCheck -->|No| RunReject["Record rejected run with reason"]
RunCheck -->|Yes| Generate["Generate report output"]
Generate --> Deliver["Deliver CSV to recipients"]
Sequence Diagram: Shared Report Rules Across On-Demand and Scheduled Flows
sequenceDiagram
participant User
participant Catalog as Report Catalog
participant Schedules as Scheduled Report Management
participant Scheduler
participant Execution as Scheduled Report Execution
participant Delivery
User->>Catalog: Select report
Catalog-->>User: Return report label, scope, limits, and fields
User->>Schedules: Save scheduled report configuration
Schedules->>Catalog: Validate configuration against report rules
Catalog-->>Schedules: Valid or rejected with reason
Scheduler->>Execution: Trigger scheduled run
Execution->>Catalog: Resolve report rules for run
Catalog-->>Execution: Scope, lookback, and parameter rules
Execution->>Delivery: Deliver generated CSV
Delivery-->>Execution: Delivery result
7. Non-Technical Implementation Approach
- Approach overview:
- First, formalize the shared report catalog so report behavior is defined once for user-facing configuration purposes.
- Second, reframe Scheduled Reports around report-specific configuration rather than a generic schedule form with ad hoc special cases.
- Third, deliver the reports that already align to backend CSV generation.
- Fourth, complete parity for the table-driven reports by aligning their export behavior to the same scheduled execution model.
- Design considerations:
- Consistency is more important than shortest-path enablement, because the business cost of diverging report rules is ongoing support friction and user mistrust.
- Scope must be explicit because User Access Log Report changes the ownership model.
- Phasing is a delivery tactic, not a different product model; both phases must point at the same end-state capability.
- Dependencies and prerequisites:
- Agreement on the user-facing executable report set that belongs in this capability.
- Agreement that User Access Log Report is account-scoped.
- Agreement that full filter parity is required for Charging Sessions, Vehicle Charging Summary, and Charger Performance.
- Availability of an execution path that can generate output for the phase-2 reports with the same semantics as on-demand exports.
8. Open Questions
- None at the time of this draft. Follow-on story shaping can decide implementation slicing within phase 1 and phase 2 without changing the capability definition.
9. Appendices
- Inputs reviewed:
- Current BetterFleet Reports page report catalog and report-module rules.
- Current Scheduled Reports capability, supported report list, and configuration model.
- Current scheduled-report execution support for Site Power Report and Daily EV Load Report.
- Baseline references:
bf-manage-web Reports page report modules and validation rules.
bf-manage-web Scheduled Reports editor and table surfaces.
bf-manage-core scheduled-report API and execution logic.
- Conceptual integration notes:
- The shared report catalog is the contract between report configuration and scheduled execution.
- Scheduled report scope is part of the core business model, not just a UI concern.
- Phase 2 is primarily an output-parity and export-alignment effort, not merely a list-expansion effort.