stronk

package module
v0.0.0-...-8897277 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 7, 2024 License: MIT Imports: 3 Imported by: 0

README

stronk

Stronk is a simple web app for tracking your exercise. It was built with Jim Wendler's 5/3/1 in mind, but is decently flexible (at least in terms of routines, the UI is pretty heavily based around the main four 5/3/1 lifts).

Your exercises are configured via a routine.json file that specifies lifts in a rough hierarchy:

  • Week - A week of workouts. A week can be 'optional'. This is used for deload weeks.
  • Day - A day of workouts
  • Movement - A set of lifts, all having the same exercise (e.g. squat, bench) and set type (e.g. warmup, assistance, etc)
  • Set - A number of target reps at a target percentage of the training max for that movement's exercise. Can optionally be 'to failure', meaning the rep target is a minimum

An example routine.example.json is included, which implements a fairly standard 5/3/1 using "Big but Boring" for the assistance work. It includes an optional deload week.

Screenshots

The training max page, where you enter your initial training maxes, which all subsequent sets will be based on.

Screenshot of the training max page, showing four inputs corresponding to the four lifts of 5/3/1, along with a selector for the smallest plate you have available at your gym

The lift/main page, where you get an overview of the day's lifts, and record them as you do them, adding rep counts and notes as relevant.

Screenshot of the lifts page, showing a series of sets broken into warmup, main, and assistance. The bottom half of the page shows buttons for recording lifts, adding notes, skipping, and more

Local Development

To run locally, you'll need a recent version of Go + some version of NPM. Install frontend dependencies (namely Svelte) with cd frontend && npm install.

Then, to run the infrastructure.

# Run the backend
go run ./cmd/server

# In another terminal
cd frontend
npm run dev

The server stores lift info in a SQLite database, which will be created + migrated on the first boot.

Frontend is available at localhost:5173, backend is localhost:8080.

Deployment

Note: the app has no authentication, make sure to introduce basic auth or deploy the app behind something like Tailscale

The main way to deploy this is with two Docker containers stronk and stronk-fe, which run the backend and frontend respectively. I run this in a local K8s deployment, using a config like:

stronk.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: stronk-deployment
  labels:
    app: stronk
spec:
  selector:
    matchLabels:
      app: stronk
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: stronk
    spec:
        containers:
        - image: <registry>/stronk-fe
          name: frontend
          env:
          - name: PUBLIC_API_BASE_URL
            value: "http://localhost:8080"
          ports:
            - containerPort: 3000
              name: web
        - image: <registry>/stronk
          name: backend
          env:
          - name: ROUTINE_FILE
            value: /config/routine.json
          - name: DB_FILE
            value: /data/stronk.db
          - name: MIGRATION_DIR
            value: /migrations
          ports:
            - containerPort: 8080
              name: http-api
          volumeMounts:
          - name: site-data
            mountPath: "/data"
            subPath: stronk
          - name: config
            mountPath: "/config"
            readOnly: true
        volumes:
        - name: site-data
          # TODO: Some kind of mount for the SQLite database
        - name: config
          configMap:
            name: stronk-config
          # This contains the routine.json file for your specific program.
---
apiVersion: v1
kind: Service
metadata:
  name: stronk
spec:
  selector:
    app: stronk
  ports:
    - name: web
      protocol: TCP
      port: 3000
      targetPort: 3000
    - name: http-api
      protocol: TCP
      port: 8080
      targetPort: 8080

And then deploy it behind something like Caddy with:

Caddyfile
https://stronk.<domain> {
	encode gzip

	handle /api/* {
		reverse_proxy stronk.<namespace>.svc.cluster.local:8080
	}

	handle {
		reverse_proxy stronk.<namespace>.svc.cluster.local:3000
	}
}

Documentation

Overview

Package stronk contains the domain types for doing exercise stuff.

Index

Constants

View Source
const (
	OverheadPress = Exercise("OVERHEAD_PRESS")
	Squat         = Exercise("SQUAT")
	BenchPress    = Exercise("BENCH_PRESS")
	Deadlift      = Exercise("DEADLIFT")
)
View Source
const (
	Warmup     = SetType("WARMUP")
	Main       = SetType("MAIN")
	Assistance = SetType("ASSISTANCE")
)
View Source
const (
	// E.g. 1775 decipounds == 177.5 lbs
	DeciPounds = WeightUnit("DECI_POUNDS")
)

Variables

View Source
var (
	ErrUserNotFound    = errors.New("user not found")
	ErrNoSmallestDenom = errors.New("no smallest denom")
)

Functions

This section is empty.

Types

type ComparableLifts

type ComparableLifts struct {
	ClosestWeight    *Lift
	PersonalRecord   *Lift
	PREquivalentReps float64
}

func CalcComparables

func CalcComparables(lifts []*Lift, weight Weight) *ComparableLifts

type Exercise

type Exercise string

func MainExercises

func MainExercises() []Exercise

type Lift

type Lift struct {
	ID        LiftID
	Exercise  Exercise
	SetType   SetType
	Weight    Weight
	SetNumber int
	Reps      int
	Note      string

	// Day - 0, 1, 2, ... in a given week
	// Week - 0, 1, 2, ... in a given iteration
	// Iteration - 0, 1, 2, ... basically how many times you've gone through the
	// routine
	DayNumber       int
	WeekNumber      int
	IterationNumber int
	ToFailure       bool
}

func FindClosest

func FindClosest(lifts []*Lift, weight Weight) *Lift

func FindPR

func FindPR(lifts []*Lift) *Lift

func (*Lift) AsOneRepMax

func (l *Lift) AsOneRepMax() Weight

func (*Lift) CalcEquivalentReps

func (l *Lift) CalcEquivalentReps(weight Weight) float64

type LiftID

type LiftID int

type Movement

type Movement struct {
	Exercise Exercise
	SetType  SetType
	Sets     []*Set
}

func (*Movement) Clone

func (m *Movement) Clone() *Movement

type Routine

type Routine struct {
	Name  string
	Weeks []*WorkoutWeek
}

func (*Routine) Clone

func (r *Routine) Clone() *Routine

type Set

type Set struct {
	RepTarget int
	// ToFailure indicates if this set should go until no more reps can be done.
	// If true, usually indicated with a "+" in the UI, like "5+"
	ToFailure bool
	// TrainingMaxPercentage is a number between 0 and 100 indicating what
	// portion of your training max this lift is going for.
	TrainingMaxPercentage int

	// WeightTarget isn't set when users configure it, only in responses sent to
	// clients.
	WeightTarget Weight

	// Only set if the lift is to failure (i.e. ToFailure == true)
	FailureComparables *ComparableLifts

	// Only set if we found a match, won't always be the case.
	AssociatedLiftID LiftID
}

func (*Set) Clone

func (s *Set) Clone() *Set

type SetType

type SetType string

type SkippedWeek

type SkippedWeek struct {
	Week      int
	Iteration int
	Note      string
}

type TrainingMax

type TrainingMax struct {
	Max      Weight
	Exercise Exercise
}

type Weight

type Weight struct {
	Unit  WeightUnit
	Value int
}

func (*Weight) String

func (w *Weight) String() string

type WeightUnit

type WeightUnit string

type WorkoutDay

type WorkoutDay struct {
	DayName   string
	Movements []*Movement
}

func (*WorkoutDay) Clone

func (w *WorkoutDay) Clone() *WorkoutDay

type WorkoutWeek

type WorkoutWeek struct {
	WeekName string
	Optional bool
	Days     []*WorkoutDay
}

func (*WorkoutWeek) Clone

func (w *WorkoutWeek) Clone() *WorkoutWeek

Directories

Path Synopsis
cmd
db
sqldb
Package sqldb implements the server.DB interface, backed by a sqlite database.
Package sqldb implements the server.DB interface, backed by a sqlite database.
testing
testdb
Package testdb is an in-memory implementation of the server.DB interface.
Package testdb is an in-memory implementation of the server.DB interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL