Damian Malliaros, a YouTube creator who tests AI tools, built a full-stack exercise tracking app by pairing Claude Code with Momen: Momen handles the backend — database, logins, permissions, server-side logic — and Claude Code builds the React frontend on top of it.
He didn't configure the backend by hand. Momen's no-code plugin connects Claude Code to a Momen account, so he described the app in plain language and Claude Code created the tables, permissions, and Actionflows directly in the project.
What the app does
- Log a workout — start a session, add exercises, record weight, reps, and RPE (how many reps you had left in the tank) for each set
- Custom exercises — pick from a seeded library (bench press, squat, deadlift) or add your own
- Automatic personal-record detection — the backend compares each new set against your history and flags it as a PR if you've beaten your previous best on that lift
- Weekly training volume — recalculated nightly on the server, whether or not the app is open
- Calorie tracking — log meals with calories, protein, carbs, and fat against a daily goal
- Per-account data scoping — a logged-in user's workouts, sets, and meals are visible only to them, while the exercise library is shared
The data model: five tables
The whole app runs on five tables — Momen's built-in account table plus four Claude Code added:
- account — Momen's built-in user table, extended here with daily_calorie_goal, unit_preference, and two fields the backend writes to on its own: weekly_volume and weekly_volume_updated_at
- exercise — name, category, tracking_type, description, and an owner_id, which is what makes custom exercises possible: seeded exercises have no owner, user-created ones point back to their account
- workout_session — one row per workout: performed_at, title, duration_min, notes
- exercise_set — the core log table: weight, reps, set_order, rpe, foreign keys to the session, the exercise, and the account, and an is_pr boolean the backend sets
- calorie_entry — logged_on, meal, food_name, calories, protein_g, carbs_g, fat_g
Damian asked Claude Code to propose this structure before building anything, reviewed it, then approved it. That order matters — get the data model right first and the frontend has something solid to bind to. It's also the difference between an app that survives its second feature and one that doesn't, which is the argument for why backend structure matters even if you don't write code.
Logins and permissions, configured not coded
Momen's built-in authentication covers signup and login, so there's no separate auth provider to wire up. Username-and-password is what the app uses; email and phone are available on the same config.
Permissions are set per role, per table, per column. The project defines a Logged-in User role that can:
- read, edit, and delete only its own workout_session, exercise_set, and calorie_entry rows — the read and write rules on all three filter on the logged-in user
- read the whole exercise library, but edit or delete only rows whose owner_id matches, so seeded lifts stay read-only while custom ones don't
- update its own account fields — calorie goal, unit preference, profile image
This is the part that would normally mean writing row-level security policies by hand. Here it's a matrix of toggles per table, and Claude Code can flip them through the plugin — Damian had it set the rules up and then reviewed them in the editor. Worth noting that only the logged-in role was tightened in this build; the anonymous role is still on Momen's permissive defaults, which is the next thing to lock down before anything like this goes live. Momen's permissions documentation covers how the role, table, and column layers fit together.
Two Actionflows doing the work on the server
The reason to put this logic on a backend at all: if PR detection runs in the browser, it only works while the tab is open, and the numbers are editable from devtools. Both of these flows run server-side, in Momen.
Detect PR on new set — a database trigger on exercise_set insert:
- fires automatically on every new set, no frontend call needed
- queries the account's previous best weight for that same exercise
- if the new set beats it, updates that row's is_pr to true
Weekly volume rollup — a scheduled job:
- runs nightly at 3 AM regardless of user activity
- sums weight × reps across every set logged in the trailing 7 days, grouped by account
- writes each total back to that account's weekly_volume field
Both are built in Momen's Actionflow editor: an input node, a code step that runs GraphQL queries and mutations against the project's own data, and a return value. What differs is only the trigger — a table insert versus a cron expression. That's the distinction Damian drew in the video: a spreadsheet-style database stores what you hand it, while a backend keeps working on it when nobody's watching. The same scheduled-job pattern shows up in things like an automatic membership downgrade.
No AI agents, no third-party API integrations, and no payment provider in this project. The logic is deterministic comparison and arithmetic, which is exactly what it should be.
The frontend, and where it lives
Claude Code generated the React interface from a short brief — dark theme, smooth animations — as four screens: a dashboard, a workout logger, a nutrition tab, and a progress view. Each one talks to the GraphQL API Momen generates automatically from the data model, so there's no backend code in the frontend repo.
Because the UI was built outside Momen, it doesn't use Momen's one-click deploy — that path is for frontends built in the Momen editor. Claude Code pushed this one to Vercel instead, with the Momen backend staying where it is.
Damian walks through all of it — the proposed data model, the permission setup, both Actionflows, the generated frontend, and the deploy — in his video.
To build something along these lines: install the Momen plugin in Claude Code, describe the data and server-side logic you need and let it build the backend first, then have it generate the frontend against the API you just created.
Top comments (0)