Spaces:
Paused
Paused
| """ | |
| Fraud Rules Engine API Router | |
| Provides endpoints for managing and using fraud detection rules | |
| """ | |
| import logging | |
| from datetime import datetime | |
| from typing import Any | |
| from fastapi import APIRouter, Body, HTTPException | |
| from pydantic import BaseModel, Field | |
| from app.services.fraud.engine import RuleEngine, rule_engine | |
| logger = logging.getLogger(__name__) | |
| router = APIRouter( | |
| prefix="", | |
| tags=["Fraud Rules Engine"], | |
| responses={404: {"description": "Not found"}}, | |
| ) | |
| # Root endpoint for E2E tests | |
| async def get_rules_root(): | |
| """Root endpoint for E2E testing""" | |
| return {"status": "healthy", "message": "Fraud rules endpoint"} | |
| def get_fraud_engine() -> RuleEngine: | |
| return rule_engine | |
| # Request/Response Models | |
| class RuleResponse(BaseModel): | |
| name: str | |
| severity: str | |
| enabled: bool | |
| config: dict[str, Any] | None = None | |
| class EvaluateTransactionRequest(BaseModel): | |
| transaction_data: dict[str, Any] = Field(description="Transaction data") | |
| async def list_rules(): | |
| """List all loaded fraud detection rules""" | |
| engine = get_fraud_engine() | |
| rules = [] | |
| for rule in engine.rules.values(): | |
| rules.append( | |
| RuleResponse( | |
| name=rule.name, | |
| severity=rule.severity.value, | |
| enabled=rule.enabled, | |
| config=rule.get_config_schema(), | |
| ) | |
| ) | |
| return rules | |
| async def get_rule(rule_name: str): | |
| """Get details of a specific rule""" | |
| engine = get_fraud_engine() | |
| if rule_name not in engine.rules: | |
| raise HTTPException(status_code=404, detail="Rule not found") | |
| rule = engine.rules[rule_name] | |
| return RuleResponse( | |
| name=rule.name, | |
| severity=rule.severity.value, | |
| enabled=rule.enabled, | |
| config=rule.get_config_schema(), | |
| ) | |
| async def evaluate_transaction( | |
| request: EvaluateTransactionRequest, context: dict[str, Any] = Body(None) | |
| ): | |
| """Evaluate a transaction against all active rules""" | |
| try: | |
| engine = get_fraud_engine() | |
| # Initialize plugins if not already loaded (simple check) | |
| # Note: In a real prod app, use a startup event `on_event("startup")` to init engine | |
| if not engine.rules: | |
| await engine.initialize() | |
| # engine.execute_rules expects a LIST of transactions | |
| alerts = await engine.execute_rules([request.transaction_data], context or {}) | |
| # Convert Alerts to dicts | |
| results = [] | |
| for alert in alerts: | |
| results.append( | |
| { | |
| "rule_name": alert.rule_name, | |
| "severity": alert.severity.value, | |
| "risk_score": alert.risk_score, | |
| "description": alert.description, | |
| } | |
| ) | |
| return { | |
| "transaction_id": request.transaction_data.get("id"), | |
| "risk_score": sum(a["risk_score"] for a in results), | |
| "triggered_rules": results, | |
| "timestamp": datetime.now().isoformat(), | |
| } | |
| except Exception as e: | |
| logger.error(f"Error evaluating transaction: {e}") | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def get_engine_status(): | |
| """Get status of all rules""" | |
| engine = get_fraud_engine() | |
| return engine.get_rule_status() | |
| # Stubbed endpoints for frontend compatibility (if needed) | |
| async def create_rule(): | |
| raise HTTPException( | |
| status_code=501, detail="Rule creation is managed via Plugins registry" | |
| ) | |
| async def delete_rule(rule_id: str): | |
| raise HTTPException( | |
| status_code=501, detail="Rule deletion is managed via Plugins registry" | |
| ) | |