Build an incident reporting system where users submit reports with location, type, photos, and description. Display incidents on a Google Map with colored markers by type and status. Other users can upvote reports with a Me Too button to increase priority. An admin dashboard provides a triage queue for acknowledging, assigning, and resolving reports. Reporter identity is hidden from public views for safety.
Building a Community Incident Reporting System in FlutterFlow
Crowd-sourced incident reporting lets communities flag issues like potholes, graffiti, broken streetlights, or accidents. The key challenges are capturing accurate location data, categorizing reports visually on a map, letting the community validate reports via upvoting, and giving administrators tools to triage and resolve incidents. This tutorial covers each piece with FlutterFlow, Google Maps, Firestore, and Cloud Functions.
Prerequisites
- A FlutterFlow project with Firestore and Firebase Authentication configured
- Google Maps API key configured in FlutterFlow project settings
- Firebase Storage for photo uploads
- Location permissions configured in the FlutterFlow project
Step-by-step guide
Set up the Firestore data model for incidents and upvotes
Set up the Firestore data model for incidents and upvotes
Create an incidents collection with fields: userId (Reference, the reporter), type (String: pothole/graffiti/streetlight/accident/flooding/other), description (String), lat (Double), lng (Double), address (String, reverse geocoded), photoUrls (Array of Strings), status (String: reported/acknowledged/inProgress/resolved), priority (String: low/medium/high, derived from confirmCount), confirmCount (Int, number of Me Too upvotes), assignedDepartment (String, nullable), adminNotes (String, nullable), createdAt (Timestamp), resolvedAt (Timestamp, nullable). Create an incident_confirmations subcollection: incidents/{id}/confirmations with userId (Reference) to track who confirmed. This prevents duplicate upvotes. Add a Firestore composite index on status + createdAt for the admin dashboard query.
Expected result: Firestore has incidents with location, type, status tracking, and a confirmations subcollection for upvote deduplication.
Build the incident submission form with location and photo capture
Build the incident submission form with location and photo capture
Create a ReportIncidentPage. On page load, get the current user's location using FlutterFlow's Get Current Location action and store lat/lng in Page State. Display a mini Google Map centered on the user's location with a draggable marker so they can adjust the exact spot. Below the map, add an incident type selector: a GridView of 6 tappable Container cards, each with an icon and label (Pothole, Graffiti, Streetlight, Accident, Flooding, Other). Selected type gets a blue border. Add a description TextField (multiline, max 500 chars). Add a photo section with FlutterFlowUploadButton supporting multiple images (up to 3). On Submit, create the incidents doc with the location, type, photos, status as reported, confirmCount 0, and the current user's ID. Show a success SnackBar and navigate to the map view.
Expected result: Users can submit incident reports with precise location, categorized type, description, and up to 3 photos.
Display incidents on a Google Map with colored markers by type
Display incidents on a Google Map with colored markers by type
Create an IncidentMapPage with a FlutterFlowGoogleMap filling most of the screen. Query all incidents where status is not resolved (or add a toggle to show resolved). For each incident, add a map marker at lat/lng with a color based on type: red for accident, orange for pothole, yellow for streetlight, blue for flooding, purple for graffiti, grey for other. Tapping a marker shows a BottomSheet with the incident details: type icon and label, description (first 100 chars), photo thumbnail (first photo), status badge (color-coded: grey=reported, blue=acknowledged, yellow=inProgress, green=resolved), confirmCount with a thumbs-up icon, and a View Details button. The View Details button navigates to IncidentDetailPage.
Expected result: The map shows all active incidents as colored markers. Tapping a marker reveals a summary with the option to view full details.
Implement the Me Too upvote system for community confirmation
Implement the Me Too upvote system for community confirmation
On the IncidentDetailPage, below the full incident details (photos, description, map, status), add a Me Too button. Before showing the button, query the confirmations subcollection for a document with the current user's ID. If found, show 'You confirmed this' in grey instead of the button. On button tap, create a confirmation doc in the subcollection with the current userId and timestamp. Increment the incident's confirmCount using FieldValue.increment(1). If confirmCount reaches 5, update priority to medium. If it reaches 15, update priority to high. Display the confirmCount prominently: 'X people confirmed this incident'. A Cloud Function can optionally send a notification to the admin when confirmCount crosses threshold values.
Expected result: Users can upvote incidents they also observe, each user can only vote once, and high vote counts automatically increase incident priority.
Build the admin triage dashboard with status management
Build the admin triage dashboard with status management
Create an AdminDashboardPage (protected by role check on page load). Display a TabBar with tabs: New (status reported), Active (acknowledged or inProgress), and Resolved. Each tab shows a ListView querying incidents by status, ordered by priority desc then createdAt asc (highest priority, oldest first). Each list item shows: type icon, address, description preview, confirmCount badge, and time since reported. Tapping opens the incident with admin controls: a DropDown to change status (acknowledged/inProgress/resolved), a DropDown for assignedDepartment (Roads, Parks, Utilities, Safety), and a TextField for adminNotes. On status change, update the incident doc. When marking resolved, set resolvedAt to now. Importantly, the admin view shows the reporter userId for follow-up, but public views never display reporter identity.
Expected result: Admins can triage incidents by priority, update statuses, assign departments, add notes, and contact reporters while public views stay anonymous.
Complete working example
1FIRESTORE DATA MODEL:2 incidents/{incidentId}3 userId: Reference (users, the reporter)4 type: String (pothole | graffiti | streetlight | accident | flooding | other)5 description: String6 lat: Double7 lng: Double8 address: String (reverse geocoded)9 photoUrls: Array of Strings10 status: String (reported | acknowledged | inProgress | resolved)11 priority: String (low | medium | high)12 confirmCount: Int (default 0)13 assignedDepartment: String (nullable)14 adminNotes: String (nullable)15 createdAt: Timestamp16 resolvedAt: Timestamp (nullable)1718 incidents/{incidentId}/confirmations/{confirmId}19 userId: Reference (users)20 timestamp: Timestamp2122PAGE: ReportIncidentPage23 Column24 FlutterFlowGoogleMap (height: 200, draggable marker at user location)25 Text "What type of incident?" (titleMedium)26 GridView (crossAxisCount: 3, height: 200)27 6x Container cards (icon + label, tappable, blue border when selected)28 Pothole | Graffiti | Streetlight | Accident | Flooding | Other29 TextField (description, multiline, maxLength: 500)30 FlutterFlowUploadButton (multiple, max: 3)31 Button "Submit Report"32 On Tap → Create incidents doc → SnackBar → Navigate map3334PAGE: IncidentMapPage35 Stack36 FlutterFlowGoogleMap (full screen)37 Markers: colored by type, from incidents query38 On Marker Tap → show BottomSheet summary39 FAB (bottom right) → Navigate ReportIncidentPage40 BottomSheet41 Row: type icon + type label + status badge42 Text (description, maxLines: 2)43 Image (first photo, 80x60)44 Row: thumbsUp icon + confirmCount + "people confirmed"45 Button "View Details" → Navigate IncidentDetailPage4647PAGE: AdminDashboardPage48 TabBar: New | Active | Resolved49 Each tab: ListView50 Query: incidents by status, order by priority desc, createdAt asc51 Card52 Row: type icon + Text(address) + Badge(confirmCount)53 Text (description, maxLines: 1)54 Text (time ago, bodySmall)55 On Tap → Incident detail with admin controls56 DropDown (status update)57 DropDown (assign department)58 TextField (admin notes)Common mistakes when creating a Crowd-Sourced Incident Reporting Feature in FlutterFlow
Why it's a problem: Displaying the reporter's name and profile in the public incident view
How to avoid: Show incidents on the map and detail pages without any reporter information. Only the admin dashboard reveals the reporter userId for follow-up purposes.
Why it's a problem: Allowing users to upvote the same incident multiple times
How to avoid: Store each confirmation in a subcollection with the userId. Before showing the Me Too button, check if a confirmation doc already exists for the current user.
Why it's a problem: Not reverse-geocoding the GPS coordinates into a readable address
How to avoid: Use Google Maps Geocoding API in a Custom Action or Cloud Function to convert lat/lng to a human-readable address and store it on the incident document.
Best practices
- Anonymize reporter identity in all public-facing views — only admins should see who reported
- Use Firestore subcollection for confirmations to enforce one-vote-per-user deduplication
- Auto-escalate priority based on confirmCount thresholds (5 = medium, 15 = high)
- Color-code map markers by incident type for instant visual categorization
- Reverse-geocode GPS coordinates to readable addresses for admin usability
- Add photo evidence support (up to 3 images) to give admins visual context for triage
- Sort the admin triage queue by priority descending, then oldest first, to surface urgent issues
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a crowd-sourced incident reporting feature in FlutterFlow. Show me the Firestore data model, incident submission form with location and photos, a map view with colored markers by type, a Me Too upvote system, and an admin triage dashboard.
Create a page with a Google Map filling most of the screen. Add a floating action button in the bottom right corner for reporting new incidents. When a map marker is tapped, show a bottom sheet with an incident type icon, description, photo, confirmation count, and a View Details button.
Frequently asked questions
How accurate is the GPS location on the incident report?
GPS accuracy is typically 3-5 meters on modern smartphones. The draggable map marker lets users fine-tune the exact location if the GPS position is slightly off.
Can I add custom incident types beyond the default six?
Yes. Store incident types in a Firestore collection with name, icon, and color fields. Query this collection to populate the type selector grid dynamically. Admins can add new types without app updates.
How do I prevent spam or false reports?
Require authentication to submit reports. Track reports per user and flag accounts with high volumes. Add a report-as-spam button on incidents so the community can self-moderate. Admins can remove false reports and warn repeat offenders.
Can I notify nearby users about new incidents?
Yes. When an incident is created, a Cloud Function can query users within a radius using geohash comparison, then send push notifications to nearby users about the new report.
How do I generate analytics on incident patterns?
Query incidents grouped by type and time period in a Cloud Function. Display results on an admin analytics page with charts showing most common incident types, average resolution time, and geographic hotspots.
What if I need a full civic reporting platform with department routing?
RapidDev has built city-scale incident reporting systems in FlutterFlow with automated department routing, SLA tracking, public transparency dashboards, and integration with municipal work order systems.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation