# Air Intelligence Backend
Real-time Air Quality Monitoring and Alert Notification System - Backend API Server
- Overview
- Key Features
- Tech Stack
- Getting Started
- Architecture
- API Documentation
- Development Guide
- Deployment
Air Intelligence Backend is a Spring Boot-based RESTful API server that provides real-time air pollution information based on NASA's NO2 air quality data, analyzes risk levels according to user location, and sends web push notifications.
- Real-time Air Quality Data Collection: Automatically fetches NO2 data from external FastAPI server every hour
- AI-Powered PM2.5 Prediction: Integrates with AI prediction service to forecast PM2.5 levels 2 hours ahead
- Pre-calculated Geographic Data & Caching:
- Generate hazardous area polygons using Convex Hull algorithm and store in MongoDB
- Grid-based point data aggregation and storage
- Batch processing to minimize real-time computation load
- Risk Level Analysis: 5-tier warning level system (SAFE, READY, WARNING, DANGER, RUN)
- Point-in-Polygon Algorithm: User location-based hazard zone determination using Ray Casting algorithm
- Web Push Notifications: Automatic alerts when users enter hazardous zones or high PM2.5 is predicted
- User Location Tracking: Store and manage users' last known coordinates
- GeoJSON Format Support: Provide air quality data in standard GeoJSON format
The system integrates with an AI prediction service to provide proactive air quality alerts.
- Scheduled Checking: Every hour, the
WarningSchedulerchecks all user locations - Polygon-Based Risk Assessment: First, determines if users are inside any hazardous warning polygons
- Predictive Analysis: For users outside warning zones, queries the AI prediction API for future PM2.5 levels
- Proactive Notifications: Sends push notifications when predicted PM2.5 exceeds threshold (>0.01) 2 hours ahead
Endpoint: POST https://fastapi.bestbreathe.us/api/predict/pm25
Request Format:
{
"lat": 37.5665,
"lon": 126.9780,
"when": "2025-10-05T14:30:00"
}Response Format:
{
"pred_pm25": 0.0123
}Implementation: NasaDataRepository.findPrediction(lat, lon)
- Automatically calculates prediction time (current time + 2 hours)
- Formats request with ISO 8601 timestamp
- Returns predicted PM2.5 concentration value
- Early Warning: Users receive notifications before air quality deteriorates
- Location-Specific Predictions: Tailored forecasts for each user's exact location
- Complementary to Real-Time Data: Combines current polygon-based warnings with future predictions
- Java 21 - LTS version
- Spring Boot 3.5.6 - Application framework
- Spring Data MongoDB - NoSQL database integration
- Spring Security - Security and CORS configuration
- Spring Validation - Input data validation
- Spring Scheduling - Batch job scheduling
- MongoDB 7.0.24 - Storage for users, air quality data, and GeoFeature data
- Lombok - Reduce boilerplate code
- Web Push (nl.martijndwars) - VAPID-based web push notifications
- BouncyCastle - Cryptography library
- SpringDoc OpenAPI - Automatic API documentation generation
- Gradle 8.x - Build tool
- Docker - Containerization
- JUnit Platform - Testing framework
- Java 21 or higher
- Docker (for running MongoDB)
- Gradle (wrapper included in project)
# Pull and run MongoDB container
docker pull mongodb/mongodb-community-server:7.0.24-rc0-ubi8
docker run --name mongodb -d -p 27017:27017 mongodb/mongodb-community-server:7.0.24-rc0-ubi8# Clone project
git clone <repository-url>
cd AIR_BE
# Build
./gradlew build
# Run application
./gradlew bootRunConfigure the following values in application.yml or as environment variables:
# Web Push VAPID keys (required)
VAPID_PUBLIC_KEY=<your-vapid-public-key>
VAPID_PRIVATE_KEY=<your-vapid-private-key>
# Cookie domain (optional, default: localhost)
COOKIE_DOMAIN=localhost
# CORS allowed origins (optional, default: http://localhost:5173)
CORS_ALLOWED_ORIGINS=http://localhost:5173
# FastAPI server URL (required)
FAST_API_URL=https://fastapi.bestbreathe.us┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Client │◄────────┤ Spring Boot API │────────►│ MongoDB │
│ (Browser) │ REST │ │ │ │
└─────────────┘ │ - Weather API │ │ - Users │
│ - User API │ │ - NasaData │
│ - Notification │ │ - GeoFeatures │
└──────────────────┘ └─────────────────┘
│ ▲
Fetch │ │ Every 1 hour
NO2 & │ │ Scheduled
Predict│ │
▼ │
┌──────────────────────────┐
│ FastAPI Server │
│ - NASA NO2 Data API │
│ - AI PM2.5 Prediction │
└──────────────────────────┘
air.intelligence/
├── config/ # Spring configuration classes
│ ├── SpringSecurityConfig.java # CORS, Security settings
│ ├── BeanConfig.java # Bean config (RestTemplate, etc.)
│ ├── ThirdPartyBeanConfig.java # External library beans (PushService, etc.)
│ └── WarningConstant.java # Warning threshold constants
│
├── controller/ # REST API endpoints
│ ├── WeatherController.java # Air quality data query API
│ ├── UserController.java # User management API
│ └── NotificationController.java # Notification subscription API
│
├── service/ # Business logic
│ ├── WeatherService.java # Weather service interface
│ ├── DefaultWeatherService.java # Cached GeoFeature data retrieval
│ ├── MockDataWeatherService.java # Mock service for testing
│ ├── UserService.java # User management service
│ ├── NotificationService.java # Push notification service
│ └── NasaDataService.java # NASA data processing
│
├── repository/ # Data access layer
│ ├── UserRepository.java # User MongoDB repository
│ ├── WeatherRepository.java # Air quality data MongoDB repository
│ ├── GeoFeatureDataRepository.java # GeoFeature cache repository
│ ├── NasaDataRepository.java # FastAPI integration (NO2 & AI Prediction)
│ └── dto/ # Repository DTOs
│ ├── No2DataDto.java # NO2 data response
│ ├── No2ResponseDto.java # NO2 API wrapper
│ └── Pm25PredictionDto.java # AI prediction response (NEW)
│
├── domain/ # MongoDB entities
│ ├── User.java # User domain
│ ├── NasaData.java # Air quality data domain
│ └── GeoFeatureData.java # GeoFeature cache domain (NEW)
│
├── dto/ # API request/response DTOs
│ ├── GeoResponse.java # GeoJSON response
│ ├── UserCreationDto.java # User creation DTO
│ ├── LastCoordUpdateRequest.java # Coordinate update request
│ └── SubscriptionRequest.java # Push subscription request
│
├── value/ # Value objects
│ ├── Coord.java # Coordinates (latitude/longitude)
│ ├── WarningLevel.java # Warning level enum
│ ├── WarningMessage.java # Warning message
│ ├── GeoFeature.java # GeoJSON Feature
│ ├── GeoFeatureType.java # GeoJSON type
│ ├── GeoProperties.java # GeoJSON Properties
│ └── Geometry.java # GeoJSON Geometry
│
├── scheduler/ # Scheduled tasks
│ └── WarningScheduler.java # Data collection, GeoFeature generation, notifications
│
├── error/ # Error handling
│ ├── errorcode/ # Error code definitions
│ ├── exception/ # Custom exceptions
│ └── handler/ # Global error handlers
│
└── util/ # Utilities
├── api/ # API response wrappers
└── http/ # HTTP utilities
[Execute every 1 hour - fixedRate]
│
▼
┌──────────────────────────────┐
│ 1. Fetch NO2 data from │
│ FastAPI (NasaDataRepo) │
└────────────┬─────────────────┘
│
▼
┌──────────────────────────────┐
│ 2. Save NasaData to MongoDB │
│ (WeatherRepository) │
│ - Delete existing data │
└────────────┬─────────────────┘
│
▼
┌──────────────────────────────┐
│ 3. Calculate & save │
│ GeoFeatures │
│ (Batch optimization) │
│ │
│ a) Polygon Features: │
│ - Group by warning level │
│ - Apply Convex Hull │
│ - Save type="polygon" │
│ │
│ b) Point Features: │
│ - Divide into 1° grid │
│ - Calculate averages │
│ - Save type="point" │
└────────────┬─────────────────┘
│
▼
┌──────────────────────────────┐
│ 4. Determine user risk level │
│ (Point-in-Polygon algo) │
│ │
│ - Query polygon data │
│ - Ray Casting algorithm │
│ - Check each user location│
└────────────┬─────────────────┘
│
▼
┌──────────────────────────────┐
│ 5. AI Prediction │
│ For users NOT in danger │
│ │
│ - Query PM2.5 prediction │
│ API (2 hours ahead) │
│ - If pred_pm25 > 0.01: │
│ Send notification │
└────────────┬─────────────────┘
│
▼
┌──────────────────────────────┐
│ 6. Send web push │
│ notifications for │
│ DANGER+ levels │
└──────────────────────────────┘
Polygon Endpoint (/api/v1/weathers/polygon)
[Client Request]
│
▼
┌─────────────────────────────┐
│ 1. Query type="polygon" │
│ from GeoFeatureDataRepo │
│ (pre-calculated data) │
└───────────┬─────────────────┘
│
▼
┌─────────────────────────────┐
│ 2. Return cached GeoJSON │
│ Polygon immediately │
│ (no real-time calc) │
└─────────────────────────────┘
Point Endpoint (/api/v1/weathers/point)
[Client Request]
│
▼
┌─────────────────────────────┐
│ 1. Query type="point" │
│ from GeoFeatureDataRepo │
│ (pre-calculated data) │
└───────────┬─────────────────┘
│
▼
┌─────────────────────────────┐
│ 2. Return cached GeoJSON │
│ Point immediately │
│ (no real-time calc) │
└─────────────────────────────┘
Previous Architecture:
- Real-time Convex Hull calculation for every API request
- MongoDB queries and complex algorithms executed per request
- High response latency and server load
Improved Architecture:
- ✅ Pre-calculation: Scheduler calculates GeoFeatures every 5 minutes
- ✅ Caching Strategy: Store in
GeoFeatureDatacollection (separated by type) - ✅ Fast Response: APIs only perform simple queries
- ✅ Consistency: All clients retrieve identical data
Performance Improvements:
- API response time: ~500ms → ~10ms (approximately 50x improvement)
- Reduced server CPU usage
- Improved concurrent user handling capacity
Uses Ray Casting Algorithm for user location-based risk level determination:
// WarningScheduler.java - isPointInPolygon()
- Cast a ray to the right from user coordinates (lon, lat)
- Count intersections with each polygon edge
- Odd number of intersections: inside (inside = true)
- Even number of intersections: outside (inside = false)| Level | NO2 Range | Description | Notification |
|---|---|---|---|
| SAFE | < 2.0 | Safe | ❌ |
| READY | 2.0 ~ 4.0 | Caution | ✅ Push notification |
| WARNING | 4.0 ~ 6.0 | Warning | ✅ Push notification |
| DANGER | 6.0 ~ 7.8 | Dangerous | ✅ Push notification |
| RUN | ≥ 7.8 | Very dangerous | ✅ Push notification |
Warning thresholds are managed in WarningConstant.java.
After running the application, access the auto-generated API documentation via SpringDoc OpenAPI:
http://localhost:8080/swagger-ui/index.html
-
GET /api/v1/weathers/polygon- Query polygon data by warning level- Response: GeoJSON FeatureCollection (Polygon)
- Returns pre-calculated cached data
-
GET /api/v1/weathers/point- Query grid-based point data- Response: GeoJSON FeatureCollection (Point)
- Returns pre-calculated cached data
POST /api/v1/users- Create userGET /api/v1/users/{userId}- Get userPUT /api/v1/users/{userId}/coord- Update user location
POST /api/v1/notifications/subscribe- Subscribe to push notifications
- Use Lombok annotations (
@RequiredArgsConstructor,@Getter,@Builder, etc.) - Use constructor injection pattern
- Interface-based service design (swappable implementations)
| Collection | Purpose | Key Fields |
|---|---|---|
users |
User information | id, lastCoord, pushSubscription, warningLevel |
nasaData |
Raw NO2 data | timestamp, kind, lat, lon, value |
geo_feature |
GeoFeature cache | timestamp, type (polygon/point), features[] |
@Scheduled(fixedRate = 1000 * 60 * 60) // Every 1 hour
public void task() {
1. Fetch NO2 data
2. Save NasaData
3. Calculate and save GeoFeatureData (polygon, point)
4. Determine user risk levels (Point-in-Polygon)
5. Determine predicted (by AI) user risk levels
6. Send push notifications
}# 1. Build application
./gradlew build
# 2. Copy jar file from build/libs/ to build/docker/
mkdir -p build/docker
cp build/libs/*.jar build/docker/app.jar
# 3. Build Docker image
docker build -t air-intelligence .
# 4. Run Docker container
docker run -d \
-p 8080:8080 \
-e VAPID_PUBLIC_KEY=<your-key> \
-e VAPID_PRIVATE_KEY=<your-key> \
-e FAST_API_URL=https://fastapi.bestbreathe.us \
-e CORS_ALLOWED_ORIGINS=https://your-domain.com \
--name air-intelligence-app \
air-intelligence