feat: define all 8 SQLModel tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 09:35:13 -06:00
parent 45b93a2988
commit 3bf1e13adc
10 changed files with 529 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
"""SQLModel model definitions for SneakySwole.
All 8 tables are defined here and re-exported for convenient imports.
"""
from app.models.user import User
from app.models.exercise import Exercise
from app.models.warmup import Warmup
from app.models.workout_day import WorkoutDay
from app.models.user_exercise_program import UserExerciseProgram
from app.models.workout_session import WorkoutSession
from app.models.workout_log import WorkoutLog
from app.models.progress_log import ProgressLog
__all__ = [
"User",
"Exercise",
"Warmup",
"WorkoutDay",
"UserExerciseProgram",
"WorkoutSession",
"WorkoutLog",
"ProgressLog",
]

35
app/models/exercise.py Normal file
View File

@@ -0,0 +1,35 @@
"""Exercise model for the exercise library catalog.
Each exercise belongs to a workout day and includes form cues.
"""
from datetime import datetime
from typing import Optional
from sqlmodel import Field, SQLModel
class Exercise(SQLModel, table=True):
"""An exercise in the workout library.
Attributes:
id: Primary key, auto-incremented.
name: Exercise name (e.g., "DB Chest Press (Floor)").
muscle_group: Target muscle group (e.g., "Chest", "Shoulders").
workout_day: Which day this exercise belongs to (Push/Pull/Lower/Full Body).
sets: Default number of sets.
tempo: Tempo notation (e.g., "3-1-2" = 3s eccentric, 1s pause, 2s concentric).
form_cues: Detailed form instructions.
created_at: Timestamp when the record was created.
"""
__tablename__ = "exercises"
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
muscle_group: str = Field(default="")
workout_day: str = Field(index=True)
sets: int = Field(default=3)
tempo: str = Field(default="")
form_cues: str = Field(default="")
created_at: datetime = Field(default_factory=datetime.utcnow)

View File

@@ -0,0 +1,39 @@
"""ProgressLog model for tracking progression suggestions and outcomes.
Records what the progression engine suggested vs what the user actually did.
"""
import datetime as dt
from typing import Optional
from sqlmodel import Field, SQLModel
class ProgressLog(SQLModel, table=True):
"""A progression tracking entry for a specific exercise.
Attributes:
id: Primary key, auto-incremented.
user_id: FK to users table.
exercise_id: FK to exercises table.
date: The date this progression entry applies to.
suggested_reps: What the engine recommended.
suggested_weight: What the engine recommended.
actual_reps: What the user actually did.
actual_weight: What the user actually used.
progression_applied: Type of progression (e.g., "reps_increase", "weight_increase", "deload").
created_at: Timestamp when the record was created.
"""
__tablename__ = "progress_log"
id: Optional[int] = Field(default=None, primary_key=True)
user_id: int = Field(foreign_key="users.id", index=True)
exercise_id: int = Field(foreign_key="exercises.id")
date: dt.date = Field(default_factory=dt.date.today)
suggested_reps: Optional[int] = Field(default=None)
suggested_weight: Optional[str] = Field(default=None)
actual_reps: Optional[int] = Field(default=None)
actual_weight: Optional[str] = Field(default=None)
progression_applied: Optional[str] = Field(default=None)
created_at: dt.datetime = Field(default_factory=dt.datetime.utcnow)

39
app/models/user.py Normal file
View File

@@ -0,0 +1,39 @@
"""User model for profile management.
Stores admin and regular user profiles with physical stats and goals.
"""
from datetime import datetime
from typing import Optional
from sqlmodel import Field, SQLModel
class User(SQLModel, table=True):
"""A user profile in the system.
Attributes:
id: Primary key, auto-incremented.
username: Unique login identifier.
password_hash: bcrypt-hashed password (admin only initially).
display_name: Human-readable name shown in the UI.
height: User's height as a string (e.g., "6'0\"").
weight: User's weight as a string (e.g., "260 lbs").
goals: Free-text training goals.
is_admin: Whether this user has admin privileges.
created_at: Timestamp when the record was created.
updated_at: Timestamp of the last update.
"""
__tablename__ = "users"
id: Optional[int] = Field(default=None, primary_key=True)
username: str = Field(index=True, unique=True)
password_hash: str = Field(default="")
display_name: str = Field(default="")
height: Optional[str] = Field(default=None)
weight: Optional[str] = Field(default=None)
goals: Optional[str] = Field(default=None)
is_admin: bool = Field(default=False)
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)

View File

@@ -0,0 +1,37 @@
"""UserExerciseProgram model for per-user exercise programming.
Links a user to an exercise with week 1 and week 4 rep/weight targets.
"""
from datetime import datetime
from typing import Optional
from sqlmodel import Field, SQLModel
class UserExerciseProgram(SQLModel, table=True):
"""Per-user programming for a specific exercise.
Attributes:
id: Primary key, auto-incremented.
user_id: FK to users table.
exercise_id: FK to exercises table.
wk1_reps: Week 1 target reps (string to support "30 sec" style).
wk4_reps: Week 4 target reps.
wk1_weight: Week 1 target weight (e.g., "30 lbs", "BW").
wk4_weight: Week 4 target weight.
created_at: Timestamp when the record was created.
updated_at: Timestamp of the last update.
"""
__tablename__ = "user_exercise_programs"
id: Optional[int] = Field(default=None, primary_key=True)
user_id: int = Field(foreign_key="users.id", index=True)
exercise_id: int = Field(foreign_key="exercises.id", index=True)
wk1_reps: str = Field(default="")
wk4_reps: str = Field(default="")
wk1_weight: str = Field(default="")
wk4_weight: str = Field(default="")
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)

33
app/models/warmup.py Normal file
View File

@@ -0,0 +1,33 @@
"""Warmup model for the standardized warmup routine.
Warmups are displayed before every workout in a fixed order.
"""
from datetime import datetime
from typing import Optional
from sqlmodel import Field, SQLModel
class Warmup(SQLModel, table=True):
"""A warmup exercise in the standardized routine.
Attributes:
id: Primary key, auto-incremented.
name: Warmup name (e.g., "Cat / Cow").
type: Category (e.g., "Thoracic Mob", "Hip Mobility").
reps: Rep scheme as a string (e.g., "8 reps", "8 each side").
form_cues: Detailed form instructions.
sort_order: Display order in the warmup sequence.
created_at: Timestamp when the record was created.
"""
__tablename__ = "warmups"
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
type: str = Field(default="")
reps: str = Field(default="")
form_cues: str = Field(default="")
sort_order: int = Field(default=0)
created_at: datetime = Field(default_factory=datetime.utcnow)

26
app/models/workout_day.py Normal file
View File

@@ -0,0 +1,26 @@
"""WorkoutDay model for the 4-day training split.
Defines the named workout days and their order.
"""
from typing import Optional
from sqlmodel import Field, SQLModel
class WorkoutDay(SQLModel, table=True):
"""A named workout day in the training program.
Attributes:
id: Primary key, auto-incremented.
name: Day name (Push, Pull, Lower, Full Body).
day_number: Order in the weekly rotation (1-4).
description: Brief description of the day's focus.
"""
__tablename__ = "workout_days"
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True, unique=True)
day_number: int = Field(unique=True)
description: str = Field(default="")

37
app/models/workout_log.py Normal file
View File

@@ -0,0 +1,37 @@
"""WorkoutLog model for per-exercise set logging.
Each log entry records one set of one exercise within a session.
"""
from datetime import datetime
from typing import Optional
from sqlmodel import Field, SQLModel
class WorkoutLog(SQLModel, table=True):
"""A single set log for an exercise within a workout session.
Attributes:
id: Primary key, auto-incremented.
session_id: FK to workout_sessions table.
exercise_id: FK to exercises table.
set_number: Which set this is (1, 2, 3...).
reps_completed: Actual reps performed.
weight_used: Weight used as string (e.g., "30 lbs", "BW").
felt_easy: Whether the user felt the set was easy (progression signal).
notes: Optional notes about this specific set.
created_at: Timestamp when the record was created.
"""
__tablename__ = "workout_logs"
id: Optional[int] = Field(default=None, primary_key=True)
session_id: int = Field(foreign_key="workout_sessions.id", index=True)
exercise_id: int = Field(foreign_key="exercises.id")
set_number: int = Field(default=1)
reps_completed: int = Field(default=0)
weight_used: str = Field(default="")
felt_easy: bool = Field(default=False)
notes: Optional[str] = Field(default=None)
created_at: datetime = Field(default_factory=datetime.utcnow)

View File

@@ -0,0 +1,31 @@
"""WorkoutSession model for tracking completed workout sessions.
Each session ties a user to a workout day on a specific date.
"""
import datetime as dt
from typing import Optional
from sqlmodel import Field, SQLModel
class WorkoutSession(SQLModel, table=True):
"""A completed workout session.
Attributes:
id: Primary key, auto-incremented.
user_id: FK to users table.
workout_day_id: FK to workout_days table.
date: The date the workout was performed.
notes: Optional free-text notes about the session.
created_at: Timestamp when the record was created.
"""
__tablename__ = "workout_sessions"
id: Optional[int] = Field(default=None, primary_key=True)
user_id: int = Field(foreign_key="users.id", index=True)
workout_day_id: int = Field(foreign_key="workout_days.id")
date: dt.date = Field(default_factory=dt.date.today)
notes: Optional[str] = Field(default=None)
created_at: dt.datetime = Field(default_factory=dt.datetime.utcnow)