—
Signed-in account and API access
Paste this on other devices (e.g. iPad) if the login flow can't reach the Worker.
Drift Analysis dashboard release history
config.h at provision time used to be hardcoded in setup.html JavaScript. Now they live on the profiles table with a dedicated editor card on Settings.config.h generator now reads these values from the selected profile row. Change cadence on Settings → next provisioned unit picks it up. Existing flashed units are still static (no downlink support), but at least you're not editing HTML.PATCH /api/profiles/:key for admin edits. Schema migration 0010_profile_cadence.sql adds the four columns and seeds the two existing profiles (spawn, longterm) with their historical values.role-aware.js loaded by every admin page — calls /api/whoami, sets body.dataset.role, injects the hide rules. One place to maintain.sponsor.html dashboard showing their fleet, positions, and stats. No more emailing URL tokens that need to be rotated./api/sponsor-view/:key where :key matches their sponsor_key. Every other endpoint returns 403. Even /api/whoami and /api/logout are the only exceptions (and they only return the sponsor's own identity).schema/0009_sponsor_users.sql adds the sponsor_key column to the users table plus an index.GET /api/dashboard — one round-trip pulls the whole snapshot.ADMIN_EMAIL / ADMIN_PASSWORD) is automatically upserted into the users table on first login, so nothing needs to be seeded manually. Existing FLEET_API_KEY sessions keep working during the rollout as a break-glass credential.POST /api/logout to delete the server-side session, not just the localStorage key. Deleting a disabled user cascades to their sessions.contributions table. Each row records: sponsor, units_purchased, price_per_unit_aud, season (freetext), invoice_ref, invoiced_at, paid_at, notes. Sponsors can have multiple contributions across seasons or as top-ups within a season.schema/0007_contributions.sql. The drifter billing columns from v4.7 (purchase_price_aud, invoice_ref, invoiced_at, paid_at) are now unused; they stay in the schema for now, will be removed in a later cleanup migration.sponsors.html page with the full sponsor list, per-sponsor billing rollup (units, total value, invoiced, paid, outstanding), aggregate strip across the top for at-a-glance totals, and a click-through detail drawer for each sponsor.schema/0006_billing_fields.sql adds four new columns to the drifters table. Apply in D1 Console (one ALTER at a time) before deploying the v4.7 Worker.runBackup() function in the Worker was returning a plain object where the router expected a Response. The wrap step then dispatched an empty-body 200 to the client, which parsed as null, and reading .key off it exploded. Every other endpoint properly wraps in jsonResponse(); missed it here.deploy.sh: a Worker Cron Trigger attach failure (usually a token permission gap on the account) no longer halts the whole script under set -e. The Worker code itself uploads successfully in that scenario; the schedule attach is the only thing that fails. Pages deploy now still runs so the frontend picks up the new version. Warning message points at the dashboard workaround.drift-analysis-backups R2 bucket with generation timestamp metadata, and prunes anything older than 30 days.--skip-backup habit that the wrangler token permission gap forced on earlier releases. Backups now come from inside the Worker, which has direct D1 read access and doesn't need any additional token./sponsor.html?key=gbrf&token=<32-char-hex>) that shows their drifters, current positions on a map, headline stats (total drifters, currently deployed, active this week, total drift-km), and deployment history. No admin controls, no other sponsors' data, no maintenance log — deliberately separate endpoint so there is no way to accidentally leak internal data through it.GET /api/sponsor-view/:key?token=xxx) validates the token via a constant-time-ish comparison and returns 403 on mismatch. No admin auth is checked; the token IS the credential.share_token column to sponsors (nullable). Apply schema/0005_sponsor_share_tokens.sql in D1 Console before deploying the v4.4 Worker.mode field is an operational state (BEACHED, DRIFTING, etc.) that only makes sense while the drifter is in the water. Previously, once a drifter was recovered to the workshop the last observed mode stayed pinned on its row — so units sitting on a bench displayed BEACHED, which is nonsensical.last_mode when a drifter comes out of the water. Historical last_lat / last_lon / last_fix_at / last_batt_mv are retained since those remain useful reference values.status === "deployed", so any drifter with an already-polluted stale mode (like the two workshop units that triggered this fix) immediately shows — without needing a DB migration. Mode filter dropdown now also gates on deployed status, so filtering by BEACHED cannot match workshop rows with a stale mode.⏳ N pending sync chip in the action bar shows the queue depth; tap it to see each pending action with Retry and Remove buttons. Conflict rule is last-write-wins — the boat is authoritative for what happened in the water.navigator.onLine. Hover for a tooltip.dtHours > 0, so two ingestion calls that landed in the same Unix second (Myriota timestamps are second-resolution, and satellite passes can deliver multiple packets per second) slipped through. Caught by re-running the Darwin smoke test: both calls got the same fixed_at and the jump was marked clean again.distance > 500 m guard stops small jitter cases from ever tripping the rule, no matter what the implied speed says.id column, so assessQuality saw undefined for last_lat / last_lon / last_fix_at and silently skipped the distance check. Caught by a smoke test that posted a Fitzroy → Darwin jump (~1900 km in 44 s) and got quality: "clean" back. The lookup now selects the denorm columns, and the null-guard uses != null so future callers can't recreate the bug with an undefined field.schema/0004_reset_test_pollution.sql — DRIFT-051's denorm state was polluted with Darwin coordinates during the v3.7 test run. Paste this in the D1 Console to reset before re-testing.POST /api/ingest/myriota endpoint that speaks Device Manager's actual webhook shape. Parses the escaped Data JSON string, decodes each 20-byte hex payload using the DriftSpawn binary format, and delegates into the same code path as the idealised /api/ingest. Point Myriota's custom destination at this URL when you register the first live module.config.h now includes the exact DriftSpawn_message_t struct definition at the top, so firmware and decoder can never drift out of sync. Layout: seq (u16), lat_e7 (i32), lon_e7 (i32), fixed_at (u32), sst_c100 (i16), batt_mv (u16), mode_sats (u8), hdop_x10 (u8) — 20 bytes exactly, matching Myriota's per-message maximum.dedup: true flag so you can tell it happened.quality: "suspect" in the track_points table. Suspect fixes are stored but do NOT update the drifter's last_lat / last_lon, so the map stays anchored to the last clean position rather than teleporting on a garbage lock. Requires a one-time schema change — see schema/0003_track_point_quality.sql.msg_per_month, so spawn-cadence and long-term profiles use their own appropriate cutoffs.@media (hover: hover) and (pointer: fine), so an iPad with a paired trackpad or mouse does get hover behaviour._headers file for Pages caching — HTML entry points now serve with no-cache, must-revalidate, and vendor assets with a one-year immutable cache. Fixes the "I deployed but it did not update" issue at the source: every future deploy is visible on refresh, no hard reload needed.config_DRIFT-###.h header (copy or download) that drops straight into the Myriota SDK build tree — one #define per parameter, so nothing gets typed twice and every flashed unit carries its identity, sponsor, area, profile, and cadence constants baked into the firmware.simulate_ingest.sh.POST /api/ingest on the Worker, ready to receive real fixes from a Myriota webhook. Accepts one point or a batch, resolves drifters by ID or module serial, auto-links each fix to the open deployment, updates the drifter's last-known position (skipping out-of-order deliveries).INGEST_TOKEN secret rather than the admin key, so a leaked webhook URL cannot pivot into the fleet management API.POST /api/ingest/simulate generates a plausible fix near a drifter's last known position and pushes it through the real ingestion path, so you can smoke-test the whole pipeline without hardware.track_points reads is scheduled for v3.5.track_points reads once v3.3's Myriota webhook lands.position: fixed was never applied). Now correctly covers the whole viewport so you can log in on any device without scrolling past the map to find the fields.?api= in URLs — the Worker URL is now baked into the frontend as a default. Bookmark the plain drift-analysis.pages.dev URL and login works out of the box.?api=<url> for local dev, ?api= (empty) for same-origin once a route is set.deploy.sh now auto-installs wrangler if it's missing (fixes the Cloud Shell wipe-on-session issue) and treats a failed D1 backup as a warning rather than a hard-stop, so schema/worker/pages steps always run.wrangler secret put ADMIN_PASSWORD.POST /api/login worker endpoint validating ADMIN_EMAIL / ADMIN_PASSWORD secrets and returning the FLEET_API_KEY.drift-analysis project.Recording at currently-selected playback speed
Preparing…