Key Components
This page provides a detailed overview of the major components in AquaGen API and how they work together.
🧩 Component Overview
1️⃣ Flask Application (app/__init__.py)
The central Flask application that bootstraps the entire system.
Key Responsibilities
- Initialize Flask app with CORS and JWT
- Register API blueprints (user, admin, external, qa)
- Configure Azure Application Insights telemetry
- Set up custom template filters
- Configure JWT token lifecycle
- Implement user context loading
Configuration
# JWT Configuration
app.config["JWT_TOKEN_LOCATION"] = ["headers", "query_string"]
app.config["JWT_SECRET_KEY"] = Config.SECRET_KEY
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=4)
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=14)
Custom Template Filters
| Filter | Purpose | Example Output |
|---|---|---|
decimal_format | Format numbers with precision | 123.456 → 123.46 |
date_time_to_date | Convert UTC datetime to date | 2024-11-09T10:30:00Z → 09/11/2024 |
date_to_date | Format date strings | 2024-11-09 → 09/11/2024 |
date_time_to_time | Extract time from datetime | 2024-11-09T10:30:00Z → 10:30:00 |
Middleware Stack
2️⃣ API Blueprints (app/apis/)
User Blueprint (user.py)
Purpose: User-facing API endpoints
Namespaces (31 total):
user- User profile and settingsaccounts- Account managementreports- Report generationdevice_data- Device data retrievaldevice_data_v2- Enhanced device data APIalerts- Alert managementnotifications- Notification endpointslanding_page- Dashboard datasummary_page- Summary reportswater_balance- Water balance analysisgranular_data- Time-series dataquality_data- Quality parameters- And more...
Authentication: All endpoints require JWT (@jwt_required())
Admin Blueprint (admin.py)
Purpose: Administrative operations
Namespaces (13 total):
admin_login- Admin authenticationindustry- Industry CRUD operationsunit- Unit/device managementuser- User managementautomated_report- Scheduled reportsdevice_data- Admin device data accessnotification- System notificationsworkspace- Workspace configurationoffline_devices- Offline device trackinginsights- Analytics insightsglobal_logs- Audit logsshift_monitoring- Shift trackinggchats- Google Chat integration
Authentication: Requires admin role (@admin_required())
External Blueprint (external.py)
Purpose: Third-party integrations
Namespaces:
external_login- External system authenticationwater_ratio- Water measurement standards
Blueprint Registration
app.register_blueprint(user_blueprint) # /api/user
app.register_blueprint(admin_blueprint) # /api/admin
app.register_blueprint(external_blueprint) # /api/external
app.register_blueprint(qa_blueprint) # /api/qa
3️⃣ Route Handlers (app/routes/)
Route handlers process HTTP requests and coordinate with services.
Report Route (report.py)
Endpoint: GET /api/user/report
@reportNamespace.route('')
class ReportRoute(Resource):
@jwt_required()
def get(self):
return ReportGetHandler().get()
Key Features:
- Parse query parameters (reportType, reportFormat, service, etc.)
- Determine date ranges based on report type
- Create
ReportRequestDataobject - Call
ReportServiceto generate report - Return formatted file (HTML/PDF/XLSX/CSV)
Flow Diagram:
Device Data Route (device_data.py)
Endpoint: GET /api/user/deviceData
Purpose: Retrieve latest sensor readings
Parameters:
unitId: Specific device/unitcategoryType: Data category (source, stock, energy, quality)startDate,endDate: Date rangestartTime,endTime: Time range
Alerts Route (alerts_routes.py)
Endpoints:
GET /api/user/alerts- List alertsPOST /api/user/alerts- Create alertPUT /api/user/alerts/{id}- Update alertDELETE /api/user/alerts/{id}- Delete alert
Features:
- Alert rule configuration
- Threshold management
- Channel configuration (email, SMS, chat)
4️⃣ Service Layer (app/services/)
Report Service (services/report/report.py)
Purpose: Central dispatcher for all report types
class ReportService:
def get_report(self):
service_type = self.report_request.serviceType
if service_type == ServiceType.WATER:
return FlowReport(self.report_request).get_report()
elif service_type == ServiceType.ENERGY:
return EnergyReport(self.report_request).get_report()
elif service_type == ServiceType.LEVEL:
return LevelReport(self.report_request).get_report()
# ... more report types
Supported Report Types (18 total):
Device Data Service (services/device_data.py)
Purpose: Process and format IoT device data
Key Methods:
get_latest_data()- Current sensor readingsget_historical_data()- Time-series dataget_device_status()- Online/offline status
Alert Processor (services/alerts/alerts_processor.py)
Purpose: Evaluate alert rules and trigger notifications
Alert Types:
- Threshold alerts (value exceeds limit)
- Device offline alerts
- Data anomaly alerts
- System alerts
Admin Services (services/admin/)
Industry Service (industry.py)
- Create, read, update, delete industries
- Configure industry settings
- Manage timezone and shift configuration
User Service (user.py)
- User CRUD operations
- Role and permission management
- Password reset and OTP
Automated Report Service (automated_report/automated_report.py)
- Schedule report generation
- Batch report processing
- Email delivery integration
5️⃣ Formatters (app/formatters/)
Report Formatter (formatters/report/report.py)
Purpose: Transform report data into various formats
class ReportFormatter:
def get_file(self):
if self.report_request.report_format == ReportFormat.HTML:
return self.get_html()
elif self.report_request.report_format == ReportFormat.PDF:
return self.get_pdf()
elif self.report_request.report_format == ReportFormat.XLSX:
return self.get_xlsx()
elif self.report_request.report_format == ReportFormat.CSV:
return self.get_csv()
Format Conversion Pipeline:
Device Data Formatters (formatters/device_data_v2/)
Polymorphic Design:
# Base Template
class DeviceDataV2FormatterTemplate:
def format(self):
pass
# Specific Formatters
class FlowDeviceDataV2Formatter(DeviceDataV2FormatterTemplate):
def format(self):
# Format flow/water data
pass
class EnergyDeviceDataV2Formatter(DeviceDataV2FormatterTemplate):
def format(self):
# Format energy data
pass
6️⃣ Database Supporter (app/database/database_supporter.py)
Purpose: Centralized database operations
Key Statistics:
- 200+ methods for data access
- Static methods for easy access
- Parallel queries with ThreadPoolExecutor
- Query optimization for Cosmos DB
Common Operations
# Get industry details
DatabaseSupporter.get_industry_details_by_id(industry_id)
# Get device data by date range
DatabaseSupporter.get_device_data_by_date_range(
industry_id, unit_id, start_date, end_date
)
# Get user by email
DatabaseSupporter.get_user_by_email(email, industry_id)
# Create notification
DatabaseSupporter.create_notification(notification_data)
Query Patterns
7️⃣ Configuration (app/config.py)
Purpose: Centralized configuration with Azure Key Vault
class Config(object):
# Database
COSMOSDBENDPOINT = smi.get(SecretName.COSMOSDBENDPOINT)
COSMOSDBKEY = smi.get(SecretName.COSMOSDBKEY)
# Authentication
AZURE_AD_APP_ID = smi.get(SecretName.AZURE_AD_APP_ID)
AZURE_AD_ISSUER = smi.get(SecretName.AZURE_AD_ISSUER)
# AI
AQUA_GPT_API_KEY = smi.get(SecretName.AQUA_GPT_API_KEY)
AQUA_GPT_MODEL = smi.get(SecretName.AQUA_GPT_MODEL)
# Environment
ENVIRONMENT = os.environ.get('ENVIRONMENT', 'development')
Security Features:
- All secrets fetched from Azure Key Vault
- No hardcoded credentials
- Environment-specific configuration
- Runtime secret rotation support
8️⃣ Authentication (app/auth/auth.py)
JWT Lifecycle:
Token Validation:
@CachedData.jwt.token_in_blocklist_loader
def check_if_token_is_revoked(jwt_header, jwt_payload: dict):
user_id = jwt_payload["userId"]
sub = jwt_payload["sub"]
return user_id in Constants.disabled_user_ids or \
sub in Constants.disabled_industry_ids
@CachedData.jwt.user_lookup_loader
def load_user(_jwt_header, jwt_data):
industry_id = jwt_data['sub']
industry_data = DatabaseSupporter.get_industry_details_by_id(industry_id)
g.timezone = industry_data['meta']['timezone']
return formatted_industry_data
9️⃣ Utilities (app/util/)
DateTimeUtil
- Timezone conversion (UTC ↔ Local)
- Date parsing and formatting
- Shift-aware time calculations
NumberUtil
- Number truncation
- Decimal precision handling
- SI unit formatting
SIUnitUtil
- Unit conversion (L, KL, ML, GL)
- Power units (W, KW, MW)
- Quality parameter units
CalculationUtil
- Statistical calculations (min, max, avg)
- Trend analysis
- Percentage calculations
🔟 Data Models (app/models/)
Model Types:
Example Model:
from flask_restx import fields
GenericSuccessModel = {
'message': fields.String(description='Success message'),
'status': fields.String(default='success'),
'status_code': fields.Integer(default=200),
'data': fields.Raw(description='Response data')
}
All components work together following the layered architecture pattern. Routes handle requests, services process business logic, formatters transform data, and the database supporter manages persistence.
📚 Next Steps
- Database Architecture - Database schema and queries
- Request Flow - Detailed request processing
- Core Concepts - Understanding reports and services