1use crate::agents::Agent;
9use crate::domain::{DomainAgent, DomainCapability, DomainKnowledge, TechRecommendation};
10use crate::error::Result;
11use crate::models::{AgentInput, AgentOutput, Finding, Severity, TaskType};
12use async_trait::async_trait;
13use uuid::Uuid;
14
15#[derive(Debug, Clone)]
35pub struct BackendAgent {
36 domain_agent: DomainAgent,
37}
38
39impl BackendAgent {
40 pub fn new() -> Self {
48 let capabilities = vec![
49 DomainCapability {
50 name: "API Design".to_string(),
51 description: "Recommendations for REST, GraphQL, or gRPC API design patterns"
52 .to_string(),
53 technologies: vec!["REST".to_string(), "GraphQL".to_string(), "gRPC".to_string()],
54 patterns: vec![],
55 },
56 DomainCapability {
57 name: "Architecture Guidance".to_string(),
58 description:
59 "Recommendations for microservices, monolithic, or serverless architectures"
60 .to_string(),
61 technologies: vec![
62 "Microservices".to_string(),
63 "Monolithic".to_string(),
64 "Serverless".to_string(),
65 ],
66 patterns: vec![],
67 },
68 DomainCapability {
69 name: "Database Design".to_string(),
70 description:
71 "Recommendations for relational, NoSQL, or graph database selection and schema design"
72 .to_string(),
73 technologies: vec![
74 "PostgreSQL".to_string(),
75 "MongoDB".to_string(),
76 "Neo4j".to_string(),
77 ],
78 patterns: vec![],
79 },
80 DomainCapability {
81 name: "Scalability".to_string(),
82 description:
83 "Recommendations for caching, load balancing, and horizontal scaling strategies"
84 .to_string(),
85 technologies: vec![
86 "Redis".to_string(),
87 "Memcached".to_string(),
88 "Load Balancers".to_string(),
89 ],
90 patterns: vec![],
91 },
92 DomainCapability {
93 name: "Security".to_string(),
94 description:
95 "Recommendations for authentication, authorization, and data protection patterns"
96 .to_string(),
97 technologies: vec![
98 "OAuth 2.0".to_string(),
99 "JWT".to_string(),
100 "TLS".to_string(),
101 ],
102 patterns: vec![],
103 },
104 DomainCapability {
105 name: "Observability".to_string(),
106 description: "Recommendations for logging, metrics, and tracing implementation"
107 .to_string(),
108 technologies: vec![
109 "ELK Stack".to_string(),
110 "Prometheus".to_string(),
111 "Jaeger".to_string(),
112 ],
113 patterns: vec![],
114 },
115 ];
116
117 let knowledge = DomainKnowledge {
118 best_practices: vec![],
119 technology_recommendations: vec![
120 TechRecommendation {
121 technology: "REST".to_string(),
122 domain: "backend".to_string(),
123 use_cases: vec![
124 "Web APIs".to_string(),
125 "Mobile backends".to_string(),
126 "Simple CRUD operations".to_string(),
127 ],
128 pros: vec![
129 "Simple and well-understood".to_string(),
130 "Stateless design".to_string(),
131 "Excellent caching support".to_string(),
132 ],
133 cons: vec![
134 "Over-fetching and under-fetching".to_string(),
135 "Versioning complexity".to_string(),
136 "Multiple requests for related data".to_string(),
137 ],
138 alternatives: vec!["GraphQL".to_string(), "gRPC".to_string()],
139 },
140 TechRecommendation {
141 technology: "GraphQL".to_string(),
142 domain: "backend".to_string(),
143 use_cases: vec![
144 "Complex data queries".to_string(),
145 "Mobile-first applications".to_string(),
146 "Real-time data".to_string(),
147 ],
148 pros: vec![
149 "Precise data fetching".to_string(),
150 "Single endpoint".to_string(),
151 "Strong typing".to_string(),
152 ],
153 cons: vec![
154 "Steep learning curve".to_string(),
155 "Query complexity".to_string(),
156 "Caching challenges".to_string(),
157 ],
158 alternatives: vec!["REST".to_string(), "gRPC".to_string()],
159 },
160 TechRecommendation {
161 technology: "gRPC".to_string(),
162 domain: "backend".to_string(),
163 use_cases: vec![
164 "Microservices communication".to_string(),
165 "High-performance systems".to_string(),
166 "Real-time streaming".to_string(),
167 ],
168 pros: vec![
169 "High performance".to_string(),
170 "Streaming support".to_string(),
171 "Language-agnostic".to_string(),
172 ],
173 cons: vec![
174 "Steep learning curve".to_string(),
175 "Browser support limitations".to_string(),
176 "Debugging complexity".to_string(),
177 ],
178 alternatives: vec!["REST".to_string(), "GraphQL".to_string()],
179 },
180 TechRecommendation {
181 technology: "PostgreSQL".to_string(),
182 domain: "backend".to_string(),
183 use_cases: vec![
184 "Relational data".to_string(),
185 "ACID transactions".to_string(),
186 "Complex queries".to_string(),
187 ],
188 pros: vec![
189 "Reliable".to_string(),
190 "Feature-rich".to_string(),
191 "Open source".to_string(),
192 ],
193 cons: vec![
194 "Vertical scaling limitations".to_string(),
195 "Complex setup".to_string(),
196 ],
197 alternatives: vec!["MySQL".to_string(), "MariaDB".to_string()],
198 },
199 TechRecommendation {
200 technology: "MongoDB".to_string(),
201 domain: "backend".to_string(),
202 use_cases: vec![
203 "Document storage".to_string(),
204 "Flexible schema".to_string(),
205 "Rapid development".to_string(),
206 ],
207 pros: vec![
208 "Flexible schema".to_string(),
209 "Horizontal scaling".to_string(),
210 "Easy to use".to_string(),
211 ],
212 cons: vec![
213 "No ACID transactions".to_string(),
214 "Higher memory usage".to_string(),
215 ],
216 alternatives: vec!["CouchDB".to_string(), "Firebase".to_string()],
217 },
218 TechRecommendation {
219 technology: "Neo4j".to_string(),
220 domain: "backend".to_string(),
221 use_cases: vec![
222 "Graph data".to_string(),
223 "Relationship queries".to_string(),
224 "Recommendation engines".to_string(),
225 ],
226 pros: vec![
227 "Powerful graph queries".to_string(),
228 "Relationship performance".to_string(),
229 "Intuitive modeling".to_string(),
230 ],
231 cons: vec![
232 "Specialized use case".to_string(),
233 "Smaller ecosystem".to_string(),
234 ],
235 alternatives: vec!["ArangoDB".to_string(), "TigerGraph".to_string()],
236 },
237 TechRecommendation {
238 technology: "Redis".to_string(),
239 domain: "backend".to_string(),
240 use_cases: vec![
241 "Caching".to_string(),
242 "Session storage".to_string(),
243 "Real-time analytics".to_string(),
244 ],
245 pros: vec![
246 "Lightning fast".to_string(),
247 "Versatile data structures".to_string(),
248 "Pub/Sub support".to_string(),
249 ],
250 cons: vec![
251 "In-memory only".to_string(),
252 "Data persistence complexity".to_string(),
253 ],
254 alternatives: vec!["Memcached".to_string(), "Hazelcast".to_string()],
255 },
256 TechRecommendation {
257 technology: "Memcached".to_string(),
258 domain: "backend".to_string(),
259 use_cases: vec![
260 "Simple caching".to_string(),
261 "Session storage".to_string(),
262 "Object caching".to_string(),
263 ],
264 pros: vec![
265 "Simple and lightweight".to_string(),
266 "Fast".to_string(),
267 "Distributed".to_string(),
268 ],
269 cons: vec![
270 "Limited data structures".to_string(),
271 "No persistence".to_string(),
272 ],
273 alternatives: vec!["Redis".to_string(), "Hazelcast".to_string()],
274 },
275 TechRecommendation {
276 technology: "Microservices".to_string(),
277 domain: "backend".to_string(),
278 use_cases: vec![
279 "Large applications".to_string(),
280 "Independent scaling".to_string(),
281 "Team autonomy".to_string(),
282 ],
283 pros: vec![
284 "Independent scaling".to_string(),
285 "Technology flexibility".to_string(),
286 "Team autonomy".to_string(),
287 ],
288 cons: vec![
289 "Operational complexity".to_string(),
290 "Network latency".to_string(),
291 "Data consistency challenges".to_string(),
292 ],
293 alternatives: vec!["Monolithic".to_string(), "Serverless".to_string()],
294 },
295 TechRecommendation {
296 technology: "Monolithic".to_string(),
297 domain: "backend".to_string(),
298 use_cases: vec![
299 "Small to medium applications".to_string(),
300 "Simple deployments".to_string(),
301 "Rapid development".to_string(),
302 ],
303 pros: vec![
304 "Simple deployment".to_string(),
305 "Easier debugging".to_string(),
306 "Better performance".to_string(),
307 ],
308 cons: vec![
309 "Scaling limitations".to_string(),
310 "Technology lock-in".to_string(),
311 "Deployment coupling".to_string(),
312 ],
313 alternatives: vec!["Microservices".to_string(), "Serverless".to_string()],
314 },
315 TechRecommendation {
316 technology: "Serverless".to_string(),
317 domain: "backend".to_string(),
318 use_cases: vec![
319 "Event-driven workloads".to_string(),
320 "Sporadic traffic".to_string(),
321 "Rapid prototyping".to_string(),
322 ],
323 pros: vec![
324 "No infrastructure management".to_string(),
325 "Auto-scaling".to_string(),
326 "Pay-per-use".to_string(),
327 ],
328 cons: vec![
329 "Cold start latency".to_string(),
330 "Vendor lock-in".to_string(),
331 "Debugging complexity".to_string(),
332 ],
333 alternatives: vec!["Microservices".to_string(), "Monolithic".to_string()],
334 },
335 TechRecommendation {
336 technology: "OAuth 2.0".to_string(),
337 domain: "backend".to_string(),
338 use_cases: vec![
339 "Third-party authentication".to_string(),
340 "Delegated access".to_string(),
341 "Social login".to_string(),
342 ],
343 pros: vec![
344 "Industry standard".to_string(),
345 "Secure delegation".to_string(),
346 "Wide adoption".to_string(),
347 ],
348 cons: vec![
349 "Complex implementation".to_string(),
350 "Token management".to_string(),
351 ],
352 alternatives: vec!["OpenID Connect".to_string(), "SAML".to_string()],
353 },
354 TechRecommendation {
355 technology: "JWT".to_string(),
356 domain: "backend".to_string(),
357 use_cases: vec![
358 "Stateless authentication".to_string(),
359 "API authentication".to_string(),
360 "Token-based auth".to_string(),
361 ],
362 pros: vec![
363 "Stateless".to_string(),
364 "Self-contained".to_string(),
365 "Cross-domain support".to_string(),
366 ],
367 cons: vec![
368 "Token revocation challenges".to_string(),
369 "Token size".to_string(),
370 ],
371 alternatives: vec!["Session tokens".to_string(), "OAuth 2.0".to_string()],
372 },
373 TechRecommendation {
374 technology: "TLS".to_string(),
375 domain: "backend".to_string(),
376 use_cases: vec![
377 "Secure communication".to_string(),
378 "Data encryption".to_string(),
379 "HTTPS".to_string(),
380 ],
381 pros: vec![
382 "Industry standard".to_string(),
383 "Wide support".to_string(),
384 "Proven security".to_string(),
385 ],
386 cons: vec![
387 "Performance overhead".to_string(),
388 "Certificate management".to_string(),
389 ],
390 alternatives: vec!["SSL".to_string()],
391 },
392 TechRecommendation {
393 technology: "ELK Stack".to_string(),
394 domain: "backend".to_string(),
395 use_cases: vec![
396 "Log aggregation".to_string(),
397 "Log analysis".to_string(),
398 "Centralized logging".to_string(),
399 ],
400 pros: vec![
401 "Powerful search".to_string(),
402 "Real-time analysis".to_string(),
403 "Open source".to_string(),
404 ],
405 cons: vec![
406 "Resource intensive".to_string(),
407 "Complex setup".to_string(),
408 ],
409 alternatives: vec!["Splunk".to_string(), "Datadog".to_string()],
410 },
411 TechRecommendation {
412 technology: "Prometheus".to_string(),
413 domain: "backend".to_string(),
414 use_cases: vec![
415 "Metrics collection".to_string(),
416 "System monitoring".to_string(),
417 "Alerting".to_string(),
418 ],
419 pros: vec![
420 "Time-series database".to_string(),
421 "Powerful queries".to_string(),
422 "Open source".to_string(),
423 ],
424 cons: vec![
425 "Pull-based model".to_string(),
426 "Limited long-term storage".to_string(),
427 ],
428 alternatives: vec!["Grafana".to_string(), "InfluxDB".to_string()],
429 },
430 TechRecommendation {
431 technology: "Jaeger".to_string(),
432 domain: "backend".to_string(),
433 use_cases: vec![
434 "Distributed tracing".to_string(),
435 "Request tracing".to_string(),
436 "Performance analysis".to_string(),
437 ],
438 pros: vec![
439 "Distributed tracing".to_string(),
440 "OpenTelemetry support".to_string(),
441 "Open source".to_string(),
442 ],
443 cons: vec![
444 "Complex setup".to_string(),
445 "Storage requirements".to_string(),
446 ],
447 alternatives: vec!["Zipkin".to_string(), "Datadog".to_string()],
448 },
449 ],
450 patterns: vec![],
451 anti_patterns: vec![],
452 };
453
454 let domain_agent = DomainAgent {
455 id: "backend-agent".to_string(),
456 domain: "backend".to_string(),
457 capabilities,
458 knowledge,
459 };
460
461 BackendAgent { domain_agent }
462 }
463
464 pub fn domain(&self) -> &str {
466 &self.domain_agent.domain
467 }
468
469 pub fn capabilities(&self) -> &[DomainCapability] {
471 &self.domain_agent.capabilities
472 }
473
474 pub fn knowledge(&self) -> &DomainKnowledge {
476 &self.domain_agent.knowledge
477 }
478
479 pub fn domain_agent(&self) -> &DomainAgent {
481 &self.domain_agent
482 }
483}
484
485impl Default for BackendAgent {
486 fn default() -> Self {
487 Self::new()
488 }
489}
490
491#[async_trait]
492impl Agent for BackendAgent {
493 fn id(&self) -> &str {
494 &self.domain_agent.id
495 }
496
497 fn name(&self) -> &str {
498 "Backend Development Agent"
499 }
500
501 fn description(&self) -> &str {
502 "Specialized agent for backend development with expertise in API design, architecture, database design, scalability, security, and observability"
503 }
504
505 fn supports(&self, task_type: TaskType) -> bool {
506 matches!(
508 task_type,
509 TaskType::CodeReview
510 | TaskType::Refactoring
511 | TaskType::Documentation
512 | TaskType::SecurityAnalysis
513 )
514 }
515
516 async fn execute(&self, input: AgentInput) -> Result<AgentOutput> {
517 let mut output = AgentOutput::default();
520
521 match input.task.task_type {
523 TaskType::CodeReview => {
524 output.findings.push(Finding {
525 id: Uuid::new_v4().to_string(),
526 severity: Severity::Info,
527 category: "backend-best-practices".to_string(),
528 message: "Backend development best practices applied".to_string(),
529 location: None,
530 suggestion: None,
531 });
532 }
533 _ => {}
534 }
535
536 Ok(output)
537 }
538}
539
540#[cfg(test)]
541mod tests {
542 use super::*;
543
544 #[test]
545 fn test_backend_agent_creation() {
546 let agent = BackendAgent::new();
547 assert_eq!(agent.id(), "backend-agent");
548 assert_eq!(agent.domain(), "backend");
549 assert_eq!(agent.name(), "Backend Development Agent");
550 }
551
552 #[test]
553 fn test_backend_agent_capabilities() {
554 let agent = BackendAgent::new();
555 let capabilities = agent.capabilities();
556 assert_eq!(capabilities.len(), 6);
557
558 assert_eq!(capabilities[0].name, "API Design");
560 assert_eq!(capabilities[0].technologies.len(), 3);
561 assert!(capabilities[0]
562 .technologies
563 .contains(&"REST".to_string()));
564 assert!(capabilities[0]
565 .technologies
566 .contains(&"GraphQL".to_string()));
567 assert!(capabilities[0]
568 .technologies
569 .contains(&"gRPC".to_string()));
570 }
571
572 #[test]
573 fn test_backend_agent_knowledge() {
574 let agent = BackendAgent::new();
575 let knowledge = agent.knowledge();
576 assert!(!knowledge.technology_recommendations.is_empty());
577 assert_eq!(knowledge.technology_recommendations.len(), 17);
578 }
579
580 #[test]
581 fn test_backend_agent_technology_recommendations() {
582 let agent = BackendAgent::new();
583 let knowledge = agent.knowledge();
584
585 let rest_rec = knowledge
587 .technology_recommendations
588 .iter()
589 .find(|r| r.technology == "REST")
590 .expect("REST recommendation not found");
591
592 assert_eq!(rest_rec.domain, "backend");
593 assert!(!rest_rec.use_cases.is_empty());
594 assert!(!rest_rec.pros.is_empty());
595 assert!(!rest_rec.cons.is_empty());
596 assert!(!rest_rec.alternatives.is_empty());
597 }
598
599 #[test]
600 fn test_backend_agent_supports_task_types() {
601 let agent = BackendAgent::new();
602 assert!(agent.supports(TaskType::CodeReview));
603 assert!(agent.supports(TaskType::Refactoring));
604 assert!(agent.supports(TaskType::Documentation));
605 assert!(agent.supports(TaskType::SecurityAnalysis));
606 assert!(!agent.supports(TaskType::TestGeneration));
607 }
608
609 #[test]
610 fn test_backend_agent_default() {
611 let agent1 = BackendAgent::new();
612 let agent2 = BackendAgent::default();
613 assert_eq!(agent1.id(), agent2.id());
614 assert_eq!(agent1.domain(), agent2.domain());
615 }
616
617 #[test]
618 fn test_backend_agent_clone() {
619 let agent1 = BackendAgent::new();
620 let agent2 = agent1.clone();
621 assert_eq!(agent1.id(), agent2.id());
622 assert_eq!(agent1.domain(), agent2.domain());
623 assert_eq!(agent1.capabilities().len(), agent2.capabilities().len());
624 }
625
626 #[test]
627 fn test_backend_agent_all_api_patterns_present() {
628 let agent = BackendAgent::new();
629 let knowledge = agent.knowledge();
630
631 let api_patterns = vec!["REST", "GraphQL", "gRPC"];
632 for pattern in api_patterns {
633 let found = knowledge
634 .technology_recommendations
635 .iter()
636 .any(|r| r.technology == pattern);
637 assert!(found, "API pattern {} not found in recommendations", pattern);
638 }
639 }
640
641 #[test]
642 fn test_backend_agent_all_databases_present() {
643 let agent = BackendAgent::new();
644 let knowledge = agent.knowledge();
645
646 let databases = vec!["PostgreSQL", "MongoDB", "Neo4j"];
647 for db in databases {
648 let found = knowledge
649 .technology_recommendations
650 .iter()
651 .any(|r| r.technology == db);
652 assert!(found, "Database {} not found in recommendations", db);
653 }
654 }
655
656 #[test]
657 fn test_backend_agent_all_architectures_present() {
658 let agent = BackendAgent::new();
659 let knowledge = agent.knowledge();
660
661 let architectures = vec!["Microservices", "Monolithic", "Serverless"];
662 for arch in architectures {
663 let found = knowledge
664 .technology_recommendations
665 .iter()
666 .any(|r| r.technology == arch);
667 assert!(found, "Architecture {} not found in recommendations", arch);
668 }
669 }
670
671 #[test]
672 fn test_backend_agent_all_caching_solutions_present() {
673 let agent = BackendAgent::new();
674 let knowledge = agent.knowledge();
675
676 let caching = vec!["Redis", "Memcached"];
677 for cache in caching {
678 let found = knowledge
679 .technology_recommendations
680 .iter()
681 .any(|r| r.technology == cache);
682 assert!(found, "Caching solution {} not found in recommendations", cache);
683 }
684 }
685
686 #[test]
687 fn test_backend_agent_all_security_technologies_present() {
688 let agent = BackendAgent::new();
689 let knowledge = agent.knowledge();
690
691 let security = vec!["OAuth 2.0", "JWT", "TLS"];
692 for tech in security {
693 let found = knowledge
694 .technology_recommendations
695 .iter()
696 .any(|r| r.technology == tech);
697 assert!(found, "Security technology {} not found in recommendations", tech);
698 }
699 }
700
701 #[test]
702 fn test_backend_agent_all_observability_tools_present() {
703 let agent = BackendAgent::new();
704 let knowledge = agent.knowledge();
705
706 let observability = vec!["ELK Stack", "Prometheus", "Jaeger"];
707 for tool in observability {
708 let found = knowledge
709 .technology_recommendations
710 .iter()
711 .any(|r| r.technology == tool);
712 assert!(found, "Observability tool {} not found in recommendations", tool);
713 }
714 }
715
716 #[test]
717 fn test_backend_agent_rest_alternatives() {
718 let agent = BackendAgent::new();
719 let knowledge = agent.knowledge();
720
721 let rest_rec = knowledge
722 .technology_recommendations
723 .iter()
724 .find(|r| r.technology == "REST")
725 .expect("REST recommendation not found");
726
727 assert!(rest_rec.alternatives.contains(&"GraphQL".to_string()));
728 assert!(rest_rec.alternatives.contains(&"gRPC".to_string()));
729 }
730
731 #[test]
732 fn test_backend_agent_postgresql_alternatives() {
733 let agent = BackendAgent::new();
734 let knowledge = agent.knowledge();
735
736 let pg_rec = knowledge
737 .technology_recommendations
738 .iter()
739 .find(|r| r.technology == "PostgreSQL")
740 .expect("PostgreSQL recommendation not found");
741
742 assert!(pg_rec.alternatives.contains(&"MySQL".to_string()));
743 assert!(pg_rec.alternatives.contains(&"MariaDB".to_string()));
744 }
745
746 #[test]
747 fn test_backend_agent_redis_alternatives() {
748 let agent = BackendAgent::new();
749 let knowledge = agent.knowledge();
750
751 let redis_rec = knowledge
752 .technology_recommendations
753 .iter()
754 .find(|r| r.technology == "Redis")
755 .expect("Redis recommendation not found");
756
757 assert!(redis_rec.alternatives.contains(&"Memcached".to_string()));
758 assert!(redis_rec.alternatives.contains(&"Hazelcast".to_string()));
759 }
760
761 #[tokio::test]
762 async fn test_backend_agent_execute() {
763 use crate::models::{
764 AgentConfig, AgentTask, ProjectContext, TaskOptions, TaskScope, TaskTarget,
765 };
766 use std::path::PathBuf;
767
768 let agent = BackendAgent::new();
769 let input = AgentInput {
770 task: AgentTask {
771 id: "task-1".to_string(),
772 task_type: TaskType::CodeReview,
773 target: TaskTarget {
774 files: vec![PathBuf::from("api.rs")],
775 scope: TaskScope::File,
776 },
777 options: TaskOptions::default(),
778 },
779 context: ProjectContext {
780 name: "backend-project".to_string(),
781 root: PathBuf::from("/tmp/backend-project"),
782 },
783 config: AgentConfig::default(),
784 };
785
786 let result = agent.execute(input).await;
787 assert!(result.is_ok());
788
789 let output = result.unwrap();
790 assert!(!output.findings.is_empty());
791 }
792}