Hamilton Rain Event Tracker - Documentation
1. Project Overview
The Hamilton Rain Event Tracker is a web application designed to automate the process of fetching, analyzing, and reporting on rainfall events within the City of Hamilton. It aggregates data from multiple sources, correlates it with specific storm water pond assets, generates rules-based summaries and advice, and produces professional PDF and CSV reports for operational use.
The primary goal is to save time and provide actionable insights for storm water management and maintenance crews.
2. Architecture & Technology Stack
The application is built on a modern, server-centric web stack:
3. Program Flow (End-to-End)
The core workflow of the application is orchestrated from the client-side Dashboard component.
1. **User Selects Date:** The user picks a date from the calendar on the main dashboard (src/components/dashboard.tsx).
2. **Initiate Analysis:** The user clicks the "Start Analysis" button. This triggers the handleAnalysis function in dashboard.tsx.
3. **Client-Side Orchestration:** The handleAnalysis function acts as the central orchestrator. It makes a series of await-ed calls to the server to fetch data in stages, updating the UI's progress bar after each step.
4. **Data Fetching (Staged):**
- The handleAnalysis function sequentially calls the getHistoricalAnalysis server function (src/ai/flows/historical-analysis-flow.ts) for each weather agency ("Open-Meteo", "Environment Canada", and "Weather Underground").
- **Open-Meteo & Environment Canada:** The function uses the getHourlyRainfallForGauges helper in src/lib/weather-api.ts to make a single, efficient batch API call for all gauges from that source.
- **Weather Underground:** For "Weather Underground", the getHistoricalAnalysis function iterates through the list of WU gauges sequentially. For each gauge, it awaits the result of the getHourlyRainfallFromWunderground function (src/lib/weather-underground-scraper.ts), which performs the web scraping. This sequential approach ensures robust data collection and returns precise start/stop times.
5. **Data Correlation:** After all data is fetched and returned to the client, handleAnalysis calls getPondReportForDate (src/lib/data.ts). This function correlates the raw rainfall numbers with the list of storm water ponds, calculating the highest rainfall recorded for each asset.
6. **Event Magnitude & QA Analysis:** The client then calls getEventMagnitude from src/lib/data.ts. This crucial function:
- Calculates storm magnitude for each primary (OM) gauge against both **historical** and **projected (2050)** IDF curves.
- Determines the event's **overall peak magnitude** (highest value from any gauge) and **predominant magnitude** (median value).
- Performs a **variance analysis** by comparing rainfall totals between paired primary (OM) and secondary (WU) gauges, flagging significant outliers.
7. **Rules-Based Analysis:** With the correlated data and magnitude analysis, handleAnalysis calls the generateRuleBasedSummary function from src/lib/data.ts. This function uses a deterministic set of rules to generate a professional synopsis and actionable advice, with specific logic to be skeptical of data from flagged outliers.
8. **UI Update:** The dashboard state is updated with all the fetched data, pond reports, and the generated summary. The results are displayed to the user in the various tables, charts, and cards.
9. **Report Generation (User-Triggered):**
- If the rainfall threshold is met, the user is prompted for a Memo ID.
- The user can click to export a PDF or CSV. This calls the handleExport function.
- For PDFs, generatePdfReport uses the jspdf and jspdf-autotable libraries to construct a multi-page report. This includes the city logo, an event summary page with high-level statistics, the generated analysis, a detailed list of triggered ponds, and QA/QC tables.
- For CSVs, helper functions generate a CSV string of the triggered ponds, raw hourly data, or logs, which is then downloaded by the browser.
4. Managing Hard-Coded Data
A key aspect of maintaining this application is keeping its core datasets up-to-date. This data is intentionally hard-coded in src/lib/data.ts for simplicity and performance but requires manual updates.
csvData:** A multi-line string variable containing the master list of all storm water ponds. To update, add, or remove a pond, you must edit this string directly, following the existing CSV format. - **Columns:** Facility Number, SWMF ID, Facility Type, Ownership, Operational Maintenance, Municipal Address, Community, Latitude, Longitude, Associated Rain Gauge.lookupValue.
- The Associated Rain Gauge.lookupValue is crucial, as it links the pond to its primary Open-Meteo rain gauge.
rainGauges:** An array of RainGauge objects. This contains the definitive list of all rain gauges the system can query, including their location, agency, and web address (for WU stations). To add a new gauge, simply add a new object to this array.gaugeMap:** A key-value object that maps an Open-Meteo gauge (primary) to a corresponding Weather Underground gauge (secondary) for QA/QC comparison. - **To update:** If you add a new OM/WU pair, create a new entry in this map. The key is the title of the Open-Meteo gauge, and the value is the title of the Weather Underground gauge.
projectedIdfCurve and historicalIdfCurve objects contain the Intensity-Duration-Frequency data used for storm magnitude calculations. These should be updated if new climate data becomes available.