projects / Active — MVP in development
GymFlow
Workout tracking platform — Next.js RSC frontend on a NestJS + Apollo GraphQL API, Prisma on PostgreSQL.
- Next.js (App Router)
- React Server Components
- NestJS
- Apollo GraphQL
- Prisma
- PostgreSQL (Supabase)
- pnpm

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
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 clientapps/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.





Stack & Decisions
| Choice | Rationale |
|---|---|
| API-first backend | The NestJS API is the single source of truth; the web app is one consumer among future clients |
| GraphQL over REST | Strong type-safety across layers — the schema is the contract from resolver to client |
| Layered backend: Resolver → Service → Domain → Prisma | Domain logic isolated from transport and ORM; each layer replaceable on its own |
| Custom JWT over Supabase Auth | Control over token issuance for future multi-client support, starting with React Native |
| PostgreSQL on Supabase | Managed 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 Components | Server-first data fetching on the web client |
Links
- Repository: github.com/Andersonrrocha/gym-flow