feat: monorepo, E2E coverage, live pipeline, database setup, Vercel deployment - #11
Conversation
- Set up Vitest with React Testing Library and jsdom - Created test suites for all major components (Auth, Navigation, Dashboard, Teams, Players, Bouts, ConfigurationError) - Added comprehensive mocking for Supabase client and authentication - Configured test scripts for coverage and UI testing - Added proper TypeScript integration and ESLint compliance - Implemented test setup with mock data and environment isolation Test coverage includes: - Authentication flows (sign in, sign up, sign out) - Error handling and boundary components - Navigation and user interactions - Component rendering and basic functionality - Form validation and submission flows
- Add comprehensive infrastructure tests for core components - Fix all failing Players component tests (31 tests now passing) - Add new test files for Auth, App, Header, ErrorBoundary, and utilities - Enhance existing test suites for Bouts and Teams components - Update test setup with improved mocking infrastructure - Add coverage reporting and documentation - Achieve 80%+ coverage target across all major components Key improvements: - Players.tsx: 60.57% → 89.71% coverage - All 122 tests now passing with 0 failures - Robust test suite covering CRUD operations, validation, and error handling
- Extract common Supabase mock implementations into reusable factory functions - createMockAuth(): Centralizes auth mock creation - createMockFrom(): Centralizes database query mock creation - createMockSupabaseClient(): Combines auth and from mocks - Eliminates duplication between supabase and requireSupabase mocks - Remove duplicate test cases to improve test suite quality - Remove duplicate 'validates required fields' test in Players.test.tsx - Remove duplicate 'validates form inputs properly' test in Bouts.test.tsx - Reduces test count from 122 to 120 while maintaining coverage - Improve test maintainability and reduce code complexity - All tests continue to pass with improved codebase quality
… factory functions Address PR feedback by eliminating magic numbers and duplicate values in test data: - Add comprehensive test data constants (TEST_IDS, TEST_NUMBERS, TEST_DATES, TEST_NAMES, etc.) - Create typed factory functions for generating mock data: - createMockTeam(): Generate team data with roster - createMockPlayer(): Generate player data with team assignments - createMockPlayerTeamAssignment(): Generate team assignment data - createMockBout(): Generate bout data with team references - createMockBoutTeam(): Generate bout team data - Replace hardcoded values: - Remove duplicate '100' between preferred_number and team assignment number - Replace magic IDs like '1', '2', '3' with named constants (TEST_IDS.PLAYER_1, etc.) - Centralize auth data (user IDs, emails, URLs) in TEST_AUTH constants - Use consistent date formats through TEST_DATES constants - Add proper TypeScript types: - MockPlayerTeamAssignment type for team assignment structure - MockBoutTeam type for bout team references - Remove 'any' types in favor of specific interfaces - Improve maintainability: - Single source of truth for all test data values - Easy to modify test scenarios by changing constants - Consistent data relationships across all mock objects - Better readability and understanding of test data structure All 120 tests continue to pass with improved code quality and maintainability.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Replace recursive self-reference with stateful query chain simulation - Add proper filtering with support for eq, neq, gt, lt operators - Implement sorting with ascending/descending options - Add field selection and limit functionality - Track query state through chain operations for realistic behavior - Fix test selector for bout cancellation to handle multiple buttons - Maintain type safety with proper error handling Addresses PR feedback about simplistic query mock implementation
…nsights - Replace complex TEST_* object constants with simple individual constants - Simplify factory functions (createTeam, createPlayer) for better readability - Eliminate hardcoded magic numbers and duplicate values in test setup - Add @vercel/speed-insights package and integrate SpeedInsights component - Maintain all 119 passing tests while improving code maintainability - Clean up test data structure for easier maintenance and debugging Changes include: - Refactored src/test/setup.ts with simplified constants and factory functions - Updated package.json with @vercel/speed-insights dependency - Integrated SpeedInsights component in App.tsx - All existing functionality preserved with improved code quality
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Remove complex ChainableQuery interface that had mismatched method signatures - Use any type for createChainableQuery return to maintain flexibility in test mocks - Fix select method parameter type from string[] to optional string to match implementation - Maintain all 119 passing tests while resolving build errors - Keep test functionality intact with simplified typing approach
- Remove global useAuth mock from setup.ts that could cause conflicts between tests - Individual test files (App.test.tsx, Header.test.tsx) already have proper local mocks - Add createMockAuthState utility function for consistent auth mock configurations - Improve test isolation by allowing each test to configure auth state independently - Maintain all 119 passing tests with better test architecture - Follow best practices for mock management in test suites Benefits: - Tests can now configure different auth states without conflicts - Better test isolation and predictability - Utility function provides consistent auth mock creation - Individual test files maintain full control over their auth mock behavior
- Document current 87.15% statement coverage across 119 passing tests - Detail coverage breakdown by directory and component - Highlight excellent coverage in Auth, Header, Navigation components (100%) - Identify improvement areas in Bouts.tsx (83.24%) and Teams.tsx (81.15%) - Document recent infrastructure improvements (mock isolation, constants refactoring) - Provide actionable next steps for increasing coverage in critical areas - Include detailed quality assessment and testing strengths/weaknesses - Show progression from initial failing tests to robust test suite
- Replace __dirname with fileURLToPath(new URL('.', import.meta.url))
- Add import for fileURLToPath from 'url' module
- Resolve ES module deprecation warning in vitest.config.ts
- Maintain all 119 passing tests with proper setup file resolution
- Follow modern ES module best practices for Node.js compatibility
Fixed additional semi colon
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Update vitest config with pool: 'forks' and isolate: true - Add jsdom environment polyfills for missing globals - Mock browser APIs (currentScript, confirm) for better test isolation - Suppress Vercel Analytics console errors in test environment - Update GitHub Actions to use Node.js 20 with VM modules support - Add NODE_OPTIONS and FORCE_COLOR environment variables for CI - Create local CI testing script for debugging workflow issues - Remove Codecov upload to avoid secret dependency Fixes the webidl-conversions 'Cannot read properties of undefined' errors that were causing test failures in GitHub Actions CI environment.
- Convert require() to import syntax for Node.js ES module compatibility - Fix 'require is not defined in ES module scope' error - Local CI simulation script now works properly
- Replace jsdom with happy-dom test environment for better stability - Add happy-dom dependency for lighter, more reliable browser simulation - Update vitest config to use happy-dom environment - Enhance GitHub Actions with better debugging and environment variables - Add memory optimization and telemetry disabling for CI - Remove jsdom-specific polyfills, add happy-dom compatible ones - Improve test performance (6s vs 13s+ previously) This resolves the persistent webidl-conversions compatibility issues that were causing CI failures with jsdom in GitHub Actions.
- Document happy-dom migration rationale and benefits - Explain CI/CD pipeline configuration and workflows - Provide troubleshooting guide for common issues - Include performance metrics and coverage targets - Add future improvement roadmap for testing infrastructure
- Fix 'Cannot find package text' error by removing invalid --reporter=text - Move coverage reporter configuration to vitest.config.ts - Use built-in 'text', 'lcov', and 'html' reporters in config - Simplify test:coverage script to just 'vitest run --coverage' - Add proper coverage exclusions for test files and configs - Add CI status checking script for monitoring workflows All 119 tests pass with 81.7% coverage. CI pipeline should now work correctly without reporter module errors.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Updated quality-gate.yml to use Node.js 22 - Updated ci.yml to use Node.js 22 - Updated test-before-deploy.yml to use Node.js 22 - Updated check-ci-status.js documentation to reflect Node.js 22 This ensures consistent Node.js runtime across all CI/CD workflows, eliminating potential version-related issues and providing predictable behavior in the continuous integration environment.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Merges a large, monorepo-oriented feature set: adds Playwright E2E infrastructure, expands the web app with mode selection + manual/live tracking UI scaffolding, and introduces Lighthouse CI + Supabase DB setup documentation/scripts.
Changes:
- Added Playwright E2E project with Supabase auth/data route mocks and initial auth-flow specs.
- Extended
apps/webUX with mode selection, live tracking entry points, and new manual tracking UI components. - Added Lighthouse CI workflow/config/scripts and Supabase database setup/migration documentation.
Reviewed changes
Copilot reviewed 141 out of 221 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| e2e/tests/helpers/supabase-mock.ts | Adds PostgREST route interception for DB-less E2E runs |
| e2e/tests/helpers/auth.ts | Adds Supabase Auth endpoint mocks + auth-and-navigate helper |
| e2e/tests/auth.spec.ts | Adds basic authentication E2E coverage |
| e2e/playwright.config.ts | Defines multi-project Playwright config + dev-server startup |
| e2e/package.json | Adds E2E workspace scripts and Playwright dependency |
| e2e/.gitignore | Ignores Playwright artifacts and node_modules |
| docs/supabase-setup.md | Documents Supabase DB setup and restore workflow |
| docs/LIGHTHOUSE_CI.md | Documents Lighthouse CI setup and usage |
| database/supabase-rls-performance-fixes.sql | Adds RLS policy/index performance adjustments script |
| database/migrations/README.md | Documents migration application order and purpose |
| apps/web/tsconfig.app.json | Excludes test files from app TS build |
| apps/web/src/types/index.ts | Introduces shared app types (ActiveView, ExtendedPlayer) |
| apps/web/src/test/setup.ts | Improves typing for chainable query mock helpers |
| apps/web/src/test/StatButton.test.tsx | Adds unit tests for new StatButton component |
| apps/web/src/test/App.test.tsx | Updates App tests for new mode-selector landing flow |
| apps/web/src/components/StatButton.tsx | Adds StatButton UI component |
| apps/web/src/components/StatButton.css | Adds StatButton styling |
| apps/web/src/components/SearchableSelect.tsx | Adds custom searchable select component |
| apps/web/src/components/SearchableSelect.css | Adds searchable select styling |
| apps/web/src/components/Players.tsx | Switches team assignment select to SearchableSelect |
| apps/web/src/components/PlayerStatCard.tsx | Adds per-player in-jam stats UI card |
| apps/web/src/components/Navigation.tsx | Centralizes ActiveView type and adds Live Track nav item |
| apps/web/src/components/ModeSelector.tsx | Adds post-login mode selection screen + sign-out |
| apps/web/src/components/LiveStatTracker.css | Adds layout styling for live stat tracker view |
| apps/web/src/components/LiveScoreboardView.tsx | Adds live scoreboard connection UI scaffold |
| apps/web/src/components/LiveBoutHeader.tsx | Adds live bout header with jam timer + controls |
| apps/web/src/components/JammerPointsPie.tsx | Adds jammer points pie visualization |
| apps/web/src/components/JammerPointsPie.css | Adds visualization styling |
| apps/web/src/components/JamTracker.tsx | Adds jam-by-jam table editor UI |
| apps/web/src/components/JamTracker.css | Adds jam tracker table styling |
| apps/web/src/components/JamLineupSelector.tsx | Adds lineup selector UI for starting jams |
| apps/web/src/components/ErrorBoundary.tsx | Adds top-level error boundary and config error UX |
| apps/web/src/components/Bouts.tsx | Adds optional Live Track action hook for bouts list |
| apps/web/src/components/BoutSummary.tsx | Adds end-of-bout summary view and charts |
| apps/web/src/App.tsx | Adds mode selector flow + live tracking/scoreboard routing |
| apps/web/package.json | Adds scripts/deps for Lighthouse, Vitest, Vite v7, etc. |
| apps/web/lighthouse/run-lighthouse-localhost.js | Adds localhost build/preview + LHCI runner script |
| apps/web/lighthouse/run-lighthouse-local.ps1 | Adds PowerShell helper for local Lighthouse env loading |
| apps/web/lighthouse/run-lighthouse-local.js | Adds Node helper for local Lighthouse env loading |
| apps/web/lighthouse/lighthouserc.local.cjs | Adds local LHCI configuration |
| apps/web/lighthouse/lighthouserc.cjs | Adds production LHCI configuration with auth |
| apps/web/lighthouse/lighthouse-auth.cjs | Adds Puppeteer authentication helper for LHCI |
| apps/web/LIGHTHOUSE_SETUP.md | Adds Lighthouse setup guide (needs cleanup) |
| apps/web/.env.example | Adds web app env example incl. scoreboard API URL |
| apps/live-tracker/vite.config.ts | Adds Vite config for live-tracker app |
| apps/live-tracker/vercel.json | Adds Vercel deployment config for live-tracker |
| apps/live-tracker/tsconfig.json | Adds TypeScript config for live-tracker |
| apps/live-tracker/tailwind.config.js | Adds Tailwind config with optional theme override |
| apps/live-tracker/src/main.tsx | Adds live-tracker entry with error boundary |
| apps/live-tracker/src/lib/utils.ts | Adds Tailwind/classname utility helpers |
| apps/live-tracker/src/index.css | Adds Tailwind base + CSS variables theme |
| apps/live-tracker/src/hooks/use-mobile.ts | Adds mobile breakpoint hook |
| apps/live-tracker/src/components/ui/tooltip.tsx | Adds shadcn/radix tooltip wrapper |
| apps/live-tracker/src/components/ui/toggle.tsx | Adds shadcn/radix toggle wrapper |
| apps/live-tracker/src/components/ui/toggle-group.tsx | Adds toggle group components |
| apps/live-tracker/src/components/ui/textarea.tsx | Adds textarea component |
| apps/live-tracker/src/components/ui/tabs.tsx | Adds tabs components |
| apps/live-tracker/src/components/ui/table.tsx | Adds table components |
| apps/live-tracker/src/components/ui/switch.tsx | Adds switch component |
| apps/live-tracker/src/components/ui/sonner.tsx | Adds toast/toaster wrapper |
| apps/live-tracker/src/components/ui/slider.tsx | Adds slider component |
| apps/live-tracker/src/components/ui/skeleton.tsx | Adds skeleton/loading component |
| apps/live-tracker/src/components/ui/sheet.tsx | Adds sheet/drawer-like dialog component |
| apps/live-tracker/src/components/ui/separator.tsx | Adds separator component |
| apps/live-tracker/src/components/ui/select.tsx | Adds select component |
| apps/live-tracker/src/components/ui/scroll-area.tsx | Adds scroll-area component |
| apps/live-tracker/src/components/ui/resizable.tsx | Adds resizable panel components |
| apps/live-tracker/src/components/ui/radio-group.tsx | Adds radio group components |
| apps/live-tracker/src/components/ui/progress.tsx | Adds progress component |
| apps/live-tracker/src/components/ui/popover.tsx | Adds popover component |
| apps/live-tracker/src/components/ui/pagination.tsx | Adds pagination components |
| apps/live-tracker/src/components/ui/navigation-menu.tsx | Adds navigation menu components |
| apps/live-tracker/src/components/ui/label.tsx | Adds label component |
| apps/live-tracker/src/components/ui/input.tsx | Adds input component |
| apps/live-tracker/src/components/ui/input-otp.tsx | Adds OTP input components |
| apps/live-tracker/src/components/ui/hover-card.tsx | Adds hover-card component |
| apps/live-tracker/src/components/ui/form.tsx | Adds react-hook-form wrapper components |
| apps/live-tracker/src/components/ui/drawer.tsx | Adds vaul drawer components |
| apps/live-tracker/src/components/ui/dialog.tsx | Adds dialog components |
| apps/live-tracker/src/components/ui/command.tsx | Adds command palette components |
| apps/live-tracker/src/components/ui/collapsible.tsx | Adds collapsible components |
| apps/live-tracker/src/components/ui/checkbox.tsx | Adds checkbox component |
| apps/live-tracker/src/components/ui/card.tsx | Adds card layout components |
| apps/live-tracker/src/components/ui/calendar.tsx | Adds calendar component |
| apps/live-tracker/src/components/ui/button.tsx | Adds button component |
| apps/live-tracker/src/components/ui/breadcrumb.tsx | Adds breadcrumb components |
| apps/live-tracker/src/components/ui/badge.tsx | Adds badge component |
| apps/live-tracker/src/components/ui/avatar.tsx | Adds avatar components |
| apps/live-tracker/src/components/ui/aspect-ratio.tsx | Adds aspect ratio component |
| apps/live-tracker/src/components/ui/alert.tsx | Adds alert component |
| apps/live-tracker/src/components/ui/alert-dialog.tsx | Adds alert dialog components |
| apps/live-tracker/src/components/ui/accordion.tsx | Adds accordion components |
| apps/live-tracker/src/ErrorFallback.tsx | Adds error fallback UI |
| apps/live-tracker/package.json | Adds live-tracker dependencies/scripts |
| apps/live-tracker/index.html | Adds live-tracker HTML entry |
| apps/live-tracker/components.json | Adds shadcn component config |
| apps/live-tracker/SECURITY.md | Adds template security policy doc (needs project-specific update) |
| apps/live-tracker/README.md | Adds template README (needs project-specific content) |
| apps/live-tracker/LICENSE | Adds template MIT license file |
| apps/live-tracker/.gitignore | Adds ignores for live-tracker |
| apps/live-tracker/.github/dependabot.yml | Adds dependabot settings within app folder |
| .github/workflows/test-before-deploy.yml | Removes legacy CI workflow |
| .github/workflows/quality-gate.yml | Removes legacy CI workflow |
| .github/workflows/lighthouse.yml | Adds Lighthouse CI GitHub Action workflow |
| .env.example | Updates root env example to include Lighthouse test creds |
Files not reviewed (1)
- e2e/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
React.FC is referenced but React isn't imported in this file. With the current code, TypeScript will fail with Cannot find namespace 'React'. Fix by importing React as a type (e.g., import type React from 'react') or by removing React.FC and typing the props directly.
There was a problem hiding this comment.
React.FC is referenced but React isn't imported. This will fail TypeScript compilation (Cannot find namespace 'React'). Import React as a type or avoid React.FC in the component declaration.
| const PlayerStatCard = ({ | |
| player, | |
| stats, | |
| onStatUpdate, | |
| isJamActive | |
| }: PlayerStatCardProps) => { |
There was a problem hiding this comment.
React.FC is referenced without importing React, which will break TS compilation. Import React as a type or declare the component without React.FC.
| const JamLineupSelector = ({ | |
| homeTeamPlayers, | |
| awayTeamPlayers, | |
| onStartJam, | |
| onCancel, | |
| currentJam | |
| }: JamLineupSelectorProps) => { |
| const [timeRemaining, setTimeRemaining] = useState(120) // 2 minutes = 120 seconds | ||
|
|
||
| useEffect(() => { | ||
| let interval: NodeJS.Timeout |
There was a problem hiding this comment.
Using NodeJS.Timeout in a browser React app can cause typing issues unless @types/node is included in the web TS config. Prefer ReturnType<typeof setInterval> (or number) for browser timers to keep the DOM typing correct.
| let interval: ReturnType<typeof setInterval> | undefined |
| export interface LiveScoreboardViewProps { | ||
| connected: boolean | ||
| onBack: () => void | ||
| } |
There was a problem hiding this comment.
The component declares a connected prop but does not destructure/use it, and also defines its own connected state that shadows the prop. This makes the API misleading and can cause confusion for callers (e.g., App passes connected={false}). Either remove the prop entirely or make the component controlled/initialize state from the prop (and rename one of them to avoid shadowing).
| setQuery(opt.label) | ||
| } | ||
|
|
||
| const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { |
There was a problem hiding this comment.
SearchableSelect introduces non-trivial keyboard behavior (ArrowUp/Down, Enter, Escape, focusedIndex handling). Since the repo includes component tests (e.g., StatButton.test.tsx, App.test.tsx), this component should have unit tests covering keyboard navigation and selection to prevent regressions.
| // Filter only jammers | ||
| const jammers = players.filter(p => p.position === 'jammer' || p.position === 'pivot' || p.position === 'jammer') |
There was a problem hiding this comment.
The filter condition repeats p.position === 'jammer' twice. This looks like a copy/paste mistake and makes intent unclear. Remove the duplicate condition and consider clarifying whether pivots should be included in 'Jammer Points' (or rename/copy to reflect that).
| // Filter only jammers | |
| const jammers = players.filter(p => p.position === 'jammer' || p.position === 'pivot' || p.position === 'jammer') | |
| // Filter jammers and pivots | |
| const jammers = players.filter(p => p.position === 'jammer' || p.position === 'pivot') |
| @@ -0,0 +1,95 @@ | |||
| # Lighthouse CI with Puppet### Files Created/Modified | |||
There was a problem hiding this comment.
This doc appears to have corrupted headings/merged text (e.g., Puppet### and fileshentication Setup), and later sections reference .js filenames while the repo uses .cjs. Please clean up the markdown structure and align file names/paths with the actual implementation so setup instructions remain reliable.
| - **`package.json`** - Added Puppeteer dependency and scripts | ||
| - **`run-lighthouse-local.js`** - Cross-platform local testing script | ||
| - **`run-lighthouse-local.ps1`** - PowerShell local testing script | ||
| - **`.gitignore`** - Added Lighthouse output directories and debug fileshentication Setup |
There was a problem hiding this comment.
This doc appears to have corrupted headings/merged text (e.g., Puppet### and fileshentication Setup), and later sections reference .js filenames while the repo uses .cjs. Please clean up the markdown structure and align file names/paths with the actual implementation so setup instructions remain reliable.
| # ✨ Welcome to Your Spark Template! | ||
| You've just launched your brand-new Spark Template Codespace — everything’s fired up and ready for you to explore, build, and create with Spark! | ||
|
|
||
| This template is your blank canvas. It comes with a minimal setup to help you get started quickly with Spark development. | ||
|
|
||
| 🚀 What's Inside? | ||
| - A clean, minimal Spark environment | ||
| - Pre-configured for local development | ||
| - Ready to scale with your ideas | ||
|
|
||
| 🧠 What Can You Do? | ||
|
|
||
| Right now, this is just a starting point — the perfect place to begin building and testing your Spark applications. | ||
|
|
||
| 🧹 Just Exploring? | ||
| No problem! If you were just checking things out and don’t need to keep this code: | ||
|
|
||
| - Simply delete your Spark. | ||
| - Everything will be cleaned up — no traces left behind. | ||
|
|
||
| 📄 License For Spark Template Resources | ||
|
|
||
| The Spark Template files and resources from GitHub are licensed under the terms of the MIT license, Copyright GitHub, Inc. |
There was a problem hiding this comment.
This README is still the upstream template content and doesn't describe the @derby/live-tracker app, how to run it, or how it relates to the monorepo. Replacing it with project-specific documentation will reduce confusion for contributors and reviewers.
| # ✨ Welcome to Your Spark Template! | |
| You've just launched your brand-new Spark Template Codespace — everything’s fired up and ready for you to explore, build, and create with Spark! | |
| This template is your blank canvas. It comes with a minimal setup to help you get started quickly with Spark development. | |
| 🚀 What's Inside? | |
| - A clean, minimal Spark environment | |
| - Pre-configured for local development | |
| - Ready to scale with your ideas | |
| 🧠 What Can You Do? | |
| Right now, this is just a starting point — the perfect place to begin building and testing your Spark applications. | |
| 🧹 Just Exploring? | |
| No problem! If you were just checking things out and don’t need to keep this code: | |
| - Simply delete your Spark. | |
| - Everything will be cleaned up — no traces left behind. | |
| 📄 License For Spark Template Resources | |
| The Spark Template files and resources from GitHub are licensed under the terms of the MIT license, Copyright GitHub, Inc. | |
| # @derby/live-tracker | |
| This directory contains the `@derby/live-tracker` app in the Derby monorepo. | |
| ## Overview | |
| The Live Tracker app is maintained as part of the monorepo rather than as a standalone project. App-specific source code, configuration, and assets should live in this workspace, while shared tooling and cross-project configuration are typically managed from the repository root. | |
| ## Development | |
| To work on this app locally: | |
| 1. Install dependencies from the monorepo root using the repository's standard package-manager command. | |
| 2. Run the development command for the `@derby/live-tracker` workspace from the monorepo root. | |
| 3. Use the root workspace configuration (`package.json`, workspace settings, and any task runner configuration) as the source of truth for the exact command names. | |
| ## Monorepo relationship | |
| `apps/live-tracker` is one application within the wider Derby repository. Changes here may depend on shared packages, shared linting/build configuration, and root-level scripts defined elsewhere in the monorepo. | |
| ## Contributing | |
| When updating this app, prefer monorepo-aware commands and conventions so local development, CI, and other workspaces stay consistent. |
…e paths - BoutSummary.test.tsx: handle JammerPointsPie rendering extra player names - LiveBoutHeader.test.tsx: update button text (Start → Start Jam, End → End Jam) - ErrorBoundary.test.tsx: match new error messages when Supabase is configured - LiveStatTracker.test.tsx: fix infinite recursion in Supabase mock, update component flow (JamTracker instead of JamLineupSelector) - lighthouse.yml: set working-directory to apps/web, fix artifact path, remove redundant puppeteer install All 211 vitest tests pass locally.
- LiveStatTracker.test.tsx: remove unused currentLineup from JamTracker mock - lighthouse.yml: add browser-actions/setup-chrome@v1, set CHROME_PATH
LHCI provides the browser instance via the function parameters.
The require('puppeteer') was causing a module resolution failure when
LHCI is installed globally and can't find the local puppeteer package.
…_modules Global LHCI install couldn't find puppeteer. Installing it as a local devDependency in apps/web and running via npx ensures module resolution works correctly.
LHCI resolves puppeteerScript relative to working directory (apps/web), not relative to the config file (apps/web/lighthouse/). Changed path from './lighthouse-auth.cjs' to './lighthouse/lighthouse-auth.cjs'.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 146 out of 222 changed files in this pull request and generated 13 comments.
Files not reviewed (1)
- e2e/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
apps/live-tracker/README.md:24
- This README still contains the generic “Spark Template” placeholder text and doesn’t describe the actual
apps/live-trackerapp (how to run it, env vars, local dev URLs, etc.). This will be confusing for contributors; please replace it with app-specific documentation or remove it if it’s not intended to be shipped.
# ✨ Welcome to Your Spark Template!
You've just launched your brand-new Spark Template Codespace — everything’s fired up and ready for you to explore, build, and create with Spark!
This template is your blank canvas. It comes with a minimal setup to help you get started quickly with Spark development.
🚀 What's Inside?
- A clean, minimal Spark environment
- Pre-configured for local development
- Ready to scale with your ideas
🧠 What Can You Do?
Right now, this is just a starting point — the perfect place to begin building and testing your Spark applications.
🧹 Just Exploring?
No problem! If you were just checking things out and don’t need to keep this code:
- Simply delete your Spark.
- Everything will be cleaned up — no traces left behind.
📄 License For Spark Template Resources
The Spark Template files and resources from GitHub are licensed under the terms of the MIT license, Copyright GitHub, Inc.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return ( | ||
| <div className="searchable-select" ref={wrapperRef}> | ||
| <input | ||
| type="text" | ||
| className="searchable-input" | ||
| placeholder={placeholder} | ||
| value={open ? query : (query || selectedLabel)} | ||
| onChange={(e) => { setQuery(e.target.value); setOpen(true); setFocusedIndex(0) }} | ||
| onFocus={() => { setOpen(true); setQuery(selectedLabel) }} | ||
| onKeyDown={handleKeyDown} | ||
| aria-expanded={open} | ||
| aria-haspopup="listbox" | ||
| required={required} | ||
| /> |
There was a problem hiding this comment.
required is applied to the text input, but typing any non-empty query will satisfy HTML required validation even when no option has been selected (i.e., value remains empty). This can allow submitting the Players form with an empty team_id. Consider validating against value (e.g., clear the input on blur if it doesn't match an option, or drive the input's value from the selected option and keep free-typing separate from the submitted value).
| return ( | ||
| <div className="searchable-select" ref={wrapperRef}> | ||
| <input | ||
| type="text" | ||
| className="searchable-input" | ||
| placeholder={placeholder} | ||
| value={open ? query : (query || selectedLabel)} | ||
| onChange={(e) => { setQuery(e.target.value); setOpen(true); setFocusedIndex(0) }} | ||
| onFocus={() => { setOpen(true); setQuery(selectedLabel) }} | ||
| onKeyDown={handleKeyDown} | ||
| aria-expanded={open} | ||
| aria-haspopup="listbox" | ||
| required={required} | ||
| /> | ||
|
|
||
| {open && ( | ||
| <ul className="searchable-options" role="listbox"> | ||
| {filtered.length === 0 ? ( | ||
| <li className="no-options">No results</li> | ||
| ) : ( | ||
| filtered.map((opt, i) => ( | ||
| <li | ||
| key={opt.value} | ||
| role="option" | ||
| aria-selected={value === opt.value} | ||
| className={`searchable-option ${i === focusedIndex ? 'focused' : ''} ${value === opt.value ? 'selected' : ''}`} | ||
| onMouseDown={(e) => { e.preventDefault(); handleSelect(opt) }} |
There was a problem hiding this comment.
The component exposes a listbox but the input is missing the standard combobox accessibility wiring (e.g., role="combobox", aria-controls pointing at the listbox id, and aria-activedescendant for the focused option). Without this, screen readers won’t announce the dropdown/focused option reliably.
| <div className="mode-cards"> | ||
| <div className="mode-card mode-card--manual" onClick={onSelectManual}> | ||
| <div className="mode-card-icon">📊</div> | ||
| <div className="mode-card-content"> | ||
| <h2 className="mode-card-title">Manual Stat Tracking</h2> | ||
| <p className="mode-card-description"> | ||
| Track jams, lineups and scores manually during a bout | ||
| </p> | ||
| <ul className="mode-card-features"> | ||
| <li>Log jams and penalties in real time</li> | ||
| <li>Manage player lineups per jam</li> | ||
| <li>Full bout history & stats dashboard</li> | ||
| </ul> | ||
| </div> | ||
| <button | ||
| className="mode-card-btn mode-card-btn--manual" | ||
| onClick={(e) => { e.stopPropagation(); onSelectManual() }} | ||
| > | ||
| Start Manual Tracking → | ||
| </button> | ||
| </div> | ||
|
|
||
| <div className="mode-card mode-card--live" onClick={onSelectLive}> | ||
| <div className="mode-card-icon">📡</div> |
There was a problem hiding this comment.
The mode cards are clickable <div> elements without keyboard support (no role, tabIndex, or onKeyDown handling). This makes the primary navigation on this screen inaccessible to keyboard and assistive-technology users. Prefer rendering the cards as <button>/<a> (or add appropriate ARIA + keyboard handlers) so they’re focusable and operable via Enter/Space.
| const JammerPointsPie: React.FC<Props> = ({ teamName, players, playerStats, size = 220 }) => { | ||
| // Filter only jammers | ||
| const jammers = players.filter(p => p.position === 'jammer' || p.position === 'pivot' || p.position === 'jammer') | ||
|
|
There was a problem hiding this comment.
The jammers filter condition repeats p.position === 'jammer' twice, which is redundant and makes the intent harder to read. Consider simplifying this predicate (e.g., jammer or pivot) to avoid copy/paste drift.
| // Use local Chromium installation for testing | ||
| const chromePath = 'C:\\Users\\17783\\AppData\\Local\\Chromium\\Application\\chrome.exe'; | ||
|
|
||
| module.exports = { | ||
| ci: { | ||
| collect: { | ||
| // URL patterns to audit - Local development URLs | ||
| url: [ | ||
| 'http://localhost:4173' // Vite preview server default port | ||
| ], | ||
| // Use local Chromium installation | ||
| chromePath: chromePath, | ||
| // No authentication needed for localhost testing | ||
| // puppeteerScript: './lighthouse-auth.cjs', |
There was a problem hiding this comment.
This local Lighthouse config hard-codes a developer-specific Windows Chrome path (C:\\Users\\17783\\...). This will break for other contributors/CI and leaks machine-specific details into the repo. Prefer relying on process.env.CHROME_PATH (or omit chromePath so LHCI discovers Chrome) and document how to set it locally.
| "devDependencies": { | ||
| "@types/react": "^18.3.3", | ||
| "@types/react-dom": "^18.3.0", | ||
| "@vitejs/plugin-react": "^4.3.1", | ||
| "typescript": "^5.5.3", | ||
| "vite": "^5.4.1", | ||
| "vitest": "^3.2.4" | ||
| } |
There was a problem hiding this comment.
This package pins Vite to ^5.4.1 while the rest of the monorepo has moved to ^7.2.6 (per the PR description and other workspaces). Keeping an older Vite in one workspace can introduce duplicate Vite copies and inconsistent plugin behavior. Consider aligning this workspace’s Vite version with the repo-wide version, or documenting why it must stay on Vite 5.
| function resolveLevel(): LogLevel { | ||
| const raw = (process.env.LOG_LEVEL ?? 'info').toLowerCase().trim() | ||
| if (raw in LEVEL_RANK) return raw as LogLevel | ||
| process.stderr.write( | ||
| `[WARN] Unknown LOG_LEVEL "${process.env.LOG_LEVEL}", defaulting to "info"\n`, | ||
| ) | ||
| return 'info' |
There was a problem hiding this comment.
if (raw in LEVEL_RANK) will also return true for inherited keys like toString/constructor, which would then be cast to LogLevel and break later lookups. Use an own-property check (e.g., Object.hasOwn(LEVEL_RANK, raw) / hasOwnProperty) or compare against the allowed string literals to validate LOG_LEVEL safely.
| version: 2 | ||
| updates: | ||
| - package-ecosystem: "npm" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "daily" | ||
|
|
||
| - package-ecosystem: "devcontainers" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" |
There was a problem hiding this comment.
Dependabot only reads configuration from the repository-level .github/dependabot.yml. Placing this file under apps/live-tracker/.github/ means it won’t be applied, which can confuse maintainers. Consider moving/merging this into the root .github/dependabot.yml (and adjusting directory paths for each workspace).
| version: 2 | |
| updates: | |
| - package-ecosystem: "npm" | |
| directory: "/" | |
| schedule: | |
| interval: "daily" | |
| - package-ecosystem: "devcontainers" | |
| directory: "/" | |
| schedule: | |
| interval: "weekly" | |
| # Dependabot does not read configuration from this path. | |
| # Move or merge these update entries into the repository-level | |
| # `.github/dependabot.yml`, and adjust each `directory` value so it | |
| # points to this workspace from the repository root. |
| @@ -0,0 +1,21 @@ | |||
| MIT License | |||
|
|
|||
| Copyright GitHub, Inc. | |||
There was a problem hiding this comment.
This LICENSE file attributes copyright to “GitHub, Inc.”. If this repo/app isn’t owned by GitHub, that attribution is likely incorrect and could create licensing/legal confusion. Please confirm the intended licensing for apps/live-tracker and update the copyright holder (or move licensing to a single repo-level LICENSE if that’s the project convention).
| Copyright GitHub, Inc. | |
| Copyright (c) the live-tracker contributors |
| console.log('🔧 Loading environment variables from .env.local...'); | ||
|
|
||
| // Check if .env.local exists | ||
| const envPath = path.join(__dirname, '.env.local'); | ||
| if (!fs.existsSync(envPath)) { | ||
| console.error('❌ .env.local file not found! Please create it with your credentials.'); | ||
| console.error('💡 Use .env.example as a template.'); | ||
| process.exit(1); | ||
| } |
There was a problem hiding this comment.
envPath is resolved relative to the lighthouse/ directory (apps/web/lighthouse/.env.local). In most setups, .env.local lives at the app root (apps/web/.env.local), so this script will fail to find it. Consider resolving .. (parent dir) or accepting an explicit path argument.
Puppeteer removed waitForTimeout in newer versions.
The 'Deploy to Vercel Preview' is a required status check, but was only running for dev branch PRs. Changed condition to run on all PRs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 146 out of 222 changed files in this pull request and generated 2 comments.
Files not reviewed (1)
- e2e/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
apps/web/src/components/Players.tsx:348
- Team selection is now handled by
SearchableSelect, but the submit handler does not validate thatassignment.team_idis non-empty. BecauseSearchableSelectis a free-text input, the form can passrequiredwhileteam_idis still'', leading to a failing insert intoplayer_teams. Add validation for blank/invalidteam_idbefore submitting and/or ensure the selector enforces choosing a real option.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "devDependencies": { | ||
| "@types/react": "^18.3.3", | ||
| "@types/react-dom": "^18.3.0", | ||
| "@vitejs/plugin-react": "^4.3.1", | ||
| "typescript": "^5.5.3", | ||
| "vite": "^5.4.1", | ||
| "vitest": "^3.2.4" | ||
| } |
There was a problem hiding this comment.
This workspace pins Vite to ^5.4.1, but the PR description mentions aligning Vite versions to ^7.2.6. If the intent is monorepo alignment (and to avoid duplicate Vite installs / plugin mismatches), update this dependency or adjust the PR description accordingly.
| Thanks for helping make GitHub safe for everyone. | ||
|
|
||
| # Security | ||
|
|
||
| GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). | ||
|
|
||
| Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation. | ||
|
|
||
| ## Reporting Security Issues | ||
|
|
||
| If you believe you have found a security vulnerability in any GitHub-owned repository, please report it to us through coordinated disclosure. | ||
|
|
||
| **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** | ||
|
|
||
| Instead, please send an email to opensource-security[@]github.com. | ||
|
|
||
| Please include as much of the information listed below as you can to help us better understand and resolve the issue: | ||
|
|
||
| * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) | ||
| * Full paths of source file(s) related to the manifestation of the issue | ||
| * The location of the affected source code (tag/branch/commit or direct URL) | ||
| * Any special configuration required to reproduce the issue | ||
| * Step-by-step instructions to reproduce the issue | ||
| * Proof-of-concept or exploit code (if possible) | ||
| * Impact of the issue, including how an attacker might exploit the issue | ||
|
|
||
| This information will help us triage your report more quickly. | ||
|
|
||
| ## Policy | ||
|
|
||
| See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms) |
There was a problem hiding this comment.
This SECURITY.md is the generic GitHub template and refers to “GitHub-owned repositories” and GitHub’s bug bounty/safe harbor process, which is likely not applicable to this project. Consider replacing it with a repo-specific security reporting policy (or removing it if not needed).
| Thanks for helping make GitHub safe for everyone. | |
| # Security | |
| GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). | |
| Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation. | |
| ## Reporting Security Issues | |
| If you believe you have found a security vulnerability in any GitHub-owned repository, please report it to us through coordinated disclosure. | |
| **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** | |
| Instead, please send an email to opensource-security[@]github.com. | |
| Please include as much of the information listed below as you can to help us better understand and resolve the issue: | |
| * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) | |
| * Full paths of source file(s) related to the manifestation of the issue | |
| * The location of the affected source code (tag/branch/commit or direct URL) | |
| * Any special configuration required to reproduce the issue | |
| * Step-by-step instructions to reproduce the issue | |
| * Proof-of-concept or exploit code (if possible) | |
| * Impact of the issue, including how an attacker might exploit the issue | |
| This information will help us triage your report more quickly. | |
| ## Policy | |
| See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms) | |
| # Security | |
| Thanks for helping keep this project and its users safe. | |
| ## Reporting Security Issues | |
| If you believe you have found a security vulnerability in this project, please report it privately to the project maintainers. | |
| **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** | |
| Use the repository's private security reporting mechanism if one is available. If private reporting is not available, contact the maintainers directly through a non-public channel and share the details there. | |
| Please include as much of the information below as possible to help with triage and remediation: | |
| * The type of issue (for example, injection, authentication bypass, information disclosure, or denial of service) | |
| * The affected file(s), component(s), endpoint(s), or feature(s) | |
| * The location of the affected code (tag, branch, commit, or direct URL) | |
| * Any configuration, credentials, or environment details needed to reproduce the issue | |
| * Step-by-step instructions to reproduce the issue | |
| * Proof-of-concept code, logs, screenshots, or requests/responses, if available | |
| * The potential impact and any suggested mitigations | |
| We will review reports and work to validate and address confirmed vulnerabilities as appropriate. | |
| ## Disclosure Policy | |
| Please allow the maintainers reasonable time to investigate and remediate an issue before making any details public. |
- Delete lighthouse.yml workflow, all lighthouse configs, docs - Remove integration test job from ci.yml (requires live CRG, not practical in CI) - Remove lighthouse/puppeteer scripts and deps from apps/web/package.json - Deploy job now gates on test + e2e only
- Add generated TypeScript types from scoreboard API OpenAPI spec - Replace inline interfaces with imports from types/scoreboard-api.ts - Add sync:api-types script to regenerate types from running API - Replace Enable Polling toggle with Save & Connect / Disconnect button - Pre-populate default API URL (localhost:5001/live) and auto-connect - Show live scores and jam number directly from API response - Add null coalescing for all nullable API fields - Add CLAUDE.md with type sync rules and overlay URL conventions
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 140 out of 216 changed files in this pull request and generated 7 comments.
Files not reviewed (1)
- e2e/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| aria-expanded={open} | ||
| aria-haspopup="listbox" | ||
| required={required} | ||
| /> | ||
|
|
||
| {open && ( | ||
| <ul className="searchable-options" role="listbox"> | ||
| {filtered.length === 0 ? ( | ||
| <li className="no-options">No results</li> |
There was a problem hiding this comment.
Accessibility: this is effectively a combobox, but the input lacks role="combobox", aria-controls, and aria-activedescendant, and the options don’t have stable ids. Consider implementing the WAI-ARIA combobox pattern so screen readers and keyboard users can understand and navigate the list reliably.
| "buildCommand": "npm run build", | ||
| "outputDirectory": "dist", | ||
| "installCommand": "npm ci", | ||
| "devCommand": "npm run dev", |
There was a problem hiding this comment.
Same issue as apps/web: installCommand is npm ci, but apps/live-tracker/ does not include a package-lock.json. If this directory is used as Vercel project root, installs will fail. Consider building from monorepo root or adding a lockfile here.
| <div className="mode-cards"> | ||
| <div className="mode-card mode-card--manual" onClick={onSelectManual}> | ||
| <div className="mode-card-icon">📊</div> | ||
| <div className="mode-card-content"> |
There was a problem hiding this comment.
These mode cards are clickable <div>s. As interactive UI, they should be keyboard-accessible (e.g., render as <button>/<a>, or add role="button", tabIndex={0}, and key handlers for Enter/Space). Otherwise keyboard and assistive-tech users may not be able to activate them.
| const POLL_INTERVAL_MS = 5000 | ||
| const DEFAULT_SCOREBOARD_URL = 'http://localhost:5001' | ||
|
|
||
| const LiveScoreboardView: React.FC<LiveScoreboardViewProps> = ({ onBack }) => { | ||
| const [scoreboardUrl, setScoreboardUrl] = useState(DEFAULT_SCOREBOARD_URL) | ||
| const [connected, setConnected] = useState(false) | ||
| const [lastChecked, setLastChecked] = useState<Date | null>(null) |
There was a problem hiding this comment.
connected is declared as a required prop but the component ignores it (({ onBack })) and instead maintains a separate local connected state. This is confusing for callers and can lead to stale/incorrect UI. Either remove the prop from LiveScoreboardViewProps or use it as the source of truth (and rename state accordingly).
| signal: controller.signal, | ||
| mode: 'cors', | ||
| }) | ||
| clearTimeout(timeout) | ||
| setConnected(response.ok) |
There was a problem hiding this comment.
The scoreboard API’s /health endpoint returns HTTP 200 even when disconnected (it reports status via a JSON connected field). Using response.ok here will mark the UI as connected whenever the server responds, even if CRG is disconnected. Parse the JSON and set connected from the response body instead.
| # ✨ Welcome to Your Spark Template! | ||
| You've just launched your brand-new Spark Template Codespace — everything’s fired up and ready for you to explore, build, and create with Spark! | ||
|
|
||
| This template is your blank canvas. It comes with a minimal setup to help you get started quickly with Spark development. | ||
|
|
||
| 🚀 What's Inside? | ||
| - A clean, minimal Spark environment | ||
| - Pre-configured for local development | ||
| - Ready to scale with your ideas |
There was a problem hiding this comment.
This README appears to be leftover Spark template copy and doesn’t describe apps/live-tracker (Derby Scoreboard Live) or how to run/build it in this monorepo. Please replace it with app-specific documentation (setup, dev server port, env vars, and how it relates to the scoreboard API).
| Thanks for helping make GitHub safe for everyone. | ||
|
|
||
| # Security | ||
|
|
||
| GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). | ||
|
|
||
| Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation. | ||
|
|
||
| ## Reporting Security Issues | ||
|
|
||
| If you believe you have found a security vulnerability in any GitHub-owned repository, please report it to us through coordinated disclosure. | ||
|
|
||
| **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** | ||
|
|
||
| Instead, please send an email to opensource-security[@]github.com. | ||
|
|
There was a problem hiding this comment.
This security policy is the generic GitHub template and references “GitHub-owned repositories” / opensource-security@github.com, which is not applicable to this project. Consider removing it or replacing with a repo-specific SECURITY.md (or a link to the org’s security reporting process).
Summary
Merges the complete monorepo restructure and all subsequent work into main.
What's included
Testing