graph TB
subgraph External["External Services"]
VATSIM[VATSIM METAR API]
end
subgraph Processing["METAR Processing"]
subgraph Fetch["Fetch Layer"]
FetchRaw[Fetch Raw METAR]
ValidateRaw[Validate Raw Data]
CheckCache[Check Redis Cache]
end
subgraph Decode["Decode Layer"]
ParseMetar[Parse METAR]
CreateTime[Create Observation Time]
FormatData[Format JSON Data]
end
subgraph Update["Update Layer"]
CompareData[Compare with Cache]
UpdateCache[Update Redis]
StoreHistory[Store in PostgreSQL]
end
end
subgraph Storage["Data Storage"]
subgraph Redis["Redis Layer"]
RC[(Redis JSON Store)]
Keys["Key Format:
metar:${icao}:current"]
TTL["TTL: 180s"]
end
subgraph Postgres["PostgreSQL Layer"]
PG[(PostgreSQL)]
Tables["metar_history Table
- id SERIAL PK
- icao VARCHAR(4)
- time VARCHAR(7)
- observation_time TIMESTAMPTZ
- raw_metar TEXT
- decoded JSONB
- created_at TIMESTAMPTZ"]
Indexes["Indexes:
- idx_metar_history_icao
- idx_metar_history_time
- idx_metar_history_observation
- idx_metar_history_jsonb"]
end
end
subgraph ErrorHandling["Error Handling"]
Retry[Connection Retry]
Logging[Winston Logger]
Validation[Data Validation]
end
%% Main Flow
VATSIM -->|HTTP GET| FetchRaw
FetchRaw -->|Raw METAR| ValidateRaw
ValidateRaw -->|Valid Data| CheckCache
CheckCache -->|Cache Miss| ParseMetar
ParseMetar -->|Parsed Data| CreateTime
CreateTime -->|Timestamped Data| FormatData
FormatData -->|JSON Data| CompareData
CompareData -->|New Data| UpdateCache
CompareData -->|New Data| StoreHistory
%% Cache Flow
CheckCache -->|Cache Hit| Return[Return Cached Data]
UpdateCache -->|Set with TTL| RC
%% Database Flow
StoreHistory -->|Insert/Update| PG
%% Error Flows
FetchRaw -.->|Error| Retry
ParseMetar -.->|Error| Logging
UpdateCache -.->|Error| Logging
StoreHistory -.->|Error| Logging
%% Styling
classDef storage fill:#f9f,stroke:#333,stroke-width:2px;
class RC,PG storage;
classDef process fill:#bbf,stroke:#333;
class FetchRaw,ParseMetar,CompareData process;
classDef error fill:#fdd,stroke:#f66;
class Retry,Logging,Validation error;