A complete web-based data analysis and reporting system for managing elementary school read-a-thon events. Built entirely with Claude Code - see how it was built below.
⚠️ DATA DEPENDENCY NOTICE This application requires CSV data from ReadAThon.com. You must download your school's data from ReadAThon.com to use this system. See Data Source section below for details.
School Overview dashboard showing team competition, top performers, and participation metrics
This application processes data from Read-A-Thon.com, the official platform where:
- Parents log their children's daily reading minutes
- Sponsors make donation pledges
- Schools download CSV exports for local analysis
This system imports those CSV files and provides comprehensive reporting and analytics.
While Read-A-Thon.com provides the core platform for tracking reading and donations, it doesn't support all the reporting and rules our school needed:
What Read-A-Thon.com Doesn't Provide:
- Team Competition: We organize classes into competing teams and need team-based leaderboards
- Grade-Specific Goals: Each grade level has different daily reading minimums (K-1: 20min, 2-3: 25min, 4-5: 30min)
- Daily Reading Caps: We impose a 2-hour (120 minute) maximum per day for contest fairness
- Participation Tracking: We track whether students participated at all each day (read any amount)
- Random Prize Drawings: We select random students daily for prizes if they've read that day
- Detailed Daily Reports: Their cumulative reports don't include our daily caps or grade-specific goals
- Team Color Bonus: We award bonus minutes for team spirit participation
Our Solution: Import the raw CSV data from Read-A-Thon.com and apply our school's custom business rules on top of it. This gives us the flexibility to generate exactly the reports and metrics we need while still using their excellent platform for parent data entry and sponsor management.
Entity Relationships:
- Students belong to Classes
- Classes belong to Teams
- Teams belong to the School
- Classes have assigned Teachers
Metrics of Interest:
- Reading Minutes (daily and cumulative, with configurable daily cap)
- Participation (did student read each day?)
- Donations Raised (total fundraising per student)
- Number of Sponsors (sponsor count per student)
- Team Color Bonus (bonus minutes for team spirit events)
Reporting: Per-day and full-contest views with 24 pre-configured reports, plus branded bulletins (Meet the Teams, Daily Scoreboard, Prize Scoreboard) to email as an image
- Modern Dashboard: Clean Bootstrap 5 interface with 10 tabs (School, Teams, Grade Level, Students, Upload, Bulletins, Reports, Workflows, Admin, Help)
- Bulletins: branded one-page bulletins copied or downloaded as an image for email - Meet the Teams (each team's classes and student counts, from the roster, ready before the contest starts), and the Daily Scoreboard and Prize Scoreboard for any contest day
- Local SQLite Database: All data stored locally - no server needed
- Multi-File CSV Upload: Upload multiple daily files at once with automatic date extraction
- 24 Pre-configured Reports: Comprehensive analysis covering all metrics
- Enhanced Report Metadata: Column descriptions, data sources, automated analysis
- Workflow Automation: Run multiple reports in sequence for daily updates
- Team Competition Tracking: Real-time team standings with color bonus support
- Data Integrity Reports: Reconciliation reports for validation
- Upload Audit Trail: Track every file upload with detailed history
- Export Capabilities: Copy to clipboard or download as CSV
- Multi-Database Support: Switch between production and sample data
🚀 AUTOMATED INSTALLATION AVAILABLE Clone the repository and run the automated installation script:
git clone https://github.com/stevensouza/readathon.git cd readathon ./install.shThis handles all prerequisites, dependencies, and setup automatically. For full installation documentation, see the Installation Guide (also available in the app's Help menu).
Repository: https://github.com/stevensouza/readathon
# Flask (app), pytest + beautifulsoup4 (tests), installed into a project virtualenv (venv/).
# (Homebrew's Python refuses system-wide "pip3 install" with "externally-managed-environment".)
python3 -m venv venv
venv/bin/pip install -r requirements.txt
# Or run the installer (creates venv/ and installs the dependencies, creates Desktop start/stop
# shortcuts). It does not start the app. ./run.sh uses venv/ automatically. Safe to rerun anytime: it skips completed steps, rewrites
# outdated Desktop shortcuts, and reports the current state even when everything is fine.
./install.shOption A: Use Sample Data (for testing)
# The repo includes a sample database with fake data
# Just run the app - it will use readathon_sample.db automatically
./run.shOption B: Use Your Own Data (one database per event year)
In the app: Admin → Database Registry → Create New Database (year, readathon_<YEAR>.db, and the three CSVs).
Or from the command line, with class_info.csv, grade_rules.csv, roster.csv in the project folder:
python3 init_data.py 2026 # creates db/readathon_2026.db and registers it as "2026 Read-a-Thon"CSV Format Requirements:
class_info.csv:class_name,home_room,teacher_name,grade_level,team_name,total_studentsgrade_rules.csv:grade_level,min_daily_minutes,max_daily_minutes_creditroster.csv:student_name,class_name,home_room,teacher_name,grade_level,team_name
See the sample_*.csv files in the repository for examples.
Note: The sample database (readathon_sample.db) and sample CSV files are included in the repository for testing. Your CSV files with real student data should NOT be committed to version control for privacy reasons - they are automatically excluded by .gitignore.
# Starts the app and opens http://127.0.0.1:5001 in your browser
./run.sh # last database you used (sample on first run)
./run.sh --db sample # sample database
./run.sh --db "2026 Read-a-Thon" # a specific year (display name or filename)
./run.sh --simple # simple view: only Upload, Bulletins, Help (remembered; --full to undo)./run.sh passes its options to python3 app.py, which you can also run directly.
Browser address: http://127.0.0.1:5001
Note: The app remembers your last database choice in .readathon_config. You can also switch databases using the dropdown menu in the navigation bar.
Simple view: the ✨ Simple view button (top right) hides everything but the daily job - Upload, Bulletins,
Help and the database selector - opens the app on the Daily Scoreboard, and hides the Upload page's delete buttons.
☰ Full view brings every page back. The choice is remembered in .readathon_config (also --simple / --full).
Press CTRL+C to stop the server.
Each event year gets its own database, db/readathon_<YEAR>.db. Last year's database is not needed to set up the new one.
- Back up the
db/folder. Real databases are gitignored (student PII), so git will not keep them. - Prepare
roster.csv,class_info.csvandgrade_rules.csvfor the new year (same columns as above). Keep them out of git. - Create the database: Admin → Database Registry → Create New Database, or
python3 init_data.py <YEAR>. - Switch to it with the header dropdown, or
./run.sh --db "<YEAR> Read-a-Thon". The app remembers the choice. - Check the student count, teams and grade goals on the School / Classes pages.
- Compare with last year (optional): copy last year's
readathon_<YEAR>.dbintodb/and restart the app; it is registered automatically. Then use Admin → Database Comparison ("Through Day N" lines up the same contest day in both years).
The contest date range is taken from the dates you upload, so nothing needs to change in code for a new year.
Code comes from git; the real databases never do (they contain student names and are gitignored). Anyone can run the app on a Mac this way:
- Get the code
git clone https://github.com/stevensouza/readathon.git cd readathon ./install.sh # creates venv/ and installs requirements.txt into it
- Add the databases you were given (privately, e.g. a zip made by
./package_data.sh):Or copy individual files such asunzip -o ~/Downloads/readathon_data_2026-10-14_1530.zip # fills db/ (run inside the readathon folder)
readathon_2025.dbandreadathon_2026.dbintodb/. - Start the app:
./run.sh(opens http://127.0.0.1:5001)- Every
db/readathon_<YEAR>.dbis registered automatically on start (the terminal prints "Registered new database file"). - Pick the year in the header dropdown. The sample database (yellow banner) is always available for practice.
- Every
- Updating the code later:
git pull(stop the app first). Thedb/folder is untouched by git.
git status never shows the database files, and they cannot be committed by accident (*.db is in .gitignore, except the sample).
When the app runs on someone else's Mac and the current state needs to go back and forth:
- Stop the app on the computer that has the latest data (
lsof -ti:5001 | xargs kill, or the Desktop "Stop" shortcut). - Package the data:
./package_data.shcreates~/Desktop/readathon_data_<date>_<time>.zipwith everything indb/. - Send it privately (AirDrop, USB stick, a private share) - it contains student names.
- On the other computer: stop the app,
git pullfor the latest code, thenunzip -o readathon_data_<date>_<time>.zipinside the readathon folder.
Only one computer should be "live" at a time. Uploads made on a computer after its data was copied elsewhere are not merged - the next copy overwrites them. Agree on who owns the data each day, and package it again after changes.
Zipping the whole folder (code + db/) also works, but moving code with git pull and data with package_data.sh keeps both machines on the same code version and makes the data zip small.
-
Upload Data
- Navigate to "Upload Data" page
- Select the date
- Upload your minutes CSV file (columns:
Reader Name,Minutes) - Upload your donations CSV file (columns:
Reader Name,Donations); its snapshot date defaults to the latest day with minutes, so money raised can be shown as of each day - Click "Upload Data"
-
Send the Daily Scoreboard
- Navigate to "📰 Bulletins" → "Daily Scoreboard" (defaults to the latest day)
- Click "Copy as image" (or "Download PNG") and paste it into the email
- At the end, use "Prize Scoreboard" for the final winners; before the contest, "Meet the Teams" introduces the teams
-
Run Reports
- Navigate to "Reports" page
- Select a report from the list
- Configure options if needed
- Click "Run Report"
- Use "Copy to Clipboard" or "Export CSV" buttons
-
Run Workflows
- Navigate to "Workflows" page
- Choose "Daily Slide Update" or "Cumulative Workflow"
- Click to run all reports in sequence
The system includes 24 pre-configured reports covering:
- Daily metrics - Day-by-day performance tracking
- Cumulative stats - Full contest summaries and leaderboards
- Team competitions - Team standings and comparisons
- Data integrity - Reconciliation and validation reports
- Prize drawings - Random winner selection by grade
- Export formats - Denormalized logs for external analysis
Group multiple reports to run in sequence:
- Daily Slide Update - Reports for daily announcements and presentations
- Final Prize Workflow - All prize-related reports for award ceremonies
- Data Reconciliation - Validation reports to verify data accuracy
- Roster - Student roster with grade, teacher, team assignments
- Daily_Logs - Daily reading minutes per student (stores both capped and uncapped values)
- Reader_Cumulative - Cumulative donations and sponsor counts per student (latest upload)
- Reader_Cumulative_History - A saved copy of the cumulative upload for each contest day (money raised as of any day)
- Class_Info - Teacher assignments and grade levels for each class
- Grade_Rules - Grade-specific reading goals (daily minimums and caps)
- Upload_History - Audit trail for all CSV uploads with timestamps and row counts
- Team_Color_Bonus - Bonus minutes for team spirit participation events
The registry (db/readathon_registry.db) also holds App_Settings: school name and contest days for the bulletins.
- Students → Classes → Teams → School
- Classes have Teachers
- Students accumulate daily reading minutes and total donations
- Teams compete based on aggregated student performance
Configurable by grade level:
- Daily minimum reading minutes (varies by grade)
- Daily maximum credited minutes (typically 120 min/day cap)
- Actual minutes read are stored even if they exceed the cap
readathon/
├── app.py # Flask web application
├── database.py # Database and report logic
├── queries.py # All SQL
├── scoreboards.py # Bulletins page data: Daily / Prize Scoreboard, Meet the Teams
├── init_data.py # Create + register db/readathon_<YEAR>.db from roster CSVs
├── clear_all_data.py # Wipe a year's uploaded data (keeps roster)
├── package_data.sh # Zip db/ to move data to another computer
├── install.sh # One-time Mac setup + Desktop shortcuts
├── run.sh # Start the app (./run.sh [--db ...] [--simple|--full]) and open the browser
├── requirements.txt # Python dependencies
├── README.md # This file
├── db/ # Databases: readathon_sample.db (in git), readathon_<YEAR>.db + registry (local only)
├── md/ # Requirements (REQUIREMENTS.md), rules, changelog
└── templates/ # HTML templates
├── base.html
├── index.html
├── upload.html
├── reports.html
└── workflows.html
To wipe a year's uploaded data (daily logs, cumulative, team color bonus, upload history) but keep its roster:
python3 clear_all_data.py readathon_2026.dbSelected tables can also be cleared from the Admin page.
The app runs on port 5001. To stop a running copy:
lsof -ti:5001 | xargs killIf you see "Student not found in roster" warnings:
- Check that student names match exactly (case-sensitive)
- Verify CSV column names are correct:
Reader NameandMinutesorDonations - Make sure CSV file is properly formatted
- Participation: A student "participated" if they read more than 0 minutes that day
- Meeting Goal: A student "met their goal" if they read at least their grade's minimum daily minutes
- Credited Minutes: Maximum 120 minutes per day counts toward totals (actual minutes are still tracked)
- Tie-Breaking: When multiple entities tie for first place, all tied winners are shown
- Framework: Flask 3.0.0
- Database: SQLite 3
- Frontend: Bootstrap 5.3.0, Bootstrap Icons
- No Internet Required: All assets served from CDN but system works offline after first load
- Platform: developed and run on macOS. Windows may need work later: the app itself should run, but the
setup/run scripts (
install.sh,run.sh,package_data.sh) are Mac-only - see Feature 40: Windows Compatibility
This application is designed to run locally and keep student data private:
Included in Repository (Safe to Share):
- Application code (
app.py,database.py, templates) - Sample database with fake data (
readathon_sample.db) - Documentation and screenshots
NOT Included (Protected by .gitignore):
- Production databases (
*.dbexcept sample) - Initialization file with real student data (
init_data.py) - CSV files with real student information
- Any files containing real student or teacher names
Important: Before pushing to public repositories, verify that .gitignore is properly configured to exclude all files containing personally identifiable information.
For issues or questions about this system, check:
- The troubleshooting section above
- Error messages in the browser console (F12)
- Terminal output when running
./run.sh
- The contest period is the range of dates uploaded to Daily_Logs (it can differ each year)
- Reports Q21-Q23 reconcile daily minutes against the cumulative totals
This project uses Event-Year Calendar Versioning: vYYYY.MINOR.PATCH, where YYYY is the read-a-thon event year.
Current Version: see the VERSION file
- 2025 event:
v2026.1.0–v2026.14.3(numbered under an earlier school-year scheme). Final code is taggedreadathon-2025-final. - 2026 event: continues from
v2026.15.0 - 2027 event: starts at
v2027.1.0
- YYYY: Event year
- MINOR: Feature additions and improvements
- PATCH: Bug fixes and minor updates
This entire application was developed using Claude Code, Anthropic's AI assistant for software development.
I provided high-level requirements and business logic. Claude Code:
- Recommended the technology stack (Flask, SQLite, Bootstrap)
- Designed the database architecture
- Wrote all Python and HTML code
- Created 23 SQL reports with complex business logic
- Implemented UI/UX with responsive design
- Built data validation and integrity checks
Total Development: ~35 features across multiple sessions using collaborative iteration.
To see the actual development process, example prompts, and lessons learned:
- Run the application and navigate to Help → How I Used Claude Code to Develop this Application
- Or view the documentation directly: templates/claude_development.html
Key topics covered:
- The 3-phase development workflow (ASCII → HTML → Production)
- Real collaborative prompt examples (high-level requirements → Claude suggests solutions)
- Token & cost management tips ($20 vs $100/month plans)
- Common challenges and best practices
- Security concerns with local AI file access
This project demonstrates that complex, production-ready applications can be built entirely with AI assistance through:
- Collaborative iteration (not detailed instructions)
- Rapid prototyping (ASCII mockups before coding)
- Incremental refinement (review, adjust, repeat)
The complete 3,723-line specification document is available in the app at Help → Application Requirements.
Good luck with your read-a-thon! 📚