Skip to main content

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

FilterPurposeExample Output
decimal_formatFormat numbers with precision123.456123.46
date_time_to_dateConvert UTC datetime to date2024-11-09T10:30:00Z09/11/2024
date_to_dateFormat date strings2024-11-0909/11/2024
date_time_to_timeExtract time from datetime2024-11-09T10:30:00Z10: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 settings
  • accounts - Account management
  • reports - Report generation
  • device_data - Device data retrieval
  • device_data_v2 - Enhanced device data API
  • alerts - Alert management
  • notifications - Notification endpoints
  • landing_page - Dashboard data
  • summary_page - Summary reports
  • water_balance - Water balance analysis
  • granular_data - Time-series data
  • quality_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 authentication
  • industry - Industry CRUD operations
  • unit - Unit/device management
  • user - User management
  • automated_report - Scheduled reports
  • device_data - Admin device data access
  • notification - System notifications
  • workspace - Workspace configuration
  • offline_devices - Offline device tracking
  • insights - Analytics insights
  • global_logs - Audit logs
  • shift_monitoring - Shift tracking
  • gchats - Google Chat integration

Authentication: Requires admin role (@admin_required())

External Blueprint (external.py)

Purpose: Third-party integrations

Namespaces:

  • external_login - External system authentication
  • water_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 ReportRequestData object
  • Call ReportService to 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/unit
  • categoryType: Data category (source, stock, energy, quality)
  • startDate, endDate: Date range
  • startTime, endTime: Time range

Alerts Route (alerts_routes.py)

Endpoints:

  • GET /api/user/alerts - List alerts
  • POST /api/user/alerts - Create alert
  • PUT /api/user/alerts/{id} - Update alert
  • DELETE /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 readings
  • get_historical_data() - Time-series data
  • get_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')
}

Component Interaction

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