Project Reflections
Workouts with Alex
Building a personal training dashboard with Claude — what worked, what didn't, and what I learned.
Objective
Build a personal workout dashboard at bernieporter.com that displays training history living in semi-structured emails between me and my trainer Alex. Since that data was trapped in Gmail, the first challenge was extracting it and storing it somewhere structured before anything could be displayed.
Stack & Tools
| AI | Claude (claude.ai chat) — not Claude Code |
| Hosting | DreamHost shared hosting — bernieporter.com |
| Backend | PHP + MySQL, deployed via SFTP from local machine |
| Debugging | Terminal on local machine for SSH into DreamHost |
| Data source | Gmail — weekly workout emails from trainer Alex |
| Data store | MySQL database hosted on DreamHost |
Process
setup_db.php
Step 1 — Schema
Script written by Claude to create two database tables. weekly_summary holds one row per training week — the day-by-day schedule (AM and PM for each day), personal notes about travel or socializing, week number, block, and date. workout_sets holds one row per logged exercise, linked back to its week — exercise name, sets, reps, weight, and notes.
workout_sync.php
Step 2 — Pipeline
The data pipeline. Connects to Gmail via OAuth, searches for all emails from Alex with "Bernie Porter - Week" in the subject, fetches each thread, sends the full email text to Claude for parsing, and writes the structured results to MySQL. Processes 5 threads at a time to avoid DreamHost's PHP execution timeout. Safe to re-run — skips anything already in the database. Running it again picks up any new workout emails automatically.
index.php
Step 3 — Dashboard
The dashboard itself. Shows the 4 most recent weeks as cards with activity counts, a monthly activity calendar with color-coded dots for each activity type, and lift trend charts for back squat and deadlift. Week detail view shows the full day-by-day schedule and a table of all logged exercises. Add
?viewnotes=yes to the URL to show personal notes.
Lessons Learned
1
Most of the mistakes were small and dumb — a typo in the database password, a missing dash in a copy-pasted Google Client ID, a placeholder API key that never got replaced with the real one. None of them were hard to fix once identified.
2
The Google OAuth setup had an unexpected wrinkle: the redirect URI needed to be
http not https because the DreamHost folder didn't have SSL configured. Easy fix once the cause was understood.3
The first version of the sync script tried to process all 35 email threads in one PHP request — which hit DreamHost's execution time limit. Switching to a batch-of-5 approach (refresh to process the next batch) solved it cleanly.
4
Some email threads were very large because my replies include a running history of prior weeks' results. This caused Claude's API parsing to fail until the token limit was increased to 4,000.
5
Lack of familiarity with developer tools slowed things down. Claude's instructions weren't always perfectly accurate — but pushing back with "I can't find that" usually surfaced better guidance. Claude was good at debugging; it just took time to work through every issue sequentially.
6
Claude introduced a few bugs of its own, but consistently found and fixed them once I pointed out that something wasn't working. Defining requirements and having Claude write the code was easy. The tricky part was getting all the pieces working together.
7
Having some development background — even very rusty — helped. Knowing the general shape of what we were building made it easier to follow Claude's instructions and recognize when something seemed off.
Bottom line: Defining requirements and having Claude write the code was the easy part. The harder part was the integration work — OAuth credentials, server configuration, API limits, deployment. That's where most of the time went.