Skip to content

BaselAshraf81/threatalert

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

53 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ThreatAlert Logo

ThreatAlert

Anonymous, community-driven real-time incident awareness β€” on a living map.

Next.js Firebase TypeScript Tailwind CSS PWA License: MIT


ThreatAlert β€” live global incident map

🌐 Live Demo Β· πŸ“Έ Screenshots Β· πŸš€ Self-host Β· 🀝 Contribute


ThreatAlert is a zero-auth, privacy-first PWA where anyone can pin an incident β€” crime, fire, disaster, civil unrest, or infrastructure failure β€” on a shared live map, and the community votes on it to verify or resolve it. No sign-up. No tracking. Just signal.


✨ Features at a Glance

Feature Details
πŸ—ΊοΈ Live Incident Map Leaflet-powered map with dark & light tile sets, animated category pins, and a pulsing user-location dot
πŸ“ One-tap Reporting FAB button, long-press anywhere on the map, or tap-to-place a pin β€” then pick a category, write a description, and attach up to 3 photos
πŸ—³οΈ Community Voting Confirm Β· Resolve Β· Flag β€” votes gate incidents from pending β†’ active using per-category thresholds; duplicate votes are blocked server-side
πŸ”” Push Notifications Browser push (FCM) with a configurable radius (1 / 5 / 10 / 25 km or worldwide) and minimum-vote threshold
🌐 3D Globe Gallery Drag-to-rotate D3.js globe showing every live incident as a glowing dot β€” tap any dot to open the full detail
πŸ“° Incident Ticker Scrollable strip of active incidents at the bottom of the screen β€” tap to fly the map to any of them
πŸ”— Deep-link Sharing Every incident gets a shareable URL that opens the app, flies to the map location, and shows the detail sheet
πŸ“² Installable PWA Runs standalone on iOS & Android with a home-screen icon and app shortcut for quick reporting
πŸŒ™ Dark / Light Theme System-aware with manual override; map tiles, UI, and globe all switch together
πŸ”’ Privacy-first Fully anonymous β€” no accounts, IPs are one-way HMAC-hashed before storage and never logged raw
⏱️ Auto-expiry Incidents expire automatically based on category (e.g. Crime: 4 h · Fire: 6 h · Disaster: 12 h)
πŸ›‘οΈ Rate limiting 5 reports per IP per hour, enforced at the Cloud Functions layer

πŸ“Έ Screenshots

ThreatAlert running on iPhone


πŸ—‚οΈ Incident Categories

Each category has its own colour-coded pin, icon, vote threshold, and time-to-live:

Icon Category TTL Votes to activate
πŸ›‘οΈ Crime / Safety 4 h 3
β›ˆοΈ Natural Disaster 12 h 2
πŸ”₯ Fire 6 h 2
🚧 Infrastructure 8 h 3
πŸ“’ Civil Unrest 6 h 4
⚠️ Other 4 h 5

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               Browser / PWA                 β”‚
β”‚  Next.js 16 Β· React 19 Β· Tailwind v4        β”‚
β”‚                                             β”‚
β”‚  MapView (Leaflet)                          β”‚
β”‚  IncidentGlobeGallery (D3.js canvas globe)  β”‚
β”‚  ReportSheet ──────────────────────┐        β”‚
β”‚  IncidentDetailSheet               β”‚        β”‚
β”‚  NotificationSheet                 β”‚        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    REST / Firestore β”‚  FCM push
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Firebase                            β”‚
β”‚                                               β”‚
β”‚  Cloud Functions (Node 20, us-east1)          β”‚
β”‚    POST /api/createIncident  ← rate-limit+    β”‚
β”‚    POST /api/voteIncident    ← dedup by IP    β”‚
β”‚    POST /api/subscribeToAlerts                β”‚
β”‚    POST /api/unsubscribeFromAlerts            β”‚
β”‚                                               β”‚
β”‚  Firestore   β€” incidents collection           β”‚
β”‚  Storage     β€” photo uploads                  β”‚
β”‚  FCM         β€” push notification delivery     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Writes always go through Cloud Functions (rate-limited, IP-hashed).
  • Reads are direct Firestore onSnapshot streams β€” the map updates in real time without polling.
  • In development with no NEXT_PUBLIC_FUNCTIONS_URL, the app falls back to direct Firestore writes for easier local testing.

πŸš€ Getting Started

Prerequisites

  • Node.js 20+
  • A Firebase project with Firestore, Storage, and Cloud Messaging enabled
  • Firebase CLI: npm i -g firebase-tools

1. Clone & install

git clone https://github.com/BaselAshraf81/threatalert.git
cd threatalert
npm install

2. Configure environment

cp .env.local.example .env.local

Open .env.local and fill in your Firebase project values (find them at Firebase Console β†’ Project Settings β†’ Your apps):

NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=

# VAPID key for Web Push β€” Firebase Console β†’ Cloud Messaging β†’ Web Push certificates
NEXT_PUBLIC_FIREBASE_VAPID_KEY=

# Salt for one-way IP hashing (never stored raw)
# Generate: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
IP_HASH_SALT=

ALLOWED_ORIGIN=http://localhost:3000

3. Set up Firestore security rules

firebase deploy --only firestore:rules

4. Deploy Cloud Functions

cd functions && npm install && cd ..
firebase deploy --only functions

5. Run locally

npm run dev

Open http://localhost:3000. The dev server auto-generates the Firebase Messaging service worker before starting.


🌍 Deploying to Production

ThreatAlert ships with configs for both Firebase Hosting and Netlify.

Firebase Hosting

npm run build
firebase deploy

Netlify

Push to your repo β€” netlify.toml handles the build command and publish directory automatically.

Don't forget to set all NEXT_PUBLIC_* environment variables in your hosting provider's dashboard, and set ALLOWED_ORIGIN to your production domain.


βš™οΈ Configuration Reference

Variable Required Description
NEXT_PUBLIC_FIREBASE_API_KEY βœ… Firebase web API key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN βœ… Firebase Auth domain
NEXT_PUBLIC_FIREBASE_PROJECT_ID βœ… Firestore project ID
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET βœ… Firebase Storage bucket
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID βœ… FCM sender ID
NEXT_PUBLIC_FIREBASE_APP_ID βœ… Firebase App ID
NEXT_PUBLIC_FIREBASE_VAPID_KEY βœ… VAPID key for push notifications
IP_HASH_SALT βœ… Secret for HMAC IP hashing
ALLOWED_ORIGIN βœ… CORS origin for Cloud Functions
NEXT_PUBLIC_FUNCTIONS_URL Optional Emulator URL for local function testing

πŸ”’ Privacy & Security

  • No accounts. No email, phone, or OAuth required β€” ever.
  • No raw IPs. Every IP is immediately one-way hashed with a secret salt using HMAC-SHA256 before any Firestore write. The original IP is never stored.
  • Rate limiting. Cloud Functions enforce a per-IP, per-hour cap of 5 incident creations and a similar cap on votes to prevent abuse.
  • Vote deduplication. The hashed IP is compared server-side to prevent the same person from voting twice on the same incident.
  • Input sanitisation. Descriptions are stripped of HTML tags and capped at 280 characters. Photo URLs are validated to only allow Firebase Storage origins before being persisted.

πŸ› οΈ Tech Stack

Layer Technology
Framework Next.js 16 (App Router)
UI React 19, Tailwind CSS v4, shadcn/ui, Radix UI
Animations Framer Motion
Map Leaflet + OpenStreetMap / Carto tiles
Globe D3.js (canvas rendering, GeoJSON land features)
Backend Firebase Cloud Functions (Node 20)
Database Firestore (real-time onSnapshot)
File storage Firebase Storage
Push Firebase Cloud Messaging (FCM) + Web Push VAPID
PWA Custom service worker, Web App Manifest
Language TypeScript 5.7
Deploy Firebase Hosting / Netlify

🀝 Contributing

Contributions are welcome! Here are some good places to start:

  • πŸ› Bug reports β€” open an issue with reproduction steps
  • πŸ’‘ Feature requests β€” open a discussion first so we can align on direction
  • πŸ”§ Pull requests β€” please open an issue or discussion before large changes
# Fork the repo, then:
git checkout -b feat/your-feature
npm run dev
# make your changes
npm run lint
git commit -m "feat: describe your change"
git push origin feat/your-feature
# open a PR πŸŽ‰

πŸ“„ License

MIT β€” see LICENSE for details.


Built with πŸ”΄ for safer, more aware communities.

⭐ Star this repo if you find it useful β€” it helps more people discover ThreatAlert!

Releases

No releases published

Packages

 
 
 

Contributors