
- Created FastAPI application with transaction ingestion endpoints - Built dynamic rule engine supporting velocity checks and aggregations - Implemented real-time and batch screening capabilities - Added rule management with versioning and rollback functionality - Created comprehensive audit and reporting endpoints with pagination - Set up SQLite database with proper migrations using Alembic - Added intelligent caching for aggregate computations - Included extensive API documentation and example rule definitions - Configured CORS, health endpoints, and proper error handling - Added support for time-windowed aggregations (sum, count, avg, max, min) - Built background processing for high-volume batch screening - Implemented field-agnostic rule conditions with flexible operators Features include transaction ingestion, rule CRUD operations, real-time screening, batch processing, aggregation computations, and comprehensive reporting capabilities suitable for fintech fraud monitoring systems.
151 lines
4.2 KiB
Python
151 lines
4.2 KiB
Python
from typing import Optional, Dict, Any, List
|
|
from datetime import datetime
|
|
from pydantic import BaseModel
|
|
|
|
# Transaction Schemas
|
|
class TransactionBase(BaseModel):
|
|
transaction_id: str
|
|
user_id: str
|
|
account_id: str
|
|
amount: float
|
|
currency: str = "NGN"
|
|
transaction_type: str # debit, credit, transfer
|
|
merchant_id: Optional[str] = None
|
|
merchant_category: Optional[str] = None
|
|
channel: str # web, mobile, atm, pos
|
|
location: Optional[str] = None
|
|
ip_address: Optional[str] = None
|
|
device_id: Optional[str] = None
|
|
status: str = "pending"
|
|
metadata: Optional[Dict[str, Any]] = None
|
|
|
|
class TransactionCreate(TransactionBase):
|
|
pass
|
|
|
|
class TransactionUpdate(BaseModel):
|
|
status: Optional[str] = None
|
|
metadata: Optional[Dict[str, Any]] = None
|
|
|
|
class Transaction(TransactionBase):
|
|
id: int
|
|
created_at: datetime
|
|
updated_at: Optional[datetime] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
# Rule Schemas
|
|
class RuleCondition(BaseModel):
|
|
field: str
|
|
operator: str # eq, ne, gt, gte, lt, lte, in, not_in, contains, starts_with, ends_with
|
|
value: Any
|
|
aggregate_function: Optional[str] = None # sum, count, avg, max, min
|
|
time_window: Optional[str] = None # "24h", "7d", "30d", etc.
|
|
group_by: Optional[List[str]] = None # ["user_id", "account_id"]
|
|
|
|
class RuleAction(BaseModel):
|
|
action_type: str # flag, block, alert, score
|
|
parameters: Dict[str, Any] = {}
|
|
|
|
class RuleBase(BaseModel):
|
|
name: str
|
|
description: Optional[str] = None
|
|
rule_type: str # velocity, amount_limit, blacklist, pattern, etc.
|
|
conditions: List[RuleCondition]
|
|
actions: List[RuleAction]
|
|
priority: int = 1
|
|
is_active: bool = True
|
|
|
|
class RuleCreate(RuleBase):
|
|
created_by: Optional[str] = None
|
|
|
|
class RuleUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
description: Optional[str] = None
|
|
conditions: Optional[List[RuleCondition]] = None
|
|
actions: Optional[List[RuleAction]] = None
|
|
priority: Optional[int] = None
|
|
is_active: Optional[bool] = None
|
|
|
|
class Rule(RuleBase):
|
|
id: int
|
|
version: int
|
|
created_by: Optional[str] = None
|
|
created_at: datetime
|
|
updated_at: Optional[datetime] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
# Screening Schemas
|
|
class ScreeningResultBase(BaseModel):
|
|
transaction_id: str
|
|
rule_id: int
|
|
rule_name: str
|
|
rule_version: int = 1
|
|
status: str # flagged, clean, error
|
|
risk_score: float = 0.0
|
|
details: Optional[Dict[str, Any]] = None
|
|
aggregated_data: Optional[Dict[str, Any]] = None
|
|
screening_type: str = "real_time"
|
|
|
|
class ScreeningResult(ScreeningResultBase):
|
|
id: int
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
class BatchScreeningRequest(BaseModel):
|
|
name: Optional[str] = None
|
|
description: Optional[str] = None
|
|
transaction_filters: Optional[Dict[str, Any]] = None
|
|
rule_ids: Optional[List[int]] = None # If None, apply all active rules
|
|
date_from: Optional[datetime] = None
|
|
date_to: Optional[datetime] = None
|
|
|
|
class ScreeningBatch(BaseModel):
|
|
id: int
|
|
batch_id: str
|
|
name: Optional[str] = None
|
|
description: Optional[str] = None
|
|
status: str
|
|
total_transactions: int = 0
|
|
processed_transactions: int = 0
|
|
flagged_transactions: int = 0
|
|
rules_applied: Optional[List[int]] = None
|
|
started_at: Optional[datetime] = None
|
|
completed_at: Optional[datetime] = None
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
# Response Schemas
|
|
class PaginatedResponse(BaseModel):
|
|
items: List[Any]
|
|
total: int
|
|
page: int
|
|
page_size: int
|
|
total_pages: int
|
|
|
|
class ScreeningResponse(BaseModel):
|
|
transaction_id: str
|
|
results: List[ScreeningResult]
|
|
overall_status: str # clean, flagged
|
|
total_risk_score: float
|
|
screening_duration_ms: float
|
|
|
|
class AggregateRequest(BaseModel):
|
|
aggregate_function: str # sum, count, avg, max, min
|
|
field: str
|
|
group_by: Optional[List[str]] = None
|
|
filters: Optional[Dict[str, Any]] = None
|
|
time_window: Optional[str] = None # "24h", "7d", "30d"
|
|
date_from: Optional[datetime] = None
|
|
date_to: Optional[datetime] = None
|
|
|
|
class AggregateResponse(BaseModel):
|
|
result: Dict[str, Any]
|
|
cache_hit: bool = False
|
|
computation_time_ms: float |