UBLoop - Campus Safety Alert System

Inspiration

Campus safety is a growing concern at universities across the country. Students often feel isolated when incidents occur, unsure if what they're experiencing is isolated or part of a larger pattern. We wanted to create a platform that empowers the UB community to stay in the loop - a real-time, crowdsourced safety network where students can report incidents, validate threats, and help each other stay safe. The idea came from late-night walks across campus, where we wished we knew what was happening around us in real-time. Traditional campus alert systems are slow and bureaucratic - we needed something instant, community-driven, and accessible from any device.

What it does

UBLoop is a real-time campus safety and lost & found platform designed specifically for the University at Buffalo. Students can:

  • Report Safety Alerts: Click anywhere on an interactive campus map to report suspicious activity, medical emergencies, hazards, or other incidents with exact GPS coordinates. Alerts are color-coded (red for suspicious, orange for medical, yellow for hazards, blue for other)
  • Community Validation: Upvote or downvote alerts to verify legitimacy and prevent false reports (50-vote limit per user)
  • Time-Travel Through Incidents: Use a timeline scrubber to see what's happening now (last 10 minutes) or scroll back to see patterns over the past 72 Hours
  • Lost & Found System: Report lost items with last-seen locations and contact info, mark items as found

How we built it

Architecture:

  • Backend: Flask (Python) with PostgreSQL database and SQLAlchemy ORM
  • Frontend: Vanilla JavaScript with Leaflet.js for interactive mapping
  • Deployment: Railway platform for hosting with automatic SSL and database provisioning
  • Database: PostgreSQL with UTC timestamps, composite unique constraints for vote tracking, and automatic schema migrations

Key Technical Decisions:

  1. Custom Geofencing: Instead of relying on Google Maps or external APIs, we implemented our own geofencing math to calculate campus boundaries using the Haversine formula for great-circle distances
  2. Vote Tracking System: Created a composite unique constraint (alert_id + device_id + ip_address) to prevent duplicate voting while allowing vote changes. This required careful transaction handling to maintain data integrity
  3. Time-Based Filtering: Implemented a dynamic timeline scrubber that filters alerts client-side for instant feedback, with server-side validation for data integrity. The "now" state shows the last 10 minutes instead of an empty state

Challenges we ran into

  • Popup Auto-Closing During Refresh: The biggest challenge was keeping map popups open when the map refreshed every 5 seconds. Initially, we tried preserving the pop-up state by tracking open pop-ups and re-opening them after clearing markers, but this caused marker duplication. The solution was to skip marker updates entirely when any popup is open, which maintains popup stability while keeping the activity feed updated.
  • Database Schema Migrations: We needed the app to work on both fresh databases and existing ones. The init_db_safe() function checks for missing columns and adds them dynamically using raw SQL ALTER TABLE statements, making deployment on Railway smooth while supporting local development.

Accomplishments that we're proud of

  • Minimal External Dependencies: No Google Maps API or paid services - we use free OpenStreetMap tiles, built geofencing with pure math (Haversine formula), and vote tracking with database constraints. Only uses the browser's native Geolocation API for the optional "Use My Location" feature
  • Scalable Vote System: The composite unique constraint and 50-vote limit prevent abuse while allowing 1.4M+ possible votes before hitting database limits
  • Production-Ready Deployment: The app auto-migrates database schemas, handles Railway's PostgreSQL URL format, and includes proper error handling and rollback mechanisms

What we learned

  • Database Constraints > Application Logic: Using composite unique constraints and foreign keys with CASCADE delete prevents data integrity issues better than manual validation
  • Mobile-First Is Hard: Designing for desktop and adapting to mobile is easier than the reverse. We learned about 100dvh, safe-area insets, and touch event handling
  • Flask SQLAlchemy Migrations: We learned to write database migration logic that's safe to run repeatedly without breaking existing data
  • Device Fingerprinting: Combining device IDs (localStorage) with IP addresses creates a robust user identification system without requiring authentication

What's next for UBLoop

  1. Push Notifications: Browser push notifications for alerts within a configurable radius of the user's location
  2. Heat Maps: Visualize incident density over time to identify high-risk areas and patterns
  3. Multi-Campus Support: Expand to other SUNY schools with campus-specific geofencing
  4. Photo Uploads: Attach images to alerts and lost items for better verification
  5. Alert Categories: More granular alert types (theft, harassment, fire, etc.) with custom icons
Share this project:

Updates