Files
SneakySwole/docs/database_schema.md
Phillip Tarrant 53e62f694f docs: replace implementation plans with architecture and API reference docs
Remove phase implementation plans, design notes, and source spreadsheet
that are no longer needed. Add architecture.md, API_REFERENCE.md, and
database_schema.md for ongoing development and debugging reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 14:19:49 -06:00

7.0 KiB

Database Schema

SQLite database at data/sneakyswole.db, managed by SQLModel ORM with Alembic migrations.


Tables

users

User profiles (admin and regular). Admin has login credentials; regular profiles are managed by the admin.

Column Type Constraints Description
id INTEGER PK, auto-increment
username VARCHAR UNIQUE, indexed Login identifier
password_hash VARCHAR default="" bcrypt hash (admin only)
display_name VARCHAR default="" Name shown in UI
height VARCHAR nullable e.g., "6'0""
weight VARCHAR nullable e.g., "260 lbs"
goals VARCHAR nullable Free-text training goals
is_admin BOOLEAN default=False Admin privileges flag
created_at DATETIME auto Record creation time
updated_at DATETIME auto Last update time

Model: app/models/user.py:User


exercises

Exercise library catalog. Each exercise belongs to a workout day.

Column Type Constraints Description
id INTEGER PK, auto-increment
name VARCHAR indexed e.g., "DB Chest Press (Floor)"
muscle_group VARCHAR default="" e.g., "Chest", "Shoulders"
workout_day VARCHAR indexed "Push", "Pull", "Lower", "Full Body"
sets INTEGER default=3 Default number of sets
tempo VARCHAR default="" e.g., "3-1-2" (eccentric-pause-concentric)
form_cues VARCHAR default="" Detailed form instructions
created_at DATETIME auto Record creation time

Model: app/models/exercise.py:Exercise


warmups

Standardized warmup routine displayed before every workout.

Column Type Constraints Description
id INTEGER PK, auto-increment
name VARCHAR indexed e.g., "Cat / Cow"
type VARCHAR default="" Category: "Thoracic Mob", "Hip Mobility", etc.
reps VARCHAR default="" e.g., "8 reps", "8 each side"
form_cues VARCHAR default="" Detailed form instructions
sort_order INTEGER default=0 Display order in warmup sequence
created_at DATETIME auto Record creation time

Model: app/models/warmup.py:Warmup


workout_days

The 4-day training split definition.

Column Type Constraints Description
id INTEGER PK, auto-increment
name VARCHAR UNIQUE, indexed "Push", "Pull", "Lower", "Full Body"
day_number INTEGER UNIQUE Order in rotation (1-4)
description VARCHAR default="" Brief focus description

Model: app/models/workout_day.py:WorkoutDay


user_exercise_programs

Per-user programming targets linking users to exercises with week 1/4 goals.

Column Type Constraints Description
id INTEGER PK, auto-increment
user_id INTEGER FK → users.id, indexed Profile this applies to
exercise_id INTEGER FK → exercises.id, indexed Exercise being programmed
wk1_reps VARCHAR default="" Week 1 target reps (e.g., "10", "30 sec")
wk4_reps VARCHAR default="" Week 4 target reps
wk1_weight VARCHAR default="" Week 1 target weight (e.g., "30 lbs", "BW")
wk4_weight VARCHAR default="" Week 4 target weight
created_at DATETIME auto Record creation time
updated_at DATETIME auto Last update time

Model: app/models/user_exercise_program.py:UserExerciseProgram


workout_sessions

A completed workout session — ties a user to a workout day on a date.

Column Type Constraints Description
id INTEGER PK, auto-increment
user_id INTEGER FK → users.id, indexed Who did the workout
workout_day_id INTEGER FK → workout_days.id Which day was trained
date DATE default=today Date the workout was performed
notes VARCHAR nullable Free-text session notes
created_at DATETIME auto Record creation time

Model: app/models/workout_session.py:WorkoutSession


workout_logs

Individual set logs within a session. Each row = one set of one exercise.

Column Type Constraints Description
id INTEGER PK, auto-increment
session_id INTEGER FK → workout_sessions.id, indexed Parent session
exercise_id INTEGER FK → exercises.id Which exercise
set_number INTEGER default=1 Set number (1, 2, 3...)
reps_completed INTEGER default=0 Actual reps performed
weight_used VARCHAR default="" Weight used (e.g., "30 lbs", "BW")
felt_easy BOOLEAN default=False Progression signal
notes VARCHAR nullable Per-set notes
created_at DATETIME auto Record creation time

Model: app/models/workout_log.py:WorkoutLog


progress_log

Progression tracking — what the engine suggested vs what the user actually did.

Column Type Constraints Description
id INTEGER PK, auto-increment
user_id INTEGER FK → users.id, indexed Profile being tracked
exercise_id INTEGER FK → exercises.id Exercise being tracked
date DATE default=today Date of progression entry
suggested_reps INTEGER nullable Engine recommendation
suggested_weight VARCHAR nullable Engine recommendation
actual_reps INTEGER nullable What user actually did
actual_weight VARCHAR nullable What user actually used
progression_applied VARCHAR nullable Type: "reps_increase", "weight_increase", "deload"
created_at DATETIME auto Record creation time

Model: app/models/progress_log.py:ProgressLog


Relationships

users
  ├── user_exercise_programs (1:N via user_id)
  ├── workout_sessions (1:N via user_id)
  └── progress_log (1:N via user_id)

exercises
  ├── user_exercise_programs (1:N via exercise_id)
  ├── workout_logs (1:N via exercise_id)
  └── progress_log (1:N via exercise_id)

workout_days
  └── workout_sessions (1:N via workout_day_id)

workout_sessions
  └── workout_logs (1:N via session_id)

Migrations

Managed by Alembic. Config at alembic.ini, migration scripts at alembic/versions/.

  • Initial migration: 1855836abf6c_initial_schema_8_tables.py — creates all 8 tables

To create a new migration:

alembic revision --autogenerate -m "description"
alembic upgrade head

Seeding

On first startup, SeedService.seed_all() reads:

  • config/exercises.yaml — exercise catalog + warmups + workout days
  • config/user_programs.yaml — per-user week 1/4 targets

Admin user is created from ADMIN_USERNAME / ADMIN_PASSWORD env vars with bcrypt hash. Seeding is skipped if data already exists.