# 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 (bounded and unbounded spatial streams)
         └── Phoenix.PubSub (targeted callsign/weather 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.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.
