Commit Graph

93 Commits

Author SHA1 Message Date
itsrubberduck
110616bc23 refactor(split): decouple app from website in preparation for the repo split
Phase 0 of the OpenSquawk repo separation. Everything happens inside the
monorepo so that the split itself becomes a mechanical path filter — filtering
first and repairing afterwards would leave two broken repos at once.

AUTH_MODE (0.1)
  New server/utils/authMode.ts, session.ts and jwt.ts (the latter extracted
  from auth.ts). requireUserSession now resolves in three steps: the app's own
  session cookie, an app-minted bearer token, then the website access token.
  Only the last one is transitional; it is marked PHASE 1 and disappears with
  the User collection. The app's session is its own JWT in a host-only cookie
  plus a short-lived bearer, so the existing Authorization call sites are
  unchanged.

  AUTH_MODE defaults to 'sso', not 'open' as the plan proposed: while the admin
  and editor surface still lives here, an unset variable would otherwise serve
  it to everyone as a local admin. requireAdmin additionally refuses in open
  mode. Both are one-line removals in Phase 1 and marked as such.

SSO handoff (0.2)
  Issuer: /api/service/auth/sso/{authorize,exchange}. Codes are stored as
  SHA-256 hashes with a TTL index and claimed by a single atomic update, so
  concurrent redemption cannot succeed twice. redirect_uri is matched against
  SSO_REDIRECT_ORIGINS by exact origin — a prefix check would accept
  app.opensquawk.de.evil.tld. There is no default and no wildcard: an empty
  allowlist disables the handoff rather than opening a redirector.
  Consumer: /api/auth/sso/callback plus app/pages/auth/callback.vue. The
  browser only ever carries the code; it is redeemed server-to-server.

Hardcoded values and leaks (0.3)
  Hotjar ID, the dome-light webhook URL and the bug-report recipient were
  compiled in. All three are env-gated and off by default now, so a foreign
  instance cannot ship analytics, cockpit telemetry or its users' bug reports
  to us. Setting HOTJAR_ID, DOME_LIGHT_WEBHOOK_URL and BUG_REPORT_NOTIFY_EMAIL
  restores the current behaviour on opensquawk.de.

Two databases, no shared Mongo (0.6)
  AppUser mirrors an identity locally. Its _id is deliberately the SSO subject,
  i.e. the website's User._id, so every existing LearnProfile, PilotProfile and
  BridgeToken reference keeps resolving without a migration.
  telemetry.ts mirrors records to the hosted service only when TELEMETRY_URL
  and SERVICE_SECRET are both set — the self-host default is that nothing ever
  leaves the instance. It writes locally first, buffers with a bound, drops on
  overflow and never blocks the request path.
  /api/service/user-deleted purges the app's half on account deletion. Unlike
  telemetry this is deliberately loud: the admin delete aborts with the user
  intact if the purge fails, because their id is the only handle for retrying.
  ?force=true overrides it and says so in the response.

Also here
  /api/service/analytics/product-session was an unauthenticated public write
  endpoint; it moves to /api/analytics/product-session behind the auth guard.
  The bridge no longer populates against User but resolves through the mirror,
  backfilling missing rows so live bridges never have to re-pair.
  .claude/worktrees was tracked and would have reached the public repo.

scripts/split-paths.txt carries the filter list, verified by
scripts/verify-split-paths.mjs: every path exists, nothing website-only is
kept, and no kept file imports a dropped one. That check found real gaps —
tests/ cannot be taken wholesale, and two shared modules were missing. Ten
remaining edges are allowlisted, each annotated PHASE 1 in the code.

Open item, flagged and not resolved: flightlabTelemetryStore is an in-process
singleton written by the bridge (app) and read by FlightLab (website). Two
repos means two processes, so that read breaks regardless of which side it
lands on. FlightLab needs an HTTP path in Phase 2/3.

Verified: 609 tests pass, vue-tsc clean. Ran against two throwaway local
MongoDBs: open mode reaches /classroom and /live-atc with no login and
persists progress; the full SSO loop works and the mirror _id matches the
website User._id; lookalike origins, code reuse, forged codes and wrong
service secrets are all rejected; ingest is idempotent on bug-report code;
deletion purges all five collections; and with the app unreachable the admin
delete fails 502 with the user still present.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 18:46:34 +02:00
itsrubberduck
176dbe17a6 merge: classroom overhaul 2026-07-27 11:55:08 +02:00
itsrubberduck
d70fffdd68 refactor(tools): forward the airport endpoints to the backend
/api/service/tools/* was a second implementation of the OSM geocoding and taxi
routing the Python backend already owns — its own Overpass client, alias
matching and scoring. It drifted: it still asked Overpass for `out center tags`,
so a runway resolved to the middle of the strip rather than a threshold, which
is the runway-endpoint bug the backend fixed. Teaching the copy about runway
endpoints would mean maintaining the geometry twice, so the copy goes instead.

Forwarding exposes origin_runway_point / dest_runway_point and
include_connectors, and inherits the backend's Overpass cache and its radius
fallback for aerodromes with no generated OSM area (EDDM), which the copy
answered with an empty feature list. Failures now carry an HTTP status as well
as the error code in the body; the old copy answered every error with 200.

The frequencies call sites needed real types: airportGeocode.ts sat under
server/api with no default export, so Nitro registered it as a route whose
return type collapsed to any and poisoned the whole API type map. The typecheck
was green because of it, not despite it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 11:30:52 +02:00
itsrubberduck
9b2beb2d78 feat(classroom): rebuild curriculum and mastery assessment 2026-07-27 10:26:45 +02:00
itsrubberduck
034ddbab2e feat(bug-reports): trace reports by code and tell Live ATC from Classroom
Every report now gets a UUID that the notification mail quotes as
"Nenne den Fehlercode <uuid> beim Commit", so a fix can be tied back to
the report it closes. The mail also names the area it came from, and the
comment field is relabelled "Fehlerbeschreibung/Featurewunsch" since it
collects feature wishes just as often as bugs.

Classroom loses its plain feedback link and gets the same reporter as
Live ATC — screenshot, arrow annotation and all. `useBugReport` takes an
options object so the communications-engine snapshot stays optional; the
dialog moves out of `live-atc/cockpit` now that both pages use it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 21:11:43 +02:00
itsrubberduck
bcf9a9621c feat(atis): serve the resolved ATIS from /api/airports/:icao/atis
Composes the three live sources into one AtisReport: VATSIM ATIS stations,
the METAR, and the OpenAIP runway ends the frequency endpoint was already
fetching and discarding.

The upstream fetches move into server/utils/airportSources.ts with a TTL cache
matched to each source (VATSIM 20s, METAR 5min, OpenAIP 6h). Without it, adding
this endpoint would have meant pulling the multi-megabyte VATSIM datafeed twice
per session start; the frequency endpoint now shares the same cached copy.

Verified against live data: EDDF (no VATSIM ATIS) synthesises information I with
runway 25C from wind 260/14, while EDDC and EDDM take letter and runway from
their live VATSIM broadcasts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 19:37:16 +02:00
itsrubberduck
1272d45bf9 feat(tts): dedicated ATIS broadcast voice on Speaches
The ATIS tag now resolves to en_GB-alba-medium — outside both voice pools —
instead of sharing 'verse' with the user's own readback voice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 11:22:44 +02:00
itsrubberduck
b359670d47 feat(tts): map logical pool voices to distinct Piper speakers on Speaches
Until now the Speaches branch sent every request to the single env-configured
model (de_DE-thorsten — a German voice for English radio), so the voice pool
had no audible effect. A server-side registry now resolves the logical voice
ids to disjoint controller/pilot Piper speakers; unknown ids keep the env
fallback and the cache key follows the resolved pair.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 10:45:49 +02:00
itsrubberduck
3172516918 feat(websim): browser A320 cockpit to test /live-atc without MSFS (WIP)
Flight model (ground/air physics, SELECTED/NAV/APPR/AUTOLAND autopilot with
STAR sequencing and ILS capture), bridge client that feeds the existing
/api/bridge/* endpoints so /live-atc can't tell it apart from a real bridge,
and the cockpit UI (PFD reuse, FCU, radio panel, Leaflet ND, three.js
exterior, spawn presets at EDDF/EDDS). Design doc:
docs/plans/2026-07-16-websim-design.md.

Also adds a local-dev-only auto-login (/dev-login, server/api/dev/login.post.ts)
that bypasses the invite-only login and MongoDB entirely via a fixed in-memory
user, so require-auth pages are reachable for local testing even when the dev
DB is unreachable. Hard-disabled outside development.

Status: unit tests green (yarn test) and typecheck clean (yarn typecheck).
Browser walkthrough of the actual cockpit (flying a preset, confirming
telemetry reaches /live-atc) is not yet done — picking up from a fresh dev
server + /dev-login?redirect=/flightlab/websim confirmed the spawn screen
renders past auth, but full instrument/map/exterior verification is still
outstanding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 18:49:31 +02:00
itsrubberduck
3fe0ea5f8a feat(sim-control): wire frequency-sim-control command channel end-to-end
Implements the open items from docs/plans/2026-07-14-frequency-sim-control-design.md
§4/§"Offen für die Implementierungsphase": a per-bridge-token in-memory command
queue piggybacked on the existing telemetry channel, plus the client-side gate
and TTS confirmations.

- server/utils/simControlQueue.ts: TTL-based queue keyed by bridge token
  (enqueue → drainPending → resolve → drainResultsForClient).
- server/api/bridge/data.post.ts: response gains a `commands` field the
  bridge drains on its next telemetry POST.
- server/api/bridge/command.post.ts (new): client enqueues a parsed command,
  re-validated server-side via isValidSimControlCommand.
- server/api/bridge/command-result.post.ts (new): bridge reports ok/failed.
- server/api/bridge/live.get.ts: response gains `commandResults` so the
  client can announce outcomes.
- shared/utils/simControl.ts: wire types, isValidSimControlCommand, and
  simControlRejectionSpeech/simControlResultSpeech TTS phrasing.
- useLiveAtcSession.ts: parseSimControl() gated on bridgeConnected, wired in
  right after the local special cases and before the frequency check —
  matched commands never reach radioBackend.transmit().
- useSimBridgeSync.ts / live-atc.vue: bridgeToken threaded through, command
  results forwarded from the telemetry poll to TTS.

43 new tests (shared parser/validation/speech + server queue lifecycle/TTL).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 09:31:17 +02:00
itsrubberduck
7c4369ce09 feat(onboarding): add PUT /api/onboarding/profile route with radioLevel side effect 2026-07-09 16:27:18 +02:00
itsrubberduck
294e48c2cd feat(onboarding): add GET /api/onboarding/profile route 2026-07-09 16:26:18 +02:00
leubeem
1d09a9fc2f feat(pm): LLM routing endpoint, usage capture, and admin review view
Backend counterpart to the Python engine's semantic router.

- POST /api/decision/route: service-secret-guarded endpoint the Python
  backend calls on regex-miss. Calls gpt-5-mini (ROUTER_LLM_MODEL),
  validates the chosen id against the candidate set, and writes both a
  UsageEvent (central cost ledger) and a routing-review record — including
  timeouts, with timeoutMs + actual latencyMs — so the budget can be tuned
- LlmRoutingDecision model + GET /api/admin/llm-routing (paginated,
  status-filtered, per-status counts)
- admin "LLM Routing" tab: transcript vs expected phrase, candidate chips
  with the chosen one highlighted, latency/budget chip, model reason
- serviceAuth util (mirrors CRON_SECRET pattern)
- .env.example: ROUTER_LLM_MODEL, SERVICE_SECRET

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 10:27:57 +02:00
itsrubberduck
7ee9392109 hotkey support 2026-06-20 03:17:53 +02:00
itsrubberduck
0e10e61e40 feat(bridge): map GPS position + true heading into telemetry
Bridge now sends latitude_deg/longitude_deg/heading_deg; map them to
PLANE_LATITUDE/PLANE_LONGITUDE/PLANE_HEADING_DEGREES_TRUE so position and
course land in the telemetry store and surface in /api/bridge/live.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:36:30 +02:00
itsrubberduck
66208d8c5d feat(pm): auto-tune radio from SimBridge telemetry via ?token
When /pm is opened with ?token=<bridge-token>, poll /api/bridge/live for
fresh telemetry. While the bridge keeps posting, mirror the sim's COM1
active frequency into the radio (only on actual sim change, so manual/flow
tuning isn't clobbered) and show a "Bridge connected" badge in the HUD.

Telemetry now carries COM_ACTIVE_FREQUENCY/COM_STANDBY_FREQUENCY from the
bridge's com_active_frequency/com_standby_frequency fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 12:30:23 +02:00
itsrubberduck
013ac12241 feat(pm): add bug-report button with screenshot annotation and admin panel
- New BugReport MongoDB model (comment, contact, userId, screenshot, pmState, status)
- POST /api/bug-reports — authenticated submit; emails emanuel@faktorxmensch.com on receipt
- GET/PATCH /api/admin/bug-reports + /[id] — admin list, detail with screenshot, status toggle
- /pm: "Bug" button in HUD captures viewport screenshot (html2canvas), shows annotation
  canvas where testers can draw arrows; submits comment + contact + state snapshot
- /admin: new "Bug Reports" tab with open-count badge, screenshot expand, "Erledigt" toggle,
  and "In /pm öffnen" link that restores captured engine state via ?restoreBugReport=<id>

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 10:05:25 +02:00
leubeem
b80feb80d6 feat(stt): seed Whisper prompt with expected readback + per-field debug UI
Whisper prompt seeding (per request):
- ptt.post.ts builds the prompt as generic ICAO bias + this state's expected
  readback appended LAST (survives the 224-token truncation), in both raw token
  form and spoken ICAO form via new radioSpeech.speakToken().
- pm.vue passes the expected phrase + active variable values; classroom.vue
  passes the lesson's expected field values.

Per-field readback debug:
- sttMatch.matchTranscriptionToFields returns fields[] (matched/missing + which
  view matched) plus normalized/denormalized transcription views.
- useRadioBackend types readback_report on the transmit response.
- pm.vue renders a "Readback check" panel in the right log rail; classroom.vue
  renders per-field rows under the STT panel.

Radio-pronunciation fixes (radioSpeech.ts):
- callsign expander handles multi-letter suffixes (DLH6RK -> Lufthansa six Romeo
  Kilo).
- toRadioSpeech now expands airports (EDDC -> Echo Delta Delta Charlie).
- bare altitudes >=1000 in a clearance context are spoken ("climb initially
  5000" -> "climb initially five thousand feet"); speeds/headings untouched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 14:12:54 +02:00
leubeem
f097141e8a feat(atc): bias Whisper STT toward aviation phraseology
Replace the generic one-line Whisper prompt with a vocabulary-rich bias prompt
(phonetic alphabet, aviation number words, common phraseology, and the airline
telephony names pulled live from DEFAULT_AIRLINE_TELEPHONY) and set
temperature: 0. Aviation R/T is a constrained domain, so seeding the expected
vocabulary improves transcription of callsigns, runways, and readbacks — the
upstream input to the decision engine. Stays within the ~224-token prompt cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:47:22 +02:00
leubeem
7367f7cdb7 feat(server): per-user AI usage tracking, cost alerting, and endpoint hardening
Usage tracking:
- new UsageEvent collection records every STT/TTS/LLM call per user with
  provider, model, volume (audio seconds, characters, tokens) and an
  estimated USD cost; self-hosted providers (Speaches/Piper) and cache
  hits record at $0
- pricing table for whisper-1, tts-1, gpt-5-nano & co. in server/utils/usage.ts
- weekly KPI mail gains an "AI-Nutzung & Kosten" section: weekly and
  rolling 30-day cost, per-kind breakdown, top 5 users by cost
- quota alert mail when rolling 30-day cost exceeds USAGE_ALERT_USD
  (default $5), at most once per calendar month (UsageAlertDelivery)

Hardening:
- /api/atc/say now requires an authenticated session (middleware
  exemption removed); useFlightLabAudio sends the bearer token
- /api/service/tools/latency requires auth (was a public LLM endpoint)
- per-user rate limits: PTT 20/min, say 60/min, latency 5/min
- cron endpoints (waitlist-drip, weekly-kpi-report) require a shared
  secret via ?secret= or x-cron-secret (CRON_SECRET, falls back to
  KPI_CRON_SECRET); allowed with a warning while unset so existing
  deployments keep working
- PTT records the actual transcribed audio duration for billing accuracy

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:17:03 +02:00
leubeem
cab7b36d85 feat(atc): accept preNormalized flag on /api/atc/say
Clients that already ran the full radiotelephony normalizer (see
normalizeATCText) pass preNormalized: true so the server skips
normalizeATC — double-normalizing corrupts the text, e.g. expandAirports
spells the city name "MAIN" letter-by-letter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:12:53 +02:00
itsrubberduck
d6aa858ff8 feat(atis): inline METAR expansion, airport name lookup, acronym fix
ATIS text often arrives in raw METAR form (e.g.
"METAR EDDF 281050Z AUTO 02008KT 320V070 CAVOK 24/02 Q1025 NOSIG"),
which TTS reads as letter-by-letter spelling. The normalizer now expands
the full WMO Code Form FM 15-XV vocabulary inline: DDHHMMZ date stamps,
compressed wind (with gusts, VRB, calm), wind variability ranges, RVR
(R25L/1500N), wind shear, slash-form temp/dewpoint, Q/A pressure,
NSC/SKC/CLR/NCD/VV cloud codes, weather phenomena (with intensity and
descriptors), recent-weather RE prefix, BECMG/TEMPO/FM/TL/AT trend
codes, and strips RMK remarks. Plus ATIS/METAR/SPECI get lowercased
so TTS pronounces them as words (pilots SPELL ILS/QNH/VOR so those
stay uppercase).

Airport ICAO codes are substituted with their OpenAIP name when the
frequencies endpoint returns one. New `airportName` field added to
the FrequencyResponse for that. Adds 7 test cases covering the user-
reported EDDF sample plus calm/VRB/gust winds, RVR, weather codes,
cloud specials, trend codes, and RMK stripping.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:45:15 +02:00
itsrubberduck
49dd5031bd feat(atis): clock-locked ATIS loop tied to tuned frequency
Real ATIS broadcasts run continuously; tuning in mid-broadcast should
drop the pilot into the current spoken position, then loop. The frontend
now generates the full announcement once via TTS, plays it as a looping
HTMLAudioElement, and seeks to ((Date.now() - lastUpdated) / duration)
on metadata-load so all clients tuned to the same ATIS hear it phase-
synced. The loop starts/stops automatically with frequency tuning and
restarts on info-letter change. say.post.ts now caches tag=atis like
tag=flightlab to avoid re-synthesizing identical announcements.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 14:43:48 +02:00
leubeem
25de89c5f5 fix: correct OpenAIP v2 airport frequency parsing (3 bugs)
The frequency panel was always empty when using OpenAIP because of three
compounding bugs in frequencies.get.ts:

1. Wrong query parameter — ?icao=EDDF performs an unfiltered full-text
   search and returns all 46 000+ airports paginated; EDDF wasn't even
   on the first page.  The correct parameter is ?search=EDDF, which
   returns exactly the one matching airport.

2. Wrong ICAO field name — the code checked airport.icao but the real
   field in the v2 API response is icaoCode.  Even on a correctly
   filtered response the match would always fail.

3. Wrong frequency field names and numeric types — each frequency item
   exposes the MHz value in a value field (not frequency / frequencyMHz),
   and the service type is a numeric code (5=Delivery, 9=Ground,
   14=Tower, 15=ATIS) rather than a string.  Added OPENAIP_TYPE_MAP to
   translate these numeric codes to the internal DEL/GND/TWR/ATIS codes
   the rest of the pipeline expects.

With these fixes EDDF now returns all 8 frequencies (Delivery 122.035,
Ground 121.805, three Tower variants, two ATIS) which are then stored in
delivery_freq / ground_freq / tower_freq / atis_freq and used for both
the frequency overview panel and the per-state frequency validation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 18:16:32 +02:00
leubeem
f2643033f9 feat: wire Python backend session to PTT, add pm.vue debug logger
- Pass  as top-level field in PTT requests so Whisper STT
  results are linked to the correct Python backend session
- Add namespaced  helper in pm.vue (info/warn/error/debug/group)
  controlled by localStorage PM_DEBUG flag; logs transmit/response
  cycles, TTS calls, flag/variable syncs, and fallback warnings
- Log backend session creation context (flow, start state, vars, flags)
  in startMonitoring
- Fix typo in text input hint: STT fails not PTT fails

and

fix: sync backend variables to frontend after each transmission

The ATC say template was rendered using the frontend engine's local
variable defaults (squawk '1234', hardcoded SID, etc.) instead of
the authoritative values from the Python backend session. This caused
the spoken clearance and the readback prompt to show different squawk
codes.

- After each backend transmission response, sync all response.variables
  into vars.value (same pattern already used for flags)
- Prefer controller_say_rendered (pre-rendered by backend) over the raw
  template for TTS scheduling, eliminating any remaining dependency on
  local variable state for the ATC speech text
2026-05-20 16:44:01 +02:00
leubeem
ea4b1e0b24 Cleanup old unused code and add id sessionId to /api/atc/ptt 2026-05-20 14:13:26 +02:00
itsrubberduck
190e44087a simbrief gefixt 2026-05-06 15:43:05 +02:00
itsrubberduck
ab89a65ea0 first version looks ok 2026-04-25 20:29:09 +02:00
itsrubberduck
10fc40e5be feat: warn when classroom speech server is unavailable 2026-04-23 09:21:23 +02:00
itsrubberduck
40dca9d8f6 Bridge dome light mode mapping and flightlab seat belt flow 2026-02-18 22:43:56 +01:00
itsrubberduck
ad1e85f0e8 add the lidl dome light temporarily 2026-02-18 21:49:03 +01:00
itsrubberduck
e818f6001e change default settings 2026-02-18 18:05:12 +01:00
itsrubberduck
3705340b47 besser error message 2026-02-17 19:10:50 +01:00
itsrubberduck
de02dc4f9e typescript 2026-02-17 18:19:55 +01:00
itsrubberduck
54c1b47dc2 fix typescript errors and update dependencies 2026-02-17 18:13:04 +01:00
itsrubberduck
59bede6ad4 add server log 2026-02-17 15:31:32 +01:00
itsrubberduck
4787a06906 feat(bridge): add unlink flow for linked tokens 2026-02-16 16:39:18 +01:00
itsrubberduck
86de549adb use 6 digit codes for bridge 2026-02-16 15:47:12 +01:00
itsrubberduck
8e01936abb Fix bridge telemetry boolean coercion for auto-advance conditions
SimConnect sends boolean fields (on_ground, parking_brake, etc.) as 0/1
numbers. The condition evaluator uses strict equality (===), so
0 === false was returning false even when the condition was semantically
met. Cast boolean telemetry fields with !! to ensure proper type matching.
Also reduce solo-mode telemetry polling from 500ms to 2000ms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:26:50 +01:00
itsrubberduck
4ac07d9352 Connect bridge telemetry to FlightLab with auto-advance triggers
Map raw bridge fields (ias_kt, on_ground, etc.) to FlightLabTelemetryState
format, add direct telemetry polling endpoint for solo mode, and show
sim condition panel in sidebar regardless of auto-advance toggle state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:16:42 +01:00
itsrubberduck
f742722e9c Unify bridge auth header and add live telemetry panel 2026-02-15 16:04:07 +01:00
itsrubberduck
346579676e fix(classroom): audio speed slider now actually changes playback speed with pitch correction
- Fix client: playbackRate was set to 1 for non-native-speed providers (Speaches/Piper),
  making the speed slider ineffective in the main Pizzicato audio path
- Fix server: pass speed parameter to Speaches TTS API
- Add pitch-preserving playback via MediaElementSourceNode when rate != 1,
  routing through the same Web Audio effects chain (radio filters, distortion, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:01:02 +01:00
itsrubberduck
acb79cdb2b feat(flightlab): sidebar, progress bars, skip speech, SimBridge telemetry & auth
- Add collapsible sidebar with phase stepper (jump between phases)
- Add SimBridge conditions panel in sidebar (live values, progress bars, targets)
- Add global progress bar (top edge, glowing) + phase-local TTS progress bar
- Add skip button to skip TTS speech while ATC is speaking
- Add skipSpeech() to audio composable (stops current Pizzicato sound)
- Wire up bridge data.post.ts with user auth (JWT) + example payload
- Add server-side telemetry store with pub/sub for Bridge→WS relay
- Extend WS handler with subscribe-telemetry message + userId tracking
- Extend sync composable with subscribeTelemetry() + onTelemetry() callback
- Add require-auth middleware to all flightlab pages
- Fix instructor station ECONNREFUSED via import.meta.client guard
- Add animations: phase transitions, button lists, fade-scale, check-pop, pulse

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 10:14:33 +01:00
itsrubberduck
af2eed2d6e dont log users id on transmission 2026-02-13 18:44:34 +01:00
itsrubberduck
a5272149c6 add todo for najan 2025-10-19 21:03:52 +02:00
Remi
1dd78b95b1 Add bidirectional airport geocode and name-aware taxi routing 2025-10-19 19:17:18 +02:00
Remi
0febe45862 Remove explicit type hints from airport geocode lookup 2025-10-19 19:07:23 +02:00
Remi
ef603bda13 Infer airport geocode types from query text 2025-10-19 19:00:32 +02:00
Remi
f4beba1b25 Add airport geocode endpoint 2025-10-19 18:56:48 +02:00
Remi
20341aa06b Refine taxiway collapse and radius default 2025-10-18 21:47:54 +02:00