Enoch AI / Case Study

DocLifts — Training, AI-Assisted Development, and QA

Updated 2026-09-15

Do you even lift, bro? After a year of training, I have plenty of evidence. DocLifts gives it a home. The ability to build and host the app with AI coding tools is icing on the cake; the reason it exists is that I actually use it at the gym.

Personal project, not a client engagement. DocLifts is a weightlifting log I built for my own training. This case study is about AI-assisted development, not AI features inside the app or a claim of client results.

The need
A phone-friendly tool to guide the next set and record what I actually lifted, with development decisions kept consistent across multiple AI coding tools.
The result
An app I use across gyms, with machine-aware logging, a flexible program builder, and 107 historical workout records in a searchable archive. Each release connects a practical feature to checks on the interface, server, data, and deployed result.

The shape of the project

DocLifts is a phone-at-the-gym tool that suggests the next set and records what I actually lifted. It is single-user and privately accessed through Tailscale. The original deployment ran on a local Ubuntu VM; in September I moved the application and database to a VPS. AI tools support development and review. The app’s training logic does not depend on an LLM.

It went from planning documents to a production deployment and through its first real production use cycle: a first-day bug surfaced, got fixed in layers, and the next real workout ran cleanly.

September 2026: features shaped by real training

Training across different gyms means different machines, equipment, and routines. Using Astra through OpenRouter for refactoring and feature development, I extended DocLifts around those practical needs.

  • Machine identity and quick-add: record the specific machine and add an exercise during a session, with plate-load suggestions that account for equipment type.
  • Backoffs from the actual top set: MAIN lifts using consecutive-backwards backoffs now derive suggested loads from the set I performed, rather than a stale template.
  • Flexible program building: a drag-and-drop editor and Traveling Push/Pull/Legs preset make it easier to arrange a routine. Transactional draft handling supports program creation.

A year of notes, now searchable

The next useful feature was bringing my older workout logs into the app. With Codex, I built a searchable archive and imported 107 workout records spanning September 2025 through September 2026. All 694 original note lines are preserved. I can search by exercise, gym, or note, filter by month, and expand a workout to see what I recorded.

The feature and the QA work developed together. Early sets and reps based on my recollection are labeled as estimates. An undated squat workout keeps a date window instead of an invented date. Verification caught shorthand that treated a rep count as a new weight; correcting the parser fixed nine entries. The archive stays separate from current progression and workout-report totals, so uncertain historical details do not change today’s load suggestions.

I tested the import against a locally restored database, checked that repeating it created no duplicates, and verified that a scoped rollback removed only the imported history. Before production import, I saved a fresh backup. Content comparisons across all 14 existing application tables confirmed that the original 31 sessions and 467 sets stayed unchanged. Type checks and the production build passed; browser checks exercised search and date filtering.

Moving the app and checking the result

DocLifts now runs in Docker Compose on Akamai Cloud (Linode) in Dallas, with private Tailscale access and daily database backups with 30-day retention. The move surfaced a missing runtime dependency, an IPv6 health-check problem, and an origin mismatch that blocked form submissions. Fixing them was part of making the deployed features usable.

After the history import, the live page returned successfully and both containers were healthy. Phone troubleshooting also caught an incomplete cutover: the old HTTPS bookmark still reached the earlier server. Moving that app-specific address to the VPS remains planned. A healthy server and the address a person actually uses are both part of checking a release.

A year of training is now searchable in the tool I use. AI-assisted development helped build the feature; engineering judgment and QA helped make its data trustworthy.

The original build: many AI tools, one set of written invariants

The central idea: rather than one assistant doing everything ad hoc, several AI tools each do what they're best at, and they stay coherent by reading the same version-controlled documents. Coordination happens through written artifacts, not shared memory — because AI tools don't reliably share memory across sessions or across products, but they can all read a file.

The coordinating artifacts:

  • Planning docs (planning_v2_*.md) — the locked source-of-truth design decisions. The standing instruction to every assistant: when in doubt, re-read these, not your training data.
  • CLAUDE.md — shared operating rules written for any AI coding tool (Claude, Cursor, others), so different assistants don't contradict one another.
  • STATUS.md — a cross-session handoff document: current state, known gaps, recent work. Any agent or human picking up the project reads this first.
  • A dedicated test-author sub-agent with its own accumulated memory files (infrastructure patterns, recurring bug shapes, a coverage map), so a specialized, repeated task gets better over time.

Division of labor in the original build

  • Claude (chat) — architecture, design review, code review, drafting documents, catching reasoning gaps. Could read and reason about the code via the repository, but couldn't write to disk.
  • Claude Code (on the server) — the executor: wrote files, ran commands, managed the database, deployed. Reads CLAUDE.md automatically on every run.
  • A cross-model review panel — during design, artifacts were run past several other LLMs (ChatGPT, Gemini, Grok) as independent reviewers.
  • The human — direction, decisions, approval, and empirical verification. The required node in the loop.

A typical cycle: design and review in chat → draft the change → hand to Claude Code to write and ship → human approves and verifies on real hardware → reconcile the docs.

What actually made it work — the transferable parts

These are the lessons worth carrying to other AI-assisted projects:

Written invariants beat memory. Lock the decisions in version-controlled docs and have every agent read them. Memory is unreliable across tools and sessions; a committed file is not. This is the single mechanism that kept multiple assistants from drifting apart.

The human is the adjudicator, and verification is empirical. AI proposes; the human decides and tests. Claims were checked, not trusted — "configured" was never treated as "working." Backups weren't just set up, they were restore-tested. A deploy wasn't "done" until it was confirmed on the actual production artifact on the real phone, not a stand-in that happened to be close. When two assistant claims conflicted, a real-world test settled it — including one case where an assistant confidently predicted a bug that testing proved didn't exist, and the prediction was retracted with the mechanism explained.

Independent model review is a real quality mechanism. Running design artifacts past multiple independent models surfaced issues a single model missed. The models showed consistent relative strengths as reviewers across this project — worth tracking if you adopt the practice, though that's a single-project observation, not a benchmark.

Doc-drift is structural, so manage it deliberately. AI-generated handoff docs systematically miss work the human did outside the AI's view. Left alone, the written record quietly diverges from reality. A recurring reconciliation pass — checking what the docs claim against what actually happened — kept the record honest. (One example: an assistant introduced an internally inconsistent date into a doc; it was caught, traced, and corrected rather than papered over.)

Self-correction is part of the loop, not a failure of it. Both the assistants and the human caught and reversed errors mid-stream — a wrong bug prediction, the date error above, an architecture decision made and then re-examined. The process assumes individual outputs will sometimes be wrong and is built to catch them, rather than trusting any single result.

The proof point

This isn't a demo. DocLifts shipped to production and entered daily real use. Day one surfaced a genuine concurrency bug — a double-session-creation race on the "Start" button. It got a layered fix: an idempotent server-side helper, a database-level partial unique index, and a client-side guard — defense at three layers rather than one. The next real workout ran cleanly; a full session logged without a hitch.

That arc — build, ship, hit reality, diagnose, fix in layers, stabilize — is the showcase. The process didn't just produce a greenfield build; it handled the messy post-deployment lifecycle, which is where most of the real work in software actually lives.

Redesigned DocLifts workout screen with exercise cards, previous performance, larger weight and rep inputs, and workout progress
The September redesign: clearer set entry, visible progress, and previous performance beside each set.
DocLifts exercise picker searching for presses, with matching exercises labeled by equipment type
Search and add an exercise during a workout without changing the program template.

Stack (for reference)

SvelteKit with Svelte 5, TypeScript, Vite, and Tailwind; PostgreSQL 16 with Drizzle ORM; Zod for validation. The current deployment uses adapter-node and Node 24 in Docker Compose on an Ubuntu 24.04 VPS, with private Tailscale access. PostgreSQL has no published host port. Daily database dumps have 30-day retention. The earlier systemd and Tailscale Serve setup belongs to the original deployment described above.

Try the work for yourself

DocLifts v0.1.0 is open source under Apache 2.0. The release includes a Docker demo with fictional workouts, so you can explore the app locally and inspect the code behind it.

Get the source and demo →

Have a workflow that needs this kind of care?

DocLifts is a personal project. The approach carries into client work: define the result, test it against real examples, and make the handoff usable. Bring a workflow or a backlog item, and we'll discuss what a first project could look like.

Book a 20-minute call →