Skip to content

Air-Intelligence/AIR_BE

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

                      # Air Intelligence Backend

Real-time Air Quality Monitoring and Alert Notification System - Backend API Server

Table of Contents

Overview

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.

Key Features

  • 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

AI-Powered PM2.5 Prediction

The system integrates with an AI prediction service to provide proactive air quality alerts.

How It Works

  1. Scheduled Checking: Every hour, the WarningScheduler checks all user locations
  2. Polygon-Based Risk Assessment: First, determines if users are inside any hazardous warning polygons
  3. Predictive Analysis: For users outside warning zones, queries the AI prediction API for future PM2.5 levels
  4. Proactive Notifications: Sends push notifications when predicted PM2.5 exceeds threshold (>0.01) 2 hours ahead

Prediction API Integration

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

Use Cases

  • 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

Tech Stack

Core

  • 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

Database

  • MongoDB 7.0.24 - Storage for users, air quality data, and GeoFeature data

Libraries

  • Lombok - Reduce boilerplate code
  • Web Push (nl.martijndwars) - VAPID-based web push notifications
  • BouncyCastle - Cryptography library
  • SpringDoc OpenAPI - Automatic API documentation generation

Build & DevOps

  • Gradle 8.x - Build tool
  • Docker - Containerization
  • JUnit Platform - Testing framework

Getting Started

Prerequisites

  • Java 21 or higher
  • Docker (for running MongoDB)
  • Gradle (wrapper included in project)

Installation & Running

1. Run MongoDB

# 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

2. Clone & Build Project

# Clone project
git clone <repository-url>
cd AIR_BE

# Build
./gradlew build

# Run application
./gradlew bootRun

Environment Variables

Configure 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

Architecture

System Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   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   β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Package Structure

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

Data Flow

1. Periodic Data Collection & Notifications (WarningScheduler)

[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            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Air Quality Data Query API (Improved Performance)

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)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Major Architecture Improvements

Batch Processing Optimization (Recent Refactoring)

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 GeoFeatureData collection (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

Point-in-Polygon Algorithm

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)

Warning Level System

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.

API Documentation

After running the application, access the auto-generated API documentation via SpringDoc OpenAPI:

http://localhost:8080/swagger-ui/index.html

Main Endpoints

Air Quality Query

  • 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

User Management

  • POST /api/v1/users - Create user
  • GET /api/v1/users/{userId} - Get user
  • PUT /api/v1/users/{userId}/coord - Update user location

Notification Subscription

  • POST /api/v1/notifications/subscribe - Subscribe to push notifications

Development Guide

Code Style

  • Use Lombok annotations (@RequiredArgsConstructor, @Getter, @Builder, etc.)
  • Use constructor injection pattern
  • Interface-based service design (swappable implementations)

MongoDB Collections

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[]

Scheduler Operation

@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
}

Deployment

Docker Build & Run

# 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

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •