# KPI Total Sales Widget API ## Overview This document describes the KPI (Key Performance Indicator) Total Sales Widget API implementation in the Analytics and Notification Service (ANS). The API provides endpoints for retrieving sales analytics data with daily, weekly, and monthly granularity. ## Architecture The implementation follows the TMS (Transaction Management Service) coding style with a clean separation of concerns: ``` app/ ├── schemas/ │ └── kpi_schema.py # Pydantic models for request/response ├── repositories/ │ └── kpi_repository.py # Data access layer (SQL queries) ├── services/ │ └── kpi_service.py # Business logic layer ├── routers/ │ └── kpi_router.py # API endpoints └── utils/ └── request_id_utils.py # Request correlation utilities ``` ## API Endpoints ### Base URL ``` /api/v1/kpi ``` ### 1. Get Total Sales KPI (POST) **Endpoint:** `POST /api/v1/kpi/total-sales` **Description:** Retrieve total sales KPI data with specified time granularity. **Authentication:** Required (Bearer token) **Permissions:** `view_analytics` **Request Body:** ```json { "merchant_id": "MERCH123", "branch_id": "BRANCH001", "metric_type": "total_sales", "granularity": "daily", "start_date": "2024-01-01T00:00:00Z", "end_date": "2024-01-31T23:59:59Z" } ``` **Request Parameters:** - `merchant_id` (string, required): Merchant identifier - `branch_id` (string, optional): Branch/Store identifier for filtering - `metric_type` (string, required): Type of KPI metric (currently supports "total_sales") - `granularity` (string, required): Time granularity - "daily", "weekly", or "monthly" - `start_date` (datetime, required): Start date for KPI calculation - `end_date` (datetime, required): End date for KPI calculation **Response:** ```json { "status": "success", "data": { "merchant_id": "MERCH123", "branch_id": "BRANCH001", "metric_type": "total_sales", "granularity": "daily", "start_date": "2024-01-01T00:00:00Z", "end_date": "2024-01-31T23:59:59Z", "data_points": [ { "period": "2024-01-01", "value": 15000.50, "transaction_count": 45, "period_start": "2024-01-01T00:00:00Z", "period_end": "2024-01-01T23:59:59Z" }, { "period": "2024-01-02", "value": 18500.75, "transaction_count": 52, "period_start": "2024-01-02T00:00:00Z", "period_end": "2024-01-02T23:59:59Z" } ], "summary": { "total": 465000.00, "average": 15000.00, "min_value": 8500.00, "max_value": 22000.00, "period_count": 31, "total_transactions": 1350 }, "generated_at": "2024-02-01T10:30:00Z" }, "message": "Total sales KPI retrieved successfully", "correlation_id": "550e8400-e29b-41d4-a716-446655440000" } ``` ### 2. Get Total Sales KPI (GET) **Endpoint:** `GET /api/v1/kpi/total-sales` **Description:** Alternative endpoint using query parameters instead of request body. **Authentication:** Required (Bearer token) **Permissions:** `view_analytics` **Query Parameters:** - `granularity` (string, required): Time granularity - "daily", "weekly", or "monthly" - `start_date` (datetime, required): Start date for KPI calculation - `end_date` (datetime, required): End date for KPI calculation - `branch_id` (string, optional): Branch/Store ID filter **Example Request:** ``` GET /api/v1/kpi/total-sales?granularity=daily&start_date=2024-01-01T00:00:00Z&end_date=2024-01-31T23:59:59Z&branch_id=BRANCH001 ``` **Response:** Same as POST endpoint ### 3. Get Widget KPI **Endpoint:** `POST /api/v1/kpi/widget/{widget_id}` **Description:** Get KPI data for a specific dashboard widget with automatic date range calculation. **Authentication:** Required (Bearer token) **Permissions:** `view_analytics` **Path Parameters:** - `widget_id` (string, required): Widget identifier **Request Body:** ```json { "widget_id": "widget_123", "granularity": "weekly", "start_date": "2024-01-01T00:00:00Z", "end_date": "2024-03-31T23:59:59Z" } ``` **Request Parameters:** - `widget_id` (string, required): Widget identifier - `granularity` (string, required): Time granularity - "daily", "weekly", or "monthly" - `start_date` (datetime, optional): Start date (defaults based on granularity) - `end_date` (datetime, optional): End date (defaults to now) **Default Date Ranges:** - Daily: Last 30 days - Weekly: Last 12 weeks - Monthly: Last 12 months **Response:** ```json { "status": "success", "data": { "widget_id": "widget_123", "kpi_data": { "merchant_id": "MERCH123", "branch_id": "BRANCH001", "metric_type": "total_sales", "granularity": "weekly", "data_points": [...], "summary": {...}, "generated_at": "2024-02-01T10:30:00Z" } }, "message": "Widget KPI retrieved successfully", "correlation_id": "550e8400-e29b-41d4-a716-446655440000" } ``` ### 4. Health Check **Endpoint:** `GET /api/v1/kpi/health` **Description:** Health check endpoint for KPI service. **Authentication:** Not required **Response:** ```json { "status": "healthy", "service": "kpi", "timestamp": "2024-02-01T10:30:00Z" } ``` ## Data Models ### KPIRequest ```python { "merchant_id": str, # Merchant identifier "branch_id": str | None, # Optional branch identifier "metric_type": str, # "total_sales", "transaction_count", "average_order_value" "granularity": str, # "daily", "weekly", "monthly" "start_date": datetime, # Start date for calculation "end_date": datetime # End date for calculation } ``` ### KPIDataPoint ```python { "period": str, # Period label (e.g., "2024-01-15", "2024-W03", "2024-01") "value": float, # Metric value for the period "transaction_count": int, # Number of transactions in period "period_start": datetime, # Period start timestamp "period_end": datetime # Period end timestamp } ``` ### KPISummary ```python { "total": float, # Total value across all periods "average": float, # Average value per period "min_value": float, # Minimum value in any period "max_value": float, # Maximum value in any period "period_count": int, # Number of periods "total_transactions": int # Total number of transactions } ``` ### KPIResponse ```python { "merchant_id": str, "branch_id": str | None, "metric_type": str, "granularity": str, "start_date": datetime, "end_date": datetime, "data_points": List[KPIDataPoint], "summary": KPISummary, "generated_at": datetime } ``` ## Time Granularity ### Daily - Aggregates sales by calendar day - Period format: `YYYY-MM-DD` (e.g., "2024-01-15") - Best for: Short-term analysis (last 30-90 days) ### Weekly - Aggregates sales by ISO week (Monday to Sunday) - Period format: `YYYY-WNN` (e.g., "2024-W03") - Best for: Medium-term trends (last 12-26 weeks) ### Monthly - Aggregates sales by calendar month - Period format: `YYYY-MM` (e.g., "2024-01") - Best for: Long-term trends (last 12-24 months) ## Database Schema The KPI API queries the `sales_trans` table from the TMS database: ```sql SELECT DATE_TRUNC(:granularity, transaction_date) as period_start, SUM(total_amount) as total_sales, COUNT(*) as transaction_count, AVG(total_amount) as avg_order_value FROM sales_trans WHERE merchant_id = :merchant_id AND transaction_date >= :start_date AND transaction_date <= :end_date AND status = 'completed' AND (:branch_id IS NULL OR branch_id = :branch_id) GROUP BY DATE_TRUNC(:granularity, transaction_date) ORDER BY period_start ASC ``` ## Error Handling ### Validation Errors (400) ```json { "status": "error", "message": "Validation error message", "correlation_id": "550e8400-e29b-41d4-a716-446655440000" } ``` ### Authentication Errors (401) ```json { "detail": "Invalid authentication credentials" } ``` ### Permission Errors (403) ```json { "detail": "Forbidden" } ``` ### Internal Errors (500) ```json { "status": "error", "message": "Failed to retrieve total sales KPI", "correlation_id": "550e8400-e29b-41d4-a716-446655440000" } ``` ## Metrics and Monitoring The API tracks the following metrics using the insightfy_utils telemetry: - `kpi_total_sales_requests` - Counter for total sales KPI requests - `kpi_widget_requests` - Counter for widget KPI requests - `kpi_validation_errors` - Counter for validation errors - `kpi_errors` - Counter for internal errors - `kpi_calculation_duration` - Histogram of KPI calculation duration - `kpi_widget_duration` - Histogram of widget KPI duration - `kpi_total_sales_value` - Histogram of total sales values ## Logging All operations are logged with structured logging including: - Merchant ID - Branch ID - Granularity - Duration - Correlation ID - Error details (when applicable) ## Authentication All endpoints (except health check) require: 1. Valid JWT token in Authorization header: `Bearer ` 2. Token must contain: - `merchant_id` - `associate_id` - `branch_id` - `role_id` ## Permissions The API uses role-based access control (RBAC): - `view_analytics` - Required for all KPI endpoints ## Usage Examples ### cURL Examples #### Get Daily Sales KPI ```bash curl -X POST "http://localhost:8000/api/v1/kpi/total-sales" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "merchant_id": "MERCH123", "branch_id": "BRANCH001", "metric_type": "total_sales", "granularity": "daily", "start_date": "2024-01-01T00:00:00Z", "end_date": "2024-01-31T23:59:59Z" }' ``` #### Get Weekly Sales KPI (Query Parameters) ```bash curl -X GET "http://localhost:8000/api/v1/kpi/total-sales?granularity=weekly&start_date=2024-01-01T00:00:00Z&end_date=2024-03-31T23:59:59Z" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" ``` #### Get Widget KPI ```bash curl -X POST "http://localhost:8000/api/v1/kpi/widget/widget_123" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "widget_id": "widget_123", "granularity": "monthly" }' ``` ### Python Examples ```python import requests from datetime import datetime, timedelta # Configuration BASE_URL = "http://localhost:8000/api/v1/kpi" TOKEN = "YOUR_JWT_TOKEN" HEADERS = { "Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json" } # Get daily sales for last 30 days end_date = datetime.utcnow() start_date = end_date - timedelta(days=30) payload = { "merchant_id": "MERCH123", "branch_id": "BRANCH001", "metric_type": "total_sales", "granularity": "daily", "start_date": start_date.isoformat() + "Z", "end_date": end_date.isoformat() + "Z" } response = requests.post( f"{BASE_URL}/total-sales", headers=HEADERS, json=payload ) if response.status_code == 200: data = response.json() kpi_data = data["data"] print(f"Total Sales: ${kpi_data['summary']['total']:,.2f}") print(f"Average: ${kpi_data['summary']['average']:,.2f}") print(f"Transactions: {kpi_data['summary']['total_transactions']}") else: print(f"Error: {response.status_code} - {response.text}") ``` ### JavaScript/TypeScript Examples ```typescript interface KPIRequest { merchant_id: string; branch_id?: string; metric_type: 'total_sales'; granularity: 'daily' | 'weekly' | 'monthly'; start_date: string; end_date: string; } async function getTotalSalesKPI( token: string, request: KPIRequest ): Promise { const response = await fetch( 'http://localhost:8000/api/v1/kpi/total-sales', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(request) } ); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } // Usage const kpiData = await getTotalSalesKPI('YOUR_JWT_TOKEN', { merchant_id: 'MERCH123', branch_id: 'BRANCH001', metric_type: 'total_sales', granularity: 'daily', start_date: '2024-01-01T00:00:00Z', end_date: '2024-01-31T23:59:59Z' }); console.log('Total Sales:', kpiData.data.summary.total); ``` ## Performance Considerations 1. **Query Optimization**: The repository uses PostgreSQL's `DATE_TRUNC` function for efficient date aggregation 2. **Index Recommendations**: Ensure indexes on: - `merchant_id` - `branch_id` - `transaction_date` - `status` 3. **Caching**: Consider implementing Redis caching for frequently accessed KPI data 4. **Pagination**: For large date ranges, consider implementing pagination or limiting the maximum date range ## Future Enhancements 1. **Additional Metrics**: - Transaction count KPI - Average order value KPI - Customer acquisition metrics - Product performance metrics 2. **Advanced Features**: - Comparison with previous periods - Trend analysis and forecasting - Real-time KPI updates - Export to CSV/Excel - Scheduled KPI reports 3. **Optimization**: - Materialized views for faster queries - Background job for pre-calculating KPIs - WebSocket support for real-time updates ## Testing Run the service and test the endpoints: ```bash # Start the service cd insightfy-bloom-ms-ans uvicorn app.main:app --reload --port 8000 # Test health check curl http://localhost:8000/api/v1/kpi/health # Test KPI endpoint (requires valid token) curl -X POST http://localhost:8000/api/v1/kpi/total-sales \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d @test_kpi_request.json ``` ## Support For issues or questions: - Check logs in the ANS service - Review correlation_id in error responses for debugging - Contact the development team ## Version History - **v1.0.0** (2024-02-01): Initial implementation - Total sales KPI with daily, weekly, monthly granularity - Widget-specific KPI endpoints - Authentication and authorization - Metrics and logging