Skip to content
Anderson Rocha

projects / Active — MVP in development

GymFlow

Workout tracking platform — Next.js RSC frontend on a NestJS + Apollo GraphQL API, Prisma on PostgreSQL.

View repository →
GymFlow — interface screenshot

Overview

GymFlow is a workout tracking platform: build workouts from an exercise library, run them as sessions with per-set weight and rep logging, and review schedule, progress, and plans from a dedicated desktop workspace. The mobile flow stays focused on logging a live session; desktop is the place to prepare training blocks and read the larger picture. Started in February 2026, it doubles as a reference build of a specific stack — Next.js App Router with React Server Components on the front, NestJS with Apollo GraphQL behind it, Prisma on PostgreSQL underneath.

It is an MVP in active development, and this page says so. The architecture is defined and documented with mermaid diagrams in the README, database integration is in progress, and custom JWT auth is the next milestone. The repository is public — the code can be read today, mid-build.

Live walkthrough

Workout from home to completion

responsive mobile app

A full mobile session: choose Upper Day, log weight and reps, complete each exercise, and land on the workout summary.

Architecture

The system is API-first: the NestJS backend is the single source of truth, and every client is a consumer of the same Apollo GraphQL API. The web app is Next.js App Router with React Server Components fetching through a GraphQL client. GraphQL was chosen over REST specifically for cross-layer type-safety — the schema is the contract, and types hold from resolver to client.

The backend is layered: Resolver → Service → Domain → Prisma. Resolvers stay thin, services orchestrate, domain logic is isolated from both GraphQL and the ORM, and Prisma is confined to the persistence edge. That is more ceremony than a solo MVP strictly needs; the trade is deliberate — the domain layer survives a transport or ORM change, and the structure holds when a second client arrives.

That second client is the reason for the auth decision. PostgreSQL runs on Supabase, but auth is custom JWT rather than Supabase Auth: owning token issuance keeps the React Native mobile client on the roadmap from coupling every consumer to Supabase's session model.

  • apps/web — Next.js App Router, React Server Components, GraphQL client
  • apps/api — NestJS + Apollo GraphQL, Prisma ORM, custom JWT auth (in progress)
  • Database — PostgreSQL on Supabase
  • Tooling — pnpm monorepo with typecheck, lint, and test pipelines

Screenshots

Captures from the MVP running locally.

GymFlow desktop training workspace showing the upcoming workout, weekly consistency, training metrics, and recent session
GymFlow desktop exercise library with search, muscle group filters, and a structured catalog table
GymFlow desktop workout builder with an exercise sequence, planned sets and reps, and a plan overview
GymFlow mobile interface 1
GymFlow mobile interface 2

Stack & Decisions

ChoiceRationale
API-first backendThe NestJS API is the single source of truth; the web app is one consumer among future clients
GraphQL over RESTStrong type-safety across layers — the schema is the contract from resolver to client
Layered backend: Resolver → Service → Domain → PrismaDomain logic isolated from transport and ORM; each layer replaceable on its own
Custom JWT over Supabase AuthControl over token issuance for future multi-client support, starting with React Native
PostgreSQL on SupabaseManaged Postgres while keeping auth and application logic in the API
pnpm monorepo (apps/web + apps/api)Shared types and tooling; typecheck, lint, and test pipelines across both apps
Next.js App Router + React Server ComponentsServer-first data fetching on the web client

Links