Admin API Reference
Base path: /api/admin · Swagger UI: /api/admin/docs
Base URLs
| Environment | Base URL |
|---|---|
| Production | https://prod-aquagen.azurewebsites.net |
| Local | http://localhost:5000 |
Example:
https://prod-aquagen.azurewebsites.net/api/admin/auth/login
https://prod-aquagen.azurewebsites.net/api/admin/industry/?targetIndustryId=IND001
https://prod-aquagen.azurewebsites.net/api/admin/automated/report/?types=daily&date=09/11/2024&formats=pdf
All endpoints (except /auth/login, /auth/swaggerLogin, and Swagger routes) require:
Authorization: Bearer <admin_access_token>
Most endpoints also require a targetIndustryId header identifying the industry to operate on. The admin JWT carries industryId: "INTERNAL" in its claims — targetIndustryId is a separate per-request parameter that selects which client industry to act on.
Authentication
GET /api/admin/auth/login
Microsoft SSO-only login. Verifies an Azure AD bearer token and issues an AquaGen admin JWT. No username/password login is supported.
GET /api/admin/auth/login
Authorization: Bearer <azure_ad_token>
tid: <tenant_id>
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Azure AD identity token (Bearer <token>) |
tid | Yes | Azure AD tenant ID — used to look up the allowed tenant |
How it works:
- Both
Authorizationandtidheaders are checked — either missing returns1403 AdminLoginService.verify_microsoft_login(token, tid)validates the Azure AD token against the tenant's JWKS endpoint and extracts the user's email- The email is looked up in Cosmos DB to find the matching admin user document
- If not found →
1401 "Not found any industries or user with the given organization account" - JWT claims are built:
{
"userId": "...",
"email": "admin@company.com",
"username": "Admin User",
"loginType": "microsoft",
"tid": "<tenant_id>",
"role": "admin",
"industryId": "INTERNAL"
} SessionTimeoutUtil.get_access_token_expiry(internal_industry)determines token lifetime from theINTERNALindustry'ssessionTimeoutconfig- Refresh token expiry is calculated via
get_refresh_token_expiry(internal_industry, False) AdminLoginDataFormatter.format_admin_data(user, access_token, refresh_token)shapes the response
Response shape:
{
"access_token": "<jwt>",
"refresh_token": "<jwt>",
"userId": "ADM001",
"email": "admin@company.com",
"username": "Admin User",
"role": "admin",
"loginType": "microsoft"
}
| Status | Cause |
|---|---|
200 | Login successful |
1401 | No admin user found for the Azure AD account |
1403 | Authorization or tid header missing |
1404 | tid not in recognised tenant list |
GET /api/admin/auth/swaggerLogin
Returns the HTML login form for the Swagger UI. Not for programmatic use.
POST /api/admin/auth/swaggerLogin
Validates credentials via UserService().verify_default_login(), sets an access_token_cookie (httponly, 1-hour max-age), and redirects to /api/admin/docs. Not for programmatic use.
GET /api/admin/auth/refresh
Issue a new admin access token using a valid refresh token. Uses @jwt_required(refresh=True).
GET /api/admin/auth/refresh
Authorization: Bearer <refresh_token>
How it works:
get_jwt_identity()extractsindustryIdfrom the refresh tokenget_jwt()extracts all claims (userId,email,username,loginType,role)- New access token issued via
create_access_token()withINTERNALindustry expiry - Rolling refresh renewal: if the refresh token expires within 7 days, a new refresh token is issued with a full expiry window. Otherwise the existing refresh token is returned unchanged.
AdminLoginDataFormatter.format_admin_data()shapes the response
| Status | Cause |
|---|---|
200 | New access_token (and optionally renewed refresh_token) returned |
422 | An access token was passed instead of a refresh token |
Automated Reports
For the full synchronous execution flow, daily vs monthly pipeline, per-industry service flags, Gmail API delivery, and test=true behaviour see Automated Reports Flow →
GET /api/admin/automated/report/
Generate reports in-memory and deliver via email to configured recipients. No files are stored anywhere.
GET /api/admin/automated/report/?types=daily&date=09/11/2024&formats=pdf&formats=xlsx
Authorization: Bearer <admin_token>
targetIndustryId: IND001
| Parameter | Required | Default | Description |
|---|---|---|---|
targetIndustryId | Yes (query) | — | Industry to generate for |
date | Yes | — | DD/MM/YYYY — report date |
types | Yes | — | daily or monthly |
formats | No | pdf, xlsx | Output formats — must be repeated params, not comma-separated |
test | No | false | If true, generates reports but skips email delivery. Log entry still written. |
emails | No | — | Extra recipient addresses — repeat param for multiple |
Critical: formats must use repeated params:
# Correct
?formats=pdf&formats=xlsx
# Wrong — will not work
?formats=pdf,xlsx
How it works:
AdminAutomatedReportService(args).process()is called- For
daily: generates a water consumption report and a daily summary report (with rain water if enabled), then sends one email per report type - For
monthly: checks per-industry feature flags and generates all enabled report types in all requested formats, then sends a single email with all attachments - Each report is generated entirely in-memory (
BytesIO) usingxhtml2pdforxlsxwriter - Email sent via Gmail API from
reports.aquagen@fluxgentech.com - Recipients:
projectsupport@fluxgentech.com+ anyemailsparam values + (unlesstest=true)meta.reports.emailIdsfrom the industry document
Monthly service flags — each checked against the industry's meta.reports.services config:
| Service | Flag key |
|---|---|
| Consumption | is_consumption_enabled |
| Rain water | is_rain_water_enabled |
| Stock / tank level | is_stock_enabled |
| Groundwater | is_groundwater_enabled |
| Summary | is_summary_enabled |
| Energy | is_energy_enabled |
| Quality | is_quality_enabled |
| Executive summary | is_executive_enabled |
Services whose flag evaluates to false are silently skipped.
| Status | Cause |
|---|---|
200 | { "message": "Automated Monthly Report Sent Successfully", "status": "Success" } |
400 | Invalid types value |
1403 | targetIndustryId or date missing |
Workspace
GET /api/admin/workspace/
Returns the admin workspace overview: list of all active industries with their current status and high-level metrics.
GET /api/admin/workspace/
Authorization: Bearer <admin_token>
How it works:
AdminWorkSpaceService().get_workspace_data() fetches all industry documents from Cosmos DB and returns a summary view including industry names, IDs, active status, last seen timestamps, and unit counts.
Response shape (marshalled to WorkspaceResponseModel):
{
"data": [
{
"industryId": "IND001",
"industryName": "XYZ Water Plant",
"place": "Chennai",
"isActive": true,
"totalUnits": 12,
"lastUpdated": "2024-11-09T10:00:00Z"
}
],
"status": "Success"
}
| Status | Cause |
|---|---|
200 | Workspace data for all industries |
Offline Devices
GET /api/admin/offlineDevices/offline
Returns all devices across all industries that have not reported data within the expected interval for the given date.
GET /api/admin/offlineDevices/offline?date=09/11/2024
Authorization: Bearer <admin_token>
| Parameter | Required | Format |
|---|---|---|
date | Yes | dd/mm/yyyy |
How it works:
AdminOfflineDevicesService(args).get_offline_devices()fetches all units and their latest timestamps- A unit is marked offline if its last reading is older than the threshold for the date view:
- Hour view: 15 minutes
- Day view: 60 minutes
- Month view: 1800 minutes
- Returns two lists: all units and offline-only units
Response shape:
{
"data": [
{
"unitId": "U001",
"unitName": "Borewell 1",
"industryId": "IND001",
"lastSeen": "2024-11-09T08:15:00Z"
}
],
"totalDevicesCount": 45,
"offlineDevicesCount": 3
}
| Status | Cause |
|---|---|
200 | List of offline devices |
404 | No offline devices found |
GET /api/admin/offlineDevices/batchProcessingInterpolation
Check which industries have gaps in processed_data that require batch processing interpolation for a given date.
GET /api/admin/offlineDevices/batchProcessingInterpolation?date=09/11/2024
Authorization: Bearer <admin_token>
| Parameter | Required | Format |
|---|---|---|
date | Yes | dd/mm/yyyy — 1403 if missing |
How it works:
AdminBatchProcessingInterpolationService(args).check_batch_processing_status() scans processed_data containers across industries for the given date to identify any that have null or missing hourly aggregates. These are industries where batch processing failed or did not run.
Response shape:
{
"data": [
{ "industryId": "IND002", "missingHours": [2, 3, 14] }
],
"status": "Success"
}
| Status | Cause |
|---|---|
200 | Industries with interpolation gaps |
1403 | date missing |
Global Logs
Base path: /api/admin/globallogs
System-wide audit log for all automated processes, report deliveries, batch runs, and admin actions. POST does not require a JWT — it is used by internal services to write logs without admin credentials.
POST /api/admin/globallogs/
Create a new log entry. No JWT required — this endpoint is called by background services.
This endpoint requires no JWT authentication. It is intentionally open so that internal background services can write log entries without admin credentials. Do not expose it to untrusted callers.
POST /api/admin/globallogs/
Content-Type: application/json
{
"source": "automated_report",
"title": "Monthly Report - IND001",
"desc": "Generated and emailed monthly report for November 2024",
"group": "reports"
}
Required body fields:
| Field | Description |
|---|---|
source | Source system or service that generated the log |
title | Short display title |
desc | Full description of the event |
group | Log group / category (e.g. reports, batch, alerts) |
Each field is validated individually — 1403 with "'<field>' missing" if any is absent.
GlobalLogsDataService(args).create_log_data() writes the entry to the global_logs_container in Cosmos DB.
| Status | Cause |
|---|---|
200 | Log entry created |
1403 | Required field missing (source, title, desc, or group) |
GET /api/admin/globallogs/
Retrieve log entries with optional filters. JWT required.
GET /api/admin/globallogs/?industryId=IND001&date=09/11/2024
Authorization: Bearer <admin_token>
| Parameter | Required | Description |
|---|---|---|
industryId | No | Filter to a specific industry |
unitId | No | Filter to a specific unit |
date | No | dd/mm/yyyy — filter by day |
month | No | mm/yyyy — filter by month |
All filters are optional — omitting all returns recent logs across all industries.
GlobalLogsDataService(args).get_log_data() queries Cosmos DB with the provided filters.
| Status | Cause |
|---|---|
200 | Array of log entries |
PATCH /api/admin/globallogs/
Update a log entry's metadata. JWT required.
PATCH /api/admin/globallogs/?id=LOG001&status=resolved&priority=high
Authorization: Bearer <admin_token>
| Parameter | Required | Valid values | Description |
|---|---|---|---|
id | Yes | — | Log entry ID — 1403 if missing |
owner | No | — | Assignee name or user ID |
priority | No | PriorityType enum | Priority level |
status | No | StatusType enum | Status update |
date | No | dd/mm/yyyy | Updated date |
month | No | mm/yyyy | Updated month |
meta | No | — | Additional metadata object |
source | No | — | Updated source label |
title | No | — | Updated title |
GlobalLogsDataService(args).update_log_data() performs a partial update on the log document.
| Status | Cause |
|---|---|
200 | Log entry updated |
1403 | id missing |
Insights
GET /api/admin/insights/
Retrieve pre-computed insights for a specific date across all active industries.
GET /api/admin/insights/?date=15_07_2024
Authorization: Bearer <admin_token>
| Parameter | Required | Format | Description |
|---|---|---|---|
date | Yes | DD_MM_YYYY (underscores, not slashes) | Date to fetch insights for — 1403 if missing |
How it works:
AdminInsightsService(args).get_insights_data_by_date() queries the insights container in Cosmos DB for the given date. Insights are pre-computed by the POST endpoint and stored as aggregated industry-level analytics.
Response shape:
{
"data": {
"date": "15_07_2024",
"industries": [
{
"industryId": "IND001",
"totalConsumption": 45000,
"onlineUnits": 10,
"offlineUnits": 2
}
]
},
"status": "Success"
}
| Status | Cause |
|---|---|
200 | Insights data for the date |
1403 | date missing |
POST /api/admin/insights/
Generate and store insights for the current date. Runs analytics across all active industries.
POST /api/admin/insights/
Authorization: Bearer <admin_token>
How it works:
AdminInsightsService(args).post_insights() iterates over all active industries, aggregates device data, computes consumption totals and online/offline counts, and upserts the result into the insights Cosmos DB container.
| Status | Cause |
|---|---|
200 | Insights generated and stored |
500 | Internal processing error |
1430 | Validation error in output data shape |
Archive Data
Base path: /api/admin/archivedata
Moves device data between active Cosmos DB storage and Azure Blob long-term archive. Both directions are destructive when the delete flag is set — data is removed from the source after a successful transfer.
POST /api/admin/archivedata/to_blob
Archive historical device data from Cosmos DB to Azure Blob Storage.
POST /api/admin/archivedata/to_blob?fromMonthYear=07/2024&deleteData=true
Authorization: Bearer <admin_token>
targetIndustryId: IND001
| Header/Param | Required | Format | Description |
|---|---|---|---|
targetIndustryId | Yes (header) | — | Industry to archive — 1403 if missing |
fromMonthYear | Yes | 07/2024 | Start month/year — 1403 if missing |
toMonthYear | No | 07/2024 | End month/year (defaults to fromMonthYear if omitted) |
deleteData | No | true/false | If true, removes data from Cosmos DB after archiving. Default: false |
How it works:
ArchiveDataService(args).migrate_data_from_db_to_blob() reads all processed_data documents for the industry within the month range, writes them to Azure Blob Storage in the archive container, and (if deleteData=true) deletes them from Cosmos DB.
Setting deleteData=true permanently removes the archived records from Cosmos DB after they are written to blob storage. This operation cannot be undone without restoring from the blob archive.
| Status | Cause |
|---|---|
200 | Data archived to blob |
400 | Invalid date range or archiving error |
404 | No data found for the range |
1403 | targetIndustryId or fromMonthYear missing |
POST /api/admin/archivedata/to_db
Restore archived data from Azure Blob Storage back into Cosmos DB.
POST /api/admin/archivedata/to_db
Authorization: Bearer <admin_token>
targetIndustryId: IND001
month: 08
year: 2024
| Header/Param | Required | Format | Description |
|---|---|---|---|
targetIndustryId | Yes (header) | — | Industry to restore — 1403 if missing |
month | Yes (header) | 08 | Month number (zero-padded, 01–12) — 1403 if missing |
year | Yes (header) | 2024 | 4-digit year — 1403 if missing |
deleteBlob | No | true/false | If true, removes the blob file after restoring. Default: false |
How it works:
ArchiveDataService(args).migrate_data_from_blob_db() reads the archived blob for the industry/month, writes documents back to Cosmos DB's active container, and (if deleteBlob=true) deletes the blob.
Setting deleteBlob=true permanently deletes the archive blob after restoring to Cosmos DB. Ensure the restore completed successfully before relying on this flag, as the blob cannot be recovered once deleted.
| Status | Cause |
|---|---|
200 | Data restored to Cosmos DB |
400 | Invalid month/year or restore error |
404 | No archived data found for month |
1403 | Required header missing |
Notifications (Admin)
POST /api/admin/notification/
Broadcast a real-time WebSocket notification to the admin app dashboard. Not stored in the database — WebSocket only.
POST /api/admin/notification/
Authorization: Bearer <admin_token>
title=System Alert&body=Batch processing completed for IND001
| Body param | Required | Description |
|---|---|---|
title | Yes | Notification title text |
body | Yes | Notification body text |
How it works:
AdminNotificationService().send_web_socket_notification(title, body) emits the notification via the WebSocket server to all connected admin dashboard clients. No persistence — clients that are not connected when the notification is sent will miss it.
This notification is WebSocket-only and is not persisted. Any admin dashboard client that is not connected at the time the notification is sent will not receive it.
| Status | Cause |
|---|---|
200 | { "message": "Notification sent successfully", "status": "success" } |
400 | WebSocket delivery error |
Validate
Base path: /api/admin/validate
Diagnostic and health-check utilities. These endpoints do not modify production data — they validate system state and send results to Google Chat groups.
GET /api/admin/validate/batchProcessing
Validate batch processing completeness for a date and post the result to a Google Chat space.
GET /api/admin/validate/batchProcessing?groupId=OPS_TEAM&date=09/11/2024
Authorization: Bearer <admin_token>
| Parameter | Required | Description |
|---|---|---|
groupId | Yes | GChatGroupId enum value — identifies the Chat space |
date | Yes | DD/MM/YYYY |
How it works:
BatchProcessingValidator().validate(date)checks all industries for missingprocessed_dataentries on the given date- Result is sent to the specified Chat group via
GChatsService().send_custom_message() - The same result is returned in the HTTP response
The validation result is sent to the specified Google Chat group in addition to being returned in the HTTP response.
| Status | Cause |
|---|---|
200 | Validation complete, result sent to GChat |
400 | Validation error or GChat delivery failure |
GET /api/admin/validate/reverseFlow
Check all units across all industries for reverse flow anomalies (negative flow readings that indicate measurement errors or pipeline reversals) and post the report to Google Chat.
GET /api/admin/validate/reverseFlow?groupId=OPS_TEAM
Authorization: Bearer <admin_token>
| Parameter | Required | Description |
|---|---|---|
groupId | Yes | GChatGroupId enum value |
ReverseFlowValidator().validate() scans recent readings for negative flow values.
| Status | Cause |
|---|---|
200 | Report sent to GChat |
400 | GChat delivery failure |
GET /api/admin/validate/storm_backend
Validate the Storm backend integration. Returns a diagnostic message confirming Storm connectivity.
GET /api/admin/validate/storm_backend
Authorization: Bearer <admin_token>
StormValidator().validator() runs a test probe against the Storm backend service.
| Status | Cause |
|---|---|
200 | { "message": "<diagnostic_result>", "status": "Success" } |
GET /api/admin/validate/unitReset
Send a reset signal to one or more units via IoT Hub. The unit devices will reboot their measurement cycle on receipt.
GET /api/admin/validate/unitReset?unitsList=U001&unitsList=U002
No JWT required for this endpoint.
This endpoint does not require a JWT. It is callable without admin authentication — ensure access is restricted at the network or gateway level if needed.
| Parameter | Required | Description |
|---|---|---|
unitsList | Yes (repeat) | Unit IDs to reset — repeat param for multiple units — 1403 if missing |
How it works:
AdminUnitResetService({'unitsList': unitsList}).reset_unit() pushes a reset command message to each unit via Azure IoT Hub's device-to-cloud messaging.
| Status | Cause |
|---|---|
200 | { "message": "Reset signal sent", "status": "Success" } |
400 | Failed to send reset message to IoT Hub |
1403 | unitsList missing |
Google Chat (GChat)
Base path: /api/admin/gchat
Send messages to internal Google Chat spaces. Used by validators and monitoring scripts to post results.
GET /api/admin/gchat/
Send a plain text message to a Google Chat group.
GET /api/admin/gchat/?message=Batch+complete&groupId=OPS_TEAM
Authorization: Bearer <admin_token>
| Parameter | Required | Description |
|---|---|---|
message | Yes | Message text |
groupId | Yes | GChatGroupId enum value — identifies which Chat space to send to |
GChatsService().send_normal_message(message, GChatGroupId(groupId)) posts to the Chat webhook.
| Status | Cause |
|---|---|
200 | { "message": "Message sent successfully", "status": "success" } |
400 | GChat webhook delivery failure |
POST /api/admin/gchat/
Send a structured (card/rich text) message to a Google Chat group.
POST /api/admin/gchat/?groupId=OPS_TEAM
Authorization: Bearer <admin_token>
Content-Type: application/json
{
"data": { ... }
}
| Parameter | Required | Description |
|---|---|---|
groupId | Yes | GChatGroupId enum value |
Body: JSON object with a data field containing the structured message payload.
GChatsService().send_custom_message(body['data'], GChatGroupId(groupId)) formats and posts the message.
| Status | Cause |
|---|---|
200 | Message sent |
400 | GChat delivery failure |
PLC EventHub
GET /api/admin/plcEventHub/data
Trigger a PLC-to-EventHub test push. Validates that the PLC integration pipeline can successfully publish a test event to Azure EventHub.
GET /api/admin/plcEventHub/data
Authorization: Bearer <admin_token>
PlcEventHubService().push_to_event_hub() publishes a test event and returns success/failure.
| Status | Cause |
|---|---|
200 | Test event pushed to EventHub |
500 | EventHub push failed |
Shift Monitoring
GET /api/admin/shift-monitoring/recent-shift-starts
Returns a list of all active industries that had a recent shift start. Used to coordinate batch processing after shift boundaries.
GET /api/admin/shift-monitoring/recent-shift-starts?source=scheduler&purpose=shift_batch_trigger
Authorization: Bearer <admin_token>
| Parameter | Required | Description |
|---|---|---|
source | Yes | Source system identifier (e.g. scheduler) |
purpose | Yes | Purpose string (e.g. shift_batch_trigger) |
How it works:
ShiftMonitoringService().push_request_to_event_hub()fetches all active industries and checks whether the current UTC time falls within 15 minutes of any industry's shiftstartAtboundary- Matching industries are returned and an EventHub trigger event is pushed for each
| Status | Cause |
|---|---|
200 | List of industries with recent shift starts |
500 | EventHub or query error |
Batch Processing Trigger
For the full Event Hub ingestion pipeline and what happens after the trigger fires see Batch Processing Flow →
GET /api/admin/bpTrigger/trigger
Manually push a batch processing trigger event to Azure EventHub for a specific industry and time. No JWT required — this endpoint is called by the batch scheduling system.
GET /api/admin/bpTrigger/trigger?industryId=IND001&time=2024-11-09T18:30:00Z&source=manual&purpose=daily_batch
| Parameter | Required | Description |
|---|---|---|
industryId | Yes | Target industry ID |
time | Yes | ISO 8601 UTC datetime string for the batch window |
source | Yes | Trigger source identifier (e.g. manual, scheduler) |
purpose | Yes | Purpose label (e.g. manual_trigger, daily_batch) |
How it works:
BpTriggerService().push_trigger_to_event_hub(args) publishes a batch processing trigger message to Azure EventHub. The EventHub consumer picks up the message and runs the interpolation and aggregation pipeline for the specified industry and time window.
This endpoint does not require a JWT. It is intended for use by the batch scheduling system and internal automation.
| Status | Cause |
|---|---|
200 | Trigger pushed to EventHub |
500 | EventHub push failed |
Bathymetry Data Processor
Base path: /api/admin/bathyDataProcessor
Lake Pulse feature — processes sonar depth survey (bathymetry) CSV data and computes static volume-area-elevation models for reservoir units.
POST /api/admin/bathyDataProcessor/process
Upload and process a raw bathymetry CSV file for a unit.
POST /api/admin/bathyDataProcessor/process?unitId=U001&date=15/01/2026&confidenceThreshold=80
Authorization: Bearer <admin_token>
targetIndustryId: IND001
Content-Type: multipart/form-data
files=<csv_file>
| Param / Header | Required | Default | Description |
|---|---|---|---|
targetIndustryId | Yes (header) | — | Industry — 1403 if missing |
files | Yes (multipart) | — | Raw sonar depth data CSV |
unitId | Yes | — | Lake/reservoir unit ID |
date | Yes | — | Survey date — DD/MM/YYYY |
confidenceThreshold | No | 100 | Filter readings below this confidence score |
distanceThresholdMetersMin | No | 0.1 | Minimum inter-point distance (meters) |
distanceThresholdMetersMax | No | 0.5 | Maximum inter-point distance (meters) |
depthSimilarityRatio | No | 0.95 | Ratio threshold for deduplication |
includeAllData | No | false | Skip confidence filtering |
includeIntermediate | No | false | Return intermediate processing results in response |
compressedOnly | No | false | Return only the compressed result set |
How it works:
- CSV parsed and point cloud deduplicated based on
depthSimilarityRatio - Readings filtered by
confidenceThreshold(unlessincludeAllData=true) - Distance thresholds remove points that are too close or too far apart
- Processed data saved to Cosmos DB as a
BATHY_DATAdocument for the unit and date - Static volume-area-elevation curve computed from the processed point cloud and stored
| Status | Cause |
|---|---|
200 | Processing statistics returned (and optionally intermediate results) |
400 | File parse error or invalid params |
1403 | targetIndustryId, unitId, or date missing |
POST /api/admin/bathyDataProcessor/recomputeStatic
Recompute the static volume model from existing processed bathymetry data without re-uploading a file.
POST /api/admin/bathyDataProcessor/recomputeStatic?unitId=U001
Authorization: Bearer <admin_token>
targetIndustryId: IND001
| Param / Header | Required | Description |
|---|---|---|
targetIndustryId | Yes (header) | Industry — 1403 if missing |
unitId | Yes | Unit ID — 1403 if missing |
Reads existing BATHY_DATA documents from Cosmos DB and recomputes the volume model. Useful after adjusting thresholds without re-uploading raw data.
| Status | Cause |
|---|---|
200 | Returns the recomputed survey dates |
400 | No existing data to recompute from |
1403 | targetIndustryId or unitId missing |
Water Quality Satellite
POST /api/admin/waterQualitySatellite/process
Process satellite imagery to derive water quality parameters for a reservoir unit.
POST /api/admin/waterQualitySatellite/process?unitId=U001&startDate=01/11/2024&endDate=30/11/2024&chlorophyllEnabled=true
Authorization: Bearer <admin_token>
targetIndustryId: IND001
| Param / Header | Required | Default | Description |
|---|---|---|---|
targetIndustryId | Yes (header) | — | Industry |
unitId | Yes | — | Reservoir unit ID |
startDate | No | — | dd/mm/yyyy — start of processing window |
endDate | No | — | dd/mm/yyyy — end of processing window |
chlorophyllEnabled | No | false | Enable chlorophyll-a concentration estimation |
spacing | No | 10 | Pixel sampling interval |
cloudCoverThreshold | No | 70 | Maximum cloud cover % — images above this threshold are skipped |
How it works:
Satellite imagery for the date range is fetched (requires imagery to be available). Spectral band analysis derives chlorophyll-a concentration and turbidity values per pixel. Results are averaged across the reservoir area and stored per date. Images with cloud cover above cloudCoverThreshold are automatically skipped.
Response shape:
{
"summary": {
"totalDates": 12,
"processedDates": 9,
"skippedDates": 3
},
"processedDates": ["2024-11-01", "2024-11-03", "..."]
}
| Status | Cause |
|---|---|
200 | Returns { "summary": {...}, "processedDates": [...] } |
500 | Satellite processing error |
Verify Monthly Data
GET /api/admin/verifyMonthlyData/
Verify data completeness for all units in a given month, and optionally trigger batch processing to fill gaps.
GET /api/admin/verifyMonthlyData/?date=11/2024&runBatchProcessing=true&excludeDates=01/11/2024&excludeDates=03/11/2024
Authorization: Bearer <admin_token>
| Parameter | Required | Default | Description |
|---|---|---|---|
date | Yes | — | MM/YYYY — month to verify |
excludeDates | No (repeat) | — | DD/MM/YYYY dates to skip — repeat param for multiple |
runBatchProcessing | No | false | If true, automatically triggers batch processing for days with missing processed_data |
How it works:
- Each day in the month is checked (excluding
excludeDates) for the presence ofprocessed_dataentries - Days with gaps are collected into a summary
- If
runBatchProcessing=true, a batch trigger is fired for each gap day
| Status | Cause |
|---|---|
200 | Verification results with gap summary |
400 | Invalid date format |
Water Balance Leakage Formula
Base path: /api/admin/waterBalanceLeakageFormula
Manages the leakage detection formula derived from the water balance graph. The formula defines which unit combinations represent inflow, outflow, and storage — used by the Leakage Evaluator to compute leakage volumes.
POST /api/admin/waterBalanceLeakageFormula/generate
Generate and store a leakage formula from the industry's water balance graph configuration.
POST /api/admin/waterBalanceLeakageFormula/generate
Authorization: Bearer <admin_token>
How it works:
AdminWaterBalanceFormulaService().generate_and_store()loads the water balance graph from theadditional_featurecontainer- If no graph is configured →
404 "No water balance graph configured for this industry" - Traverses the graph to identify inflow nodes, outflow nodes, and storage nodes for each subgraph
- Generates a formula document per subgraph and stores it in the
additional_featurecontainer withtype: "waterBalanceLeakageFormula"
| Status | Cause |
|---|---|
200 | Formula generated and stored — returns the formula data |
404 | No water balance graph configured for the industry |
GET /api/admin/waterBalanceLeakageFormula/
Retrieve the stored leakage formula for the industry.
GET /api/admin/waterBalanceLeakageFormula/?ignoreGraphWithNoFormula=true
Authorization: Bearer <admin_token>
| Parameter | Required | Default | Description |
|---|---|---|---|
ignoreGraphWithNoFormula | No | true | If true, subgraphs without a formula are excluded from the response |
AdminWaterBalanceFormulaService().get_stored(ignoreGraphWithNoFormula) fetches the stored formula document from Cosmos DB.
| Status | Cause |
|---|---|
200 | Returns formula data (empty object {} if no formula stored) |
Water Balance Leakage Evaluator
GET /api/admin/waterBalanceLeakageEvaluator/evaluate
Evaluate water balance and compute leakage estimation for an industry based on its configured leakage formula.
GET /api/admin/waterBalanceLeakageEvaluator/evaluate?date1=09/11/2024&type=DAY
Authorization: Bearer <admin_token>
| Parameter | Required | Description |
|---|---|---|
date1 | Yes | DD/MM/YYYY — evaluation date/period start |
type | Yes | DAY, MONTH, or YEAR |
storeToDb | No | Default false — if true, writes evaluation result to Cosmos DB |
How it works:
- Loads the leakage formula configured for the industry from the
additional_featurecontainer - If no formula configured →
404 "No leakage formula configured" - Fetches inflow and outflow readings for the specified period
- Applies the formula:
leakage = inflow - outflow - (storage_end - storage_start) - If
storeToDb=true, upserts the result into the water balance leakage container
| Status | Cause |
|---|---|
200 | Leakage evaluation result with percentage and volume |
404 | No leakage formula configured for the industry |
Hourly Consumption Alert Email
GET /api/admin/hourlyConsumptionAlertEmail/
Check hourly consumption thresholds across all units for the target industry and send an alert email if any unit exceeds its configured threshold.
GET /api/admin/hourlyConsumptionAlertEmail/
Authorization: Bearer <admin_token>
targetIndustryId: IND001
| Header | Required |
|---|---|
targetIndustryId | Yes |
How it works:
- Loads each unit's
hourlyThresholdfrom the industry'salertsConfig - Fetches the current hour's consumption for each unit
- Units exceeding their threshold are collected
- If any unit exceeds its threshold, an alert email is sent via Gmail API to configured recipients
Response shape:
{
"data": [
{ "unitId": "U001", "unitName": "Main Inlet", "consumption": 1500, "threshold": 1000, "exceeded": true }
],
"status": "Success"
}
| Status | Cause |
|---|---|
200 | Per-unit check results returned |
Status Code Reference
| Code | Meaning |
|---|---|
200 | Success |
400 | Bad request / validation error / user limit exceeded |
401 | Unauthorised — invalid or missing admin JWT |
404 | Resource not found |
420 | JWT expired |
440 | Session revoked — token inactive in token_logs |
500 | Internal server error |
1401 | User or industry not found in Cosmos DB |
1402 | Invalid admin credentials |
1403 | Missing required header, parameter, or body field |
1404 | Invalid tenant ID or invalid data |
1430 | JSON schema validation failure |