Inspiration
Water leaks and other service problems are easier to address when people can describe what they saw, include a location and photo, and follow up later. CitizenWater was shaped around that simple citizen-led journey, with offline use in mind.
What it does
- Captures or selects a photo, requests device location, and matches the location to the nearest contact in a small, clearly labeled sample utility directory.
- Saves report details and the photo in browser IndexedDB so pending reports remain available on that device, including offline.
- When the citizen chooses Open email draft, the Express server stores a shared copy in Supabase and returns a private link that expires after 30 days. Photo access uses a short-lived signed URL.
- Opens the citizen's email app with a prefilled draft. The citizen reviews and sends it; CitizenWater does not send or verify email.
- Lets the citizen record whether the issue remains open or is fixed. This is citizen follow-up, not independent confirmation from the utility.
The app does not require an account. Reports saved locally are specific to that browser and device. The utility directory contains limited sample data; it is not worldwide or verified service-area coverage.
How we built it
The user interface is built with HTML, CSS, and browser JavaScript. IndexedDB keeps reports and photo files on the device. A Node.js 24 and Express server connects to Supabase Postgres and a private Storage bucket when the citizen requests a share link. The PWA manifest and service worker support installation and cache the public app shell. Email uses a prefilled mailto draft in the citizen's email app; there is no paid AI or email-provider API.
Challenges we ran into
Getting a photo from the browser to the server and then into a private Supabase bucket required checking each step separately. We resolved a bucket-name mismatch and a browser photo-read issue during development. We also had to make offline status honest: reconnecting cannot send an email, and opening a draft cannot prove it was sent. Camera and location testing on phones also requires HTTPS and browser permissions.
Accomplishments that we're proud of
The main journey now works from writing a report through private photo sharing and later follow-up. The learner confirmed that the private report/photo link worked, that closing a draft leaves the report pending, and that offline pending reports remain saved until the citizen reviews them. Fixed reports can be archived, and the PWA can be installed on supported phone browsers.
What we learned
Local browser storage and cloud storage solve different problems: IndexedDB keeps a report available on one device, while Supabase provides the shared report link. A service-role key must stay on the server. A mailto draft hands control to the citizen's email app, so CitizenWater cannot know whether a message was sent or delivered. Testing the actual browser, phone, and hosting environment helped uncover setup issues that were not visible from the code alone.
What's next for CitizenWater
The next steps are to verify location behavior in the remaining target browser, expand the utility directory with confirmed contacts and service areas, and add production safeguards such as automatic cleanup of expired cloud photos and reports, monitoring, and stronger abuse controls. Utility acknowledgements and repair verification would require a separate utility-facing workflow.
Built With
- css
- express.js
- github
- html
- indexeddb
- javascript
- node.js
- nominatim
- openstreetmap
- pwa
- render
- rest
- supabase
- supabasepostgres
Log in or sign up for Devpost to join the conversation.