NorthReport

Inspiration

Urban safety reporting is broken. Residents see hazards every day — potholes, broken streetlights, flooding, unsafe crosswalks — but filing a 311 report feels like shouting into the void. There's no feedback, no community visibility, and no way to know if your neighbors are seeing the same thing. Meanwhile, city officials lack real-time ground truth about what's actually happening in neighborhoods.

We were inspired by the way platforms like Snapchat and Reddit keep communities engaged — ephemeral stories, persistent threads, upvotes that surface what matters most. We asked: what if that same engagement model powered civic infrastructure? What if reporting a pothole was as easy as posting a story, and the most critical issues automatically rose to the top?

NorthReport was born from the belief that the people closest to the problem are the best sensors a city has. We set out to build a platform that treats every resident as a contributor to neighborhood intelligence — and uses AI to turn that raw signal into action.

What it does

NorthReport is a feed-first, AI-powered neighborhood safety platform that transforms community reports into actionable intelligence for the City of Waterloo, Ontario.

Community Feed (Voices from the Ground)

  • Residents post what they see in two formats:
    • Stories — 24-hour ephemeral content (Snapchat-style), perfect for "heads up, there's flooding on King St right now"
    • Posts — persistent, Reddit-style threads with comments, upvotes, and reposts for ongoing issues
  • A momentum + risk ranking algorithm ensures the most urgent and trending items surface first:
    • feedScore = momentum × 0.6 + risk × 0.4
    • Momentum factors in recency (12-hour half-life decay) and engagement (upvotes, comments, reposts)
    • Risk factors in AI-classified severity and corroboration from multiple reporters
  • Users can upvote, comment, repost, and flag content
  • Any voice post can be converted into a structured hazard report with one tap — Gemini analyzes the content and generates a formal report

Smart Report Agent

  • A camera-first reporting flow: snap a photo, and Gemini 2.0 Flash automatically classifies the hazard (category, subcategory, severity), generates a description, and analyzes the image for specific findings
  • Supports voice-guided reporting — users can refine descriptions by speaking naturally
  • Categories include infrastructure, environmental, safety, and accessibility issues

Voice-First Interface

  • "Hey NorthReport" wake phrase activates hands-free interaction via the Web Speech API
  • Gemini classifies voice commands into intents: file a report, take a photo, get educated about a hazard, or submit
  • Responses are spoken back via ElevenLabs text-to-speech (with browser SpeechSynthesis fallback)
  • Keyword-based fallback ensures resilience even when AI classification is slow

City Heatmap (Snap Map-style)

  • A 3D globe visualization powered by the Cobe library shows hotspots of recent community activity
  • Geohash bucketing (6-character precision, ~0.6km grid cells) aggregates reports by location while preserving privacy
  • Tap a hotspot to view the stack of recent stories, posts, and reports from that area
  • Supports deep linking: ?location=downtown flies to a specific neighborhood

AI-Powered Intelligence

  • Report Classification: Every submission is auto-classified by category, subcategory, and severity with an AI-generated summary
  • Pattern Detection: Gemini analyzes 14 days of data to find trends (week-over-week comparison), geographic clusters, and anomalies
  • Feed Explanation: Tap any item for an AI-generated explanation — why it matters, risk level, evidence, and suggested next actions
  • Education Mode: Point your camera at anything and ask "What is this?" — Gemini explains the subject, its community impact, and actionable tips
  • Weekly Digests: AI-generated markdown summaries of neighborhood activity, key issues, trends, and recommended actions

Leader Dashboard

  • Community leaders and city officials get a dedicated dashboard with:
    • Neighborhood Health Gauge — overall, infrastructure, and safety subscores (0–100) with trend direction
    • Pattern Analysis — AI-detected trends, clusters, and anomalies visualized on cards
    • Weekly Digest — auto-generated safety summary
    • Auto-File 311 — one-click filing of critical/high-severity reports to the City of Waterloo's 311 system

Assisted 311 Filing

  • Gemini maps reports to the appropriate city department (Public Works, Waterloo Water, Bylaw Enforcement, Parks, etc.)
  • Generates professional descriptions with Ontario bylaw references (e.g., MMS Reg 239/02 for road maintenance, By-law 10-221 for property standards)
  • Produces a pre-filled 311 form preview that leaders can review and submit
  • Filing status is tracked and visible in the dashboard

Location Privacy

  • All location data is bucketed using 6-character geohashes (~0.6km precision)
  • No exact coordinates appear in feed aggregates
  • Approximate labels like "near Downtown Waterloo" replace precise addresses

How we built it

Frontend

  • Next.js 16 with the App Router for file-based routing and server/client component architecture
  • React 19 with hooks-only state management (no global store)
  • Tailwind CSS 4 with a custom dark glassmorphism theme for a modern, polished UI
  • Framer Motion for smooth animations on feed cards, drawer reveals, and page transitions
  • Leaflet + React-Leaflet and Mapbox GL for interactive 2D maps; Cobe for the 3D globe visualization
  • html2canvas + jsPDF for generating downloadable report PDFs

Backend

  • Next.js API Routes (App Router) — 40+ RESTful endpoints returning Response.json() with standardized error handling
  • Firebase Admin SDK with Firestore as the sole database — collections for users, voices, reports, neighborhoods, patterns, filed 311 reports, comments, votes, and reposts
  • Auth0 v4 for authentication with a proxy middleware (proxy.ts) handling CSP headers and route protection
  • In-memory rate limiting at 50 requests/minute per user per action (no Redis dependency)

AI Layer

  • Google Gemini 2.0 Flash (@google/generative-ai) for all AI tasks — chosen for its speed, multimodal capabilities (text + image), and structured JSON output
  • Retry logic with aggressive JSON cleanup to handle markdown fence artifacts in Gemini responses
  • 10 distinct AI prompt templates: report classification, voice classification, voice-to-report conversion, pattern detection, digest generation, voice command routing, camera command routing, feed explanation, education, and 311 form generation

Voice System

  • Web Speech API for wake phrase detection and speech-to-text
  • ElevenLabs API (eleven_turbo_v2_5 model) for natural text-to-speech responses
  • Browser SpeechSynthesis as a fallback TTS engine
  • Wake phrase patterns handle variations: "hey north report", "northreport", "hey north reports"

Data & Location

  • Firestore stores all data including base64-encoded images (no separate Cloud Storage)
  • ngeohash library for geohash encoding
  • Turf.js for geospatial calculations
  • Client-side filtering for hidden items (avoids Firestore composite index limitations)

Seeding & Testing

  • npm run seed script populates Firestore with Waterloo-specific test data: neighborhoods, users, voices, and reports across multiple severity levels
  • /mock-311 page simulates the City of Waterloo's 311 portal for end-to-end testing

Challenges we ran into

  • Gemini JSON parsing: Gemini occasionally wraps structured JSON output in markdown code fences or includes trailing artifacts. We built aggressive cleanup logic — stripping fences, extracting JSON from mixed responses, and implementing retry logic to handle intermittent formatting issues.

  • Real-time feed ranking: Balancing momentum (what's trending) with risk (what's dangerous) required careful tuning. A viral post about a funny pothole shouldn't outrank a critical report about a gas leak. We landed on a 60/40 momentum-to-risk split with a 12-hour half-life decay that keeps the feed fresh without burying urgent items.

  • Location privacy vs. utility: Showing exact GPS coordinates is a privacy risk, but vague locations make reports useless. The 6-character geohash (~0.6km grid) was our sweet spot — precise enough for city workers to locate issues, approximate enough to protect reporters.

  • Voice command reliability: The Web Speech API's accuracy varies wildly across browsers and accents. We implemented a keyword-based fallback classifier that catches common intents even when Gemini classification fails or is too slow.

  • Firestore limitations: No native full-text search, limited composite indexes, and query constraints (no inequality filters on multiple fields) forced us to do more filtering client-side and design our data model carefully around Firestore's strengths.

  • Auth0 + Next.js 16 integration: Auth0's v4 SDK with Next.js App Router required a custom proxy middleware approach to handle route protection, CSP headers, and automatic user document creation on first login.

  • Image storage: Storing base64-encoded images directly in Firestore documents approaches the 1MB document size limit. We carefully manage image sizes and compression to stay within bounds.

  • Map SSR issues: Leaflet and Mapbox GL don't support server-side rendering. We implemented dynamic imports with SSR disabled and careful loading states to avoid hydration mismatches.

Accomplishments that we're proud of

  • Voice-first civic engagement: "Hey NorthReport" turns hazard reporting into a hands-free, 10-second interaction. A resident walking past a broken sidewalk can file a report without stopping or pulling out their phone to type.

  • AI that actually helps: Gemini doesn't just classify — it explains why something matters, detects patterns humans would miss (week-over-week trend spikes, geographic clusters), and generates professional 311 descriptions with Ontario bylaw references. The AI is a force multiplier, not a gimmick.

  • Feed ranking that surfaces what matters: The momentum + risk algorithm ensures that a critical infrastructure failure gets visibility even with few upvotes, while community-validated issues gain momentum through engagement. The feed feels alive and responsive.

  • End-to-end 311 pipeline: From a resident snapping a photo to a leader auto-filing a 311 report with the correct city department, bylaw reference, and professional description — the entire pipeline is AI-assisted and takes minutes instead of the typical bureaucratic runaround.

  • Privacy-first location design: The geohash bucketing system protects reporter privacy while giving city workers enough precision to act. No exact home addresses ever appear in the feed.

  • 40+ API endpoints: A comprehensive, well-structured API layer with consistent error handling, rate limiting, and role-based access control — all built on Next.js API routes without a separate backend server.

  • Pattern detection that finds real insights: The AI analyzes 14 days of community data and surfaces trends ("pothole reports up 200% this week"), clusters ("3 water main issues within 0.6km"), and anomalies that leaders can act on immediately.

  • Dual content model: Stories for ephemeral "right now" updates and Posts for persistent community threads — with seamless conversion to structured reports. This mirrors how people actually communicate about their neighborhoods.

  • The landing page experience: A 3D globe flythrough that zooms into Waterloo, setting the stage for a platform that's global in ambition but hyper-local in execution.

What we learned

  • AI output is unpredictable: Even with structured JSON prompts, Gemini's output format varies between calls. Building robust parsing with fallbacks is essential — never trust that AI will return clean JSON every time.

  • Civic tech needs engagement loops: The biggest challenge in civic platforms isn't technology — it's getting people to use them. Borrowing engagement mechanics from social media (upvotes, stories, feeds) makes civic participation feel natural rather than bureaucratic.

  • Privacy and utility are in constant tension: Every design decision around location data required balancing "how useful is this for the city?" against "could this identify or endanger the reporter?" The geohash approach was a hard-won compromise.

  • Voice interfaces need graceful degradation: The Web Speech API is powerful but unreliable. Every voice feature needs a manual fallback, and every AI classification needs a keyword-based backup. Users shouldn't notice when the AI fails.

  • Firestore is great until it isn't: Firestore's real-time capabilities and simple API are fantastic for rapid development, but its query limitations (no joins, limited compound queries, 1MB document limit) require creative workarounds and careful data modeling.

  • Feed algorithms are political: Deciding what content rises to the top is a values decision, not just a technical one. We learned to be intentional about weighting risk alongside popularity — a feed that only shows popular content fails its civic mission.

  • Multimodal AI unlocks new UX patterns: Gemini's ability to analyze images + text together enabled features we couldn't have built otherwise — the education mode ("point your camera and ask"), image-based report classification, and visual hazard detection.

  • Role-based access matters from day one: Building separate resident and leader experiences early (not as an afterthought) shaped the entire architecture for the better. Leaders need dashboards and filing tools; residents need a fast, social feed.

What's next for NorthReport

  • Real-time push notifications: Alert residents when a report in their neighborhood is acknowledged or resolved, and notify leaders when a critical issue is filed.

  • Native mobile app: The voice-first, camera-first UX is begging for a native iOS/Android experience with background wake phrase listening and native camera integration.

  • Multi-city expansion: Generalize the 311 integration beyond Waterloo — map city departments, bylaws, and form fields for other Ontario municipalities and beyond.

  • Verified resolution tracking: Close the loop by letting city workers mark issues as resolved, with before/after photos that the community can verify.

  • Community reputation system: Reward consistent, accurate reporters with reputation scores that boost their content's visibility and credibility.

  • Offline-first reporting: Allow residents to file reports without connectivity, syncing automatically when back online — critical for infrastructure failures that may knock out local networks.

  • Multilingual support: Waterloo is a diverse, multicultural city. Adding multilingual voice commands and AI summaries (starting with French, Mandarin, and Arabic) would dramatically expand accessibility.

  • Integration with city GIS systems: Overlay NorthReport data on municipal GIS layers (water mains, road maintenance schedules, utility grids) to give leaders richer context for decision-making.

  • Predictive analytics: Use historical pattern data to predict where issues are likely to occur — e.g., which intersections flood after heavy rain, which neighborhoods see seasonal pothole spikes.

  • Open data API: Publish anonymized, aggregated neighborhood safety data as an open API for researchers, journalists, and other civic tech projects to build on.


Sponsor Technologies

Reactiv — NFC-Powered App Clip for Instant Reporting

We built an App Clip experience powered by Reactiv that lets residents tap an NFC tag placed at a known problem location (e.g., a bus stop, intersection, or park entrance) to instantly open NorthReport's report flow — no app install required. The NFC tag encodes a deep link with location metadata, so when a resident taps their iPhone against it, the App Clip launches directly into the Smart Report Agent with the location pre-filled. This removes the two biggest friction points in civic reporting: downloading an app and manually entering an address. City workers can deploy NFC tags at hotspots identified by NorthReport's pattern detection, creating a physical-digital feedback loop where AI-detected problem areas get physical reporting infrastructure.

ElevenLabs — Natural Voice Responses

NorthReport's voice-first interface uses ElevenLabs' eleven_turbo_v2_5 model for text-to-speech responses. When a user says "Hey NorthReport" and files a report by voice, the AI's responses are spoken back using ElevenLabs' natural-sounding voices rather than robotic browser speech synthesis. This is critical for accessibility and hands-free use — a resident walking past a broken sidewalk can have a full conversational interaction without looking at their screen. We use the ElevenLabs streaming API (/v1/text-to-speech/{voice_id}) through a server-side proxy (/api/tts) to keep API keys secure, with automatic fallback to the browser's built-in SpeechSynthesis API when ElevenLabs is unavailable or when latency matters more than voice quality.

Gemini API — The AI Brain Behind Everything

Google Gemini 2.0 Flash is the core intelligence layer powering every AI feature in NorthReport. We chose it for three reasons: speed (Flash variant for real-time interactions), multimodal capability (text + image analysis in a single call), and structured JSON output mode. Gemini powers 10 distinct AI workflows:

  1. Report Classification — Analyzes photos + descriptions to classify hazards by category, subcategory, and severity
  2. Voice Command Routing — Classifies spoken commands into intents (report, photo, educate, submit)
  3. Voice-to-Report Conversion — Transforms natural language voice posts into structured hazard reports
  4. Pattern Detection — Analyzes 14 days of community data to find week-over-week trends, geographic clusters, and anomalies
  5. Weekly Digest Generation — Produces markdown neighborhood safety summaries
  6. Feed Explanation — Generates on-demand explanations for why a report matters, with risk context and suggested actions
  7. Education Mode — "Point your camera and ask" — Gemini explains what you're looking at and its community impact
  8. 311 Form Generation — Maps reports to the correct city department, cites relevant Ontario bylaws (e.g., MMS Reg 239/02), and generates professional descriptions
  9. Camera Command Routing — Classifies camera-based interactions into the right workflow
  10. Image Analysis — Extracts specific findings from uploaded hazard photos (crack measurements, debris types, damage extent)

We implemented retry logic with aggressive JSON cleanup (stripping markdown fences, extracting JSON from mixed responses) to handle Gemini's occasional formatting quirks in production.

Google Antigravity — Agentic Development at Scale

Antigravity was our primary development environment for the entire project, and its impact on our velocity was massive. Here's how we leveraged it:

Agentic Workflow Architecture: Rather than using Antigravity as a simple code autocomplete, we treated it as an agentic development partner. We structured our prompts as detailed specifications — describing entire component architectures, scroll animation sequences, and API endpoint contracts — and let Antigravity plan, implement, and verify autonomously. For example, the entire Mapbox scrollytelling landing page (camera keyframes, dot stagger system, phone mockup with screen transitions, finale overlay) was built through a single agentic session that planned the 4-layer scroll architecture, wrote 500+ lines of coordinated React/Framer Motion code, and verified it in the browser.

Multi-Agent Parallelism: Antigravity's ability to run browser subagents alongside code generation was critical. While making code changes, we had Antigravity simultaneously launch browser agents to verify scroll animations, capture screenshots, and test responsive layouts — all within the same workflow. This meant we caught visual regressions immediately rather than in a separate manual QA cycle.

Skill-Based Prompting: We leveraged Antigravity's skill system to create reusable development patterns. Complex operations like "build a scroll-driven animation with Framer Motion useScroll + useTransform + useSpring in a 400vh container with 4 progression layers" became repeatable patterns that Antigravity could execute with minimal token overhead. Instead of re-explaining the same animation framework every time, we referenced established patterns and focused tokens on what was different about each new component.

Context-Efficient Token Management: With 40+ API endpoints, 30+ React components, and multiple animation systems, context management was essential. We structured conversations around focused tasks (one component at a time), used Antigravity's knowledge item system to persist architectural decisions across sessions, and minimized redundant file reads by leveraging the codebase search and outline tools before making edits. This let us work on a large Next.js codebase without hitting context limits or losing coherence across sessions.

Verification-Driven Development: Every major feature went through Antigravity's PLANNING → EXECUTION → VERIFICATION cycle. After implementing a component, Antigravity would start a dev server, open a browser, scroll through the page, capture screenshots, and report back with visual confirmation — turning what would normally be a manual 5-minute test into an automated 30-second check. This was especially valuable for scroll-driven animations where visual verification is the only meaningful test.

Auth0 — Authentication & Route Protection

We use Auth0 v4 SDK (@auth0/nextjs-auth0) with a custom proxy middleware architecture for authentication. Instead of the traditional /api/auth/* route pattern, our proxy.ts intercepts requests at /auth/* and delegates to Auth0's middleware — handling login, logout, callback, and session management. The proxy also applies Content Security Policy headers with dynamic nonces, restricts frame-src and connect-src to Auth0 domains, and protects app routes (/feed, /map, /dashboard, /report) from unauthenticated access. On first login, a server-side hook automatically creates a user document in Firestore with the Auth0 profile data (name, email, picture, neighborhood preferences), so the app is immediately personalized. The useUser() hook from Auth0's client SDK powers conditional UI throughout — from "Get Started" vs. "Go to Dashboard" on the landing page to the profile avatar dropdown with logout on the dashboard.

Built With

Share this project:

Updates