Skip to content

System Architecture

Nguyα»…n Tri BΓ£o ThαΊ―ng edited this page May 5, 2026 · 1 revision

πŸ—οΈ System Architecture


Overview β€” 3-Layer Stack

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  External Data Sources                                      β”‚
β”‚  Open-Meteo Weather API  Β·  OpenAQ Air Quality API          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  AI Server β€” FastAPI Python  (port 8000)                    β”‚
β”‚                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Ensemble   β”‚  β”‚    Cache     β”‚  β”‚    Anomaly        β”‚   β”‚
β”‚  β”‚   Model     β”‚  β”‚   Manager   β”‚  β”‚    Detector        β”‚   β”‚
β”‚  β”‚ RF+ARIMA+XGBβ”‚  β”‚  60-min job β”‚  β”‚  Spike + XAI       β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚  District Heatmap Β· 22 quαΊ­n Β· ThreadPoolExecutor    β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚ REST / JSON
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Backend β€” ASP.NET Core 8  (port 7276)                         β”‚
β”‚                                                                β”‚
β”‚  AirController  Β·  DashboardController  Β·  ActivityController  β”‚
β”‚  AnomalyController  Β·  AssistantController  Β·  AdminController β”‚
β”‚  NotificationController                                        β”‚
β”‚                                                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚
β”‚  β”‚  PostgreSQL 16 β€” Users Β· Preferences Β·        β”‚             β”‚
β”‚  β”‚  ActivitySchedules Β· ChatMessages Β· AlertLogs β”‚             β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚ REST / JWT Bearer
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Frontend β€” React 18 + TypeScript + Vite  (port 5173)       β”‚
β”‚                                                             β”‚
β”‚  Dashboard  Β·  Activity  Β·  Heatmap  Β·  Assistant  Β·  Guide β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Core Design Principle: Cache-Based Architecture

The AI model never runs per-request. Instead:

APScheduler (every 60 min)
    └── run_compute()
        β”œβ”€β”€ Fetch weather + air quality from Open-Meteo / OpenAQ
        β”œβ”€β”€ Run Ensemble model (RF + ARIMA + XGBoost)
        β”œβ”€β”€ Write forecast_cache.csv   (7-day hourly Γ— 4 profiles)
        β”œβ”€β”€ Write history_cache.csv    (30-day hourly Γ— 4 profiles)
        β”œβ”€β”€ Write current_cache.json   (current snapshot Γ— 4 profiles)
        β”œβ”€β”€ run_anomaly_detection()    β†’ anomaly_log.json
        β”œβ”€β”€ _trigger_alert_check()     β†’ .NET sends Telegram/Email
        └── compute_district_heatmap() β†’ district_cache.csv

Benefits:

  • Client response time < 50ms (reads CSV/JSON, no model inference)
  • Stable under high concurrent traffic
  • Admin can trigger manual recompute anytime

Technology Stack

Layer Technology Version
Frontend React + TypeScript + Vite 18 / 5.x / 5
Backend ASP.NET Core 8.0
AI Server FastAPI + Python 0.111 / 3.11
Database PostgreSQL 16
ORM Entity Framework Core 8
Charts Recharts latest
AI Chat Google Gemini 2.5 Flash
Notifications Telegram Bot + SMTP β€”
Container Docker Compose 2.x

Key Source Files

AI Server (src/airsafenet_ai/app/)

File Purpose
api.py FastAPI routes + lifespan
predict.py Main RF inference (lazy-loaded)
ensemble_predict.py RF + ARIMA + XGBoost ensemble
cache_manager.py 60-min compute pipeline
scheduler.py APScheduler job
anomaly_detector.py Spike detection + XAI
districts.py 22-district parallel heatmap
features.py Lag, rolling, cyclical features
data_loader.py Open-Meteo + OpenAQ fetch
aqi.py EPA PM2.5 β†’ AQI conversion
profiles.py 5 health group risk/recommendation
config.py LAT/LON/paths/constants

Backend (src/airsafenet_backend/)

File Purpose
Controllers/AirController.cs /api/air/* β€” current, forecast, history, explain
Controllers/DashboardController.cs /api/dashboard/* β€” summary, chart, full
Controllers/ActivityController.cs /api/activity/* β€” CRUD + risk scoring
Controllers/AssistantController.cs /api/assistant/* β€” Gemini AI chat
Controllers/NotificationController.cs /api/notification/* β€” alert dispatch
Controllers/AdminController.cs /api/admin/* β€” cache trigger, status
Services/AiCachedService.cs Reads from AI server cache via HTTP

Frontend (src/airsafenet_frontend/src/)

Directory Contents
pages/ Dashboard, Activity, Heatmap, Assistant, Guide, Preferences, Admin
components/dashboard/ 30+ visualization components
components/assistant/ Chat, conversations, streaming
components/common/ Toast, SectionHeader, StatusChip
api/ http.ts, air.ts, dashboard.ts, assistant.ts, admin.ts
types/ TypeScript type definitions
hooks/ useAdminCache, useAiExplain, useTypewriter

Clone this wiki locally