Commit Graph
19 Commits
Author SHA1 Message Date
tajniak81andClaude Opus 4.8 5960fb4806 Show current weather on the Overview
Add a weather card to the Web App Overview, wired like the OpenSky live-map
overlay and backed by the OpenWeather plugin.

- API Server: GET /api/integrations/openweather/current resolves the
  caller's cascade, gates it (master/org/personal opt-in/key), and returns
  trimmed current conditions for the configured or a supplied ?lat=&lon=
  point; off/keyless returns {unavailable, detail} so the card degrades.
- BFF relay (forwards the location override) + route; api.js client.
- Dashboard: a Weather card stacked above Schedule showing an emoji
  condition, temperature in the resolved unit, description, location, and a
  feels-like/wind/humidity/cloud grid. Location follows the same cascade as
  the map (drone -> phone -> browser -> default) without prompting for geo;
  refreshes every 10 min while on Overview.
- validLatLon test; rebuilt embedded frontend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:34:01 +02:00
tajniak81andClaude Opus 4.8 522fe450eb Report keyless OpenWeather as degraded, not down
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>
2026-07-14 12:23:31 +02:00
tajniak81andClaude Opus 4.8 6d73c89cc8 Show OpenWeather API call usage in the app
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>
2026-07-14 11:49:19 +02:00
tajniak81andClaude Opus 4.8 285551fe8a Let OpenWeather Units fall through the settings cascade
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>
2026-07-14 11:31:42 +02:00
tajniak81andClaude Opus 4.8 6231b43076 Add OpenWeather plugin with full Web App settings cascade
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>
2026-07-14 11:21:48 +02:00
tajniak81andClaude Opus 4.8 15bff7f517 Add adjustable probe area for OpenSky test connection
Let the OpenSky health probe run over a chosen bounding box without
touching the saved default, so its credit cost (which scales with area)
can be checked cheaply.

- Backend: the plugin health endpoint (panel Check) and the OpenSky
  health endpoint (Web App Test connection) accept an optional ?bbox=,
  validated with validBBox and applied to a transient probe instance;
  both BFF and API forward it. Saved config is untouched.
- API panel: a "Probe area" picker beside each bbox-capable plugin's
  Check button — saved default, all countries (grouped by continent),
  or Custom. Adds a compact pv-input-sm style.
- Web App: a "Test area" picker beside Test connection, using the full
  country list (new countryGroups() helper) plus Custom. This is where
  the probe is authenticated and the credit cost is shown.

Builds pass across both Go modules and both frontends. Panel picker
verified live (186 options, defaults to saved default).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 10:25:59 +02:00
tajniak81andClaude Opus 4.8 763cc67081 List all countries in the API panel bounding-box picker
Add API Server/panel/src/countries.js (the full world dataset, mirroring
the Web App's) with a countryGroups() helper, and have the OpenSky bbox
picker render every country grouped by continent instead of just Europe
plus a handful. Panel picker now offers 177 countries (European, Asian,
African, North/South American, Oceanian) alongside World, Continents and
Custom.

Verified live: Plugins → OpenSky → Configure shows the grouped list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 00:17:22 +02:00
tajniak81andClaude Opus 4.8 94f6876024 Add location-aware automatic default bounding box
The OpenSky "Default bounding box" now follows where flying happens.
A new "Automatic" picker mode (the default) resolves the live-map area
from a location cascade — drone telemetry → phone GPS → browser
geolocation → the user's Region country → Europe — instead of a fixed
box. Manual presets and Custom coordinates still work.

- Web App: new shared countries.js dataset (all countries + bbox,
  offline point→country); the bbox picker gains all European countries
  and an Automatic option (client pref prefs.autoBbox); the Region
  setting expands from 6 locale entries to all countries; the live map
  resolves the cascade each poll and sends it as ?bbox=.
- API Server: the states endpoint accepts and validates a ?bbox=
  override (validBBox); the Web App BFF forwards the query; the hub
  relays new phoneLatitude/phoneLongitude telemetry to the Web App.
- Fly App: reports the phone's own GPS (geolocator) alongside
  telemetry, used as the "your location" fallback.
- API panel: the OpenSky bbox picker lists all European countries.

Builds verified across web, panel, both Go modules and the Fly App
APK. Region list, Automatic default and the cascade ?bbox= override
verified in the browser.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 00:07:12 +02:00
tajniak81andClaude Opus 4.8 150758b0bf Add bounding-box region picker to the API Server plugin panel
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>
2026-07-13 23:28:23 +02:00
tajniak81andClaude Opus 4.8 c5e34e32be Add region picker for OpenSky default bounding box
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>
2026-07-13 23:20:08 +02:00
tajniak81andClaude Opus 4.8 6a007fd25e Fix API panel re-injecting field defaults over cleared values
startPluginEdit pre-filled any empty field with its descriptor default,
treating an explicitly cleared field (stored "") the same as one never set
(undefined). So a saved-blank OpenSky bounding box reappeared as the
default 50.5,3.2,53.7,7.3 on reopen (and would be re-persisted on save).
Only inject a default when the field has never been stored (undefined), so
intentional blanks stay blank.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 23:09:46 +02:00
tajniak81andClaude Opus 4.8 125d0ccc7d Make air-traffic refresh interval configurable, resolved from plan
Add a refresh-interval control to the Map settings popover: Auto (follows
the OpenSky plan) or a fixed 15/30/60/120s. The states endpoint now
resolves a recommended interval from the resolved plan (anonymous 60s,
standard 30s, contributor 15s) and returns it alongside the aircraft, so
"Auto" tracks the plan's credit budget and update rate. Polling reschedules
live when the effective interval changes; the map caption reflects it. New
airTrafficInterval preference (default 'auto', persisted + synced).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 22:58:19 +02:00
tajniak81andClaude Opus 4.8 a578555b43 Show live OpenSky air traffic on the Overview Live map
Add GET /api/integrations/opensky/states: resolves the caller's OpenSky
cascade and returns trimmed aircraft state vectors (icao24, callsign,
country, lat/lng, heading, velocity, altitude, onGround) for their bbox.
Reuses the settings gates (global master / org / personal opt-in) and is
backed by a new Manager.InvokeWith that runs the plugin's states.bbox
action on a transient instance. Proxied through the Web App BFF.

DeviceMap now overlays these as rotatable plane markers (accent when
airborne, grey on ground) with tooltips; Dashboard polls every 30s while
Overview is visible and shows an aircraft count badge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 22:15:18 +02:00
tajniak81andClaude Opus 4.8 28291e27d7 Add in-app document preview
Adds an inline preview for stored document files alongside download.

- API Server: GET /api/documents/{id}/file honours ?inline=1, serving an
  inline Content-Disposition so the browser renders the file instead of
  forcing a download (default stays attachment).
- Web App: BFF forwards the inline flag; documentPreviewUrl() helper; an eye
  icon; and a preview modal (Teleported to body) that picks a viewer from the
  file extension — images -> <img>, PDFs/text -> <iframe>, else a
  download-instead fallback. Closes on backdrop click or Escape.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 20:18:40 +02:00
tajniak81andClaude Opus 4.8 52f84ad6cf Add compliance & operational document store (PocketBase)
Introduces a `documents` collection and full-stack UI for tracking pilot
certificates, aircraft registrations, insurance, airspace authorisations,
contracts, and other paperwork.

- Migration 1720300800_add_documents.js (also provisioned live on remote PB):
  doc_type/owner/expiry/status/access_tier + file blob, a self-referential
  `replaces` version chain, audit fields, and a partial index on expiry_date.
- API Server (documents.go): role-scoped CRUD, server-computed expiry
  assessment, ?expiring=N query, versioning (replaces -> version+1, old row
  auto-archived), and streamed blob download. admin.go gains multipart upload,
  file tokens, and protected-file streaming.
- Web App: BFF passthrough (multipart create + streamed download), api.js
  client fns, and Documents.vue wired into the Documents nav slot.

Blobs live in PocketBase file storage for now; only that backend swaps when
S3-compatible object storage lands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 19:46:18 +02:00
tajniak81andClaude Opus 4.8 e3106d7b60 Show status latency at end of detail line in API panel
Reorder the Status card meta() detail so HTTP status and URL come
first and the latency (ms) reads last, e.g. "HTTP 200 · <url> · 12ms".
Rebuild the embedded panel assets.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 18:36:17 +02:00
tajniak81andClaude Opus 4.8 09da889c15 Add Users and Organizations management to API Server panel
The superadmin panel had backend CRUD for users/orgs (internal/api/users.go,
orgs.go) but no UI. Add two tabs to panel/src/App.vue:

- Users: create form (email/password/role/org), list with role + org badges,
  inline editor (email/role/org/verified/password reset), and delete. Self-role
  change and self-delete are suppressed to mirror the server-side guards.
- Organizations: create, inline rename, and delete, with client-derived member
  counts; delete is disabled while an org still has members.

PocketBase validation errors are unwrapped into a readable line via a shared
apiError() helper. Rebuilds the embedded panel bundle (dist).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 18:29:50 +02:00
tajniak81andClaude Opus 4.8 e9b27530ec Add drone-pilot logbook system (BEK 1649 §5)
Model Denmark's Dronebekendtgørelsen § 5 (on top of EU 2019/947) across all
three tiers: schema, API Server, and Web App.

Schema (migration 1720300700_add_logbook.js): two collections — `drones`
(classification inputs: mtom, is_toy, autologs, c_class, operator no.) and
`flights` (§5 minimum content + category/purpose/logging-path + operational
maturity + a retention_until computed as operation_date + 5y). Locked API
rules; access flows through the service account like users/orgs.

API Server (logbook.go, logbook_export.go): /api/drones and /api/flights CRUD
with per-role scoping in Go (user→own, admin→org, superadmin→all), plus
GET /api/logbook/export (CSV — the "readable electronic format" for
Trafikstyrelsen / pending police disclosure). Compliance is computed
server-side per flight: exemption (toy / club-area / <250 g hobby), effective
logging path, and red flags (autologs-without-FDR, specific-category-without-
authorisation, missing §5 fields, past retention). Manual-path saves missing a
§5 field are blocked (422).

Web App: BFF proxies (export preserves the CSV Content-Type/Disposition),
api.js client fns, and a Logbook.vue view (Flights/Drones tabs, inline forms,
compliance badges + expandable detail, Export CSV) wired into Dashboard.vue,
replacing the placeholder. Includes the rebuilt embedded dist bundle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 13:11:39 +02:00
tajniak81andClaude Opus 4.8 afc6952eda Initial commit: PilotVault multi-service project
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>
2026-07-13 11:43:33 +02:00