5 Commits
Author SHA1 Message Date
tajniak81andClaude Opus 4.8 183c83c177 Stop reporting the flight controller's serial as the drone's
getSerialNumber() is a BaseComponent method, so every component answers for
itself — and the bridge reads it off the flight controller. A Mavic Pro reports
08RDE1J00103H1 (what DJI Go labels "Flight Controller SN") where the airframe
sticker, and the registration, say 08QDE3H012032E. We were publishing the former
as the drone's serial, onto records that exist to satisfy BEK 1649 §5.

Same trap as 002e484, where a component's own firmware stood in for the
aircraft's, but with no correct source to switch to: MSDK v4 exposes no
aircraft-level serial at all — BaseProduct offers only the model and the
firmware package version — so the registered serial can only be typed by hand.

So split the two rather than pick one:

  serial                    the airframe's, hand-entered, and the only one that
                            reaches the logbook and the CSV export
  flight_controller_serial  what the aircraft reports; auto-filled on connect,
                            and what POST /api/drones/auto now upserts on

Keying auto-add on the flight controller's serial keeps the fleet recognising a
connected drone without typing — it is stable per airframe — while leaving the
compliance record's serial to the pilot. A flight controller swapped in a repair
now costs a duplicate fleet entry to merge, where before it would have quietly
rewritten what the logbook claimed the drone was.

Note droneInput.payload() is a whole-record write, so any UI editing a drone must
round-trip flightControllerSerial; blanking it forks the drone into a duplicate
on its next connect. Drones.vue carries it through the edit form for that reason.

The migration copies existing serials into flight_controller_serial rather than
moving them: every current value came from auto-add and is therefore a flight
controller's, but a pilot may since have corrected one by hand and this cannot
tell them apart. Copying keeps auto-add matching the airframes it matched before.
Applied to the remote PocketBase, where drones held no records, so the backfill
was a no-op there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 18:36:14 +02:00
tajniak81andClaude Opus 4.8 33595c99e8 Add a Drones fleet section that fills itself in on connect
The fleet lived as a tab inside the Logbook, which buried it, and every
drone had to be typed in by hand — model, serial and firmware copied off
an airframe the app was already talking to.

Promote it to its own nav section above Logbook, and let a connecting
drone register itself. The Fly App already forwarded model, serial and
firmware upstream; the hub was keeping only the model. It now carries the
identity through to DeviceState, and the Web App offers it to a new
POST /api/drones/auto, which upserts keyed by serial. The auto path only
writes what the aircraft is authoritative about (model, both firmware
versions) and never touches what the pilot curates.

Serial and the firmware versions resolve on their own schedules after
connect — the serial in seconds, the aircraft firmware sometimes a minute
later — so nothing along the path treats an absent value as a cleared one,
and a later event filling firmware in still reaches the server. The auto
call rides every telemetry frame, so the client remembers the identity
tuple it last sent and only a change goes out; a 4xx is the server's
settled answer and is not retried, or one drone connected for an hour
would mean one request per frame for an hour.

New fields on drones: firmware, controller_firmware, and registration for
the FAA/CAA aircraft number — distinct from operator_number, which stays
the EU operator ID. Controller firmware is the remote controller's own
version, read from its component; the flight controller's version is a
different quantity and stays off this field (see 002e484). name becomes
optional and is now the pilot's custom name: auto-added drones arrive
unnamed, so the API serves a computed displayName (name, else model +
serial) for the fleet table, the flight picker and the CSV export. A
unique index on serial is what keeps the find-then-create path from
forking a drone's history across two records.

The schema is applied to the remote PocketBase; the migration is here for
fresh deployments, which the remote does not read.

Verified against a simulated device over the real socket with identity
resolving late: one record from four events, both firmware versions
filled, curated fields intact across re-registration, and a drone deleted
while connected coming back on the next frame.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 17:04:12 +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 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