Files
gravl/.planning/research/STACK.md
T
2026-02-15 22:48:57 +01:00

2.8 KiB

Technology Stack: Workout Logging UX Improvements

Project: Gravl — PPL Workout Tracker (UX Milestone) Researched: 2026-02-15 Scope: UX improvements to existing React 18 + Vite + Express + PostgreSQL app

What the Codebase Already Has

Layer Technology Version Notes
Frontend framework React 18.2.0 JSX, hooks-based
Build tool Vite 5.0.8 Already fast
Routing react-router-dom 6.21.0 Mostly unused — App.jsx uses manual view state
Styling Plain CSS + CSS custom properties Dark fitness theme, --accent, --bg-* vars defined
Backend Express REST API, /api/* endpoints
Database PostgreSQL workout_logs, programs, exercises tables
State React useState Local component state, no global store
HTTP Native fetch Direct fetch() calls in App.jsx

Form Validation: React Hook Form + Zod

Technology Version Purpose Why
react-hook-form 7.x Input registration, validation Zero re-renders on keystroke. Integrates with native <input> without wrapping.
zod 3.x Schema for weight/reps z.number().min(0).max(500) reads as documentation.
@hookform/resolvers 3.x Bridge RHF <-> Zod Required; maintained by RHF team.

Why not Formik: Higher re-render cost. Context-based, creates overhead for per-set inline inputs.

Number Input Stepper: Custom Component (No Library)

Build a custom StepperInput component with existing CSS variables. The requirement — +/- buttons flanking a number field with a unit label — is ~30 lines of React. Weight step: 2.5 kg. Reps step: 1.

Set Count Management: React State Only

Add a localSets state initialized from exercise.sets. +/- controls add/remove entries. Copy last set's weight as default for added sets.

Custom Workout Creation: Existing Stack

Use existing React + fetch + PostgreSQL. Add a WorkoutBuilderPage.jsx. No new global state needed initially.

Touch Target Sizing: CSS Only

Critical rule: font-size: 1rem (minimum 16px) on all inputs prevents iOS Safari auto-zoom. Minimum 44px height on all interactive elements per iOS HIG.

What NOT to Add

Library Why to Avoid
Formik Higher re-render cost; worse DX for inline per-row forms
Material UI / Chakra UI Conflicts with custom dark CSS; adds 200KB+
TanStack Query Simple fetch pattern doesn't warrant it yet
Framer Motion Minimal animation intent; complex on budget phones
Redux Toolkit Overkill for 5-page single-user app

Installation Summary

npm install react-hook-form zod @hookform/resolvers

Bundle impact: ~38KB gzipped total addition.