AWS Builder Center
Will my street flood? Building a street-level flood guide for India on AWS

Will my street flood? Building a street-level flood guide for India on AWS

District flood warnings do not tell you about your own street. Vellam does: one level for any street in India for the next 48 hours, the reasons behind it, and what to do. How we built it on Lambda, DynamoDB, SNS and SAM with rules instead of a model, and the four things our own replays and tests showed we had wrong.



Flood warnings in India are issued for a district. Floods happen street by street.
I live in Chennai. In December 2015, and again in December 2023, large parts of the city went under water, and many of the same streets flooded both times. Each time the warning said something like "heavy rain likely over Chennai district". That is true and almost useless. It does not tell you whether your own street will flood, when, or whether to move the bike tonight.

For Environmental Hacks, the second event of the WeMakeDevs x AWS Bharat Builds Tour, our team DoodleByte built Vellam to answer that one question. Vellam is the Tamil word for flood.

What it does

You search for any place in India, use your location, or tap a spot on the map. Vellam gives one of four levels (Low, Watch, High, Severe) for each six hours of the next 48, and then three things a district warning never gives you:
  1. Why. Every fact behind the level, labelled by where it came from: the forecast, the terrain, the map, the 2015 flood record, the reservoir bulletin, or a neighbour's report.
  1. What to do. Steps for that level, with helplines, in English and twelve Indian languages.
  1. Whether to trust it. For any spot, the last 30 days of day-ahead forecasts beside the rain that actually fell.

It also shows your street in 3D with real ground heights and a slider that raises the water, suggests higher roads to move a vehicle to, takes reports of water from neighbours, and emails you when your street is at risk.


The decision I am most glad we made: rules, not a model

It was tempting to hand the forecast to a language model and ask "will this street flood?". We did not, for one reason: a wrong "Low" is the one failure this product cannot afford, and nobody can check a model's reasoning at two in the morning.
So fixed rules set every level. The India Meteorological Department's rain classes (heavy from 64.5 mm in 24 hours, very heavy from 115.6 mm) are combined with what kind of place the street is:
  • Did a street within 60 metres flood in 2015?
  • Is there a lake, river or canal within 300 metres?
  • Is the ground low, or lower than the ground around it?
  • Is a reservoir upstream nearly full, or releasing?
The same street and the same forecast always give the same answer, and the answer lists every fact it used. The core of the engine does no input or output at all, which is why its 94 tests run without a network or an AWS account.

A model appears in exactly one place. A neighbour can attach a photo to a report, and a decision model answers two typed questions about it: is this flood water, and how deep. It returns probabilities, and the rules hold those to thresholds. The model never sets a level.

The architecture

Everything runs in ap-south-1 and is defined in one AWS SAM template of 19 resources.

Service
What it does in Vellam
AWS Amplify Hosting
Serves the dashboard
Amazon API Gateway (HTTP API)
The public API, throttled to 2 requests a second
AWS Lambda
Two functions: the API, and a job that reassesses 105 places
Amazon DynamoDB
One on-demand table for terrain, assessments, reports and snapshots
Amazon EventBridge Scheduler
Runs the job every three hours
Amazon SNS
Email alerts, filtered per street
AWS Systems Manager Parameter Store
The one secret
AWS CloudFormation, through SAM
The whole stack
A request goes from the browser to API Gateway to Lambda. The function checks DynamoDB for an assessment made this hour; if there is none it fetches the forecast and the terrain, applies the rules, and keeps the result for the hour. Neighbours' reports are applied after that cache, so a report shows in the answer the moment it is sent.
Three AWS features did real work for us:
  • DynamoDB time-to-live. Reports expire after 48 hours and assessments after an hour. DynamoDB removes them, so we wrote no cleanup job.
  • SNS filter policies. One topic carries both city alerts and per-street alerts. Each subscription filters on a message attribute, so a resident hears about their own street and nobody else's.
  • Parameter Store. The token for the photo check is a SecureString created by hand. It is in no template and no code.
There is no queue and no stream, on purpose. The work is one request at a time and one scheduled job. Adding a broker would have meant running something all day to carry almost nothing.

What went wrong, and what it taught us

This is the part I would most like other builders to read.
Our first thresholds were wrong, and only data showed it. We first counted a street as "flooded in 2015" if a marked street was within 150 metres. When we measured it, that rule said yes to 52% of random points in the city. It was not telling anyone anything. We cut it to 60 metres. The same happened with ground height: the elevation data is a coarse grid that includes rooftops, and it described Velachery, one of the most flooded parts of Chennai, as raised ground.
A replay exposed a hole in the model. We replayed December 2015 through our rules. The historical rain record showed 49 mm for a day when the reservoir's own gauge measured 475 mm, so the replay was nearly dry, and Saidapet, beside the Adyar river, came out as only Watch on the day 29,000 cusecs were released into it. The lesson was that a reservoir release is a hazard of its own: the water arrives down the river from rain that fell somewhere else. A heavy release now sets a floor under the level, whatever the rain at that spot.
Testing on the live system found a bug the tests missed. One report was being read back as two, which let a single anonymous report raise a street to High. The cause was a floating point rounding error in how we searched neighbouring map cells. We only saw it because we sent a real report to the deployed API and looked at the answer.
Good results can be weak evidence. Replaying Cyclone Michaung, Vellam rated 16 of the 17 localities documented as flooded as High or Severe. That sounds strong. But it flagged 62 of 65 localities that day, so a rule that warned everyone would have scored the same. We say so on the site, and we name the one it missed, Perungudi.


What I would tell another builder

  • Write down what your product cannot do. Our README has a section called "Where not to trust it". Writing it changed what we built.
  • Replay the past before you trust the present. Every replay found something.
  • Keep the part that decides free of input and output. It made the rules testable in seconds.
  • New AWS accounts have limits you will only meet at deploy time. We hit the Amplify app limit, blocked Bedrock access and zero GPU quota. Check your quotas on day one, not on the last day.
  • Use AI tools, and say that you did. We used Claude Code as a pair programmer throughout, and ElevenLabs for the demo's voice. The decisions, and the responsibility for what the product tells a resident, stayed with us.

What is next

Outside Chennai, Vellam knows the rain, the ground and the nearby water, but has no flood history. The next step is to add that record for other cities, and to measure the photo check against real, labelled flood photos before it counts for more.
The northeast monsoon starts this month. If you live in a city that floods, look up your street before the first heavy night.
Team DoodleByte: Gowtham K, Jaya Suriya T R, Pranav A S, Kannan K.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article