# ANGULAR 18 FRONTEND DESIGNER SPECIALIST # Expert-level Angular 18 architecture design with TypeScript, standalone components, and modern patterns import json from typing import Dict, Any, List from loguru import logger try: import anthropic CLAUDE_AVAILABLE = True except ImportError: CLAUDE_AVAILABLE = False class Angular18Designer: """Expert Angular 18 Frontend Designer - Processes tagged rules from requirement-processor""" def __init__(self): self.framework = "Angular 18" self.language = "TypeScript" self.claude_client = None if CLAUDE_AVAILABLE: try: self.claude_client = anthropic.Anthropic() logger.info(f"✅ {self.framework} Designer initialized with Claude AI") except Exception as e: logger.warning(f"⚠️ Claude AI not available for {self.framework}: {e}") else: logger.warning(f"⚠️ Claude AI not available for {self.framework}") async def design_frontend_architecture( self, functional_requirements: Dict[str, Any], business_context: Dict[str, Any], tech_stack: Any ) -> Dict[str, Any]: """Design comprehensive Angular 18 frontend architecture from tagged rules""" logger.info(f"🎨 Designing {self.framework} frontend architecture...") try: # Extract all tagged rules from requirement-processor tagged_rules = self._extract_tagged_rules(functional_requirements) if not tagged_rules: logger.warning("⚠️ No tagged rules found, using basic architecture") return self._generate_basic_architecture(functional_requirements) logger.info(f"📋 Processing {len(tagged_rules)} tagged rules for Angular 18 design") if self.claude_client: return await self._generate_ai_architecture( tagged_rules, functional_requirements, business_context, tech_stack ) else: return self._generate_rule_based_architecture( tagged_rules, functional_requirements, business_context, tech_stack ) except Exception as e: logger.error(f"❌ {self.framework} AI generation failed: {e}") return self._generate_rule_based_architecture( tagged_rules, functional_requirements, business_context, tech_stack ) def _extract_tagged_rules(self, functional_requirements: Dict[str, Any]) -> List[Dict[str, Any]]: """Extract all tagged rules from requirement-processor output""" all_rules = [] # Extract from detailed_requirements with tagged rules detailed_requirements = functional_requirements.get('detailed_requirements', []) for req in detailed_requirements: requirement_name = req.get('requirement_name', 'Unknown') feature_name = req.get('feature_name', 'Unknown') rules = req.get('rules', []) for rule in rules: all_rules.append({ "rule_text": rule, "requirement_name": requirement_name, "feature_name": feature_name, "source": "detailed_requirements" }) # Extract from tagged_rules array (fallback) tagged_rules = functional_requirements.get('tagged_rules', []) for tagged_rule in tagged_rules: all_rules.append({ "rule_text": tagged_rule.get('rule_text', ''), "requirement_name": tagged_rule.get('requirement_name', 'Unknown'), "feature_name": tagged_rule.get('feature_name', 'Unknown'), "rule_id": tagged_rule.get('rule_id', ''), "source": "tagged_rules" }) # Extract from business_logic_rules (final fallback) business_rules = functional_requirements.get('business_logic_rules', []) for rule in business_rules: all_rules.append({ "rule_text": rule, "requirement_name": "General", "feature_name": functional_requirements.get('feature_name', 'General'), "source": "business_logic_rules" }) logger.info(f"✅ Extracted {len(all_rules)} tagged rules for Angular 18 processing") return all_rules async def _generate_ai_architecture( self, tagged_rules: List[Dict[str, Any]], functional_requirements: Dict[str, Any], business_context: Dict[str, Any], tech_stack: Any ) -> Dict[str, Any]: """Generate AI-powered Angular 18 architecture based on tagged rules""" # Build comprehensive prompt with all tagged rules rules_text = "" for rule in tagged_rules: rules_text += f"- {rule['feature_name']} → {rule['requirement_name']}: {rule['rule_text']}\n" feature_name = functional_requirements.get('feature_name', 'Angular Application') complexity = functional_requirements.get('complexity_level', 'medium') prompt = f"""You are a senior Angular 18 architect. Design a complete, production-ready frontend architecture based on these specific tagged business rules. PROJECT CONTEXT: - Application: {feature_name} - Complexity: {complexity} - Framework: Angular 18 with TypeScript - Backend: ASP.NET Core Web API 8 - Database: MS SQL Server 2022 TAGGED BUSINESS RULES TO IMPLEMENT: {rules_text} Design a comprehensive Angular 18 architecture that implements ALL these tagged rules with: 1. **PROJECT STRUCTURE** (Angular 18 specific) - Standalone components architecture - Feature-based module organization - Lazy loading strategy - Signal-based state management 2. **COMPONENTS FOR EACH RULE** - Analyze each tagged rule and determine what Angular components are needed - Use Angular 18 standalone components - Implement new control flow syntax (@if, @for, @switch) - Component communication patterns 3. **SERVICES & DATA MANAGEMENT** - HTTP services for ASP.NET Core Web API integration - State management with Signals or NgRx (based on complexity) - Data models and interfaces matching backend DTOs - Error handling and loading states 4. **ROUTING & NAVIGATION** - Route configuration for each feature/requirement - Route guards for authentication/authorization - Lazy loading modules - Navigation workflows based on business rules 5. **FORMS & VALIDATION** - Reactive forms for data entry requirements - Custom validators based on business rules - Form state management - Dynamic form generation if needed 6. **UI/UX IMPLEMENTATION** - Angular Material 3 components - Responsive design with Angular CDK - Theme configuration - Accessibility compliance 7. **TESTING STRATEGY** - Unit tests with Jest/Jasmine - Component testing - Integration tests - E2E tests with Cypress Return detailed JSON with specific Angular 18 components, services, modules, and implementation details that cover ALL tagged rules. CRITICAL: - Each tagged rule should map to specific Angular components/services - Use Angular 18 features (standalone components, signals, new control flow) - Include exact file structure and component specifications - Ensure 100% coverage of all tagged business rules JSON Format: {{ "framework_info": {{"name": "Angular 18", "version": "18.x", ...}}, "project_structure": {{"src/app/": {{"features/": "...", "shared/": "..."}}}}, "components": [{{ "name": "ComponentName", "path": "src/app/features/...", "purpose": "Implements rule: [specific rule text]", "type": "standalone", "dependencies": [...], "inputs": [...], "outputs": [...] }}], "services": [...], "routing": {...}, "forms": [...], "state_management": {...}, "ui_framework": {...}, "testing": {...}, "implementation_ready": true }}""" try: message = self.claude_client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=8000, temperature=0.1, messages=[{"role": "user", "content": prompt}] ) claude_response = message.content[0].text.strip() try: architecture = json.loads(claude_response) logger.info(f"✅ {self.framework} AI architecture generated successfully") # Add tagged rules coverage analysis architecture["tagged_rules_coverage"] = self._analyze_rules_coverage(tagged_rules, architecture) return architecture except json.JSONDecodeError: logger.warning(f"⚠️ {self.framework} AI response wasn't valid JSON, using fallback") return self._generate_rule_based_architecture(tagged_rules, functional_requirements, business_context, tech_stack) except Exception as e: logger.error(f"❌ {self.framework} Claude API error: {e}") raise e def _generate_rule_based_architecture( self, tagged_rules: List[Dict[str, Any]], functional_requirements: Dict[str, Any], business_context: Dict[str, Any], tech_stack: Any ) -> Dict[str, Any]: """Generate Angular 18 architecture based on tagged rules analysis (fallback without AI)""" feature_name = functional_requirements.get('feature_name', 'Angular Application') # Analyze tagged rules to generate components and services components = self._generate_components_from_rules(tagged_rules) services = self._generate_services_from_rules(tagged_rules) routes = self._generate_routes_from_rules(tagged_rules) forms = self._generate_forms_from_rules(tagged_rules) return { "framework_info": { "name": "Angular 18", "version": "18.x", "language": "TypeScript", "cli_version": "18.x", "node_version": "18+ or 20+", "standalone_components": True }, "project_structure": { "src/app/": { "core/": "Singleton services, guards, interceptors", "shared/": "Shared standalone components, pipes, directives", "features/": "Feature-based standalone components with lazy loading", "models/": "TypeScript interfaces and DTOs matching backend", "services/": "HTTP services for API communication", "guards/": "Route guards for authentication/authorization", "interceptors/": "HTTP interceptors for auth/error handling", "pipes/": "Custom pipes for data transformation", "directives/": "Custom directives for DOM manipulation" } }, "components": components, "services": services, "routing": { "strategy": "Lazy loading with standalone components", "routes": routes, "guards": ["AuthGuard", "RoleGuard", "CanDeactivateGuard"], "resolvers": ["DataResolver for pre-loading data"] }, "forms": forms, "state_management": { "approach": "Angular 18 Signals for reactive state", "complex_state": "NgRx Store for complex business logic", "http_state": "HTTP services with signal-based caching" }, "http_communication": { "base_service": "ApiService with HttpClient", "interceptors": ["AuthInterceptor", "ErrorInterceptor", "LoadingInterceptor"], "error_handling": "Global error handling with user notifications" }, "ui_framework": { "library": "Angular Material 3", "theming": "Material 3 design tokens", "responsive": "Angular CDK Layout for responsive design", "accessibility": "CDK a11y for accessibility compliance" }, "testing": { "unit": "Jest or Jasmine/Karma with TestBed", "integration": "Component integration tests", "e2e": "Cypress or Playwright for end-to-end testing", "coverage": "Istanbul for code coverage reporting" }, "build_optimization": { "standalone_components": "Tree-shakeable standalone architecture", "lazy_loading": "Route-based code splitting", "bundle_optimization": "Angular CLI build optimizations", "pwa": "Service Worker for progressive web app features" }, "tagged_rules_coverage": self._analyze_rules_coverage(tagged_rules, {}), "implementation_ready": True, "expert_level": True, "angular_18_features": [ "Standalone components architecture", "New control flow syntax (@if, @for, @switch)", "Signals for reactive programming", "Improved hydration for SSR", "Material 3 design system integration" ] } def _generate_components_from_rules(self, tagged_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """Generate Angular 18 components based on tagged business rules""" components = [ { "name": "AppComponent", "path": "src/app/app.component.ts", "type": "standalone", "purpose": "Root application component with navigation shell", "implements_rules": [], "dependencies": ["CommonModule", "RouterOutlet", "MaterialModule"], "template_features": ["Navigation", "Header", "Footer", "Router Outlet"] } ] # Analyze each tagged rule to generate specific components for rule in tagged_rules: rule_text = rule['rule_text'].lower() feature_name = rule['feature_name'] requirement_name = rule['requirement_name'] # Generate components based on rule content if any(word in rule_text for word in ['display', 'show', 'list', 'view']): components.append({ "name": f"{feature_name.replace(' ', '')}ListComponent", "path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-list.component.ts", "type": "standalone", "purpose": f"Display list view for: {rule['rule_text']}", "implements_rules": [rule['rule_text']], "dependencies": ["CommonModule", "MaterialModule", "RouterModule"], "inputs": ["data", "loading", "error"], "outputs": ["itemSelected", "actionTriggered"], "template_features": ["Data table", "Filtering", "Pagination", "Search"] }) if any(word in rule_text for word in ['create', 'add', 'new', 'form', 'input']): components.append({ "name": f"{feature_name.replace(' ', '')}FormComponent", "path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-form.component.ts", "type": "standalone", "purpose": f"Form component for: {rule['rule_text']}", "implements_rules": [rule['rule_text']], "dependencies": ["CommonModule", "ReactiveFormsModule", "MaterialModule"], "inputs": ["initialData", "editMode"], "outputs": ["formSubmit", "formCancel"], "template_features": ["Reactive forms", "Validation", "Material form fields"] }) if any(word in rule_text for word in ['edit', 'update', 'modify']): components.append({ "name": f"{feature_name.replace(' ', '')}EditComponent", "path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-edit.component.ts", "type": "standalone", "purpose": f"Edit component for: {rule['rule_text']}", "implements_rules": [rule['rule_text']], "dependencies": ["CommonModule", "ReactiveFormsModule", "MaterialModule"], "inputs": ["itemId", "item"], "outputs": ["updateComplete", "editCancel"], "template_features": ["Pre-populated forms", "Validation", "Save/Cancel actions"] }) if any(word in rule_text for word in ['approve', 'workflow', 'status', 'process']): components.append({ "name": f"{feature_name.replace(' ', '')}WorkflowComponent", "path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-workflow.component.ts", "type": "standalone", "purpose": f"Workflow management for: {rule['rule_text']}", "implements_rules": [rule['rule_text']], "dependencies": ["CommonModule", "MaterialModule", "CdkStepperModule"], "inputs": ["workflowData", "currentStep"], "outputs": ["stepComplete", "workflowFinish"], "template_features": ["Stepper", "Status indicators", "Action buttons"] }) if any(word in rule_text for word in ['calculate', 'total', 'amount', 'compute']): components.append({ "name": f"{feature_name.replace(' ', '')}CalculatorComponent", "path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}-calculator.component.ts", "type": "standalone", "purpose": f"Calculation component for: {rule['rule_text']}", "implements_rules": [rule['rule_text']], "dependencies": ["CommonModule", "ReactiveFormsModule", "MaterialModule"], "inputs": ["calculationInputs"], "outputs": ["calculationResult", "calculationError"], "template_features": ["Calculation inputs", "Real-time results", "Formula display"] }) return components def _generate_services_from_rules(self, tagged_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """Generate Angular 18 services based on tagged business rules""" services = [ { "name": "ApiService", "path": "src/app/core/services/api.service.ts", "purpose": "Base HTTP service for ASP.NET Core Web API communication", "injectable": "root", "dependencies": ["HttpClient"], "methods": ["get", "post", "put", "delete", "patch"], "implements_rules": [] }, { "name": "AuthService", "path": "src/app/core/services/auth.service.ts", "purpose": "Authentication and authorization service", "injectable": "root", "dependencies": ["HttpClient", "Router"], "methods": ["login", "logout", "isAuthenticated", "getToken", "refreshToken"], "implements_rules": [] } ] # Generate services based on tagged rules processed_features = set() for rule in tagged_rules: rule_text = rule['rule_text'].lower() feature_name = rule['feature_name'] requirement_name = rule['requirement_name'] # Avoid duplicate services for same feature service_key = f"{feature_name}_{requirement_name}" if service_key in processed_features: continue processed_features.add(service_key) # Generate data service for each feature/requirement services.append({ "name": f"{feature_name.replace(' ', '')}DataService", "path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/services/{requirement_name.lower().replace(' ', '-')}.service.ts", "purpose": f"Data service for {feature_name} - {requirement_name}", "injectable": "root", "dependencies": ["ApiService"], "methods": self._generate_service_methods_from_rule(rule), "implements_rules": [rule['rule_text']], "api_endpoints": self._generate_api_endpoints_from_rule(rule, feature_name, requirement_name) }) # Generate specific services based on rule content if any(word in rule_text for word in ['validate', 'check', 'verify']): services.append({ "name": f"{feature_name.replace(' ', '')}ValidationService", "path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/services/{requirement_name.lower().replace(' ', '-')}-validation.service.ts", "purpose": f"Validation service for: {rule['rule_text']}", "injectable": "root", "dependencies": [], "methods": ["validate", "validateField", "getValidationErrors"], "implements_rules": [rule['rule_text']] }) if any(word in rule_text for word in ['calculate', 'compute', 'total']): services.append({ "name": f"{feature_name.replace(' ', '')}CalculationService", "path": f"src/app/features/{feature_name.lower().replace(' ', '-')}/services/{requirement_name.lower().replace(' ', '-')}-calculation.service.ts", "purpose": f"Calculation service for: {rule['rule_text']}", "injectable": "root", "dependencies": [], "methods": ["calculate", "validateInputs", "formatResult"], "implements_rules": [rule['rule_text']] }) return services def _generate_routes_from_rules(self, tagged_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """Generate Angular routing configuration based on tagged rules""" routes = [ { "path": "", "redirectTo": "/dashboard", "pathMatch": "full" }, { "path": "dashboard", "component": "DashboardComponent", "title": "Dashboard" } ] # Generate routes for each feature/requirement processed_routes = set() for rule in tagged_rules: feature_name = rule['feature_name'] requirement_name = rule['requirement_name'] # Create unique route path route_path = f"{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}" if route_path in processed_routes: continue processed_routes.add(route_path) routes.append({ "path": route_path, "loadComponent": f"() => import('./features/{feature_name.lower().replace(' ', '-')}/{requirement_name.lower().replace(' ', '-')}.component').then(m => m.{feature_name.replace(' ', '')}{requirement_name.replace(' ', '')}Component)", "title": f"{feature_name} - {requirement_name}", "data": { "breadcrumb": f"{feature_name} > {requirement_name}", "implemented_rules": [rule['rule_text']] } }) return routes def _generate_forms_from_rules(self, tagged_rules: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """Generate Angular reactive forms based on tagged rules""" forms = [] for rule in tagged_rules: rule_text = rule['rule_text'].lower() feature_name = rule['feature_name'] requirement_name = rule['requirement_name'] if any(word in rule_text for word in ['create', 'add', 'input', 'form', 'enter']): forms.append({ "name": f"{feature_name.replace(' ', '')}{requirement_name.replace(' ', '')}Form", "purpose": f"Form for: {rule['rule_text']}", "type": "reactive", "fields": self._extract_form_fields_from_rule(rule), "validators": self._extract_validators_from_rule(rule), "implements_rules": [rule['rule_text']] }) return forms def _generate_service_methods_from_rule(self, rule: Dict[str, Any]) -> List[str]: """Generate service methods based on rule content""" methods = [] rule_text = rule['rule_text'].lower() if any(word in rule_text for word in ['get', 'retrieve', 'fetch', 'load']): methods.extend(["getAll", "getById", "search"]) if any(word in rule_text for word in ['create', 'add', 'new']): methods.append("create") if any(word in rule_text for word in ['update', 'modify', 'edit']): methods.append("update") if any(word in rule_text for word in ['delete', 'remove']): methods.append("delete") if any(word in rule_text for word in ['validate', 'check']): methods.append("validate") return methods if methods else ["getAll", "getById", "create", "update", "delete"] def _generate_api_endpoints_from_rule(self, rule: Dict[str, Any], feature_name: str, requirement_name: str) -> List[str]: """Generate API endpoint paths based on rule""" base_path = f"/api/{feature_name.lower().replace(' ', '-')}" endpoints = [] rule_text = rule['rule_text'].lower() if any(word in rule_text for word in ['get', 'list', 'retrieve']): endpoints.extend([f"GET {base_path}", f"GET {base_path}/{{id}}"]) if any(word in rule_text for word in ['create', 'add']): endpoints.append(f"POST {base_path}") if any(word in rule_text for word in ['update', 'edit']): endpoints.append(f"PUT {base_path}/{{id}}") if any(word in rule_text for word in ['delete', 'remove']): endpoints.append(f"DELETE {base_path}/{{id}}") return endpoints def _extract_form_fields_from_rule(self, rule: Dict[str, Any]) -> List[Dict[str, str]]: """Extract form fields from rule content""" fields = [] rule_text = rule['rule_text'].lower() # Common fields based on rule content if 'name' in rule_text: fields.append({"name": "name", "type": "text", "required": True}) if 'description' in rule_text: fields.append({"name": "description", "type": "textarea", "required": False}) if 'email' in rule_text: fields.append({"name": "email", "type": "email", "required": True}) if 'amount' in rule_text or 'price' in rule_text: fields.append({"name": "amount", "type": "number", "required": True}) if 'date' in rule_text: fields.append({"name": "date", "type": "date", "required": True}) if 'status' in rule_text: fields.append({"name": "status", "type": "select", "required": True}) return fields if fields else [{"name": "name", "type": "text", "required": True}] def _extract_validators_from_rule(self, rule: Dict[str, Any]) -> List[str]: """Extract validation requirements from rule content""" validators = [] rule_text = rule['rule_text'].lower() if 'required' in rule_text or 'must' in rule_text: validators.append("Validators.required") if 'email' in rule_text: validators.append("Validators.email") if 'minimum' in rule_text or 'max' in rule_text: validators.append("Validators.min") if 'unique' in rule_text: validators.append("CustomValidators.unique") return validators def _analyze_rules_coverage(self, tagged_rules: List[Dict[str, Any]], architecture: Dict[str, Any]) -> List[Dict[str, Any]]: """Analyze how well the architecture covers the tagged rules""" coverage_analysis = [] for rule in tagged_rules: rule_text = rule['rule_text'] coverage = { "rule_text": rule_text, "feature_name": rule['feature_name'], "requirement_name": rule['requirement_name'], "covered_by_components": [], "covered_by_services": [], "covered_by_routes": [], "coverage_complete": False } # Check component coverage components = architecture.get("components", []) for component in components: if rule_text in component.get("implements_rules", []): coverage["covered_by_components"].append(component["name"]) # Check service coverage services = architecture.get("services", []) for service in services: if rule_text in service.get("implements_rules", []): coverage["covered_by_services"].append(service["name"]) # Determine if coverage is complete coverage["coverage_complete"] = ( len(coverage["covered_by_components"]) > 0 or len(coverage["covered_by_services"]) > 0 ) coverage_analysis.append(coverage) return coverage_analysis def _generate_basic_architecture(self, functional_requirements: Dict[str, Any]) -> Dict[str, Any]: """Generate basic Angular 18 architecture when no tagged rules are available""" feature_name = functional_requirements.get('feature_name', 'Angular Application') return { "framework_info": { "name": "Angular 18", "version": "18.x", "language": "TypeScript", "status": "basic_architecture_no_tagged_rules" }, "components": [ { "name": "AppComponent", "path": "src/app/app.component.ts", "type": "standalone", "purpose": "Root application component" }, { "name": "DashboardComponent", "path": "src/app/features/dashboard/dashboard.component.ts", "type": "standalone", "purpose": "Main dashboard view" } ], "services": [ { "name": "ApiService", "path": "src/app/core/services/api.service.ts", "purpose": "HTTP communication service" } ], "routing": { "routes": [ {"path": "", "redirectTo": "/dashboard", "pathMatch": "full"}, {"path": "dashboard", "component": "DashboardComponent"} ] }, "implementation_ready": True, "requires_tagged_rules": True, "tagged_rules_coverage": [] }