Drop the descriptor Default of 60 so the global panel field can be left
blank. A non-blank global value sits at the top of the cascade and locks
every lower layer, so the fixed default made the per-minute limit
un-overridable by organizations and users. Blank now means "inherit";
the runtime still falls back to 60 when no layer sets a value, so the
usage gauge is unchanged. Update the descriptor help and the Settings
row copy to explain the inherit behavior.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The panel health probe tests the global plugin config only. When the
plugin is enabled as a master switch with no global API key (users supply
their own), the probe reported a hard "down", which read as broken.
Return "degraded" with an explanatory detail instead — a keyless master
switch is a valid setup, nothing is failing. The Web App user-facing path
is unchanged: a caller whose effective key is empty still gets "down" with
an actionable "add one to connect" message before the plugin is called.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OpenWeather reports no remaining quota (only 429 when over), so add an
in-app gauge that counts the calls PilotVault itself makes and shows them
against the plan's per-minute limit.
- Plugin: process-wide usage store bucketed per API key (hashed) into the
current minute and UTC day; a do() wrapper counts each request that
reaches OpenWeather (transport errors consume no quota, so uncounted).
Health and Invoke both route through it.
- New callsPerMinute config field (default 60) that cascades global -> org
-> user; plugin contract gains plugins.HealthUsage on Health.
- Web App: a "Calls per minute limit" field and an "API call usage" meter
in the OpenWeather card, shown after Test connection and cached.
- Counts reset on restart and cover only PilotVault's own calls (noted in
the UI); the account dashboard stays authoritative.
- Tests for per-key counting and minute/day rollover; rebuilt frontend.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Units field carried a Default of "metric" and had no blank option, so
the global panel layer always set a value and locked organizations and
users out of changing it. Mirror the fix already applied to OpenSky's plan.
- Plugin descriptor: drop the "metric" Default and add a blank "Not set"
option; runtime still falls back to metric when no layer sets it.
- Web App: add a "Not set" choice to the Units control and stop forcing
metric back into the form on load.
- Test guards that the units field has no Default and offers a blank option.
- Rebuilt embedded frontend.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Builtin API Server connector for the OpenWeather API (current weather +
5-day forecast for a point, API-key auth, stdlib-only), surfaced to end
users through the same three-layer settings cascade as OpenSky/WebDAV.
- New builtin plugin (internal/plugins/builtin/openweather) with
health probe, weather.current/forecast.5day capabilities, and tests.
- resolveOpenWeather cascade (global -> org -> user) with per-field
independent resolution and API-key masking; GET/PUT/health endpoints.
- Web App BFF relays, api.js client, and a Settings card under
APIs - External (scope switch, enable toggles, test connection).
- Resolver unit tests + rebuilt embedded frontend.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Give the superadmin Plugins panel the same OpenSky "Default bounding
box" experience as the Web App: a grouped preset dropdown (World /
Continents / Countries) plus a Custom option for manual
lamin,lomin,lamax,lomax entry.
Introduce a "bbox" config-field type (rendering hint only; unknown
types still degrade to a text input) and mark the OpenSky bbox field
with it. Values that match a preset render as the region name.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the free-text bounding-box field in the Web App OpenSky
settings with a grouped preset picker (World / Continents / Countries)
plus a Custom option that keeps the manual lamin,lomin,lamax,lomax
entry. Saved values that match a preset render as the friendly region
name, including in the locked/inherited display.
Change the API Server default bounding box to Europe to match the new
"Europe" preset.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add API Server (Go/PocketBase), Web App (Go BFF + Vue), Fly App
(Flutter/DJI MSDK), Adobe Plugin, and Docker/Docker AIO deployment
configs. Design assets and build artifacts are gitignored.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>