1#[derive(Debug, Clone, PartialEq, Eq)]
19#[non_exhaustive]
20pub enum SupportTier {
21 Community,
23 Standard,
25 Premium,
27 Enterprise,
29}
30
31impl core::fmt::Display for SupportTier {
32 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33 match self {
34 Self::Community => write!(f, "Community"),
35 Self::Standard => write!(f, "Standard"),
36 Self::Premium => write!(f, "Premium"),
37 Self::Enterprise => write!(f, "Enterprise"),
38 #[allow(unreachable_patterns)]
39 _ => write!(f, "Unknown"),
40 }
41 }
42}
43
44#[derive(Debug, Clone)]
49pub struct SupportConfig {
50 pub github_issues_url: &'static str,
52 pub github_discussions_url: &'static str,
54 pub documentation_url: &'static str,
56 pub api_reference_url: &'static str,
58 pub email: &'static str,
60 pub response_time_hours: u32,
62 pub resolution_time_hours: Option<u32>,
64 pub tier: SupportTier,
66 pub security_email: &'static str,
68 pub changelog_url: &'static str,
70}
71
72impl Default for SupportConfig {
73 fn default() -> Self {
74 Self {
75 github_issues_url: "https://github.com/cool-japan/scirs/issues",
76 github_discussions_url: "https://github.com/cool-japan/scirs/discussions",
77 documentation_url: "https://cool-japan.github.io/scirs/",
78 api_reference_url: "https://docs.rs/scirs2-core/latest/scirs2_core/",
79 email: "support@cooljapan.dev",
80 response_time_hours: 48,
81 resolution_time_hours: None,
82 tier: SupportTier::Community,
83 security_email: "security@cooljapan.dev",
84 changelog_url: "https://github.com/cool-japan/scirs/blob/master/CHANGELOG.md",
85 }
86 }
87}
88
89impl SupportConfig {
90 pub fn for_tier(tier: SupportTier) -> Self {
92 match tier {
93 SupportTier::Community => Self::default(),
94 SupportTier::Standard => Self {
95 response_time_hours: 24,
96 resolution_time_hours: Some(72),
97 tier: SupportTier::Standard,
98 ..Self::default()
99 },
100 SupportTier::Premium => Self {
101 response_time_hours: 8,
102 resolution_time_hours: Some(48),
103 tier: SupportTier::Premium,
104 ..Self::default()
105 },
106 SupportTier::Enterprise => Self {
107 response_time_hours: 4,
108 resolution_time_hours: Some(24),
109 tier: SupportTier::Enterprise,
110 ..Self::default()
111 },
112 #[allow(unreachable_patterns)]
113 _ => Self::default(),
114 }
115 }
116
117 pub fn summary(&self) -> String {
119 let mut lines = Vec::new();
120 lines.push(format!("SciRS2 Support Configuration ({})", self.tier));
121 lines.push(format!(" Issues: {}", self.github_issues_url));
122 lines.push(format!(" Discussions: {}", self.github_discussions_url));
123 lines.push(format!(" Documentation: {}", self.documentation_url));
124 lines.push(format!(" API Reference: {}", self.api_reference_url));
125 lines.push(format!(" Email: {}", self.email));
126 lines.push(format!(" Security: {}", self.security_email));
127 lines.push(format!(
128 " Response time: {} hours",
129 self.response_time_hours
130 ));
131 if let Some(resolution) = self.resolution_time_hours {
132 lines.push(format!(" Resolution: {} hours", resolution));
133 }
134 lines.push(format!(" Changelog: {}", self.changelog_url));
135 lines.join("\n")
136 }
137}
138
139pub fn support_info() -> SupportConfig {
141 SupportConfig::default()
142}
143
144#[derive(Debug, Clone)]
146pub struct EscalationPath {
147 pub steps: Vec<EscalationStep>,
149}
150
151#[derive(Debug, Clone)]
153pub struct EscalationStep {
154 pub step: u32,
156 pub action: String,
158 pub channel: String,
160 pub wait_hours: u32,
162}
163
164pub fn default_escalation_path() -> EscalationPath {
166 EscalationPath {
167 steps: vec![
168 EscalationStep {
169 step: 1,
170 action: "Search existing GitHub issues and documentation".into(),
171 channel: "Self-service".into(),
172 wait_hours: 0,
173 },
174 EscalationStep {
175 step: 2,
176 action: "Open a new GitHub issue with reproduction steps".into(),
177 channel: "GitHub Issues".into(),
178 wait_hours: 48,
179 },
180 EscalationStep {
181 step: 3,
182 action: "Post in GitHub Discussions for community help".into(),
183 channel: "GitHub Discussions".into(),
184 wait_hours: 24,
185 },
186 EscalationStep {
187 step: 4,
188 action: "Email support team with issue link".into(),
189 channel: "Email".into(),
190 wait_hours: 24,
191 },
192 EscalationStep {
193 step: 5,
194 action: "For security issues, email security team directly".into(),
195 channel: "Security Email".into(),
196 wait_hours: 0,
197 },
198 ],
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_support_config_default() {
208 let config = SupportConfig::default();
209 assert!(!config.github_issues_url.is_empty());
210 assert!(!config.documentation_url.is_empty());
211 assert!(!config.email.is_empty());
212 assert!(config.response_time_hours > 0);
213 assert_eq!(config.tier, SupportTier::Community);
214 }
215
216 #[test]
217 fn test_support_info_returns_community() {
218 let config = support_info();
219 assert_eq!(config.tier, SupportTier::Community);
220 }
221
222 #[test]
223 fn test_support_tiers_response_times() {
224 let community = SupportConfig::for_tier(SupportTier::Community);
225 let standard = SupportConfig::for_tier(SupportTier::Standard);
226 let premium = SupportConfig::for_tier(SupportTier::Premium);
227 let enterprise = SupportConfig::for_tier(SupportTier::Enterprise);
228
229 assert!(community.response_time_hours >= standard.response_time_hours);
230 assert!(standard.response_time_hours >= premium.response_time_hours);
231 assert!(premium.response_time_hours >= enterprise.response_time_hours);
232 }
233
234 #[test]
235 fn test_support_tier_display() {
236 assert_eq!(SupportTier::Community.to_string(), "Community");
237 assert_eq!(SupportTier::Standard.to_string(), "Standard");
238 assert_eq!(SupportTier::Premium.to_string(), "Premium");
239 assert_eq!(SupportTier::Enterprise.to_string(), "Enterprise");
240 }
241
242 #[test]
243 fn test_support_config_summary() {
244 let config = SupportConfig::for_tier(SupportTier::Premium);
245 let summary = config.summary();
246 assert!(summary.contains("Premium"));
247 assert!(summary.contains("8 hours"));
248 assert!(summary.contains("48 hours"));
249 assert!(summary.contains("github.com"));
250 }
251
252 #[test]
253 fn test_escalation_path() {
254 let path = default_escalation_path();
255 assert!(
256 path.steps.len() >= 4,
257 "Expected at least 4 escalation steps"
258 );
259 for (i, step) in path.steps.iter().enumerate() {
260 assert_eq!(step.step as usize, i + 1);
261 assert!(!step.action.is_empty());
262 assert!(!step.channel.is_empty());
263 }
264 }
265
266 #[test]
267 fn test_enterprise_tier_has_resolution_time() {
268 let config = SupportConfig::for_tier(SupportTier::Enterprise);
269 assert!(
270 config.resolution_time_hours.is_some(),
271 "Enterprise tier must have resolution time"
272 );
273 }
274
275 #[test]
276 fn test_security_email_present() {
277 let config = support_info();
278 assert!(
279 config.security_email.contains('@'),
280 "Security email must be a valid email"
281 );
282 }
283}