MotorSignal-App/docs/CODEX_HANDOFF_2026-09-08.md

8.3 KiB

MotorSignal Agent Handoff

Last updated: 2026-09-08

Mission

MotorSignal is a Flutter motorcycle telemetry app with a Next.js companion website and a FastAPI/PostgreSQL production API. Current work covers the public website, Firebase-linked app data, RBAC/admin operations, and VPS deployment.

Workspace:

C:\Users\Bill\Desktop\flutter-app

Production:

Website: https://motorsignal.app
API: https://api.motorsignal.app
VPS: motorsignal-admin@89.31.239.10

Never put SSH keys, passwords, Firebase private credentials, JWT secrets, SMTP credentials, or database passwords in this file or Git.

Read First

  1. Root AGENTS.md and its referenced C:\Users\Bill.codex\RTK.md.
  2. docs/PRODUCTION_DEPLOYMENT_CHECKLIST.md.
  3. docs/WEBSITE_ADMIN_CURRENT_STATE.md.
  4. Relevant docs under docs/agents/.

Rules that matter:

  • Investigate source, callers, schemas, and tests before changing behavior.
  • Do not casually change Flutter telemetry cadence, SensorFusion, RideStateMachine, or Drift schema 7.
  • Preserve the offline-first ride sync pipeline and stable cloud ride IDs.
  • Behavioral changes need focused automated coverage.
  • Preserve unrelated dirty-worktree changes.
  • Do not commit or push without explicit authorization.

Current Local State

The worktree is intentionally dirty. Preserve all existing changes.

The website currently includes:

  • Firebase account linking and Firestore app-data display.
  • Password reset, email verification, and session management.
  • RBAC-protected admin console with user, vehicle, ride, and audit views.
  • Stitch-inspired landing page.
  • Completed public Features, Group Rides, Clubs, and Pricing pages.
  • Public menu links for Features, Group rides, Clubs, Pricing, Download, and Support.
  • Hero image at website/public/images/motorsignal-hero.jpg.

Important files:

website/app/page.tsx
website/app/features/page.tsx
website/app/group-rides/page.tsx
website/app/clubs/page.tsx
website/app/pricing/page.tsx
website/app/account/page.tsx
website/app/admin/page.tsx
website/app/globals.css
website/components/site-header.tsx
website/components/companion-list.tsx
website/components/app-cloud-data.tsx
website/components/firebase-link.tsx
website/components/session-manager.tsx
website/lib/firebase-client.ts

The latest public-page source is newer than the deployed bundles. Build and package it before deploying.

Stitch Reference Assets

Downloaded under stitch/admin-dashboard-revamp/:

  • flagship-landing/
  • features-telemetry-architecture/
  • group-rides-pack-radar/
  • clubs-fleet-intelligence/
  • pricing-hardware-plans/
  • rider-account-portal/
  • Admin console screenshot and generated HTML

These are design references. Do not copy fake Stitch KPI values into production data displays unless labeled illustrative. Admin KPIs should come from real API totals.

Firebase Data Contract

The Flutter app writes:

users/{firebaseUid}/motorcycles/{motorcycleId}
users/{firebaseUid}/rides/{cloudRideId}

Motorcycle fields include year, makeName, modelName, variantName, nickname, and isDefault.

Ride fields include startTime, distanceMiles, topSpeedMph, motorcycleYear, motorcycleMake, motorcycleModel, qualityRating, and telemetry bundle metadata.

Website AppCloudData reads these owner-scoped collections after Google/Firebase account linking. Firestore rules enforce the Firebase owner UID. Do not merge records using email alone.

Firebase project:

motoapp-d22e0

Backend Firebase linking validates the identity and stores users.firebase_uid. X.509 certificate parsing is fixed and covered by a regression test.

Backend and Production

Backend source:

backend/motorsignal_api/

Important files:

backend/motorsignal_api/alembic/versions/e0f5a7123b46_link_firebase_identity.py
backend/motorsignal_api/tests/test_firebase_auth.py
backend/motorsignal_api/tests/test_api_smoke.py

Services:

motorsignal-api.service
motorsignal-website.service
nginx.service

Release layout:

/opt/motorsignal/current
/opt/motorsignal/releases/<release>

The API expects /opt/motorsignal/current/app and /opt/motorsignal/current/venv.

Deployment History

20260908-06  Account Firestore app-data display
20260908-07  Stitch-inspired admin console
20260908-08  First public landing/features/rides/clubs implementation
20260908-09  Expanded landing page

Checksums:

20260908-08 website:
5ab316a7889b76185bee3af86798bf51d22c4dac41907afe27104c0d4d2ea91c

20260908-09 website:
ab561d8974ab10f9f9755c7c54d2df71ea64b4a6e3417d60c0ff112ea10d5f94

The latest full Features, Group Rides, Clubs, and Pricing implementation was made after release 09 and has not been packaged. Build a new release, preferably 20260908-10, from the current source.

The active VPS release is not confirmed. Check it:

readlink -f /opt/motorsignal/current

Deployment Procedure

Build:

cd website
npm run build

Package the current standalone website:

$release='20260908-10'
$stage="scratch/deploy/$release"
New-Item -ItemType Directory -Path "$stage/website" -Force | Out-Null
Copy-Item website/.next/standalone/* "$stage/website" -Recurse -Force
New-Item -ItemType Directory -Path "$stage/website/.next/static" -Force | Out-Null
Copy-Item website/.next/static/* "$stage/website/.next/static" -Recurse -Force
if (Test-Path website/public) { Copy-Item website/public "$stage/website/public" -Recurse -Force }
Compress-Archive -Path "$stage/website" -DestinationPath "$stage/motorsignal-website-$release.zip" -Force

Upload with the existing SSH key:

scp -i C:\Users\Bill\.ssh\motorsignal_prod scratch/deploy/20260908-10/motorsignal-backend-20260908-10.zip scratch/deploy/20260908-10/motorsignal-website-20260908-10.zip motorsignal-admin@89.31.239.10:/tmp/

Verify SHA-256 on both local and remote files before staging.

Root/provider-console cutover:

set -euo pipefail
RELEASE=20260908-10
DIR=/opt/motorsignal/releases/$RELEASE
printf 'DIR=%s\n' "$DIR"
test "$DIR" = "/opt/motorsignal/releases/$RELEASE"
install -d -o motorsignal -g motorsignal "$DIR"
unzip -q /tmp/motorsignal-backend-$RELEASE.zip -d "$DIR"
unzip -q /tmp/motorsignal-website-$RELEASE.zip -d "$DIR"
ln -sfn backend/app "$DIR/app"
ln -sfn backend/alembic "$DIR/alembic"
ln -sfn backend/alembic.ini "$DIR/alembic.ini"
ln -sfn backend/requirements.lock "$DIR/requirements.lock"
cp -a /opt/motorsignal/current/venv "$DIR/venv"
chown -R motorsignal:motorsignal "$DIR"
ln -sfn "$DIR" /opt/motorsignal/current
systemctl restart motorsignal-api
systemctl restart motorsignal-website
sleep 3
curl -fsS https://api.motorsignal.app/api/v1/health
curl -fsS -I https://motorsignal.app/
curl -fsS -I https://motorsignal.app/features
curl -fsS -I https://motorsignal.app/group-rides
curl -fsS -I https://motorsignal.app/clubs
curl -fsS -I https://motorsignal.app/pricing

Current Deployment Blocker

The user reported:

ln: failed to create symbolic link '/opt/motorsignal/releases/20260908-08/app/app': File exists

This means DIR was likely set one level too deep, ending in /app, or a command was run with an incorrect working directory. The correct target is:

/opt/motorsignal/releases/20260908-08/app

not:

/opt/motorsignal/releases/20260908-08/app/app

Always reset and print DIR before symlink commands. Use ln -sfn for known release-local symlinks. Do not recursively delete a release without inspecting it using find, stat, and readlink.

Validation Remaining

The latest local website build passed:

npm run build

Still needed:

  • Package the latest source as release 20260908-10.

  • Deploy and verify the VPS release.

  • Browser-check the public routes after deployment.

  • Test signed-in Firebase-backed Group Rides, Clubs, and Account data with the real account.

  • Confirm the hero image loads through the standalone bundle.

  • Run the complete Flutter gates before declaring the broader project complete:

    flutter test flutter analyze flutter build apk --debug

Do not claim Firebase rides exist unless the app has completed cloud sync. Local-only rides will not appear in Firestore.

Git Safety

No commit or push was authorized for this handoff. Do not stage the entire repository because it contains unrelated ongoing work. Stage only explicitly requested files if a later user authorizes a commit.