Commit Graph

28 Commits

Author SHA1 Message Date
Billie Ponder e0de6f22ba
feat(website): smooth motorcycle replay animation with 60 FPS sub-sample interpolation (#40)
* feat(website): smooth motorcycle replay animation with 60 FPS interpolation and shortest-path heading

* fix(website): eliminate map pan thrashing, pause snapping, and non-finite coordinate exceptions in replay

* chore(website): remove development test page and screenshots, add authentic telemetry verification

* fix(website): reset replay carry on ride switch and translate fixture to synthetic coordinates

---------

Co-authored-by: Developer <dev@example.com>
2026-10-14 22:02:32 -04:00
Developer b61d1ebeec fix(website): monotonic timestamp ride IDs, zero-budget cursor guard, and modal input preservation
- Guard advancePlaybackIndex against spuriously advancing when budgetMs <= 0 on duplicate timestamps
- Use monotonic millisecond timestamp in commitGroupRide to eliminate timestamp corruption and collision hazards
- Preserve CreateGroupRideModal form inputs on failed commit so users do not lose typed data
- Add regression tests in vitest suites for zero-budget duplicate timestamps, timestamp fidelity, and input preservation
2026-10-14 15:07:00 -04:00
Developer a709b058b3 fix(website): replay edge-case resilience and concurrent ride submission guards
- Add replay regression test suite covering irregular/jittered timestamps, identical/zero dt, inverted timestamps, large gaps, pause/resume timing reconciliation, manual seek, speed changes, and large datasets (144k points).
- Harden advancePlaybackIndex against non-finite/NaN budget and timestamp delta anomalies.
- Reset lastTimeRef and cap frameDelta in WebTelemetryReplayModal to eliminate sudden jumps on speed switching or background tab resumes.
- Guard group-ride creation with in-flight isSubmitting state and disabled submit button in CreateGroupRideModal; guarantee unique collision-free ride IDs across concurrent submissions.
- Remove obsolete Vercel reference in website/.env.example in favor of Vultr VPS and Caddy; add npm test script.
2026-10-14 14:45:41 -04:00
Developer dd35b216d1 fix(website): persisted-only ride creation and reconciled replay timing (PR #38 hardening)
Phase 1 — group ride creation (no phantom rides):
- Check authentication and Firestore availability BEFORE touching UI state; an unauthenticated
  user (or unavailable Firestore) now gets an actionable error and no phantom ride, instead of a
  local entry that was never saved.
- Insert the ride into UI state ONLY after batch.commit() confirms the write; on commit failure
  nothing is inserted and an error is shown.
- Prevent duplicate submissions: the create modal disables its submit button while in flight, and
  the hub guards with a ref.
- The join code remains the real Firestore document id (no fabricated ids).
- Extract commitGroupRide (pure, dependency-injected) so every path is unit-testable.

Phase 2 — replay playback timing:
- The elapsed clock and rider marker both derive from the same cursor, so they cannot drift.
- Manual seeks (scrub, restart, corner jump, arrow keys) go through seekTo(), which reconciles
  playback timing (clears carry/last-frame) so no stale budget is applied after a seek.
- Make gap compression explicit: a caption labels the timeline as recorded elapsed time and warns
  that dead time in multi-segment recordings is skipped during playback.

Tests: commitGroupRide (unauthenticated / unavailable / commit-ok / commit-failed); group-rides
hub now uses an authenticated mock with deterministic Firebase — authenticated create persists,
unauthenticated create is blocked with no phantom, a failed commit leaves no phantom, and the
create modal blocks duplicate submits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 13:12:49 -04:00
Developer 6956e809a3 fix(website): truthful group-ride creation — no false success, no fabricated GPS (Phase 3)
Creating a ride from the hub had two integrity problems:
- The "Created … success" toast fired optimistically before the Firestore write, and a
  commit failure was only console.error'd — so a user could be told the ride was created
  when nothing persisted (the ride would then vanish on the next snapshot).
- Every created ride wrote a hardcoded meetingPoint at 34.5378, -83.9849 (Helen, GA)
  regardless of the typed location — fabricated GPS attached to real rides.

Fixes:
- Report success only after `batch.commit()` resolves; on failure, roll back the optimistic
  insert and show an error. When there is no authenticated session / Firestore, keep the
  local entry for responsiveness but make no cloud-success claim.
- Extract buildWebGroupRidePayload (pure): stores the rally point as displayName/address
  text and omits latitude/longitude (the web form has no map picker / geocoder, so we never
  fabricate coordinates). mapFirestoreRideToSummary already treats a missing coordinate as
  "not pinned yet".

Join-by-code, join/leave, edit, and delete flows were reviewed and persist/authorize
correctly; no changes needed there.

Tests: buildWebGroupRidePayload asserts no fabricated lat/lon, rally-point text/fallback,
authoritative organizer/access fields, scheduled-time handling, and club identity. Existing
group-ride UI tests remain green.

Known limitation: true address autocomplete and automatic route-distance calculation require
a geocoding/routing API that does not exist in this codebase; distance and rally point remain
free-text until that backend lands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:49:16 -04:00
Developer ae1980b4ed fix(website): synchronize telemetry replay playback with recorded time (Phase 4)
The replay loop advanced the cursor by one sample every 50 ms / speed, assuming a uniform
20 Hz stream. Recorded telemetry is not always uniform (segment breaks and GPS-loss gaps up
to 5 s), so the rider marker drifted out of sync with the elapsed-time readout — which is
derived from real timestamps — and "1x" did not match real time across gaps.

Make playback timestamp-driven:
- Add advancePlaybackIndex(points, fromIndex, budgetMs): a pure helper that consumes a
  budget of virtual recorded time, advancing by the real delta between samples so the
  marker tracks the elapsed-time clock. Disconnected transitions (per
  areTelemetryPointsConnected) are compressed to a single 50 ms step so playback never
  stalls across multi-second dead time. No coordinates are altered.
- Drive the rAF loop with frameDelta * playbackSpeed plus carry-over, resuming from an
  index ref so manual scrubs are honored.

Verified sound without changes: SHA-256-checked R2/inline telemetry load, CSV/GPX parse and
export integrity, loading/error/empty overlays, and tile-provider fallback.

Tests: advancePlaybackIndex covers uniform cadence, carry-over, gap compression, end-clamp,
and empty input. Existing replay/export/corner tests remain green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:36:07 -04:00
Developer 2cb3ef9694 fix(website): label fallback club routes and chat as examples (W-routes, W-chat)
When a club has no curated routes or a chat channel has no messages, the data layer
returned fixture content with no indication it was sample data, so riders could mistake
MotorSignal's "Coastal Marshes" route or canned chat messages for their club's real data.

Flag fixture-sourced content and label it in the UI:
- Add isExample to ClubRoute and ChatMessage; set it on every fixture fallback path
  (empty Firestore collection/channel and the dev demo preview).
- Founder Routes: amber "Examples" count, an explanatory banner, and a per-card "Example"
  badge when the routes shown are samples.
- Founder Chat: an "Example thread" pill (instead of "Live Connected") and a banner when
  the only messages are examples, so the header never claims a live conversation that
  does not exist.

Tests: example-labelled routes render the banner/badge/count; example-labelled chat
renders the banner and "Example thread" pill and does not claim "Live Connected".
Existing route/chat tests (real data, no isExample) remain green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:08:15 -04:00
Developer 3ba94777a1 fix: resolve Android CI breakpoint overflow and address Codex PR #28 findings
- Fix RenderFlex overflow at short landscape breakpoint (640x320) by scaling center controls in ResponsiveDashboardLayout and clamping LeanAngleIndicator bounds
2026-10-09 18:53:39 -04:00
Developer 20da9ee27d feat(core): reconcile local development, hybrid design, sensor fusion, and docs
- Consolidate Hybrid v1 tokens, theme extensions, and core UI components (HybridCard, HybridMetricTile, HybridRidingActionBar, HybridStaticRecBadge)
2026-10-09 05:12:01 -04:00
Developer 602aa962e2 fix(website): isolate Firebase configuration for staging and enforce safety guards 2026-10-08 10:50:28 -04:00
Developer c956ffd7bd feat(website): add club curated routes, live squad chat, and portal navigation 2026-10-02 12:39:38 -04:00
Developer f495ec0cac feat: add club members and wall management 2026-10-01 08:31:45 -04:00
Developer 71cd994b2f feat(mobile): add community social feed, tactical layers, club wall, launch curves, and curvy routes (v1.0.2+102) 2026-09-29 11:50:48 -04:00
Billie Ponder c1aa68ac43
feat(group-rides): secure club join moderation and discovery (Phase 3A) (#26)
* feat(clubs): enable admin group ride governance

* feat(clubs): add secure member ride discovery

* fix(clubs): protect meeting location in ride discovery

* feat(group-rides): secure club join moderation

* test(clubs): update ride discovery expectations

* test(founder-portal): update rides governance expectations

* fix(group-rides): resolve pre-merge findings on join moderation and discovery

- Block participant hard deletes for accepted status and organizer role for all callers

- Support atomic accessUids removal on invitation decline in firestore.rules

- Restrict mutual-block checks to approvals in GroupRideService, allowing decline of blocked requests

- Implement cursor-paginated candidate scanning with block filtering in website discovery API

- Add comprehensive emulator, vitest, and unit tests covering all 5 findings

* fix(discovery): page candidates until 30 eligible rides collected or query exhausted

- Remove artificial 150 candidate scan ceiling in club rides discovery route

- Continue cursor pagination until 30 unblocked eligible rides are collected or upcoming schedule query is exhausted

- Add test verifying pagination continues past 150 blocked rides to collect all 30 eligible rides

---------

Co-authored-by: Developer <dev@example.com>
2026-09-24 12:00:48 -04:00
Billie Ponder 54886753b7
feat(ops): add dual speedtest options, support ticket fixes, cms sync, and overview card redesign (#23)
Co-authored-by: Developer <dev@example.com>
2026-09-22 01:38:54 -04:00
Billie Ponder 9d99bfa4e4
feat(ops): implement production operations infrastructure dashboard (phase 1) (#14)
* feat(ops): implement production operations infrastructure dashboard (phase 1)

- Add backend read-only infrastructure metrics collector (CPU, RAM, swap, disk with 80%/90% thresholds, uptime, network cumulative totals, systemd service allowlist) using standard library only (no psutil).

- Register GET /api/v1/ops/infrastructure endpoint guarded by require_ops_roles('operator', 'owner').

- Add Next.js API proxy route /api/ops/infrastructure validating ops session cookie and forwarding to backend.

- Implement dark-surface OperationsInfrastructure component in website admin console with 30s visibility-gated polling and overlap prevention.

- Add comprehensive backend and frontend test suites (8 backend tests, 43 ops-experience tests).

* fix(ops): query internal website version endpoint defensively on verified port 3001

- Query internal website GET /api/version on verified production listener http://127.0.0.1:3001 (configurable via WEBSITE_INTERNAL_URL).

- Parse JSON defensively with a 4096-byte response bound and validate exact 40-char hex revision pattern.

- Add comprehensive tests for valid, missing, malformed, oversized, and unreachable version responses.

- Do not expose internal URLs or connection errors in API responses.

* fix(ops): map postgresql service to cluster unit postgresql@14-main and preserve health errors

- Map public logical service ID 'postgresql' to fixed systemd unit 'postgresql@14-main'.

- Reject direct systemd unit names and arbitrary service names.

- Preserve HTTP 5xx responses as degraded on /api/health before root fallback.

- Add regression tests for postgresql unit mapping, API response name stability, and health 5xx preservation.

---------

Co-authored-by: Developer <dev@example.com>
2026-09-20 17:14:21 -04:00
Billie Ponder 59900f46f2
feat(web): add clubs rides management (#9)
Add the disabled Founder Portal Club Rides scaffold aligned with the live GroupRide.clubId domain.

Keep production discovery and actions disabled until a privacy-preserving read path and real management destinations are implemented.
2026-09-20 07:23:00 -04:00
Developer 4dc6e0526d fix(web): address clubs review findings
- Gate ranks-roles management route on canManageSettings with safe
  unauthorized state, matching sibling founder-management routes
- Enforce HTTPS image URL invariant for club logo/banner in the data
  layer (validateClubImageUrl) and in Firestore rules, preserving
  null/empty clearing
2026-09-20 02:35:37 -04:00
Developer b01054b696 fix(web): repair clubs management experience 2026-09-20 02:02:22 -04:00
Developer d5dcc97495 feat(website): standardize dark glass design system, obsidian contrast buttons, and rider account management 2026-09-18 18:35:31 -04:00
Developer 9418aa2ac8 feat(clubs): add public syndicates directory, club discovery, and founder management portal 2026-09-18 18:35:21 -04:00
Developer fa2fccd137 feat(ops): add incident management, user administration, support tickets, and website CMS 2026-09-18 18:35:12 -04:00
Developer cd5201c13a fix: isolate marketing layout checkpoint 2026-09-12 18:36:53 -04:00
Developer 8681e6f259 feat: add Operations incident management 2026-09-10 14:48:08 -04:00
Developer 55b3a5908a feat: add isolated MotorSignal Operations console 2026-09-10 08:17:06 -04:00
Developer 58193f6de4 feat: add founder club applications workflow 2026-09-09 08:37:34 -04:00
Developer d544292a3c feat: add founder club settings and governance lifecycle 2026-09-09 07:51:48 -04:00
Developer 5eb47e8c09 feat: add founder club profile and sub-routing foundation 2026-09-09 07:06:45 -04:00