Architecture Overview
Air Tracker is a real-time aircraft tracking application built with Angular 20, leveraging modern standalone components, signal-based reactivity, and a clean feature-based architecture.Technology Stack
Core Framework
- Angular 20.2.0 - Modern standalone components architecture
- TypeScript 5.9.2 - Type-safe development
- RxJS 7.8.0 - Reactive programming for async operations
- Zone.js 0.15.0 - Change detection management
UI Framework
- Angular Material 20.2.14 - Material Design components
- Angular CDK 20.2.14 - Component Dev Kit (Overlay, Portal, Layout)
- Leaflet 1.9.4 - Interactive maps
- leaflet-moving-rotated-marker 0.0.1 - Animated aircraft markers
Build & Development
- Angular CLI 20.2.2 - Build tooling
- ESLint 9.39.1 - Code quality
- Jasmine/Karma - Testing framework
Air Tracker uses Angular’s modern standalone component architecture, eliminating the need for NgModules and embracing a more streamlined development experience.
Application Structure
The application follows a feature-based folder structure with clear separation of concerns:Architecture Principles:
- Core - Singleton services loaded once at app startup
- Features - Self-contained feature modules with their own services, components, and models
- Shared - Reusable components, pipes, and utilities used across features
Component Hierarchy
The application uses a hierarchical component structure:Component Responsibilities
FlightsShellComponent (flights-shell.component.ts:56)
The main container component that:
- Initializes smart polling on mount
- Orchestrates child components (map, list, filters)
- Manages responsive flight detail views (overlay vs bottom sheet)
- Uses Angular effects to react to selection and viewport changes
FlightsMapComponent (flights-map.component.ts:20)
Interactive Leaflet map that:
- Renders aircraft markers with rotation and animation
- Updates markers reactively using Angular effects
- Handles marker click events for flight selection
- Supports multiple base layers (streets, satellite)
FlightsListComponent (flights-list.component.ts:48)
Tabular view with:
- Material Table with sorting
- Reactive data binding using effects
- Row selection for flight details
- Custom sorting accessor for flight properties
Data Flow Architecture
Air Tracker implements a unidirectional data flow pattern:Data Flow Principles
- Single Source of Truth:
FlightsStoreServiceholds all flight-related state - Readonly Signals: Components consume state via readonly signals, preventing direct mutations
- Actions for Updates: Components call store methods (
updateFilters,setSelectedFlightId) to modify state - Computed Derivations: Filtered views are automatically computed from base state
- Effects for Side Effects: Component effects react to signal changes for DOM updates
Why Signals over Observables?Angular signals provide:
- Automatic change detection optimization
- Simpler mental model (no subscription management)
- Better TypeScript inference
- Built-in computed values and effects
- Fine-grained reactivity
Standalone Components Architecture
Air Tracker uses Angular’s standalone components introduced in Angular 14 and stabilized in v15+:Benefits of Standalone Architecture
- No NgModules: Simpler mental model, no module hierarchy to manage
- Direct Imports: Components declare dependencies directly in their
importsarray - Tree-Shakeable: Better bundle optimization
- Lazy Loading: Simplified lazy loading with route-level code splitting
- Provider Scoping: Services can be provided at component level or root
Service Layer
Core Services
ApiConfigService (core/services/api-config.service.ts:16)
Centralized API configuration:
ViewportService (core/services/viewport.service.ts:8)
Responsive breakpoint detection using CDK Layout:
All core services use
providedIn: 'root' to ensure singleton behavior across the application.Routing Configuration
Simple routing with layout wrapping:Key Architectural Decisions
Responsive UI StrategyFlight details render differently based on viewport:
- Desktop: CDK Overlay positioned on the left
- Mobile/Tablet: Material Bottom Sheet
DTO to Model MappingThe app maintains separate DTOs (data transfer objects) and domain models:
- DTOs (
shared/models/*.dto.ts) - Match API contracts - Models (
features/*/models/*.model.ts) - App-specific domain objects
mapFlightDtoToFlight) handle transformations.Performance Optimizations
- OnPush Change Detection: Map component uses
ChangeDetectionStrategy.OnPush - Computed Signals: Filtered flights auto-memoize, only recalculate when dependencies change
- Lazy Loading Ready: Route-based code splitting supported (not yet implemented)
- Zone Coalescing:
provideZoneChangeDetection({ eventCoalescing: true })reduces change detection cycles - Leaflet Layer Management: Reuses marker instances instead of destroying/recreating
Next Steps
- State Management - Deep dive into signal-based reactive state
- API Integration - Backend communication patterns
