Overview
Aero is organized as a monorepo containing all backend services, client applications, and supporting tools. This architecture enables code sharing, consistent versioning, and streamlined development workflows across the entire platform.Backend architecture
Core API (api/)
The heart of Aero is a NestJS REST API built with TypeScript, providing all flight tracking functionality.
Technology stack
- Framework: NestJS 10.4 with TypeScript 5.7
- Database: PostgreSQL with Prisma ORM 6.1
- Caching: Redis via ioredis
- Authentication: JWT with argon2 password hashing
- Documentation: OpenAPI/Swagger + Scalar API Reference
- Security: Helmet middleware for HTTP headers
- Logging: Morgan for HTTP request logging
Module structure
The API follows NestJS modular architecture:Each module contains its own controller, service, DTOs (Data Transfer Objects), and entities following NestJS best practices.
Database schema
The Prisma schema defines comprehensive models for aviation data: Core entities:User- User accounts with authenticationFlight- Tracked flights with real-time dataFlightBooking- User flight bookings with seat and travel detailsFlightPositions- Individual position data points for flight pathsFlightAwareData- Extended FlightAware flight information
Airport- Global airport database (IATA/ICAO codes, coordinates, timezone)Airline- Airline information with logosAircraft- Aircraft details (registration, type, age, photos)AircraftRegistration- Historical registration data
GreatCircleDistance- Calculated flight distancesFlights- Flight search results cache
API endpoints
Key endpoint groups: Authentication (/auth)
POST /auth/register- Create new user accountPOST /auth/login- Authenticate and receive JWTGET /auth/@me- Get current user details
/flight)
GET /flight- Get detailed flight informationGET /flight/search- Search for flights by identifierGET /flight/track- Get flight path with all position data
/flight/booking)
POST /flight/booking- Create a flight bookingGET /flight/booking/:bookingId- Get booking detailsPUT /flight/booking/:bookingId- Update bookingDELETE /flight/booking/:bookingId- Delete bookingGET /flight/booking/flight/:flightId- Get all bookings for a flight
/flights)
GET /flights- Search flights between airports by datePOST /flights/airline- Get airline informationGET /flights/tracked- Get all tracked flights
GET /airports- Search airportsGET /airlines- Get airline information
External API integrations
Aero integrates with multiple flight data providers:- FlightAware - Primary source for real-time flight tracking
- AviationStack - Flight search between airports
- AeroDataBox (via RapidAPI) - Aircraft and additional flight data
- OpenSky Network - Open-source flight tracking data
Caching strategy
Redis is used extensively to minimize external API calls and improve performance:- Flight search results cached by route and date
- Airport and airline data cached indefinitely
- Real-time flight positions cached with short TTL (30-60 seconds)
- User session data stored in Redis
Client applications
Flutter mobile app (app/)
Cross-platform mobile application for iOS and Android.
Features
- Real-time tracking - Live flight position on interactive maps
- Flight search - Find flights by number or route
- Booking management - Save and manage flight bookings
- Home widgets - Quick access to tracked flights
- Offline support - Local caching with offline viewing
- Dynamic icons - Customizable app icons
- Wear OS sync - Send flight data to smartwatch
Architecture
State management
The app uses Provider for state management:API integration
The app uses an auto-generated Dart client from the OpenAPI specification:Background updates
Workmanager handles periodic widget updates:Wear OS companion (wearos/)
Native Wear OS app built with Kotlin and Jetpack Compose.
Features
- Quick access - View tracked flights at a glance
- Watch tiles - Show flight status on watch face
- Complications - Add flight data to any watch face
- Phone sync - Receive flight updates from the mobile app
- Local storage - Room database for offline access
Architecture
Data synchronization
The Wear OS app communicates with the mobile app using the Wearable Data Layer API:Marketing website (landing/)
Modern React landing page for Aero.
Technology
- React 19 with TypeScript
- Vite for fast builds
- Tailwind CSS for styling
- shadcn/ui component library
Structure
Supporting tools
Data scraper (scraper/)
Web scraping tool for airline data using Playwright and Bun.
Data scripts (scripts/)
Utilities for data management and migrations:
- Import airport data from OpenFlights
- Bulk airline data processing
- Database seeding and migrations
- Data cleanup and normalization
OpenAPI client (openapi/)
Auto-generated Dart API client created from the NestJS OpenAPI specification:
Data flow
Here’s how data flows through the system when tracking a flight:Database storage
Flight data is stored in PostgreSQL with relationships to user, aircraft, and positions
Response with positions
API returns flight details including current position and historical path data
Deployment
Backend deployment
The NestJS API can be deployed to any Node.js hosting platform:- PostgreSQL database (managed or self-hosted)
- Redis instance for caching
- Environment variables for API keys and secrets
Mobile app deployment
Android native configuration is fully set up. iOS configuration may require additional setup.
Web deployment
Performance considerations
Caching strategy
- Static data (airports, airlines) cached indefinitely
- Flight positions cached for 30-60 seconds
- Search results cached for 5 minutes
- User sessions stored in Redis with 7-day expiry
Database optimization
- Indexed fields for fast lookups (flight numbers, airport codes, registration)
- Composite indexes on frequently queried combinations
- JSON fields for flexible flight data storage
- Automatic position data cleanup for landed flights
API rate limiting
To protect external APIs:- Aggressive caching reduces API calls
- Flight positions only updated when actively viewed
- Batch requests where possible
- Graceful degradation when rate limits hit
Development workflow
Monorepo advantages
- Shared types - API types used directly in mobile app
- Version sync - All components updated together
- Code reuse - Shared utilities and constants
- Atomic changes - API and client updated in single PR
Code generation
OpenAPI specification automatically generates:- Swagger documentation
- Dart API client for Flutter
- Type-safe request/response interfaces
Next steps
API reference
Explore all available API endpoints
Mobile development
Build features for the Flutter app
Database schema
Deep dive into the data models
Contributing
Learn how to contribute to Aero