progit_plugin_sdk/traits/analytics.rs
1// SPDX-License-Identifier: LSL-1.0
2// Copyright (c) 2025 Markus Maiwald
3
4//! Analytics plugin traits
5//!
6//! Traits for plugins that compute metrics, generate reports, or export data.
7
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10
11use super::core::{Issue, Plugin, PluginResult};
12
13/// Query parameters for filtering issues in analytics
14#[derive(Debug, Clone, Serialize, Deserialize, Default)]
15pub struct AnalyticsQuery {
16 /// Date range for the query
17 pub date_range: Option<DateRange>,
18 /// Filter by statuses
19 pub statuses: Vec<String>,
20 /// Filter by tags
21 pub tags: Vec<String>,
22 /// Filter by assignees
23 pub assignees: Vec<String>,
24 /// Filter by sprints
25 pub sprints: Vec<u32>,
26 /// Include deleted issues
27 pub include_deleted: bool,
28 /// Maximum number of results
29 pub limit: Option<usize>,
30 /// Offset for pagination
31 pub offset: Option<usize>,
32}
33
34/// Date range for queries
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct DateRange {
37 /// Start date (ISO 8601)
38 pub start: String,
39 /// End date (ISO 8601)
40 pub end: String,
41}
42
43/// Types of metrics that can be computed
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
45pub enum MetricType {
46 /// Issues completed per sprint/week
47 Velocity,
48 /// Time from created to done
49 LeadTime,
50 /// Time from in-progress to done
51 CycleTime,
52 /// Total issues completed in period
53 Throughput,
54 /// Work in progress count
55 WIP,
56 /// Percentage of issues that are blocked
57 BlockedRatio,
58 /// Estimated vs actual effort accuracy
59 EffortAccuracy,
60 /// Number of issues by status
61 StatusDistribution,
62 /// Number of issues by tag
63 TagDistribution,
64 /// Number of issues by assignee
65 AssigneeWorkload,
66 /// Custom metric with name
67 Custom(String),
68}
69
70/// Result of a metric computation
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct MetricValue {
73 /// The metric that was computed
74 pub metric: MetricType,
75 /// The computed value
76 pub value: f64,
77 /// Unit of measurement (e.g., "issues", "days", "percent")
78 pub unit: String,
79 /// Breakdown by category (per-tag, per-assignee, etc.)
80 pub breakdown: Option<HashMap<String, f64>>,
81 /// Trend compared to previous period
82 pub trend: Option<Trend>,
83}
84
85/// Trend indicator for metrics
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct Trend {
88 /// Change from previous period
89 pub change: f64,
90 /// Percentage change
91 pub change_percent: f64,
92 /// Direction of change
93 pub direction: TrendDirection,
94}
95
96/// Direction of trend change
97#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
98pub enum TrendDirection {
99 Up,
100 Down,
101 Stable,
102}
103
104/// Types of reports that can be generated
105#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
106pub enum ReportType {
107 /// Burndown chart data
108 Burndown,
109 /// Burn-up chart data
110 BurnUp,
111 /// Velocity trend over time
112 VelocityTrend,
113 /// Cumulative flow diagram data
114 CumulativeFlow,
115 /// Lead time trend over time
116 LeadTimeTrend,
117 /// Tag distribution pie chart
118 TagDistribution,
119 /// Assignee workload bar chart
120 AssigneeWorkload,
121 /// Sprint summary
122 SprintSummary,
123 /// Custom report with name
124 Custom(String),
125}
126
127/// A generated report
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct Report {
130 /// Type of report
131 pub report_type: ReportType,
132 /// Report title
133 pub title: String,
134 /// When the report was generated (ISO 8601)
135 pub generated_at: String,
136 /// Data points for charting
137 pub data_points: Vec<DataPoint>,
138 /// Summary statistics
139 pub summary: HashMap<String, serde_json::Value>,
140 /// Report-specific metadata
141 pub metadata: HashMap<String, serde_json::Value>,
142}
143
144/// A single data point in a report
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct DataPoint {
147 /// X-axis label (date, sprint number, etc.)
148 pub label: String,
149 /// Y-axis values (can have multiple series)
150 pub values: HashMap<String, f64>,
151}
152
153/// Export formats for data
154#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
155pub enum ExportFormat {
156 /// JSON format
157 Json,
158 /// CSV format
159 Csv,
160 /// Markdown format
161 Markdown,
162 /// HTML format
163 Html,
164 /// Custom format with name
165 Custom(String),
166}
167
168/// Historical issue snapshot for analytics
169#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct IssueSnapshot {
171 /// The issue at this point in time
172 pub issue: Issue,
173 /// When this snapshot was taken (ISO 8601)
174 pub snapshot_time: String,
175 /// Status at snapshot time
176 pub status_at_time: String,
177 /// Sprint at snapshot time
178 pub sprint_at_time: Option<u32>,
179}
180
181/// Sprint definition
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct Sprint {
184 /// Sprint number
185 pub number: u32,
186 /// Sprint name (optional)
187 pub name: Option<String>,
188 /// Start date (ISO 8601)
189 pub start_date: String,
190 /// End date (ISO 8601)
191 pub end_date: String,
192 /// Sprint goal
193 pub goal: Option<String>,
194 /// Total effort committed
195 pub committed_effort: u32,
196 /// Total effort completed
197 pub completed_effort: u32,
198}
199
200/// Status transition record
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct StatusTransition {
203 /// Issue ID
204 pub issue_id: String,
205 /// Previous status
206 pub from_status: String,
207 /// New status
208 pub to_status: String,
209 /// When the transition occurred (ISO 8601)
210 pub timestamp: String,
211 /// Who made the change
212 pub by_user: Option<String>,
213}
214
215/// Trait for plugins that compute metrics, generate reports, or export data
216pub trait AnalyticsPlugin: Plugin {
217 /// Query issues with filters
218 ///
219 /// Returns issues matching the query parameters.
220 fn query_issues(&mut self, query: &AnalyticsQuery) -> PluginResult<Vec<Issue>>;
221
222 /// Compute a specific metric
223 ///
224 /// Calculates the requested metric for the given date range.
225 fn compute_metric(
226 &mut self,
227 metric: MetricType,
228 range: &DateRange,
229 ) -> PluginResult<MetricValue>;
230
231 /// Generate a report
232 ///
233 /// Creates a full report of the requested type for the given date range.
234 fn generate_report(
235 &mut self,
236 report_type: ReportType,
237 range: &DateRange,
238 ) -> PluginResult<Report>;
239
240 /// Export data in specified format
241 ///
242 /// Exports filtered data in the requested format. Returns raw bytes.
243 fn export(
244 &mut self,
245 format: ExportFormat,
246 query: &AnalyticsQuery,
247 ) -> PluginResult<Vec<u8>>;
248
249 /// Get available metrics
250 ///
251 /// Returns list of metrics this plugin can compute.
252 fn available_metrics(&self) -> Vec<MetricType> {
253 vec![
254 MetricType::Velocity,
255 MetricType::LeadTime,
256 MetricType::CycleTime,
257 MetricType::Throughput,
258 MetricType::WIP,
259 ]
260 }
261
262 /// Get available report types
263 ///
264 /// Returns list of reports this plugin can generate.
265 fn available_reports(&self) -> Vec<ReportType> {
266 vec![
267 ReportType::Burndown,
268 ReportType::VelocityTrend,
269 ]
270 }
271
272 /// Get available export formats
273 ///
274 /// Returns list of export formats this plugin supports.
275 fn available_formats(&self) -> Vec<ExportFormat> {
276 vec![
277 ExportFormat::Json,
278 ExportFormat::Csv,
279 ]
280 }
281
282 /// Get historical snapshots
283 ///
284 /// Returns historical issue snapshots for trend analysis.
285 fn get_snapshots(
286 &mut self,
287 _range: &DateRange,
288 ) -> PluginResult<Vec<IssueSnapshot>> {
289 // Default: no historical data
290 Ok(vec![])
291 }
292
293 /// Get status transitions
294 ///
295 /// Returns status transition history for cycle time analysis.
296 fn get_transitions(
297 &mut self,
298 _range: &DateRange,
299 ) -> PluginResult<Vec<StatusTransition>> {
300 // Default: no transition data
301 Ok(vec![])
302 }
303
304 /// Get sprint definitions
305 ///
306 /// Returns sprint information for sprint-based reports.
307 fn get_sprints(&mut self) -> PluginResult<Vec<Sprint>> {
308 // Default: no sprint data
309 Ok(vec![])
310 }
311}