airbrief/PROJECT.md
Dave Campbell 1658eda480 Initial commit: AirBrief MVP
Airport lookup and route weather strip. Pulls from aviationweather.gov
with no API key. Decodes METAR/TAF client-side. Hosted at
rockcampbell.com/airbrief via nginx proxy on rocklab.
2026-06-16 14:31:40 +00:00

118 lines
5.1 KiB
Markdown
Raw Permalink 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.

# AirBrief — Project Status
*Last updated: June 16, 2026*
---
## What It Is
A static web app for business aviation situational awareness — specifically built for Airshare line pilots and flight control. Not a certified briefing replacement. Gives a fast, clean weather picture before the official brief happens.
**Live at:** rockcampbell.com/airbrief
**Target users:**
- Line pilot at KMKC with 24 legs today, needs a 90-second weather picture
- Flight control building the day's operation, wants to flag potential weather disruptions
---
## Current State (MVP Complete)
### Airport Lookup (single ICAO/IATA)
Type one airport ID → full detail view:
- Flight category badge (VFR / MVFR / IFR / LIFR), color coded
- Wind, visibility, ceiling, altimeter (inHg — Kollsman window value), temp/dewpoint
- Sky conditions (tagged)
- Present weather decoded to plain English
- METAR: plain-English paragraph + raw text
- TAF: plain-English per change group (Initial / From / Temporary / Becoming / Probability) + raw text
### Route Weather (multiple space-separated IDs)
Type `KMKC KSTL KDEN` → route view:
- Flight category strip: colored badges per airport with visibility and ceiling
- Per-airport detail cards: wind, vis, ceiling, altimeter, temp/dewpoint, plain-English summary, obs time
- Active hazard summary: SIGMETs and AIRMETs filtered to the route bounding box, sorted by severity (convective SIGMETs first)
---
## Tech Stack
| Layer | Choice | Notes |
|---|---|---|
| Frontend | Vanilla HTML/CSS/JS | Single file, no framework, no build step |
| Weather data | aviationweather.gov public API | No key, no cost, no rate limit |
| Hazard data | aviationweather.gov `/airsigmet` | Same API, returns SIGMETs + AIRMETs |
| METAR/TAF decode | Client-side JS | No third-party decoder — all done in-browser |
| Hosting | hugo-site nginx container on rocklab | Static file served directly from disk |
| CORS proxy | Nginx location `/airbrief-api/` | aviationweather.gov doesn't send CORS headers; nginx proxies server-side |
---
## File Locations
```
/home/rock/airbrief/
├── index.html ← entire app (single file)
└── PROJECT.md ← this file
```
**Nginx proxy config:** `/home/rock/docker/rockcampbell/nginx.conf`
- `/airbrief` → serves `/srv/airbrief/` (the airbrief directory)
- `/airbrief-api/` → proxies to `https://aviationweather.gov/api/data/`
**Docker volume mount:** `/home/rock/docker/rockcampbell/docker-compose.yml`
- `/home/rock/airbrief:/srv/airbrief:ro`
Changes to `index.html` go live immediately — no container restart needed.
---
## API Endpoints in Use
All routed through the local proxy at `/airbrief-api/`:
| Endpoint | Used for |
|---|---|
| `/metar?ids=KMKC&format=json&hours=2` | METAR for one or multiple airports (comma-separated) |
| `/taf?ids=KMKC&format=json` | TAF including structured `fcsts` array |
| `/airsigmet?format=json` | All active SIGMETs and AIRMETs |
**Key API field notes:**
- `fltCat` (capital C) — flight category; computed from ceiling/vis as fallback
- `altim` — in **hPa**, not inHg. Divide by 33.8639 to get the Kollsman window value
- `visib` — string, may return `"10+"` rather than a number
- `clouds[]` — array of `{cover, base, type}` objects; base in feet
---
## Hazard Filtering
When displaying route hazards, the app builds a bounding box from the lat/lon of all found airports (±3 degrees padding) and filters the SIGMET/AIRMET list to hazards whose coordinates overlap that box. Hazards with no coordinate data are included.
Sort order: convective SIGMETs → other SIGMETs → AIRMETs.
Color: red = convective SIGMET, orange = other SIGMET or severe turb/ice, yellow = AIRMET.
---
## v2 Backlog (do not build until David returns to this)
From the original project brief — in priority order:
1. **Winds Aloft by waypoint** — enter cruise altitude (FL350, FL410), get forecast winds and temps at each route waypoint. API: `/windtemp?format=json`
2. **Flight Category Map** — Leaflet.js map centered on the route, stations color-coded by flight category, route corridor overlay. Deferred because Turf.js route geometry math was saved for post-MVP.
3. **PIREPs near route** — pilot reports filtered to the route corridor. API: `/pirep?format=json`
4. **TFRs** — active temporary flight restrictions. API: `/tfr?format=json` (different response format from airsigmet)
5. **Multi-leg trip view** — full day's operation across multiple aircraft
6. **Saved routes / push alerts**
7. **Radar layer** on the map
8. **Mobile PWA** (offline-capable)
9. **Integration with Airshare/Horizon trip data**
---
## Known Notes / Gotchas
- The `airsigmet` endpoint returns ~2,000 records nationally. Bounding box filtering cuts this down significantly for regional routes. For very short routes the box is small; for cross-country the box is large and more hazards show.
- TAF not always available for smaller airports (returns empty array — handled gracefully).
- IATA identifiers (e.g., `MKC`) work in addition to ICAO (`KMKC`).
- Route input accepts space, comma, or slash as separators.
- The disclaimer is required on every page per the original brief.