aprs.me/docs/architecture/overview.md

92 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Architecture Overview
## System Purpose
Real-time visualization of APRS (Automatic Packet Reporting System) packets on an interactive map. Tracks amateur radio stations, weather data, and station telemetry via APRS-IS network feed.
## Technology Stack
| Layer | Technology |
|---|---|
| Language | Elixir 1.17+ |
| Web Framework | Phoenix 1.8 + LiveView 1.2 |
| Database | PostgreSQL + PostGIS |
| APRS Parsing | `aprs` (Gleam BEAM library) |
| Map Client | Leaflet (lazy-loaded) |
| Charts | Chart.js (lazy-loaded) |
| Metrics | PromEx + Telemetry |
| Deployment | Kubernetes (ArgoCD), Fly.io, Docker |
## High-Level Data Flow
```
APRS-IS Network (TCP)
Aprsme.Is (GenServer — TCP connection manager)
│ raw APRS frames parsed via aprs.parse/1
PacketProducer (GenStage — water-mark backpressure)
│ buffers incoming packets, signals backpressure upstream
PacketConsumer pool (GenStage consumers)
│ sanitize → normalize → insert into Postgres
│ broadcast to PubSub
├──► Postgres packets table (daily-partitioned)
└──► Broadcasting
├── SpatialPubSub (viewport-filtered, grid-indexed)
├── StreamingPacketsPubSub (ETS-based, bounds-filtered)
└── Phoenix.PubSub (per-callsign topics)
LiveView clients (MapLive, PacketsLive, InfoLive)
Mobile WebSocket clients (MobileChannel)
```
## Supervision Tree
```
Aprsme.Application
├── Aprsme.Repo
├── Phoenix.PubSub
├── Aprsme.Cache / DeviceCache / WeatherCache / RegexCache
├── Aprsme.RateLimiter
├── Aprsme.PacketPipelineSupervisor
│ ├── PacketProducer
│ └── PacketConsumerPool
│ └── PacketConsumer (×N)
├── Aprsme.BroadcastTaskSupervisor
├── Aprsme.Is.IsSupervisor
│ └── Aprsme.Is
├── Aprsme.SpatialPubSub
├── Aprsme.StreamingPacketsPubSub
├── Aprsme.CleanupScheduler
├── Aprsme.PartitionManager
├── Aprsme.PostgresNotifier
├── Aprsme.ConnectionMonitor
├── Aprsme.SignalHandler
├── Aprsme.ShutdownHandler
├── Aprsme.PromEx
├── Cluster modules (optional, via libcluster)
└── AprsmeWeb.Endpoint (Bandit)
```
## Key Design Decisions
### Database Partitioning
The `packets` table is **daily-partitioned** via `PartitionManager`. High ingestion volume makes partitioning essential for query performance and retention cleanup.
### Spatial Filtering
Rather than broadcasting every packet to every client, `SpatialPubSub` maintains a 1° grid spatial index. Clients register their map viewport bounds; only packets intersecting those bounds are delivered.
### Backpressure
`PacketProducer` uses water-mark backpressure (>80% buffer → pause TCP; <30% resume) to prevent memory exhaustion under load spikes.
### Symbol System
APRS symbols are rendered client-side from sprite sheets. `AprsSymbol` provides server-side symbol table lookups for info pages.
### Clustering
Optional multi-node deployment via `libcluster`. Uses leader election to designate the node that maintains the APRS-IS connection. Packets are relayed to other nodes via `PacketDistributor`.
### Lazy Asset Loading
The map bundle (Leaflet + plugins) and chart bundle (Chart.js) are loaded on-demand only for pages that need them, keeping initial page load small.