TracktTabs — Real-time race day dashboard for backyard ultra runners. Vue 3 + Supabase, hosted on Neocities.
shell-bundle.js monkey-patches Vue.createApp to inject AppShell nav componentssupabase-client.js is the single Supabase client instance shared by all modules?v=N query params on script importsEvery active HTML page and what it loads. All pages use Vue 3 Options API.
| Page | Title | Module JS | JS Version | Shell | Imports |
|---|---|---|---|---|---|
index-v3.html |
Command Center | index-v3.js | ?v=4 | yes | supabase-client, user-manager, crew-link-service, api-service |
race-day-v3.html |
Race Day Dashboard | race-day-v3.js | ?v=11 | yes | 19 imports (largest page) |
profile-select-v3.html |
Sign In | profile-select-v3.js | ?v=7 | yes | supabase-client, user-manager, role-service, crew-link, image-storage, pr-verification, spectator-privacy, passwordHash |
settings-v3.html |
Settings | settings-v3.js | ?v=8 | yes | settings-service, user-manager, supabase-client, weather-provider, photo-upload |
plan-v3.html |
Plan Wizard | plan-v3.js | ?v=9 | yes | plan-data-service, user-manager, product-database, custom-metrics, crew-link, api-service, shared components |
analysis-v3.html |
Analysis | analysis-v3.js | ?v=6 | yes | analysis-service, user-manager, social-feed-service |
compare-v3.html |
Compare Races | compare-v3.js | ?v=3 | yes | analysis-service, api-service, user-manager, supabase-client |
conditions-v3.html |
Conditions | conditions-v3.js | ?v=3 | yes | conditions-service-v3, weather-provider, sweat-math, user-manager, race-profile-service |
practice-v3.html |
Practice Sessions | practice-v3.js | ?v=2 | yes | practice-session-service, custom-metrics, user-manager, config |
bibboard.html |
Bib Board | bibboard.js | ?v=5 | no | supabase-client, role-service, crew-link, image-storage, pr-verification, spectator-privacy, passwordHash |
reset-password.html |
Reset Password | reset-password.js | ?v=2 | no | supabase-client |
These pages exist but use older patterns or inline scripts: admin.html, crew-troubleshoot.html, live-race.html, live-tracking.html, fuel-menu.html, sweat-analyzer.html, and ~10 experimental lab pages (analytics-lab, energy-terrain, race-replay, pace-tunnel, mountain-climb, body-systems, catlap-vr, race-time-machine).
All ES module services in js/services/. Each is a singleton.
| Service | Exports | Imports From | Status |
|---|---|---|---|
| supabase-client.js | supabase, supabaseClient, waitForAuthReady, getSession, getAuthUid, isAuthenticated | (none — root module, uses window.supabase UMD) | core |
| user-manager.js | userManager, hashPassword, verifyPassword | api-service, supabase-client?v=2, passwordHash | core |
| api-service.js | apiService | supabase-client?v=2 | core |
| settings-service.js | settingsService | supabase-client?v=2, user-manager?v=2 | ok |
| role-service.js | roleService | supabase-client?v=2 | ok |
| crew-link-service.js | crewLinkService | supabase-client?v=2, role-service | ok |
| runner-in-service.js | runnerInService, RunnerInService, SOURCE_RANKS | supabase-client?v=2, role-service | ok |
| active-targets-service.js | activeTargetsService, ActiveTargetsService | race-profile-service, user-manager?v=2, config | ok |
| plan-data-service.js | planDataService, RACE_FORMATS, calculateRecommendedTargets, + 5 more | supabase-client?v=2 | ok |
| analysis-service.js | analysisService | supabase-client?v=2, api-service no ?v, custom-metrics, sweat-math | version |
| race-profile-service.js | raceProfileService, DEFAULT_PROFILE, FORMAT_PRESETS, SWEAT_MULTIPLIERS | api-service no ?v | version |
| conditions-service-v3.js | conditionsServiceV3 | supabase-client?v=2, user-manager?v=2, weather-provider, sweat-math | ok |
| weather-provider-service.js | weatherProviderService | user-manager?v=2 | ok |
| practice-session-service.js | practiceSessionService | supabase-client?v=2, config | ok |
| social-feed-service.js | socialFeedService, SocialFeedService, PAGE_SIZE | supabase-client?v=2 | ok |
| milestone-service.js | milestoneService, MilestoneService | supabase-client?v=2, social-feed-service | ok |
| cheer-service.js | cheerService, CheerService | supabase-client?v=2, role-service, social-feed-service | ok |
| reaction-service.js | reactionService, ReactionService | supabase-client?v=2 | ok |
| spectator-privacy-service.js | spectatorPrivacyService | supabase-client?v=2 | ok |
| photo-upload-service.js | photoUploadService, PhotoUploadService | supabase-client?v=2 | ok |
| image-storage-service.js | imageStorageService | supabase-client?v=2 | ok |
| custom-metrics-service.js | customMetricsService | supabase-client?v=2 | ok |
| lap-clock-service.js | lapClockService | supabase-client?v=2 | ok |
| crew-checklist-service.js | crewChecklistService, CrewChecklistService | supabase-client?v=2 | ok |
| crew-service.js | crewService | supabase-client?v=2 | ok |
| live-race-service.js | liveRaceService | supabase-client?v=2 | ok |
| offline-data-service.js | offlineDataService | indexed-db, supabase-client?v=2 | ok |
| gpsStorageService.js | GPSStorageService | supabase-client?v=2 | ok |
| gpx-map-service.js | gpxMapService, GpxMapService | (none) | ok |
| pr-verification-service.js | prVerificationService | supabase-client?v=2 | ok |
| race-settings.js | raceSettings | user-manager?v=2 | ok |
| speech-service.js | speechService, SpeechService | (none) | ok |
| crew-alerts-service.js | crewAlertsService, CrewAlertsService, DEFAULT_THRESHOLDS | (none) | ok |
| product-database-service.js | productDatabaseService | (none) | ok |
| sweat-math.js | StatsEngine, SweatMath | (none) | ok |
| decision-tree.js | decisionTree | (none) | ok |
| image-service.js | imageService | (none) | ok |
| indexed-db.js | openDB | (none) | ok |
| profile-check.js | requireRaceProfile, getProfileStatus, renderProfileBlocker | race-profile-service | ok |
How modules depend on each other. Core modules at top, pages at bottom.
Vue 3 runtime. Exposes window.Vue
Supabase JS client UMD. Exposes window.supabase
IIFE. Monkey-patches Vue.createApp to register AppShell, nav, toast, command palette components.
window.supabase.createClient() — no ES imports35 services. Most import only supabase-client. Some import user-manager or api-service. See Services tab for full list.
role-service — imported by runner-in, crew-link, cheer, bibboardsocial-feed-service — imported by milestone, cheer, analysis-v3race-profile-service — imported by active-targets, conditions, profile-checkcrew-link-service — imported by index-v3, plan-v3, profile-select, bibboardspeech-service, crew-alerts-service, product-database-servicesweat-math, decision-tree, image-servicegpx-map-service, indexed-dbSupabase PostgreSQL tables. RLS policies active on core tables.
PK: user_id (text)
Columns: auth_uid (UUID, nullable), name, email, password_hash, settings (JSONB), profile_image, banner_image, weight_kg, caffeine_half_life, flavor_text, bib_number
Used by: user-manager, api-service, settings-service, crew-link, role-service
PK: id
FK: user_id → users
Columns: lap_number, timestamp, carbs, fluids, sodium, caffeine, protein, fiber, mood, notes, run_time, runner_in_timestamps (JSONB)
Used by: api-service, analysis-service, race-day-v3
PK: id
FK: user_id → users
Columns: plan_data (JSONB — race_status, targets, pacing, caffeine schedule)
Used by: api-service, plan-data-service, race-day-v3, index-v3
PK: id
FK: user_id → users
Columns: name, category, carbs, fluids, sodium, caffeine, protein, fiber, notes
Used by: api-service, fuel-menu page
PK: id
FK: user_id → users
Columns: crew_user_id, name, role, crew_code, status
Used by: crew-link-service, crew-service, index-v3
race_profiles, condition_snapshots, practice_sessions, practice_laps, race_comparisons, lap_clock_entries, social_feed, cheers, reactions, custom_metrics
Phase 1 migration added granular RLS policies to users, laps, race_plans, fuel_items, crew_members. Old "Allow all operations" blanket policies still exist and need cleanup (sql/auth-migration-phase1-cleanup.sql). The blanket policies override the granular ones, meaning RLS is effectively open until cleanup runs.
Hosting, service worker, deploy process, vendored libraries.
curl -F "file=@file" -H "Authorization: Bearer KEY" neocities.org/api/uploadbackyard-crew-v9.0.0cache: 'no-store'cache: 'no-store'skipWaiting() + clients.claim() + notifies clientsProblems found during the April 17, 2026 audit. Ordered by severity.
The app loads correctly in a clean browser (verified via Chrome automation). The user's phone/PWA has an old service worker cached that serves stale JS files, preventing Vue from mounting. The SW has been updated to v9 with cache: 'no-store' for JS/CSS, but the user's device hasn't picked up the new SW yet. Fix: User must clear caches via debug.html, or delete and reinstall the PWA.
Phase 1 auth migration added granular RLS policies, but the old blanket "Allow all operations" policies on users, laps, race_plans, fuel_items were never dropped. These override the new policies, meaning any anonymous user with the anon key can read/write all data. Fix: Run sql/auth-migration-phase1-cleanup.sql in Supabase dashboard.
3 files import api-service.js?v=5 (index-v3, plan-v3, race-day-v3). 6 files import api-service.js with no version (user-manager, analysis-service, race-profile-service, compare-v3, offlineApi, syncManager). Browser treats these as different module specifiers, potentially loading the module twice with separate instances. Fix: Add ?v=5 consistently to all api-service imports.
user-manager.js imports import { apiService } from './api-service.js' (no ?v). Pages that import user-manager?v=2 AND api-service?v=5 may get two separate api-service module instances with two separate Supabase clients. Impact: Potential duplicate network requests, inconsistent state.
These pages don't load shell-bundle.js or performance-bundle.js. If their templates use <app-shell>, Vue will fail to compile. If they don't use it, this is fine (standalone pages).
All files are manually edited and deployed. No minification, no bundling, no type checking, no linting. Cache busting is manual (?v=N params). Easy to ship stale code or version mismatches.
Global error catchers and dynamic import wrapper were added for debugging. These should be removed before race day. The module import was changed from <script type="module" src="..."> to an inline <script type="module"> with dynamic import().
Phases 1-3 complete. Phase 4 remaining: create Supabase Auth accounts for existing users, backfill auth_uid, remove auth.uid() IS NULL anon fallback, enforce RLS, drop password_hash column, remove legacy userId params from api-service.
All other page files use Options API. settings-v3.js uses setup() with ref(), reactive(), onMounted(). Functionally fine but inconsistent with codebase convention.
This file is the core of the app and is very large. Any change risks regressions. Consider splitting into smaller composables or sub-components after race day.
Old v1/v2 pages still exist. Not linked from active navigation but still accessible via URL.