Skip to content
Ezequiel Olivero

Case study — 2026 · Personal · Live

Sunnsteel

Build a routine, train against it, and let the numbers move themselves.

The Sunnsteel dashboard: today's scheduled workout, a weekly completion target, active days, total sessions and lifetime volume.
Fig. 01Dashboard — the scheduled session and the week at a glance

At a glance

Role
Solo — product, design, full stack
Timeline
2026 — present
Status
Live in production
Codebases
2 apps + 1 npm package
Frontend
Next.js 15 · React 18 · TypeScript
Backend
NestJS 11 · Prisma 6
Data
PostgreSQL · Redis
Tests
75+ Vitest specs, CI-gated

Overview

Sunnsteel is a training app for people who follow a written programme rather than improvising in the gym. You describe a routine once — which days you train, which exercises run on each day, how many sets, what rep range, how long to rest — and the app turns it into a schedule you can execute against, session by session.

The part that makes it more than a logbook is progression. Each exercise carries a scheme that decides what happens after a session is finished: hold the load, add reps until the top of the range and then add weight, or advance each set independently. When you close a session the app applies that rule and rewrites the next one, so the programme moves forward without anyone editing a spreadsheet.

It is built as two deployable TypeScript applications — a Next.js client and a NestJS API — with a third package holding the types they exchange. That last piece is the load-bearing decision: it is what stops the two halves drifting apart, and it is described in full further down.

My role

  • Product design and information architecture
  • Frontend: App Router client, component system, all state and caching
  • Backend: REST API, authorization, data model and migrations
  • The shared contracts package and its release process
  • CI, deployment and the local dev tooling

Architecture

System topology

Three codebases

sunnsteel-frontend
Next.js App Router client, rendered entirely client-side · TypeScript
sunnsteel-backend
NestJS REST API — auth, persistence, scheduled jobs, metrics · TypeScript
@sunsteel/contracts
Published DTOs, enums and response types shared by both · TypeScript

One request, end to end

  1. A route component renders and calls a typed hook — it never fetches anything itself.
  2. The hook reads from TanStack Query; on a cache miss it delegates to a service function.
  3. The service issues the HTTP call, attaching the Supabase access token as a bearer credential.
  4. A NestJS guard verifies that token against Supabase and upserts the caller into the local users table.
  5. The controller validates the body against a DTO — unknown fields are rejected rather than ignored.
  6. The service runs the business logic and reads or writes through Prisma.
  7. A mapper converts the Prisma row into an @sunsteel/contracts type before serialisation.
  8. TanStack Query caches the typed response, and every component subscribed to that key re-renders.

Stack by layer

Feature deep-dives

Engineering decisions

What's next