Skip to main content

Admin API Reference

Base path: /api/admin · Swagger UI: /api/admin/docs

Base URLs

EnvironmentBase URL
Productionhttps://prod-aquagen.azurewebsites.net
Localhttp://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>
HeaderRequiredDescription
AuthorizationYesAzure AD identity token (Bearer <token>)
tidYesAzure AD tenant ID — used to look up the allowed tenant

How it works:

info
  1. Both Authorization and tid headers are checked — either missing returns 1403
  2. AdminLoginService.verify_microsoft_login(token, tid) validates the Azure AD token against the tenant's JWKS endpoint and extracts the user's email
  3. The email is looked up in Cosmos DB to find the matching admin user document
  4. If not found → 1401 "Not found any industries or user with the given organization account"
  5. JWT claims are built:
    {
    "userId": "...",
    "email": "admin@company.com",
    "username": "Admin User",
    "loginType": "microsoft",
    "tid": "<tenant_id>",
    "role": "admin",
    "industryId": "INTERNAL"
    }
  6. SessionTimeoutUtil.get_access_token_expiry(internal_industry) determines token lifetime from the INTERNAL industry's sessionTimeout config
  7. Refresh token expiry is calculated via get_refresh_token_expiry(internal_industry, False)
  8. 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"
}
StatusCause
200Login successful
1401No admin user found for the Azure AD account
1403Authorization or tid header missing
1404tid 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:

info
  1. get_jwt_identity() extracts industryId from the refresh token
  2. get_jwt() extracts all claims (userId, email, username, loginType, role)
  3. New access token issued via create_access_token() with INTERNAL industry expiry
  4. 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.
  5. AdminLoginDataFormatter.format_admin_data() shapes the response
StatusCause
200New access_token (and optionally renewed refresh_token) returned
422An access token was passed instead of a refresh token

Automated Reports

info

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
ParameterRequiredDefaultDescription
targetIndustryIdYes (query)Industry to generate for
dateYesDD/MM/YYYY — report date
typesYesdaily or monthly
formatsNopdf, xlsxOutput formats — must be repeated params, not comma-separated
testNofalseIf true, generates reports but skips email delivery. Log entry still written.
emailsNoExtra recipient addresses — repeat param for multiple
warning

Critical: formats must use repeated params:

# Correct
?formats=pdf&formats=xlsx

# Wrong — will not work
?formats=pdf,xlsx

How it works:

info
  1. AdminAutomatedReportService(args).process() is called
  2. For daily: generates a water consumption report and a daily summary report (with rain water if enabled), then sends one email per report type
  3. 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
  4. Each report is generated entirely in-memory (BytesIO) using xhtml2pdf or xlsxwriter
  5. Email sent via Gmail API from reports.aquagen@fluxgentech.com
  6. Recipients: projectsupport@fluxgentech.com + any emails param values + (unless test=true) meta.reports.emailIds from the industry document

Monthly service flags — each checked against the industry's meta.reports.services config:

ServiceFlag key
Consumptionis_consumption_enabled
Rain wateris_rain_water_enabled
Stock / tank levelis_stock_enabled
Groundwateris_groundwater_enabled
Summaryis_summary_enabled
Energyis_energy_enabled
Qualityis_quality_enabled
Executive summaryis_executive_enabled

Services whose flag evaluates to false are silently skipped.

StatusCause
200{ "message": "Automated Monthly Report Sent Successfully", "status": "Success" }
400Invalid types value
1403targetIndustryId 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:

info

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"
}
StatusCause
200Workspace 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>
ParameterRequiredFormat
dateYesdd/mm/yyyy

How it works:

info
  1. AdminOfflineDevicesService(args).get_offline_devices() fetches all units and their latest timestamps
  2. 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
  3. 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
}
StatusCause
200List of offline devices
404No 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>
ParameterRequiredFormat
dateYesdd/mm/yyyy1403 if missing

How it works:

info

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"
}
StatusCause
200Industries with interpolation gaps
1403date 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.

warning

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:

FieldDescription
sourceSource system or service that generated the log
titleShort display title
descFull description of the event
groupLog 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.

StatusCause
200Log entry created
1403Required 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>
ParameterRequiredDescription
industryIdNoFilter to a specific industry
unitIdNoFilter to a specific unit
dateNodd/mm/yyyy — filter by day
monthNomm/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.

StatusCause
200Array 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>
ParameterRequiredValid valuesDescription
idYesLog entry ID — 1403 if missing
ownerNoAssignee name or user ID
priorityNoPriorityType enumPriority level
statusNoStatusType enumStatus update
dateNodd/mm/yyyyUpdated date
monthNomm/yyyyUpdated month
metaNoAdditional metadata object
sourceNoUpdated source label
titleNoUpdated title

GlobalLogsDataService(args).update_log_data() performs a partial update on the log document.

StatusCause
200Log entry updated
1403id 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>
ParameterRequiredFormatDescription
dateYesDD_MM_YYYY (underscores, not slashes)Date to fetch insights for — 1403 if missing

How it works:

info

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"
}
StatusCause
200Insights data for the date
1403date 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:

info

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.

StatusCause
200Insights generated and stored
500Internal processing error
1430Validation 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/ParamRequiredFormatDescription
targetIndustryIdYes (header)Industry to archive — 1403 if missing
fromMonthYearYes07/2024Start month/year — 1403 if missing
toMonthYearNo07/2024End month/year (defaults to fromMonthYear if omitted)
deleteDataNotrue/falseIf true, removes data from Cosmos DB after archiving. Default: false

How it works:

info

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.

warning

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.

StatusCause
200Data archived to blob
400Invalid date range or archiving error
404No data found for the range
1403targetIndustryId 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/ParamRequiredFormatDescription
targetIndustryIdYes (header)Industry to restore — 1403 if missing
monthYes (header)08Month number (zero-padded, 01–12) — 1403 if missing
yearYes (header)20244-digit year — 1403 if missing
deleteBlobNotrue/falseIf true, removes the blob file after restoring. Default: false

How it works:

info

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.

warning

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.

StatusCause
200Data restored to Cosmos DB
400Invalid month/year or restore error
404No archived data found for month
1403Required 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 paramRequiredDescription
titleYesNotification title text
bodyYesNotification body text

How it works:

info

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.

note

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.

StatusCause
200{ "message": "Notification sent successfully", "status": "success" }
400WebSocket 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>
ParameterRequiredDescription
groupIdYesGChatGroupId enum value — identifies the Chat space
dateYesDD/MM/YYYY

How it works:

info
  1. BatchProcessingValidator().validate(date) checks all industries for missing processed_data entries on the given date
  2. Result is sent to the specified Chat group via GChatsService().send_custom_message()
  3. The same result is returned in the HTTP response
note

The validation result is sent to the specified Google Chat group in addition to being returned in the HTTP response.

StatusCause
200Validation complete, result sent to GChat
400Validation 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>
ParameterRequiredDescription
groupIdYesGChatGroupId enum value

ReverseFlowValidator().validate() scans recent readings for negative flow values.

StatusCause
200Report sent to GChat
400GChat 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.

StatusCause
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.

note

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.

ParameterRequiredDescription
unitsListYes (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.

StatusCause
200{ "message": "Reset signal sent", "status": "Success" }
400Failed to send reset message to IoT Hub
1403unitsList 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>
ParameterRequiredDescription
messageYesMessage text
groupIdYesGChatGroupId enum value — identifies which Chat space to send to

GChatsService().send_normal_message(message, GChatGroupId(groupId)) posts to the Chat webhook.

StatusCause
200{ "message": "Message sent successfully", "status": "success" }
400GChat 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": { ... }
}
ParameterRequiredDescription
groupIdYesGChatGroupId 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.

StatusCause
200Message sent
400GChat 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.

StatusCause
200Test event pushed to EventHub
500EventHub 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>
ParameterRequiredDescription
sourceYesSource system identifier (e.g. scheduler)
purposeYesPurpose string (e.g. shift_batch_trigger)

How it works:

info
  1. 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 shift startAt boundary
  2. Matching industries are returned and an EventHub trigger event is pushed for each
StatusCause
200List of industries with recent shift starts
500EventHub or query error

Batch Processing Trigger

info

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
ParameterRequiredDescription
industryIdYesTarget industry ID
timeYesISO 8601 UTC datetime string for the batch window
sourceYesTrigger source identifier (e.g. manual, scheduler)
purposeYesPurpose label (e.g. manual_trigger, daily_batch)

How it works:

info

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.

note

This endpoint does not require a JWT. It is intended for use by the batch scheduling system and internal automation.

StatusCause
200Trigger pushed to EventHub
500EventHub 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 / HeaderRequiredDefaultDescription
targetIndustryIdYes (header)Industry — 1403 if missing
filesYes (multipart)Raw sonar depth data CSV
unitIdYesLake/reservoir unit ID
dateYesSurvey date — DD/MM/YYYY
confidenceThresholdNo100Filter readings below this confidence score
distanceThresholdMetersMinNo0.1Minimum inter-point distance (meters)
distanceThresholdMetersMaxNo0.5Maximum inter-point distance (meters)
depthSimilarityRatioNo0.95Ratio threshold for deduplication
includeAllDataNofalseSkip confidence filtering
includeIntermediateNofalseReturn intermediate processing results in response
compressedOnlyNofalseReturn only the compressed result set

How it works:

info
  1. CSV parsed and point cloud deduplicated based on depthSimilarityRatio
  2. Readings filtered by confidenceThreshold (unless includeAllData=true)
  3. Distance thresholds remove points that are too close or too far apart
  4. Processed data saved to Cosmos DB as a BATHY_DATA document for the unit and date
  5. Static volume-area-elevation curve computed from the processed point cloud and stored
StatusCause
200Processing statistics returned (and optionally intermediate results)
400File parse error or invalid params
1403targetIndustryId, 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 / HeaderRequiredDescription
targetIndustryIdYes (header)Industry — 1403 if missing
unitIdYesUnit 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.

StatusCause
200Returns the recomputed survey dates
400No existing data to recompute from
1403targetIndustryId 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 / HeaderRequiredDefaultDescription
targetIndustryIdYes (header)Industry
unitIdYesReservoir unit ID
startDateNodd/mm/yyyy — start of processing window
endDateNodd/mm/yyyy — end of processing window
chlorophyllEnabledNofalseEnable chlorophyll-a concentration estimation
spacingNo10Pixel sampling interval
cloudCoverThresholdNo70Maximum cloud cover % — images above this threshold are skipped

How it works:

info

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", "..."]
}
StatusCause
200Returns { "summary": {...}, "processedDates": [...] }
500Satellite 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>
ParameterRequiredDefaultDescription
dateYesMM/YYYY — month to verify
excludeDatesNo (repeat)DD/MM/YYYY dates to skip — repeat param for multiple
runBatchProcessingNofalseIf true, automatically triggers batch processing for days with missing processed_data

How it works:

info
  1. Each day in the month is checked (excluding excludeDates) for the presence of processed_data entries
  2. Days with gaps are collected into a summary
  3. If runBatchProcessing=true, a batch trigger is fired for each gap day
StatusCause
200Verification results with gap summary
400Invalid 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:

info
  1. AdminWaterBalanceFormulaService().generate_and_store() loads the water balance graph from the additional_feature container
  2. If no graph is configured → 404 "No water balance graph configured for this industry"
  3. Traverses the graph to identify inflow nodes, outflow nodes, and storage nodes for each subgraph
  4. Generates a formula document per subgraph and stores it in the additional_feature container with type: "waterBalanceLeakageFormula"
StatusCause
200Formula generated and stored — returns the formula data
404No 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>
ParameterRequiredDefaultDescription
ignoreGraphWithNoFormulaNotrueIf true, subgraphs without a formula are excluded from the response

AdminWaterBalanceFormulaService().get_stored(ignoreGraphWithNoFormula) fetches the stored formula document from Cosmos DB.

StatusCause
200Returns 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>
ParameterRequiredDescription
date1YesDD/MM/YYYY — evaluation date/period start
typeYesDAY, MONTH, or YEAR
storeToDbNoDefault false — if true, writes evaluation result to Cosmos DB

How it works:

info
  1. Loads the leakage formula configured for the industry from the additional_feature container
  2. If no formula configured → 404 "No leakage formula configured"
  3. Fetches inflow and outflow readings for the specified period
  4. Applies the formula: leakage = inflow - outflow - (storage_end - storage_start)
  5. If storeToDb=true, upserts the result into the water balance leakage container
StatusCause
200Leakage evaluation result with percentage and volume
404No 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
HeaderRequired
targetIndustryIdYes

How it works:

info
  1. Loads each unit's hourlyThreshold from the industry's alertsConfig
  2. Fetches the current hour's consumption for each unit
  3. Units exceeding their threshold are collected
  4. 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"
}
StatusCause
200Per-unit check results returned

Status Code Reference

CodeMeaning
200Success
400Bad request / validation error / user limit exceeded
401Unauthorised — invalid or missing admin JWT
404Resource not found
420JWT expired
440Session revoked — token inactive in token_logs
500Internal server error
1401User or industry not found in Cosmos DB
1402Invalid admin credentials
1403Missing required header, parameter, or body field
1404Invalid tenant ID or invalid data
1430JSON schema validation failure