Project Overview
PrimeScore is a real-time sports broadcasting and viewer experience tool that provides live updates, visualizations, and commentary feeds for ongoing games.
- Match Viewer — Instantly view the current score, live game clock, team lineups, and real-time updates on possession. Track all key events—such as goals, fouls, cards, and substitutions, presented with clear visuals and context.
- Event Feed & Timeline — Experience a detailed, animated timeline of in-game events, each with precise timestamps. See substitutions, cards, goals, and other actions as they happen, with smooth animations and color-coded highlights for easy tracking.
- Match Setup — Effortlessly create new matches, add or edit teams and players, and set up expected schedules. Organizers can manage rosters, assign roles, and configure match details before kickoff.
- Live Input — Enter events and update scores in real time with intuitive controls. Supports pausing and resuming the match clock, as well as editing the event timeline to correct or update past actions. All changes are reflected instantly for viewers.
- Interactive Commentary-Integrate live commentary feeds, fan polls, and reactions to keep the audience engaged and informed throughout the match.
High-Level Architecture
PrimeScore uses a client–server architecture:
- Frontend (React on Vercel): Chosen because React's component-based structure makes it ideal for building dynamic UIs like scoreboards and dashboards, while Vercel provides seamless deployments, global CDN, and automatic scaling for fast access worldwide.
- Backend (Node.js/Express on Azure): Selected for its ability to handle real-time data efficiently. Node.js/Express offers lightweight, scalable APIs for match setup and live feeds, while Azure provides reliability, monitoring, and scalability as the platform grows.
- Database (Firestore): Used for its real-time synchronization capabilities, ensuring that match updates, team changes, and events appear instantly for all users. Firestore also scales automatically and integrates smoothly with Firebase services.
- Authentication (Firebase Auth): Provides secure, role-based access management. It was chosen because it supports multiple authentication methods and allows us to easily manage roles (admin, manager, viewer) with minimal setup.
UML Diagrams
Basic Wireframe
Third-Party Code Documentation
This project uses multiple third-party frameworks, libraries, developer tools, and external APIs. These components were carefully selected to accelerate development, ensure reliability, and support real-time sports data integration.
Frameworks & Libraries
Backend
- Express.js (v5.1.0)
- Purpose: Web framework for building RESTful APIs.
- Why Used: Handles routing, middleware, and HTTP request/response handling.
- Challenges: Migration from Express 4 to 5 required adapting middleware.
- Cloudinary (v2.7.0)
- Purpose: Cloud storage for media uploads.
- Why Used: Stores match-related images (logos, banners) with fast delivery.
- Challenges: Authentication via API key and secure URL handling.
- CORS (v2.8.5)
- Purpose: Cross-Origin Resource Sharing middleware.
- Why Used: Allows the frontend (React) to interact with backend APIs securely.
- Challenges: Configuring allowed origins without overexposing endpoints.
- Dotenv (v17.2.2)
- Purpose: Loads environment variables.
- Why Used: Secures API keys (Firebase, SoccerDataAPI, Rugby API).
- Challenges: Ensuring `.env` files are excluded from Git.
- Firebase-Admin (v13.4.0)
- Purpose: Server-side SDK for Firebase Auth & Firestore.
- Why Used: Validates tokens and enforces role-based access (admin, official, resident).
- Challenges: Token verification in middleware and syncing with client Firebase SDK.
- Multer (v2.0.2)
- Purpose: Middleware for file uploads.
- Why Used: Handles user uploads (team logos, documents).
- Challenges: Managing file storage before pushing to Cloudinary.
Frontend
- React (v19.1.0) — Frontend library for building UI; dynamic rendering of live match data and dashboards.
- React-DOM (v19.1.0) — Integrates React components with the DOM.
- React-Router-DOM (v7.8.0) — Client-side routing; protects routes with Firebase authentication.
- Lucide-React (v0.541.0) — Lightweight icon set for React.
- React-Icons (v5.5.0) — Additional icons for UI.
- Firebase (v12.1.0) — Client SDK for Firebase Auth & Firestore; handles login, token issuance, and Firestore reads/writes.
Testing & Developer Tools
- Jest (v30.0.5) — Testing framework for unit/integration/coverage tests.
- Supertest (v7.1.4) — HTTP assertions for Express apps.
- Nodemon (v3.1.10) — Auto-restarts Node.js server during development.
- Babel — Transpiles ES6+ syntax for Jest/Node.
- ESLint (v9.30.1 + plugins) — Enforces coding standards (with React Hooks & refresh plugins).
- Vite (v6.3.5) — Frontend bundler & dev server with HMR support.
- Rollup (v4.46.2) — Bundler used internally by Vite.
- Codecov Vite Plugin (v1.9.1) — Coverage reporting.
Third-Party APIs
SoccerDataAPI
- Purpose: Real-time and seasonal soccer data.
- Endpoints Used: livescores, matches
- Coverage: EPL, La Liga, Serie A, PSL
- Challenges: Nested JSON, league ID mapping, date/time parsing.
NewsData API Integration
- Purpose: To provide users with up-to-date sports news content from around the world.
- Features: Categorizes articles by sport type (e.g., football, basketball, cricket) and region.
- Customizable: Uses query parameters for keywords, languages, and countries to ensure content diversity and relevance.
Implementation Summary:
- Axios is used to send GET requests to the NewsData API endpoint.
- API key is stored securely in environment variables (
process.env.NEWSDATA_API_KEY). - Backend fetches data based on selected sport and passes it to the frontend for rendering.
- Results are filtered to only include sports-related news for performance and relevance.
Example Endpoint:
https://newsdata.io/api/1/news?apikey=YOUR_API_KEY&q=sports&language=en
More Info: NewsData API Documentation
YouTube API Integration
- Purpose: To display engaging sports video content alongside news articles.
- Features: Fetches short-form sports videos (YouTube Shorts) relevant to trending sports content.
- Dynamic filtering by sport type (e.g., football, basketball).
Implementation Summary:
- Backend communicates with YouTube’s API using Axios requests.
- API credentials managed securely via environment variables (
process.env.YOUTUBE_API_KEY). - Query parameter
qdetermines which sport’s shorts are fetched (default is “football”). - Only short videos (YouTube Shorts) are displayed using the custom "PrimeShots" section.
Example Endpoint:
https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&q=football+shorts&key=YOUR_API_KEY
More Info: YouTube Data API Documentation
ScoreDataAPI (Rugby)
- Purpose: Real-time rugby match data.
- Endpoints Used: competitions, matches, livescores
- Coverage: Rugby World Cup, Rugby Championship, URC, Currie Cup
- Challenges: Mapping rugby-specific events (try, conversion) to UI.
Summary
- Build scalable backend (Express, Firebase-Admin) and frontend (React, Vite).
- Implement secure authentication and role-based access.
- Provide real-time sports data (soccer & rugby) via APIs.
- Maintain code quality with testing and linting tools.
- Deliver polished UX with icons and fast builds.
API Implementation
All endpoints are implemented and mostly bug-free, providing comprehensive sports data management, user authentication, and real-time match functionality. The API follows RESTful principles with role-based access control and comprehensive error handling.
1. Authentication Endpoints
Base URL: /auth
POST /auth/google
Purpose: Google OAuth authentication for user login and signup
Access: Public
Request Body:
{
"idToken": "string (Google ID token)",
"action": "login" | "signup"
}
Response (Success):
{
"message": "Login successful" | "Signup successful",
"user": {
"username": "string",
"email": "string",
"role": "admin" | "manager" | "viewer",
"picture": "string (URL)",
"profile": {},
"createdAt": "timestamp"
}
}
Features:
- Creates new users with default "viewer" role on signup
- Validates Google ID tokens using Firebase Admin SDK
- Prevents duplicate user registration
- Returns user data with role-based permissions
2. User Management Endpoints
Base URL: /api/users
GET /api/users/me
Purpose: Get current authenticated user profile
Access: Requires Bearer token authentication
Headers: Authorization: Bearer {token}
Response: Current user profile data with role and preferences
PUT /api/users/me
Purpose: Update current user profile information
Access: Requires Bearer token authentication
Request Body: Updated user profile fields
POST /api/users/upload
Purpose: Upload profile image to Cloudinary storage
Access: Public
Content-Type: multipart/form-data
Body: Form data with 'picture' file field
Response: Cloudinary URL of uploaded image
GET /api/users/viewMatches
Purpose: Get all matches available for viewing
Access: Public endpoint
Response: Array of all matches with basic information
3. Admin Management Endpoints
Base URL: /api/admin
Access Level: Admin role required for all endpoints
POST /api/admin/createMatch
Purpose: Create new match with teams, timing, and competition details
Request Body:
{
"homeTeam": "string",
"awayTeam": "string",
"competition": "string",
"date": "ISO date string",
"venue": "string",
"sport": "soccer" | "rugby"
}
PATCH /api/admin/updateMatchStatus/:id
Purpose: Update match status (upcoming, live, finished, postponed)
Parameters: id - Match document ID
Request Body: { "status": "live" | "finished" | "postponed" }
PATCH /api/admin/updateScore/:id
Purpose: Update live match scores
Parameters: id - Match document ID
Request Body:
{
"homeScore": number,
"awayScore": number
}
POST /api/admin/addMatchEvent/:id
Purpose: Add match events (goals, cards, substitutions, tries)
Parameters: id - Match document ID
Request Body:
{
"type": "goal" | "card" | "substitution" | "try" | "conversion",
"team": "home" | "away",
"player": "string",
"minute": number,
"details": "additional info"
}
GET /api/admin/allTeams
Purpose: Get all registered teams in the system
Response: Array of team objects with names, logos, and details
GET /api/admin/teams/:teamName/players
Purpose: Get all players for a specific team
Parameters: teamName - Name of the team
Response: Array of player objects with positions and details
DELETE /api/admin/deleteMatch/:id
Purpose: Permanently delete a match and all associated data
Parameters: id - Match document ID
Response: Confirmation of deletion
4. Team Manager Endpoints
Base URL: /api/manager
Access Level: Authentication required for all endpoints
POST /api/manager/createTeam
Purpose: Create a new team with manager ownership
Request Body:
{
"name": "string",
"sport": "soccer" | "rugby",
"logo": "string (URL)",
"description": "string"
}
POST /api/manager/addPlayers
Purpose: Add players to manager's team
Request Body:
{
"teamId": "string",
"players": [{
"name": "string",
"position": "string",
"number": number,
"age": number
}]
}
GET /api/manager/myTeam
Purpose: Get teams owned by the authenticated manager
Response: Manager's team data with player roster
GET /api/manager/players/:teamId
Purpose: Get all players for a specific team
Parameters: teamId - Team document ID
DELETE /api/manager/player/:playerId
Purpose: Remove a player from team roster
Parameters: playerId - Player document ID
5. Display & Match Data Endpoints
Base URL: /api/display
Access Level: Public endpoints for match viewing
GET /api/display/display-matches
Purpose: Get all match events formatted for display components
Access: Public
Response: Array of matches with live events, scores, and timing
Used By: Live match displays, scoreboards, match cards
How to Access: You can freely access our display API directly via this link:
https://prime-backend.azurewebsites.net/api/display/display-matches
Justification: The display API is the only public endpoint provided for external access. This decision ensures that users and third-party applications can easily retrieve live match data and events for display purposes, without exposing sensitive or administrative functionality. By keeping other endpoints private, we maintain data integrity, security, and compliance with user privacy standards, while still supporting open access to real-time match information for viewers and integrators.
Implementation Details: The display API is optimized for performance and relevance. It aggregates match data from our backend, filters for live and display-ready events, and returns results in a format suitable for dashboards, widgets, and external integrations. No authentication is required, making it ideal for public-facing applications and sports data platforms.
GET /api/display/past-matches
Purpose: Get completed matches with final results
Access: Public
Response: Historical match data with final scores and statistics
Used By: Past matches page, results displays
GET /api/display/match-events/:id
Purpose: Get detailed events for a specific match
Parameters: id - Match document ID
Access: Public
Response:
{
"matchId": "string",
"events": [{
"type": "goal" | "card" | "substitution",
"minute": number,
"team": "home" | "away",
"player": "string",
"timestamp": "ISO date"
}],
"score": {
"home": number,
"away": number
}
}
Used By: Match detail pages, event timelines
POST /api/storeMatch
Purpose: Store match data retrieved from external sports APIs
Access: Internal use
Request Body: Match data from SoccerDataAPI or Rugby API
Features:
- Processes data from SoccerDataAPI and ScoreDataAPI
- Maps external API format to internal database schema
- Handles league ID mapping and date/time parsing
- Updates existing matches or creates new ones
6. Live Feed Endpoints
Base URL: /api/feed
POST /api/feed/:matchId/start
Purpose: Initialize live match feed and start real-time updates
Parameters: matchId - Match document ID
Request Body: Match start configuration
POST /api/feed/:matchId/event
Purpose: Add real-time events to live match feed
Parameters: matchId - Match document ID
Request Body: Event data (goals, cards, etc.)
Features:
- Real-time Firebase updates to connected clients
- Event validation and formatting
- Automatic score calculation
7. Rugby Live Data Endpoints
Base URL: /api/rugby/live
POST /api/rugby/live
Purpose: Get live rugby match data from ScoreDataAPI
Request Body: Competition and date filters
Response: Live rugby matches with scores and events
GET /api/rugby/live/:date
Purpose: Get rugby fixtures for a specific date
Parameters: date - Date in YYYY-MM-DD format
Response: Scheduled rugby matches for the date
Coverage:
- Rugby World Cup matches
- Rugby Championship fixtures
- URC (United Rugby Championship)
- Currie Cup competitions
8. Match Clock Endpoints (Restricted Access)
Base URL: /api/match-clock
Access Level: Admin/Official roles only with strict authentication
Match clock endpoints are intentionally NOT made publicly available for the following critical security and operational reasons:
Why Match Clocks Are Not Publicly Available:
- Match Integrity Protection — Only authorized match officials should control timing to prevent score manipulation and match-fixing attempts
- Role-Based Security — Clock control requires verified admin/official roles with proper authentication tokens to ensure only qualified personnel manage matches
- Abuse Prevention — Public access could allow unauthorized users to disrupt live matches, pause games inappropriately, or cause confusion among spectators
- Official Supervision — Match timing must remain under strict official supervision per international sports regulations and governing body requirements
- Data Consistency — Centralized control ensures accurate, synchronized match timing across all platforms, mobile apps, and broadcast systems
- Competition Integrity — Prevents external interference in official match timing that could affect player performance, betting odds, or tournament outcomes
- Audit Trail — Restricted access allows proper logging of all timing changes for post-match reviews and dispute resolution
Available Endpoints (Admin/Official Access Only):
POST /api/match-clock/:matchId/start
Purpose: Start or resume the match clock
Parameters: matchId - Match document ID
Request Body:
{
"startTime": "ISO timestamp",
"period": "first_half" | "second_half" | "extra_time",
"reason": "match_start" | "resume_play"
}
POST /api/match-clock/:matchId/pause
Purpose: Pause the match clock for official stoppages
Request Body:
{
"reason": "injury" | "substitution" | "var_check" | "weather",
"pausedAt": "ISO timestamp"
}
POST /api/match-clock/:matchId/stop
Purpose: Stop the match clock (end of period/match)
Request Body:
{
"finalTime": "ISO timestamp",
"period": "half_time" | "full_time" | "extra_time_end",
"reason": "period_end" | "match_end"
}
GET /api/match-clock/:matchId
Purpose: Get current clock state and timing information
Response:
{
"matchId": "string",
"startTime": "ISO timestamp",
"elapsed": number,
"running": boolean,
"period": "string",
"pausedReason": "string | null",
"lastUpdated": "ISO timestamp"
}
DELETE /api/match-clock/:matchId
Purpose: Reset or delete match clock (emergency use)
Access: Super admin only
Response: Confirmation of clock reset
9. General API Features & Security
Security & Access Control
- CORS Protection — Configured specifically for Vercel frontend (prime-score.vercel.app) and localhost development (port 5173)
- Role-Based Access Control — Three-tier system: admin (full access), manager (team management), viewer (read-only)
- JWT Token Verification — Bearer token authentication using Firebase Admin SDK for all protected endpoints
- Admin Middleware — Dedicated middleware for admin-only operations with role verification
- Authentication Middleware — General auth middleware for user-specific operations
Technical Implementation
- Firebase Integration — Real-time database updates, authentication, and Firestore document management
- Cloudinary Integration — Secure image upload and storage with API key authentication
- Error Handling — Comprehensive error responses with proper HTTP status codes (400, 401, 403, 404, 500)
- Request Validation — Input validation and sanitization for all endpoints
- Rate Limiting — Built-in protection against API abuse and excessive requests
Data Processing
- External API Integration — Seamless data import from SoccerDataAPI and ScoreDataAPI
- Real-time Synchronization — Firebase listeners ensure instant updates across all connected clients
- Data Transformation — Automatic mapping between external API formats and internal database schema
- File Upload Support — Multer middleware for handling team logos and user profile images
- JSON Processing — Efficient handling of complex nested sports data structures
Monitoring & Maintenance
- Comprehensive Logging — Detailed request/response logging for debugging and monitoring
- Health Check Endpoint — GET /api/hello for system status verification
- Environment Configuration — Secure environment variable management for API keys and secrets
- Testing Coverage — Extensive Jest test suites for all major endpoints and controllers
- Azure Deployment — Hosted on Azure App Service with automatic scaling and monitoring
Public API Access Guide
This section provides comprehensive information on how to access PrimeScore APIs publicly, including base URLs, authentication methods, and integration examples for external developers and applications.
Base URLs
- Production:
https://prime-backend.azurewebsites.net - Development:
http://localhost:3000
Public Endpoints (No Authentication Required)
Authentication
POST https://prime-backend.azurewebsites.net/auth/google
Content-Type: application/json
{
"idToken": "your-google-id-token",
"action": "login" | "signup"
}
Public Match Data
GET https://prime-backend.azurewebsites.net/api/users/viewMatches
Returns: All matches available for public viewing
Display & Match Information
GET https://prime-backend.azurewebsites.net/api/display/display-matches
GET https://prime-backend.azurewebsites.net/api/display/past-matches
GET https://prime-backend.azurewebsites.net/api/display/match-events/{matchId}
Rugby Live Data
GET https://prime-backend.azurewebsites.net/api/rugby/live/{date}
POST https://prime-backend.azurewebsites.net/api/rugby/live
System Health
GET https://prime-backend.azurewebsites.net/api/hello
GET https://prime-backend.azurewebsites.net/
Protected Endpoints (Authentication Required)
For protected endpoints, include a Bearer token in the Authorization header:
Authorization: Bearer your-firebase-id-token
JavaScript Example
fetch('https://prime-backend.azurewebsites.net/api/users/me', {
method: 'GET',
headers: {
'Authorization': 'Bearer your-firebase-token',
'Content-Type': 'application/json'
}
})
CORS Configuration
The API accepts requests from:
https://prime-score.vercel.app(production frontend)http://localhost:5173(development frontend)
Note: For access from other domains, CORS configuration needs to be updated in backend/src/middleware/cors.js
API Testing Examples
Using cURL
# Public endpoint
curl https://prime-backend.azurewebsites.net/api/users/viewMatches
# Protected endpoint
curl -H "Authorization: Bearer your-token" \
https://prime-backend.azurewebsites.net/api/users/me
Using JavaScript/Fetch
// Public API call
const matches = await fetch('https://prime-backend.azurewebsites.net/api/users/viewMatches')
.then(res => res.json());
// Protected API call with authentication
const userData = await fetch('https://prime-backend.azurewebsites.net/api/users/me', {
headers: {
'Authorization': `Bearer ${firebaseToken}`
}
}).then(res => res.json());
Using Postman
- Set base URL:
https://prime-backend.azurewebsites.net - Add endpoint path (e.g.,
/api/users/viewMatches) - For protected routes, add header:
Authorization: Bearer {token} - Set Content-Type:
application/json
Integration Examples
Mobile App Integration
const API_BASE = 'https://prime-backend.azurewebsites.net';
// Get live matches
const liveMatches = await fetch(`${API_BASE}/api/display/display-matches`)
.then(res => res.json());
// Get specific match events
const matchEvents = await fetch(`${API_BASE}/api/display/match-events/matchId123`)
.then(res => res.json());
Website Widget Integration
// Embed live scores on external website
fetch('https://prime-backend.azurewebsites.net/api/display/display-matches')
.then(response => response.json())
.then(matches => {
// Display matches in your widget
matches.forEach(match => {
console.log(`${match.homeTeam} vs ${match.awayTeam}: ${match.score}`);
});
})
.catch(error => console.error('API Error:', error));
Restricted Access APIs
These endpoints are NOT publicly accessible and require specific roles:
- Admin APIs:
/api/admin/*— Admin role required - Manager APIs:
/api/manager/*— Authentication required - Match Clock APIs:
/api/match-clock/*— Admin/Official only
Error Handling
The API returns standard HTTP status codes:
- 200: Success
- 400: Bad Request (invalid parameters)
- 401: Unauthorized (missing or invalid token)
- 403: Forbidden (insufficient permissions)
- 404: Not Found
- 500: Internal Server Error
Example Error Response
{
"error": "Unauthorized",
"message": "Invalid or expired token"
}
Rate Limiting & Usage Guidelines
- Rate Limits: Managed by Azure App Service
- Token Expiry: Firebase tokens typically expire after 1 hour
- Best Practices: Cache responses when possible, handle errors gracefully
- Support: Contact the development team for additional access or higher rate limits
Components used in Primescore
This section documents custom React components developed for PrimeScore. These components were carefully designed to provide reusable, efficient solutions for match event handling and user interface animations.
Custom Components
MatchEventAnimation
- Purpose: Advanced React component providing real-time match event animations with intelligent display rules, user tracking, and Firebase integration.
- Why Used: Creates engaging user experience by showing animated notifications for live match events while preventing duplicate animations and managing state efficiently across sessions.
- Challenges: Managing localStorage persistence, preventing infinite re-renders, handling multiple event types, and coordinating Firebase real-time listeners.
Comprehensive Event Support
- Football Events — Goals, fouls, substitutions, yellow/red cards with sport-specific styling
- Rugby Events — Tries, conversions, penalties, drop goals with points tracking
- Netball Events — Goals, penalties, player positions with quarter-based timing
- Multi-Sport Detection — Automatically adapts animation styles based on sport type
- Score Tracking — Monitors homeScore and awayScore changes for goal animations
- Event Arrays — Processes complex event structures with nested data
Advanced Animation Management
- 15-second Duration — Configurable animation timeouts with automatic cleanup
- Persistent Tracking — localStorage with user metadata and timestamp tracking
- 5-minute Window — Only shows animations for recent events within time threshold
- Unique Identifiers — Stable event IDs using match state, scores, and rounded timestamps
- Real-time Detection — Firebase onSnapshot listeners for instant event updates
- Match Clock Integration — Respects 3-hour match limits and auto-stop rules
State Management & Performance
- Ref-based Tracking — Uses useRef to prevent unnecessary re-renders during event processing
- Initial Load Handling — Distinguishes between first page load and live updates
- Firebase Listeners — Real-time document listeners for each ongoing match
- Polling Fallback — Backup polling mechanism if Firebase listeners fail
- Memory Management — Proper cleanup of timers, listeners, and localStorage on unmount
- Animation Queue — Manages multiple simultaneous animations per match
Animation Rules
- First Visit: User sees animation for recent scoring events (within 5 minutes)
- Refresh/Reopen: Same scoring events won't trigger animations again
- New Events: Only genuinely new scoring events trigger animations
- Persistence: Works across browser sessions via localStorage
- Time Limit: After 5 minutes from an event, no animations are shown
- Duration: Each animation runs for exactly 15 seconds
Browser Compatibility
- Supports all modern browsers with localStorage and React support
- Graceful fallback handling for localStorage errors
- No external dependencies beyond React
- Efficient match data comparison and automatic cleanup
MatchClock Component
- Purpose: Sophisticated real-time match timing component with Firebase integration, sport-specific auto-stop rules, and comprehensive server synchronization.
- Why Used: Provides accurate match timing with pause/resume functionality, real-time synchronization across all clients, and automatic safety limits for different sports.
Props and Configuration
- matchId (required) — Unique match identifier for API calls and Firebase document references
- status (required) — Match status determining control visibility ("ongoing" shows controls)
- showControls (optional) — Boolean flag to hide/show control buttons (default: true)
- sportType (optional) — Sport category for auto-stop duration limits (Football: 120min, Rugby: 90min, Netball: 60min)
Advanced Timing Features
- Dual Synchronization — Firebase real-time listeners + REST API fallback for reliability
- Live Time Calculation — Client-side timer with server elapsed time for smooth updates
- Sport-Specific Limits — Automatic clock stopping based on sport type duration rules
- Pause Reasons — Custom pause messages stored and displayed (Half-time, Injury, etc.)
- 3-Hour Safety Limit — Global maximum duration to prevent runaway clocks
- Persistent State — Clock state survives browser refreshes and network interruptions
Firebase Real-time Integration
- Document Listeners — onSnapshot integration with matchClocks collection
- Automatic Sync — Instant clock updates across all connected clients
- Offline Support — Firebase offline persistence maintains state during network issues
- Conflict Resolution — Server timestamps ensure consistent time calculations
- Real-time startTime — Firebase Timestamp integration for precise time tracking
- Live Elapsed Calculation — Dynamic time computation based on running state and server time
Clock Control Features
- Start/Resume: Sends POST request to start or resume the match clock
- Pause: Prompts for reason and pauses clock with explanation stored
- Stop: Immediately ends timing and updates server state
- Time Display: Shows elapsed time in MM:SS format with proper zero-padding
- Pause Reason Display: Shows pause explanation when clock is stopped
- Auto-refresh: Syncs with server after each control action
API Integration
- Uses GET /api/match-clock/{matchId} for fetching current state
- Uses POST /api/match-clock/{matchId}/start for starting/resuming
- Uses POST /api/match-clock/{matchId}/pause for pausing with reason
- Uses POST /api/match-clock/{matchId}/finish for stopping the clock
- Includes comprehensive error handling with console logging
- Automatically cleans up intervals to prevent memory leaks
OngoingMatches Component
- Purpose: A comprehensive React component that displays real-time ongoing matches with live scores, events, and match statistics.
- Why Used: Provides users with a centralized view of all active matches, including live updates, match clocks, event tracking, and animated notifications for scoring events.
Key Features
- Real-time Updates — Polls server every 10 seconds for live match data
- Sport Filtering — Displays matches filtered by sport type when provided via navigation state
- Live Score Tracking — Shows current scores with automatic goal detection and animation
- Match Event Display — Lists fouls, substitutions, goals, and cards in chronological order
- Match Clock Integration — Displays elapsed time using MatchClock component
- Goal Animations — Triggers visual animations when new goals are scored
- Status Filtering — Only displays matches with "ongoing" status and no end time
State Management
- Match Data: Stores array of ongoing matches with live updates
- Loading States: Manages initial loading and update indicators
- Event Tracking: Monitors scoring events for animation triggers
- Error Handling: Displays user-friendly error messages for API failures
- Animation State: Tracks highlighted matches and animation timing
- Last Updated: Shows timestamp of most recent data refresh
Event Processing
- Score Calculation — Processes match events to calculate current scores
- Goal Detection — Compares previous and current scores to detect new goals
- Event Categorization — Separates fouls, substitutions, goals, and cards
- Animation Triggering — Initiates goal animations with unique identifiers
- Match Highlighting — Applies visual effects to matches with recent events
- Event Cleanup — Removes animation states after completion
API Integration & Data Flow
- Fetches data from GET /api/display/display-matches endpoint
- Filters matches by status ("ongoing") and sport type if specified
- Implements automatic polling with 10-second intervals for real-time updates
- Detects data changes using JSON comparison to trigger updates only when needed
- Integrates with MatchClock component for individual match timing
- Handles network errors gracefully with user feedback
UpcomingMatches Component
- Purpose: A React component that displays scheduled and confirmed matches that haven't started yet, providing users with comprehensive upcoming match information.
- Why Used: Allows users to view future match schedules, plan attendance, and stay informed about upcoming sporting events with detailed match information including venues, times, and teams.
Key Features
- Sport Filtering — Displays matches filtered by sport type when provided via navigation state
- Status-based Filtering — Only shows matches with "scheduled" or "confirmed" status
- Date and Time Formatting — Presents match start times in user-friendly format with weekday, date, and time
- Venue Information — Shows match location with map pin icon for easy identification
- Sport Icons — Visual indicators for different sports (⚽ Football, 🏀 Basketball, 🏏 Cricket)
- Responsive Grid Layout — Displays matches in organized card format with consistent styling
Data Management
- Match Fetching: Retrieves all matches from /api/users/viewMatches endpoint
- Client-side Filtering: Filters matches by status and sport type after data retrieval
- Loading States: Shows loading indicator while fetching match data
- Error Handling: Logs errors to console and gracefully handles API failures
- Empty State: Displays user-friendly message when no upcoming matches exist
- Sport Context: Receives sport type from navigation state for targeted filtering
Display Components
- Match Cards — Individual cards showing team matchups, status, and timing
- Team Display — Shows home vs away team names with "VS" separator
- DateTime Section — Calendar icon with formatted date and time display
- Venue Section — Map pin icon with venue location information
- Sport Identification — Trophy icon with sport type and competition details
- Navigation Controls — Back button for returning to previous view
API Integration & Filtering
- Fetches data from GET /api/users/viewMatches endpoint on component mount
- Applies dual filtering: status must be "scheduled" or "confirmed"
- Matches sport type from navigation state when provided (case-insensitive)
- Handles missing or undefined sport types gracefully
- Uses single API call with client-side filtering for performance
- Provides fallback display when no matches meet filter criteria
MatchEvents Component
- Purpose: An administrative React component that allows authorized users to record live match events during ongoing games.
- Why Used: Provides match officials and administrators with a streamlined interface to log goals, fouls, and substitutions in real-time, ensuring accurate match records and live score updates.
Key Features
- Multi-Event Support — Handles three event types: goals, fouls, and substitutions
- Dynamic Form Fields — Form inputs change based on selected event type
- Team Selection — Allows selection between home and away teams for all events
- Player Management — Single player input for goals/fouls, dual player input for substitutions
- Time Validation — Accepts match time between 1-120 minutes (including extra time)
- Admin Authorization — Includes admin role header for API authentication
- Status Feedback — Displays success/error messages after event submission
Event Type Handling
- Goals: Records player name, team, and time with POST to /api/feed/{matchId}/goal
- Fouls: Records player name, team, and time with POST to /api/feed/{matchId}/foul
- Substitutions: Records both incoming and outgoing players with POST to /api/feed/{matchId}/substitution
- Dynamic Validation: Required fields change based on event type selection
- Form Reset: Clears all input fields after successful submission
- Error Handling: Displays user-friendly error messages for failed submissions
Form Management
- State Management — Uses React hooks for form state and user feedback
- Conditional Rendering — Shows relevant input fields based on event type
- Input Validation — Enforces required fields and time range constraints
- Auto-clear Fields — Resets form inputs after successful event recording
- Status Messages — Provides immediate feedback on submission success or failure
- Hardcoded Match ID — Currently uses fixed match ID for demonstration purposes
API Integration & Security
- Uses POST requests to three different feed endpoints based on event type
- Includes "x-user-role: admin" header for authorization verification
- Sends JSON payload with event-specific data structure
- Handles HTTP errors with try-catch blocks and user notifications
- Currently targets hardcoded match ID "9WiywRUkmwXChq4IGEQo"
- Requires backend API authentication for all event recording operations
Loading Component
- Purpose: A reusable React loading screen component that provides consistent loading states across the application with animated visual feedback.
- Why Used: Provides users with visual feedback during data fetching, authentication, and other asynchronous operations to improve user experience and reduce perceived wait times.
Visual Design
- Full-Screen Overlay — Covers entire viewport with dark gradient background matching app theme
- Circular Spinner — Rotating border animation with gold accent color (#d19f13)
- Loading Text — "Loading …" text with pulsing animation for subtle engagement
- Animated Dots — Three colored dots with bouncing animation (blue, purple, indigo)
- Z-index Priority — High z-index (9999) ensures loading screen appears above all content
- Responsive Design — Adapts to all screen sizes with flexible centering
Animation Features
- Spinner Rotation: Continuous 360-degree rotation with 1-second duration
- Text Pulsing: Opacity fade between 100% and 60% over 1.5 seconds
- Dot Bouncing: Sequential vertical bouncing with 150ms delays creating wave effect
- Smooth Transitions: CSS animations provide fluid motion without performance impact
- Color Gradient: Dots use different shades of gold/yellow for visual interest
- Accessibility: Respects user preferences for reduced motion
Usage Patterns
- Authentication Loading — Displayed during Google OAuth login process
- Page Transitions — Shows during route navigation and initial page loads
- Data Fetching — Used while loading matches, teams, and player data
- Profile Loading — Shown during user profile and team information retrieval
- Modal Overlays — Can be integrated into modal dialogs for form submissions
- Conditional Rendering — Easily toggled based on loading state variables
LoginModal & SignupModal Components
- Purpose: Modal dialog components for user authentication with Google OAuth integration and sleek overlay design.
- Why Used: Provides secure, user-friendly authentication without page redirects, supporting both login and signup flows with social authentication.
Authentication Features
- Google OAuth Integration — Single-click authentication using Firebase Auth and Google provider
- Colorful Icons — FcGoogle and FaFacebookF icons with proper branding colors
- Modal Overlay — Dark backdrop with centered modal for focused user interaction
- Cross-Modal Navigation — Users can switch between login and signup modals seamlessly
- Close Controls — Multiple ways to dismiss modal (X button, backdrop click, ESC key)
- Loading States — Visual feedback during authentication process
Security & Error Handling
- Firebase Authentication: Secure OAuth flow with automatic token management
- Router Integration: Automatic navigation after successful authentication
- Error Messages: User-friendly error handling for failed authentication attempts
- Session Management: Persistent login state across browser sessions
- Role Assignment: Automatic user role detection and context setting
- Mobile Compatibility: Responsive design for mobile authentication flows
ProfileCard & ProfileDetails Components
- Purpose: User profile management components that display and allow editing of user information with Cloudinary image integration.
- Why Used: Enables users to view and update their profile information, including profile pictures, with real-time synchronization to Firebase and Cloudinary.
Profile Management Features
- Profile Picture Upload — Drag-and-drop or click-to-select image upload with Cloudinary integration
- Real-time Updates — Immediate profile synchronization with Firebase Authentication
- Loading States — Integrated Loading component during profile operations
- Form Validation — Client-side validation for profile information updates
- Responsive Design — Mobile-friendly profile editing interface
- Error Handling — User-friendly error messages for upload and update failures
Navbar Component
- Purpose: Responsive navigation component with role-based menu items and mobile hamburger menu functionality.
- Why Used: Provides consistent navigation across all pages with different menu options based on user roles (admin, manager, viewer).
Navigation Features
- Role-Based Menus — Different navigation options for admin, manager, and viewer roles
- Mobile Responsive — Hamburger menu for mobile devices with smooth animations
- Profile Integration — User avatar and name display with dropdown menu
- Active Link Highlighting — Visual indication of current page location
- Logout Functionality — Secure logout with Firebase Auth integration
- Logo Integration — PrimeScore branding with clickable home navigation
ConfirmModal Component
- Purpose: Reusable confirmation dialog for destructive actions like deleting matches, teams, or players.
- Why Used: Prevents accidental deletions by requiring explicit user confirmation with clear action descriptions.
Confirmation Features
- Customizable Messages — Dynamic title and description based on action context
- Action Buttons — Distinct styling for confirm (danger) and cancel (safe) actions
- Modal Overlay — Focused interaction with backdrop blur effect
- Keyboard Support — ESC key to cancel, Enter key to confirm
- Loading States — Visual feedback during action execution
- Accessibility — Screen reader friendly with proper ARIA labels
MatchForm & MatchEventForm Components
- Purpose: Administrative forms for creating matches and recording live match events with comprehensive validation and team/player integration.
- Why Used: Enables admins to create matches and record real-time events with proper data validation and user-friendly interfaces.
Form Management
- Team Selection — Dropdown menus populated from database with sport-specific filtering
- Player Auto-complete — Dynamic player lists based on selected teams
- Event Type Handling — Different form fields for goals, fouls, substitutions, cards
- Validation Rules — Required field validation, time constraints, and data format checking
- Real-time Preview — Live preview of match information as user types
- Error Feedback — Immediate validation feedback with helpful error messages
Utility Components
MatchesList Component
- Purpose: Generic list component for displaying match collections with filtering, sorting, and pagination capabilities.
- Why Used: Provides consistent match display formatting across different pages (ongoing, upcoming, past matches) with reusable styling and functionality.
LeagueModal & MatchTypeModal Components
- Purpose: Selection modals for choosing leagues and match types when navigating to specific sport categories or external API integrations.
- Why Used: Enables users to filter content by specific leagues or match types while maintaining clean navigation flows.
TimerSelector Component
- Purpose: Time selection component for match scheduling with date/time picker integration and timezone handling.
- Why Used: Provides user-friendly time selection for match creation with proper formatting and validation.
Performance & Optimization
- Lazy Loading — Components load on-demand to reduce initial bundle size
- Memoization — React.memo and useMemo for expensive computations and re-renders
- Error Boundaries — Graceful error handling to prevent complete app crashes
- Code Splitting — Route-based code splitting for faster page loads
- CSS Optimization — Modular CSS files loaded only when components are used
- Image Optimization — Cloudinary integration for automatic image resizing and format optimization
Current Product Backlog
- Implement real-time live score updates for ongoing matches
- Build event timeline for match feeds (goals, fouls, substitutions, cards)
- Enable match status transitions (upcoming → ongoing → completed) with admin controls
- Allow managers to create/edit teams and assign player roles
- Support manual event input and timeline editing for admins
- Integrate live commentary and stats overlays for viewers
- Enhance match setup: venue, time, teams, and player management
- Improve authentication and role-based access (admin, manager, viewer)
- Refactor API endpoints for clarity and RESTful design
- Expand test coverage for backend
- Polish UI/UX for match viewer and event feed (responsive, accessible)
- Update documentation with new API details and setup instructions
Sprint 1 User Stories
- As a viewer, I want to create an account and log in, so that I can access my homepage.
- As a viewer, I want to see upcoming matches on my homepage, so that I stay updated on events.
- As a viewer, I want to open a profile page, so that I can view my profile details.
- As a viewer, I want to edit my personal details, so that my profile stays up-to-date.
- As a viewer, I want to log out and return to the Welcome page, so that I exit my session safely.
- As a developer, I want to host a documentation site on GitHub Pages, so contributors can access docs easily.
- As a developer, I want to set up backend testing, so that I can ensure the system works correctly.
- As an admin, I want to create a match using a form, so that it appears under upcoming matches for viewers.
- As an admin, I want to log in to the Admin page, so that I can access the admin homepage.
- As a developer, I want to deploy the app to Vercel (frontend) and Azure (backend), so that it's hosted online.
Sprint 2 User Stories
- As a viewer, I want to see the live score of my team, so that I can follow the match in real time.
- As a viewer, I want to see the recent fouls and substitutions that have been made in the game
- As a manager, I want to create a new team, so that I can manage my players and participate in matches.
- As a manager, I want to add players to a team, so that I can build my roster.
- As an admin, I want to see the scheduled matches so that im able to start the match at the right time and date
- As an admin, I want to update the status of a match from upcoming to ongoing, so that fans and players know the match has started.
- As an admin, I want to update the events of the matches, so that the viewers can see the events occuring in the match.
Sprint 3 User Stories
- As a viewer, I want to see netball,rugby and football options so i can watch a sport of my choice
- As a viewer, I want to see animations for current match events so I don't have to refresh to see changes
- As an admin, I want to see match clock so I can add event with correct time
- As an admin, I want to see a predefined list of players and teams so I don't write teams and players not in the database
Sprint 2 Bug Resolution
During Sprint 2, the team decided to prioritize bug fixing before starting Sprint 3. This was crucial to prevent app instability and crashes as we scale. A total of 17 issues were identified, including critical bugs, minor UI/UX inconsistencies, and improvement tasks to prepare the app for new features.
Timeline & Burndown
The bug resolution effort ran from Wednesday, 24th to Wednesday, 1st. Referring to the sprint burndown chart, we observed:
- Days 1–2: Focused on reproducing and prioritizing bugs (bug count remained constant).
- Day 3: Major drop (≈ 40% of bugs resolved).
- Days 4–6: Gradual resolution of remaining issues.
- End of Sprint: Only one low-priority bug remained open, moved to Sprint 3.
Bug Metrics
- Resolved: 16/17 bugs (≈ 94% completion)
- Velocity: 12 bug cards closed within this sprint
- Overdue: 3 improvement tasks carried over to Sprint 3
- In Progress: 1 open bug card by sprint close
Outcome
By addressing the majority of issues before Sprint 3, the app is now more stable, reducing the risk of runtime crashes and allowing the team to focus on new features. This approach helped reduce technical debt and will improve velocity in upcoming sprints.
Agile Methodology
PrimeScore was developed using the Agile Scrum methodology, which emphasized iterative development, continuous feedback, and adaptability. The development process was divided into several sprints, each focused on delivering specific functional modules and improvements.
The team collaborated using Trello for sprint management, GitHub for CI/CD and version control, and Microsoft Teams and WhatsApp for communication.
- A sprint backlog listing prioritized features or bugs.
- Regular stand-ups for progress updates.
- Reviews and retrospectives to assess progress and plan upcoming goals.
Through Agile, the PrimeScore team maintained flexibility, accountability, and continuous delivery of value.
Sprint 01 – Agile
Goal: Establish the project foundation and core system components.
This sprint focused on setup, initial deployment, and the implementation of authentication and UI structure.
- Project Setup:
Initialized the React frontend and Node.js + Express backend projects.
Installed dependencies and configured Firebase Firestore and Auth (Admin SDK).
Set up .env configuration and environment variables. - Deployment and CI/CD:
Deployed the backend to Azure and frontend to Vercel.
Integrated both deployments with GitHub for automated CI/CD pipelines. - Authentication and Authorization:
Developed login functionality for both Admin and Viewer roles.
Implemented secure authentication through Firebase. - UI Foundation:
Created navigation bar and placeholder pages (Dashboard, Profile, Match List).
Set up initial front-end structure and layout. - Documentation:
Created a documentation site on GitHub with UML diagrams and guidelines.
Documented local setup, branching strategy, and commit conventions.
Outcome:
Sprint 1 delivered a fully functional environment setup, integrated CI/CD, and a working authentication system, laying the groundwork for the next development cycles.
Sprint 02 – Agile
Goal: Implement live score updates, team management, and real-time event handling.
- Match Management:
Implemented functionality for creating, editing, and managing matches.
Added support for match lifecycle transitions (upcoming → ongoing → completed). - Real-time Updates:
Built event timeline for live feeds (goals, fouls, substitutions, cards).
Integrated APIs for Live Updates, Feed, and Display (manual + live modes). - Team and Player Management:
Enabled creation of teams and player assignment.
Supported manual input of match events by admins. - Enhancements:
Improved authentication and role-based access for admins, managers, and viewers.
Refactored API endpoints for better RESTful design. - UI/UX and Documentation:
Polished interface for the Match Viewer and Event Feed.
Updated technical documentation with new API and setup details.
Outcome:
By the end of Sprint 2, PrimeScore featured live match updates, dynamic team management, and real-time event feeds, achieving the first complete “game flow” between admins and viewers.
Sprint 03 - Agile
The Sprint 3 planning meeting focused on prioritizing carryover tasks from Sprint 2 and addressing technical improvements. The discussion as issued by the tutor was based on ensuring that aspects of our projects are well documented and improving documentation from Sprint 02.
- Bug, Third-Party, and feedback documentation.
- Past matches from local leagues and more as indicated under bug tracking.
- Add more sports including Netball and Rugby.
Main issues discussed during the daily standups were the following:
- Resolving bugs more quickly to allow focus on current sprint tasks
- Leveraging free APIs to meet the system’s basic requirements
- Expanding the system to support all sports in a more general way
- Ensuring that documentation is clear, structured, and well-maintained
The stakeholder saw the progress of the app, which included the Rugby Fixtures, and suggested we add the results from the API to our database to avoid exceeding the limit of API requests.
The retrospective was a moment of reflection but also focused on introducing Jest for automated testing. Every team member was assigned a number of Components and Pages to test. Although some members were still fixing bugs and making app improvements, the testing effort was considered a partial success and set a foundation for stronger test coverage in future sprints.
Sprint 04 – Agile
Goal: Testing, optimization, and documentation polish for final delivery.
- Frontend Testing:
Tested over 10+ React components including LoginModal, MatchClock, UserProfile, MatchEventForm, LiveMatches, and AdminHomepage.
Conducted unit and integration tests to ensure UI consistency and responsiveness. - Backend and API Testing:
Verified APIs for external access and secure communication.
Ensured session management and expiry handling worked as intended. - Bug Fixing and Improvements:
Resolved key issues such as event refreshing, clock synchronization, and navigation inconsistencies.
Cleaned unnecessary components and modularized match administration. - Documentation and Code Quality:
Enhanced documentation and linting for project maintainability.
Finalized architectural documentation and database schema updates. - Finalization:
Conducted final team reviews on methodology, architecture, and testing outcomes.
Completed general discussions and planning for deployment submission.
Outcome:
Sprint 4 finalized PrimeScore with a polished, tested, and well-documented platform. It marked the successful conclusion of the Agile development cycle, ensuring a stable and deployable system.
Developer Setup Guide
git clone https://github.com/your-repo/primescore.git
# Prerequisites
# - Node.js (v18+ recommended)
# - npm (v9+ recommended)
# - (Optional) VS Code for best experience
# 1. Set up the frontend
cd frontend
npm install
# Create a .env file if you need to override API URLs or add keys
# Example: VITE_API_BASE_URL, VITE_FIREBASE_API_KEY, etc.
npm run dev
# 2. Set up the backend (in a new terminal)
cd backend
npm install
# Copy .env.example to .env and fill in Firebase credentials and any other secrets
npm run dev
# 3. Access the app
# - Frontend: http://localhost:5173 (default Vite port)
# - Backend: http://localhost:3000 (default Express port)
# 4. (Optional) Run tests
# In backend: npm test
- Environment Variables: Both frontend and backend use
.envfiles for secrets and config. Never commit secrets to git. - Proxy Setup: The frontend is configured to proxy
/apirequests to the backend during development (seevite.config.js). - Firebase: You need a Firebase project and service account for backend integration. Place your credentials in
backend/.envas shown in.env.example. - Common Issues: If you see CORS errors or API 404s, make sure both servers are running and the proxy is set up correctly.
- Recommended Tools: VS Code, Postman (for API testing), and GitHub Desktop or CLI for version control.
- Hot Reload: Both frontend and backend support hot reload for rapid development.
If you encounter issues, check the README files in each folder or contact the project maintainer.
Sprint 04 – Agile
Goal: Testing, optimization, and documentation polish for final delivery.
- Frontend Testing:
Tested over 10+ React components including LoginModal, MatchClock, UserProfile, MatchEventForm, LiveMatches, and AdminHomepage.
Conducted unit and integration tests to ensure UI consistency and responsiveness. - Backend and API Testing:
Verified APIs for external access and secure communication.
Ensured session management and expiry handling worked as intended. - Bug Fixing and Improvements:
Resolved key issues such as event refreshing, clock synchronization, and navigation inconsistencies.
Cleaned unnecessary components and modularized match administration. - Documentation and Code Quality:
Enhanced documentation and linting for project maintainability.
Finalized architectural documentation and database schema updates. - Finalization:
Conducted final team reviews on methodology, architecture, and testing outcomes.
Completed general discussions and planning for deployment submission.
Outcome:
Sprint 4 finalized PrimeScore with a polished, tested, and well-documented platform. It marked the successful conclusion of the Agile development cycle, ensuring a stable and deployable system.
Git Workflow Overview
PrimeScore follows a structured Git workflow that ensures code quality, enables collaboration, and maintains stable releases through automated testing and deployment pipelines.
Repository Structure
- Repository:
ItCanCode/PrimeScorehosted on GitHub - Main Branch:
main— production-ready, stable code with deployment triggers - Testing Branches:
Testing,frontend-testing— integration testing environments - Feature Branches:
feature/match-clock-integration,feature/*— new development work - Coverage Badge: Codecov integration displays real-time test coverage status
Branching Strategy
- Main Branch Protection:
mainbranch is protected and requires pull request reviews - Feature Development: Create feature branches from
mainusing descriptive names - Naming Convention:
feature/description,bugfix/issue-name,hotfix/critical-fix - Integration Testing: Use
Testingbranch for pre-production validation - Parallel Development: Multiple team members can work on separate features simultaneously
- Branch Cleanup: Delete feature branches after successful merge to keep repository clean
Commit Standards
Conventional Commits Format
type(scope): short description
[optional body]
[optional footer]
Commit Types
- feat: New features (e.g.,
feat(match-clock): add real-time synchronization) - fix: Bug fixes (e.g.,
fix(auth): resolve login redirect issue) - docs: Documentation updates (e.g.,
docs(api): update endpoint descriptions) - style: Code formatting, no logic changes (e.g.,
style(components): fix eslint warnings) - refactor: Code restructuring (e.g.,
refactor(database): optimize query performance) - test: Test additions or modifications (e.g.,
test(match-clock): add unit tests for pause/resume) - chore: Build, dependencies, tooling (e.g.,
chore(deps): update react to v19.1.0)
Pull Request Workflow
- Create Feature Branch: Branch off from
mainwith descriptive name - Development & Testing: Implement feature with comprehensive tests
- Pre-PR Checklist:
- Run local tests:
npm testin both frontend and backend - Check linting:
npm run lintto ensure code standards - Verify build:
npm run buildsucceeds without errors - Update documentation if needed
- Run local tests:
- Create Pull Request: Target
mainbranch with descriptive title and description - Automated Checks: GitHub Actions run CI/CD pipeline automatically
- Code Review: At least one team member approval required before merge
- Merge Strategy: Squash and merge to maintain clean commit history
Continuous Integration Pipeline
GitHub Actions Workflows
- CI and Coverage (
backend-ci.yml)- Triggers: Push/PR to
main,Testing,frontend-testing - Node.js 20 setup with dependency caching
- Backend tests with Jest coverage reporting
- Frontend tests with React Testing Library
- Codecov integration for coverage tracking and reporting
- JUnit XML test result uploads
- Triggers: Push/PR to
- Azure Deployment (
main_prime-backend.yml)- Triggers: Push to
mainbranch for production deployment - Node.js 22 build environment
- Automated build, test, and deployment to Azure App Service
- Production slot deployment with rollback capabilities
- Coverage reporting to Codecov during deployment
- Triggers: Push to
Code Quality Standards
- ESLint Configuration: React hooks and refresh plugins with custom rules
- Coverage Requirements: 80% project coverage target via Codecov
- Automated Testing: Jest for backend, React Testing Library for frontend
- Security Scanning: NPM audit checks for vulnerable dependencies
- Pre-commit Hooks: Lint and format code before commits
- Build Verification: All PRs must pass build process before merge
Development Environment Setup
# Initial repository setup
git clone https://github.com/ItCanCode/PrimeScore.git
cd PrimeScore
# Create and switch to feature branch
git checkout -b feature/your-feature-name
# Stage and commit changes
git add .
git commit -m "feat(component): add new feature description"
# Push feature branch
git push origin feature/your-feature-name
# Create pull request via GitHub UI
# After approval and merge, cleanup
git checkout main
git pull origin main
git branch -d feature/your-feature-name
Deployment Strategy
- Frontend: Vercel automatic deployments from
mainbranch - Backend: Azure App Service deployments via GitHub Actions
- Environment Variables: Separate configurations for development, testing, and production
- Database: Firebase Firestore with separate projects for environments
- CDN: Static assets served via Vercel's global CDN
- Monitoring: Codecov for test coverage, Azure monitoring for backend performance
Security & Best Practices
- Environment Files:
.envfiles excluded from Git via.gitignore - API Keys: Stored as GitHub Secrets and Azure App Service settings
- Branch Protection: Main branch requires PR reviews and status checks
- Dependency Management: Regular npm audit scans for security vulnerabilities
- Supply Chain Security: Monitor for compromised packages (recent chalk/debug attack)
- Access Control: Team members have appropriate repository permissions
Project Management Integration
- Trello Board: Task management and sprint planning
- GitHub Issues: Bug tracking and feature requests linked to commits
- Sprint Integration: Feature branches correspond to sprint backlog items
- Documentation: GitHub Pages hosting for comprehensive project documentation
- Release Notes: Generated from conventional commit messages
Database Documentation
Schema Overview
- teams (collection)
teamId— unique identifier (auto-generated)teamName— full name of the teamshortName— abbreviation for displayssportType— sport category (Football, Basketball, Rugby, Netball)city— home city locationcreatedBy— UID of the manager who created the teamcreatedAt— timestamp when team was created
- players (collection)
playerId— unique identifier (auto-generated)name— player's full nameteamId— reference toteams.teamIdposition— player's field positionnumber— player's jersey numberage— player's agecreatedBy— UID of the manager who added the playercreatedAt— timestamp when player was added
- matches (collection)
matchId— unique identifier (auto-generated)matchName— descriptive match titlehomeTeam— home team nameawayTeam— away team namehomeTeamId— reference toteams.teamId(home)awayTeamId— reference toteams.teamId(away)startTime— scheduled start date and timevenue— location where match is playedsportType— sport category for this matchstatus— match state (upcoming | ongoing | completed | finished)homeScore— current home team scoreawayScore— current away team scorecreatedAt— timestamp when match was createdupdatedAt— timestamp of last updateend_time/endTime— match completion timestamp
- matchEvents (collection) — real-time match event tracking
matchId— identifier matching parent match documenthomeScore— current home team scoreawayScore— current away team scoreisRunning— boolean indicating if match is activeperiod— current game period/halfevents— array of individual match events with:type— event type (goal, foul, substitution, card, etc.)time— game time when event occurred (in minutes)team— team involved (home/away)player— player name involved in eventplayerIn— incoming player (substitutions only)playerOut— outgoing player (substitutions only)card— card type (yellow/red) if applicablepoints— points scored (sport-specific)extra— additional event metadatatimestamp— ISO timestamp when event was recordedcreatedAt— initial document creation timestampupdatedAt— last modification timestamp
- matchClocks (collection) — real-time match timing system
matchId— unique identifier matching parent matchelapsed— accumulated elapsed time in secondsrunning— boolean indicating if clock is currently activestartTime— Firebase timestamp when clock was last startedpausedReason— reason for clock pause (if applicable)createdAt— initial clock creation timestampupdatedAt— last clock state update timestamp- Auto-stop Rules:
- Football: 120 minutes (7200 seconds)
- Rugby: 90 minutes (5400 seconds)
- Netball: 60 minutes (3600 seconds)
- Global maximum: 3 hours (10800 seconds)
- Real-time Synchronization: Uses Firebase listeners for instant clock updates across all clients
- Pause/Resume Support: Maintains accurate elapsed time during game interruptions
- Upcoming_Matches (collection) — external API integration cache
id— external match identifier from sports APIhome— home team name from external sourceaway— away team name from external sourcetime— scheduled match timedate— scheduled match date
- users (Firebase Authentication) — user account management
uid— unique Firebase Auth user identifieremail— user's email addressdisplayName— user's display namerole— user permission level (admin, manager, viewer)photoURL— profile picture URL (Cloudinary integration)createdAt— account creation timestamplastLoginAt— last authentication timestamp
Database Relationships & Architecture
- Match Clock Integration: Each match can have an associated
matchClocksdocument that provides real-time timing functionality - Event Tracking:
matchEventsdocuments store live match statistics and event arrays, linked bymatchId - Team-Player Hierarchy: Players belong to teams via
teamIdforeign key relationship - User Ownership: Teams and players are associated with users via
createdByfield containing Firebase Auth UID - Role-Based Access: User roles (admin, manager, viewer) control CRUD permissions across collections
- External API Cache:
Upcoming_Matchesstores third-party sports data to reduce API calls
Real-Time Features
- Live Match Clock:
- Automatic time calculation with pause/resume support
- Sport-specific duration limits with auto-stop functionality
- Real-time synchronization across all connected clients
- Persistent state preservation during browser sessions
- Event Broadcasting:
- Instant event updates (goals, fouls, substitutions) pushed to all viewers
- Score updates reflected immediately in match documents
- Event animations triggered by real-time Firebase listeners
- Match Status Transitions:
- Automatic status updates (upcoming → ongoing → completed)
- Clock integration triggers match status changes
- End time stamping when matches are completed
Data Validation & Security
- Firebase Rules: Collection-level security rules enforce user authentication and role-based permissions
- Backend Validation: API endpoints validate required fields, data types, and business logic constraints
- Ownership Verification: Users can only modify teams/players they created, admins have broader access
- Event Integrity: Match events include timestamps and validation to prevent data corruption
- Clock Safety: Maximum duration limits prevent runaway clocks, auto-stop after 3 hours globally
Performance Optimizations
- Indexed Queries: Common queries (by status, sportType, createdBy) are indexed for fast retrieval
- Batch Operations: Multiple player additions and event updates use Firestore batch writes
- Real-time Listeners: Efficient use of Firebase onSnapshot for live updates without polling
- Cached External Data: Sports API results stored locally to minimize external API calls
- Client-side Filtering: Frontend filters ongoing matches locally to reduce database queries
Deployment Info
The database is deployed on Firebase Firestore, which provides:
- Global availability and auto-scaling
- Real-time synchronization for instant updates across clients
- Seamless integration with Firebase Authentication and Cloud Functions
- Built-in offline support with automatic data synchronization
- Multi-region replication for high availability
- ACID transactions for data consistency
Choice Justification
Firestore was chosen over traditional SQL databases because of its ability to handle real-time data streams, which are critical for sports event updates. Its document-based schema allows flexible team/player structures, while built-in offline support ensures users can continue to view cached data even without a connection. The match clock system particularly benefits from Firestore's real-time listeners, enabling instant synchronization of elapsed time across all connected clients without the need for polling mechanisms. Firestore also reduces backend overhead since it integrates smoothly with Firebase Auth and serverless functions for secure access control.
Testing Documentation
Automated Testing
Frontend Testing
Test coverage reports indicate that the UI implementation is largely accurate. Detailed coverage metrics can be reviewed on Frontend Codecov.
- ConfirmModal
- Render: Renders modal correctly.
- Interaction: Opens/closes on confirm/cancel.
- Error Handling: Invalid/missing props.
- LeagueModal
- Render: Displays league creation form.
- Interaction: Submits with valid input, rejects invalid input.
Loading,NavBar- Render: Loading spinner/nav elements visible.
- Interaction: Nav links redirect correctly.
- PastMatch, PastMatches
- Render: Shows past match cards/list.
- Props: Displays correct team names, scores.
- Error Handling: Handles empty/no data gracefully.
- TeamManagement
- Render: Management dashboard loads.
- Interaction: Adding/removing players.
- Integration: Updates state & context correctly.
- LoginModal, SignupModal
- Render: Forms load correctly.
- Interaction: Form validation (empty, invalid input).
- Integration: API/auth calls triggered on submit.
- context
- Unit: Provides global state.
- Integration: Wraps components and shares auth/user state.
- MatchEventForm
- Render: Loads form fields.
- Interaction: Submits valid events, rejects invalid fields.
- MatchAdminInterface
- Render: Admin dashboard loads.
- Interaction: Start/stop match, update scores/events.
- Integration: Fetches from backend & updates UI.
- WelcomePage, SportsSelector
- Render: Loads landing page & sport options.
- Interaction: Selecting sport updates navigation.
- MatchClock, MatchType, TimerSelector
- Render: Displays time, type, and timer options.
- Interaction: Countdown works, type selection updates state.
- Error Handling: Invalid timer values.
- HomePage
- Render: Loads homepage layout.
- Integration: Fetches data from services.
- UpcomingMatches
- Render: Lists upcoming matches.
- Error Handling: Displays fallback for no matches.
- services (6)
- Unit: Test API calls individually (mocks).
- Integration: Valid responses update components.
- Error Handling: Failed requests handled with fallback.
ProfileCard,ProfileDetails,UserProfile- Render: Display user info.
- Props: Correctly shows passed-in user data.
- Integration: Edits update user profile context/state.
MatchesList,OngoingMatches,LiveMatches- Render: Displays matches list.
- Interaction: Updates when a match goes live.
- Integration: Fetch data from backend services.
AdminHomepage- Render: Loads admin dashboard.
- Interaction: Navigation to management tools.
RugbyFixture- Render: Displays rugby fixtures.
- Error Handling: No fixtures → empty state message.
Backend Testing
Test coverage reports confirm that the backend functionality is well tested across controllers, services, and integrations. A detailed breakdown of backend coverage can be viewed on Backend Codecov .
- Authentication
verifyGoogleToken- Unit: Validates valid/invalid Google tokens.
- Error Handling: Rejects expired/malformed tokens.
googleAuth- Integration: Signup & login flows with Firestore/Google.
- Error Handling: Duplicate accounts, invalid credentials.
- Manager Controller
createTeam- Unit: Creates a team object.
- Integration: Saves team in Firestore.
- Error Handling: Firestore write failure.
addPlayers- Unit: Validates player input & ownership.
- Integration: Updates Firestore team with players.
- Error Handling: Invalid owner, missing player data.
myTeam- Unit: Retrieves team by user ID.
- Error Handling: Team not found, Firestore errors.
- Admin Controller
createMatch- Unit: Creates match object.
- Integration: Saves match in Firestore.
- Error Handling: Invalid data, Firestore errors.
updateMatchStatus- Unit: Updates match status values.
- Error Handling: Match not found, invalid status.
updateScore- Unit: Increments score fields.
- Integration: Records goals as events.
- Error Handling: Invalid match ID, Firestore errors.
addMatchEvent- Unit: Validates event type (card, foul, etc).
- Integration: Adds event to Firestore.
- Error Handling: Invalid payload, match not found.
allTeams- Unit: Fetches list of teams.
- Integration: Filters by sport type.
- Error Handling: Empty collection, Firestore failure.
- LiveSport Controller
batchAddMatches- Unit: Accepts bulk match payload.
- Error Handling: Empty payload, invalid fields.
- Feed Controller
startMatch- Unit: Initializes match events object.
- Integration: Links to match ID.
- Error Handling: Invalid match reference.
recordGoal- Unit: Updates home/away scores.
- Integration: Records goal event.
- Error Handling: Invalid team side, missing match.
recordSubstitution- Unit: Validates substitution fields.
- Integration: Saves substitution event.
- Error Handling: Invalid player data.
recordFoul- Unit: Records foul type (with/without card).
- Integration: Links foul event to match.
- Error Handling: Invalid foul input.
- Display Controller
getMatchEventsById- Unit: Fetches events by match ID.
- Error Handling: Invalid ID, no events.
getmatchEvents- Unit: Fetches all ongoing matches.
- Integration: Includes linked events.
- Error Handling: No active matches, Firestore errors.
# Run backend tests
cd backend
npm install
npm test
# Run frontend tests
cd frontend
npm install
npm test
# To view full coverage:
npm test -- --coverage
Developers are required to write tests for all new features and bug fixes before merging. This ensures that user feedback and automated verification work together to maintain quality.
PrimeScore NPM Supply Chain Security Audit – Sprint 3
Date: 29 September 2025
Scope: Check for presence of compromised NPM packages from the September 2025 “debug & chalk” attack.
Compromised Packages (Baseline, from Aikido)
backslash, chalk-template, supports-hyperlinks, has-ansi, simple-swizzle, color-string, error-ex, color-name, is-arrayish, slice-ansi, color-convert, wrap-ansi, ansi-regex, supports-color, strip-ansi, chalk, debug, ansi-styles
4.1 Manual / Quick Checklist
Objective
Quickly inspect PrimeScore’s dependencies for compromised packages using manual commands and npm audit tools.
Steps & Commands
List all direct dependencies in package.json:
jq -r '.dependencies + .devDependencies | keys[]' package.json
Result:
firebase
lucide-react
No direct references to compromised packages found.
Inspect transitive dependencies in package-lock.json:
jq -r '.dependencies | keys[]' package-lock.json
⚠️ Encountered error at line 1078: null has no keys
Reason: Some dependencies may be optional or malformed. Proceed to node_modules scan.
Check if compromised packages exist in node_modules:
for p in backslash chalk-template supports-hyperlinks has-ansi simple-swizzle color-string error-ex color-name \
is-arrayish slice-ansi color-convert wrap-ansi ansi-regex supports-color strip-ansi chalk debug ansi-styles; do
if [ -d "node_modules/$p" ]; then echo "FOUND: $p in node_modules"; fi
done
No direct matches detected.
Trace key compromised packages with npm ls:
npm ls debug chalk ansi-regex supports-color --all
PrimeScore@ C:\...\PrimeScore
└── (empty)
No direct installation of these packages.
Run npm audit to detect known vulnerabilities:
npm audit --json > audit.json
audit.json Full Output
{
"auditReportVersion": 2,
"vulnerabilities": {},
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 0,
"moderate": 0,
"high": 0,
"critical": 0,
"total": 0
},
"dependencies": {
"prod": 88,
"dev": 0,
"optional": 0,
"peer": 1,
"peerOptional": 0,
"total": 88
}
}
}
No known vulnerabilities detected by npm audit.
Check package publish times for suspicious versions:
npm view debug time
npm view chalk time
Detected malicious versions published around 2025-09-08
PrimeScore does not reference these recent versions.
Interpretation (4.1)
PrimeScore has no direct compromised packages.
Manual inspection shows potential risk only in transitive dependencies, which requires deeper automated scanning.
4.2 Automated Scan – Python
Objective
Use scan_compromised.py to recursively check both direct and transitive dependencies and installed node_modules.
Command:
python3 scan_compromised.py
Results
Package Location in Project
ansi-regex node_modules/ansi-regex
ansi-styles node_modules/ansi-styles
color-convert node_modules/color-convert
color-name node_modules/color-name
strip-ansi node_modules/strip-ansi
wrap-ansi node_modules/wrap-ansi
Direct dependencies: None
Transitive dependencies: Present → included via other packages (likely chalk or similar)
Installed node_modules: Confirmed
Interpretation
Direct findings: No immediate compromise.
Transitive findings: Compromised packages exist deeper in dependency tree.
Installed packages: Remediation needed to remove malicious versions if present.
Recommended Actions
- Identify which top-level packages pull in the transitive compromised packages:
npm ls ansi-regex wrap-ansi color-convert color-name strip-ansi - Update or replace top-level packages if safe versions exist.
- Regenerate lockfile and reinstall dependencies:
rm -rf node_modules package-lock.json npm install - Continue running
scan_compromised.pyafter every dependency update. - Use SCA tools (Snyk, GitHub Dependabot, GitHub code scanning) for continuous monitoring.
- Educate developers to avoid phishing attacks targeting maintainers.
Conclusion
PrimeScore is not directly compromised by the recent NPM supply chain attacks.
Transitive dependencies contain compromised packages. Immediate remediation recommended:
- Trace top-level packages
- Update or lock safe versions
- Regenerate node_modules and lockfile
This audit ensures PrimeScore’s supply chain remains safe against the September 2025 NPM malware.
📄 Software Supply Chain Security Report
1. Cause of the Supply Chain Attack
The attack originated from an upstream compromise in the npm registry. Attackers gained access to maintainers’ accounts or credentials and published malicious versions of legitimate packages. Developers installing updates pulled in this malware automatically.
📦 Compromised Packages and Versions
The following packages were identified in the September 2025 supply chain attack. These are known to be malicious or compromised versions:
| Package | Version |
|---|---|
| backslash | 0.2.1 |
| chalk-template | 1.1.1 |
| supports-hyperlinks | 4.1.1 |
| has-ansi | 6.0.1 |
| simple-swizzle | 0.2.3 |
| color-string | 2.1.1 |
| error-ex | 1.3.3 |
| color-name | 2.0.1 |
| is-arrayish | 0.3.3 |
| slice-ansi | 7.1.1 |
| color-convert | 3.1.1 |
| wrap-ansi | 9.0.1 |
| ansi-regex | 6.2.1 |
| supports-color | 10.2.1 |
| strip-ansi | 7.1.1 |
| chalk | 5.6.1 |
| debug | 4.4.2 |
| ansi-styles | 6.2.2 |
Note: While these packages were compromised at the specified versions, our audit confirmed that PrimeScore does not directly depend on them. However, some were found as transitive dependencies via other libraries, which poses an indirect risk.
3. Audit of Our Packages (Web-App & API)
# List direct dependencies
jq -r '.dependencies + .devDependencies | keys[]' package.json
# Run audit
npm audit --json > audit-results.json
# Production-focused audit
npm audit --production
Results:
- Total packages checked: 842
- Critical vulnerabilities: 2
- High vulnerabilities: 5
- Moderate vulnerabilities: 7
- Compromised packages: None detected
4. Report of Packages (Upstream Risk)
Cross-checking against known compromised packages revealed
no matches. However, outdated sub-dependencies like
glob-parent@5.1.1 (ReDoS vulnerability) and
minimist@1.2.5 (Prototype pollution) still pose risks.
5. Protecting Against Supply Chain Attacks (Upstream Defense)
- Pin dependencies with
package-lock.json - Enable MFA on npm accounts
- Use CI/CD scanning tools (npm audit, Snyk, OWASP Dependency-Check)
- Prefer trusted maintainers/organizations
- Maintain private mirrors (Verdaccio)
- Avoid floating versions (
^,~)
6. Protecting Against Product Infection (Local Defense)
- Run installs in isolated containers (Docker)
- Monitor runtime integrity for abnormal behavior
- Apply principle of least privilege
- Use SBOMs (Software Bill of Materials)
- Regular penetration testing
- Static code analysis for obfuscation
7. Recommendations
- Patch flagged vulnerabilities (
npm audit fix) - Integrate CI/CD dependency scanning
- Document & track dependencies per release
- Educate developers on dependency security
- Monitor npm advisories continuously
User Feedback
User Feedback Process
We follow a structured process to collect and integrate user feedback:
- Feedback Collection — Users submit feedback via a google form.
- Review — The development team reviews and categorizes feedback (bug, feature request, usability).
- Prioritization — Items are logged into the product backlog and tagged for the appropriate sprint.
- Follow-up — Users are notified when their feedback results in an update.
A survey was conducted with 28 participants to gather feedback on the app.The resuls are sumarized below.
Participant Roles
- Viewer: 16 (57.1%)
- Team Manager: 5 (17.9%)
- Admin: 6 (21.4%)
Survey Ratings
| Question | Average Rating |
|---|---|
| Familiarity with live sports apps | 3.68 / 5 |
| Ease of navigating Match Viewer | 3.61 / 5 |
| Clarity of Event Feed | 3.61 / 5 |
| Satisfaction with Live Scoreboard layout | 3.89 / 5 |
| Speed and responsiveness | 3.39 / 5 |
| Overall satisfaction | 3.57 / 5 |
Most Useful Features
- Match Viewer: 15 responses (57.7%)
- Event Feed: 14 responses (53.8%)
- Match Setup: 10 responses (38.5%)
- Manual Input Panel: 10 responses (38.5%)
- Live Scoreboard: 15 responses (57.7%)
Least Used or Unnecessary Features
- News and Contact on navigation bar
- Profile
- Event Feed
- Live Scoreboard
- None
Reported Issues
- Clock not working on live matches
- Admin bugs: starting match before scheduled date
- Manual input panel limited to football-specific events
- Cannot access certain leagues (e.g., Premier League)
- Suggestions: confirmation prompts, customizable user profiles, multi-sport compatibility
Recommendation
- Yes: Majority of users
- No: Some users
- Maybe: Some users
Feedback Integration
The feedback gathered has been prioritized for integration in future sprints. Key actions include:
- Enhancing Event Feed clarity and filtering
- Making Manual Input Panel multi-sport compatible
- Adding confirmation prompts for match creation and event input
- Fixing clock and Live Scoreboard display issues
- Streamlining navigation and removing unnecessary menu items
Performance
Performance analysis was conducted using
Google PageSpeed Insights
.
The report provides detailed metrics on page load times, responsiveness, and overall desktop performance for the deployed application.