South Broward Player Development System - Full Stack Serverless Web Application
A data-driven player development and retention platform built for South Broward High School football. The system tracks athlete performance across five physical tests, calculates bodyweight-adjusted scores across four weight classes, and assigns tier rankings. The result is non-transferable earned status designed to combat the transfer epidemic in South Florida high school football.
Tech Stack: JavaScript · Python · AWS Lambda · DynamoDB · API Gateway · Cognito · Amplify · S3 · CloudFront · React · Chakra UI · Recharts
🔗 Live App · GitHub Repo
The Problem
South Florida high school football has a transfer epidemic. Players leave programs mid-season chasing playing time or perceived opportunities. Coaches turn over. Rosters reset annually.
The result is no continuity, no culture, and no community investment. When fans don't know the players, they stop showing up. When alumni can't follow a kid's journey from freshman to senior, they stop donating.
Before this system, there was nothing tying a player to the program beyond a roster spot. A kid could transfer tomorrow and lose nothing. No status, no recognition, no proof of what he built.
The solution isn't to trap kids. It's to build something worth staying for. A tiered ranking system where players earn visible, wearable status over time gives them something to work toward and something to lose if they leave.
When a kid has spent two years climbing up the rankings, he thinks twice before starting over as nobody at another school. The kid who reached the top of his class gets recognized in front of the team, on the field, and in recruiting conversations. The system rewards the players who stick with the program. That's the point.
What I Built
Backend. AWS Lambda Functions (Python)
- Roster Management. Full CRUD operations for player records. Each player gets an auto-generated ID using the first four letters of their last name, first two of their first name, and a two-digit sequence number (e.g.,
BRADHO01). Supports individual entry and CSV batch upload. Validates required fields and enforces data integrity before any write hits DynamoDB. - Attendance Tracking. Coaches mark attendance per session. No self-reporting, no honor system. The system calculates attendance percentages over time and surfaces them on player profiles and dashboards. Every record is timestamped and tied to the authenticated coach who submitted it.
- Performance Scoring Engine. The core of the system. When a coach submits test results, Lambda calculates bodyweight-adjusted multipliers for the three strength lifts, looks up point values from the scoring tables, and sums across all five tests. The total determines the player's tier:
- Puppy (0–29)
- Dog (30–54)
- Big Dog (55–74)
- Alpha (75–84)
- Beast Mode (85+)
- Audit Logging. Every insert, update, and delete is logged to a dedicated DynamoDB audit table (
sb-dog-house-audit-log). Each entry includes a UUID, action type, detail string, timestamp, and the authenticated user who performed the action. This creates a complete, immutable record of every data change in the system.
Calculated scores are stored in DynamoDB, which serves as the single source of truth. The React frontend reads stored values but never calculates them.
Scoring System. Four Weight Classes
The scoring system went through three major iterations. The original single-multiplier approach severely penalized heavier players. A 250-pound lineman squatting 450 is impressive, but a flat bodyweight multiplier would rank him below a 160-pound kid squatting 300.
The final v3 system uses four weight classes with independently calibrated Beast Mode benchmarks:
Weight Class | Squat | Bench | Clean | 40-Yard | Vertical |
Light (<170 lbs) | 355 | 255 | 225 | 4.5s | 35" |
Medium (170–220 lbs) | 385 | 315 | 245 | 4.6s | 33" |
Heavy (220–260 lbs) | 405 | 335 | 275 | 4.8s | 31" |
Super Heavy (260+ lbs) | 425 | 355 | 275 | 4.9s | 28" |
These numbers were validated against several experienced South Florida coaches, whose calibration data was collected via a survey system I deployed through AWS.
Database. DynamoDB
All data lives in DynamoDB. Player records, attendance logs, performance scores, and the audit log. Serverless, no infrastructure to manage, and a natural fit with Lambda. Tables use composite keys for efficient querying across players, dates, and score history.
Authentication. AWS Cognito
Cognito handles coach authentication and user management. Role-based access ensures only authenticated coaches can submit data or modify records.
Frontend. React + Chakra UI
Single-page application built in React with Chakra UI. Styled in South Broward's school colors (red, yellow, white, grey). Key views:
- Dashboard. Program-wide overview with Recharts visualizations. Tier distribution, attendance trends, top performers, and roster composition.
- Roster Management. Searchable, sortable roster with inline player details. Supports individual add, edit, delete, and CSV batch upload.
- Attendance Calendar. Visual calendar interface for marking and reviewing daily attendance. Coaches see at a glance who's showing up.
- Performance Scores. Score entry form with live tier calculation. As a coach enters test results, the system shows the projected tier in real time before submission.
- Player Profiles. Individual view with attendance statistics, performance history, current tier, and progression tracking.
- Leaderboard. Ranked player list sortable by total score, individual tests, or attendance percentage.
- Depth Chart. Position-based roster view. Reads pre-calculated scores directly from DynamoDB. Contains no scoring logic of its own.
Data Standardization. CSV Batch Upload
Rosters can be uploaded via CSV with validated column mapping. The system parses incoming files, validates required fields, generates player IDs, and batch-writes to DynamoDB. This allows coaches to onboard an entire roster in one action rather than entering 60+ players individually.
Coach Calibration Survey. Amplify + CloudFront
To validate the scoring benchmarks, I built and deployed a separate survey application using AWS Amplify and CloudFront. The survey collected Beast Mode threshold estimates from experienced South Florida coaches across all four weight classes and five tests.
Responses were stored in DynamoDB and compared against each other to identify consensus ranges. This was a standalone tool built specifically to support the scoring calibration process. Not part of the main application.
Dashboard
The dashboard gives coaches a real-time overview of program health. Who's showing up, who's improving, and where the roster stands.
Program Overview. Tier distribution chart, attendance trends, and top performers at a glance. Coaches can see whether the program is developing or stalling without digging into individual profiles.
Attendance Calendar. Visual daily attendance tracking. Color-coded cells make it immediately obvious who's been consistent and who's dropping off.
Player Profile. Individual athlete view showing current tier, all test scores, attendance percentage, and performance history. This is the page a coach pulls up when a college recruiter calls.
Score Entry with Live Tier Calculation. As a coach enters test results, the system calculates the multiplier, looks up points, and shows the projected tier in real time before submission.
How It Worked in Production
The workflow starts with the coach. At the beginning of a season or training cycle, the coach uploads the full roster via CSV. Names, positions, weights, jersey numbers. The system generates player IDs and creates records in DynamoDB.
Daily, coaches open the attendance view and mark who showed up. The system timestamps each record and ties it to the authenticated coach.
Quarterly (or whenever testing occurs), coaches enter performance results. Squat, bench, clean, 40 time, and vertical. Lambda calculates multipliers, looks up points from the weight-class-adjusted scoring tables, sums the total, and assigns the tier.
The player's profile updates immediately. The leaderboard re-ranks. The dashboard refreshes.
Over time, the system builds a longitudinal picture of every player:
- Where they started
- How fast they're developing
- Whether they've plateaued
- How their commitment (attendance) correlates with their performance gains
Key Engineering Decisions
DynamoDB as Single Source of Truth for Scoring. Scores and tiers are calculated once by Lambda at submission time and stored in DynamoDB. The frontend reads and displays stored values rather than recalculating them in JavaScript every time a page loads. One source of truth, no drift between what the UI shows and what the database stores.
Four Weight Classes Instead of One Multiplier. The original single-multiplier approach was mathematically unfair to heavier athletes. A four-class system (Light, Medium, Heavy, Super Heavy) with independently calibrated benchmarks ensures a 250-pound lineman squatting 450 gets recognized at the same caliber as a 165-pound skill player squatting 330. This required building separate scoring tables per class, but fairness across positions was the priority.
Server-Side Security Enforcement. The React UI uses role-based rendering so coaches see edit controls and players don't. But real access control is enforced in Lambda. API Gateway validates Cognito tokens before any Lambda invocation. The frontend determines what users see. The backend determines what users can do.
Audit Logging on All Mutations. Every insert, update, and delete writes to a dedicated audit log table. Each entry includes a UUID, action type, detail string, timestamp, and authenticated user. This creates an immutable paper trail for a system where player data directly impacts tier status and recognition.
CSV Batch Upload for Roster Onboarding. Coaches manage 60–80+ player rosters. Individual data entry is a non-starter for adoption. CSV upload with server-side validation lets a coach onboard the entire roster in one action. The system handles ID generation and data integrity checks.
Coach-Validated Benchmarks. The Beast Mode thresholds weren't set by theory or by copying a generic strength standard. They were calibrated against data collected from experienced South Florida coaches via a survey system I deployed through AWS. More experienced coaches provided numbers closer to the calibrated system. Less experienced coaches tended to calibrate to "best player in program" rather than "D1 prospect."
What I'd Improve
Partial Score Entry with Save/Submit Workflow. Currently the score form requires all five tests to be entered at once. In reality, a player doesn't test squat, bench, clean, 40, and vertical in the same session. Testing is spread across multiple days.
The improvement would let coaches save partial scores as a draft, come back on a different day to add remaining tests, and then explicitly submit the complete set. Only submitted scores would feed into the leaderboard, tier calculations, and dashboard charts. Drafts would be visible to the coach but excluded from all rankings until finalized.
Role-Based Views with Cognito Groups. The system currently has a single authenticated user type (coach). The next step would be creating two Cognito user groups. One for coaches and one for players.
Coaches would see the full management interface. Roster editing, attendance marking, score entry, and audit logs. Players would see a read-only view of their own profile, scores, tier status, and progress. This would likely require updating every API endpoint and page component to serve different content based on group membership.
API Gateway OPTIONS/CORS Cost Optimization. Every API call that triggers a CORS preflight sends an OPTIONS request before the actual GET or POST. This effectively doubles the number of API Gateway invocations and the associated cost.
I'd research whether this can be mitigated through API Gateway caching on OPTIONS responses or by consolidating endpoints. For a low-traffic application the cost is negligible. But it's worth understanding before scaling.
Full CI/CD Pipeline with Staging Environments. The current deployment process is manual. Code changes go directly to production after local testing. A proper CI/CD pipeline with separate dev and staging environments would allow testing against real data without risking production. This is something we may implement in the near future.
Cognito User Pool Attribute Planning. The current Cognito user pool only requires a name attribute. Adding fields like email, role, or phone after pool creation isn't supported by Cognito. The pool has to be deleted and recreated from scratch. That means re-registering all existing users.
In hindsight, I would have defined the full set of required and optional attributes upfront. Cognito treats attribute configuration as immutable. Plan your auth schema before deployment.