d48a1886dd
- Add custom_workouts and custom_workout_exercises tables (schema) - New endpoints: - GET /api/exercises - List all exercises for picker - POST /api/custom-workouts - Fork program workout - GET /api/custom-workouts - List user's custom workouts - GET /api/custom-workouts/:id - Get workout with exercises - PUT /api/custom-workouts/:id - Update workout exercises - DELETE /api/custom-workouts/:id - Delete custom workout - Updated endpoints for source_type support: - GET /api/logs - Filter by source_type and custom_workout_id - POST /api/logs - Save with source_type and custom_workout_id - DELETE /api/logs - Support custom workout log deletion - Adds Phase 4 planning overview Completes: 04-01-schema-migration, 04-02-backend-api Next: 04-03-frontend-workout-edit
217 lines
8.2 KiB
SQL
217 lines
8.2 KiB
SQL
-- Gravl Database Schema
|
|
|
|
-- Users table
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id SERIAL PRIMARY KEY,
|
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
gender VARCHAR(10),
|
|
age INT,
|
|
weight DECIMAL(5,1),
|
|
neck_cm DECIMAL(4,1),
|
|
waist_cm DECIMAL(4,1),
|
|
hip_cm DECIMAL(4,1),
|
|
experience_level VARCHAR(20),
|
|
bench_1rm DECIMAL(5,1),
|
|
squat_1rm DECIMAL(5,1),
|
|
deadlift_1rm DECIMAL(5,1),
|
|
goal VARCHAR(30),
|
|
workouts_per_week INT,
|
|
onboarding_complete BOOLEAN DEFAULT FALSE,
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
-- Programs table
|
|
CREATE TABLE IF NOT EXISTS programs (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
weeks INTEGER DEFAULT 6,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Program days (e.g., Push, Pull, Legs)
|
|
CREATE TABLE IF NOT EXISTS program_days (
|
|
id SERIAL PRIMARY KEY,
|
|
program_id INTEGER REFERENCES programs(id) ON DELETE CASCADE,
|
|
day_number INTEGER NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Exercises master table
|
|
CREATE TABLE IF NOT EXISTS exercises (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
muscle_group VARCHAR(100),
|
|
description TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Program exercises (which exercises on which day)
|
|
CREATE TABLE IF NOT EXISTS program_exercises (
|
|
id SERIAL PRIMARY KEY,
|
|
program_day_id INTEGER REFERENCES program_days(id) ON DELETE CASCADE,
|
|
exercise_id INTEGER REFERENCES exercises(id) ON DELETE CASCADE,
|
|
sets INTEGER DEFAULT 3,
|
|
reps_min INTEGER DEFAULT 8,
|
|
reps_max INTEGER DEFAULT 12,
|
|
order_num INTEGER DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Workout logs
|
|
CREATE TABLE IF NOT EXISTS workout_logs (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER DEFAULT 1,
|
|
program_exercise_id INTEGER REFERENCES program_exercises(id) ON DELETE CASCADE,
|
|
date DATE NOT NULL,
|
|
set_number INTEGER NOT NULL,
|
|
weight DECIMAL(10,2),
|
|
reps INTEGER,
|
|
completed BOOLEAN DEFAULT FALSE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Create indexes
|
|
CREATE INDEX IF NOT EXISTS idx_workout_logs_user_date ON workout_logs(user_id, date);
|
|
CREATE INDEX IF NOT EXISTS idx_workout_logs_exercise ON workout_logs(program_exercise_id);
|
|
CREATE INDEX IF NOT EXISTS idx_program_days_program ON program_days(program_id);
|
|
CREATE INDEX IF NOT EXISTS idx_program_exercises_day ON program_exercises(program_day_id);
|
|
|
|
-- Insert PPL Program
|
|
INSERT INTO programs (name, description, weeks) VALUES
|
|
('Push/Pull/Legs', 'Classic 6-day PPL split for strength and hypertrophy. 6-week progressive program.', 6)
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Insert exercises
|
|
INSERT INTO exercises (name, muscle_group, description) VALUES
|
|
-- Push exercises
|
|
('Bench Press', 'Chest', 'Barbell bench press - main chest compound'),
|
|
('Overhead Press', 'Shoulders', 'Standing barbell overhead press'),
|
|
('Incline Dumbbell Press', 'Chest', 'Incline dumbbell press for upper chest'),
|
|
('Lateral Raises', 'Shoulders', 'Dumbbell lateral raises for side delts'),
|
|
('Tricep Pushdowns', 'Triceps', 'Cable tricep pushdowns'),
|
|
('Overhead Tricep Extension', 'Triceps', 'Cable or dumbbell overhead extension'),
|
|
|
|
-- Pull exercises
|
|
('Deadlift', 'Back', 'Conventional deadlift - main posterior chain compound'),
|
|
('Barbell Rows', 'Back', 'Bent over barbell rows'),
|
|
('Pull-ups', 'Back', 'Bodyweight or weighted pull-ups'),
|
|
('Face Pulls', 'Rear Delts', 'Cable face pulls for rear delts and rotator cuff'),
|
|
('Barbell Curls', 'Biceps', 'Standing barbell curls'),
|
|
('Hammer Curls', 'Biceps', 'Dumbbell hammer curls'),
|
|
|
|
-- Legs exercises
|
|
('Squat', 'Quads', 'Barbell back squat - main leg compound'),
|
|
('Romanian Deadlift', 'Hamstrings', 'RDL for hamstrings and glutes'),
|
|
('Leg Press', 'Quads', 'Machine leg press'),
|
|
('Leg Curls', 'Hamstrings', 'Lying or seated leg curls'),
|
|
('Calf Raises', 'Calves', 'Standing or seated calf raises'),
|
|
('Walking Lunges', 'Quads', 'Dumbbell walking lunges')
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Insert program days for PPL
|
|
INSERT INTO program_days (program_id, day_number, name) VALUES
|
|
(1, 1, 'Push A'),
|
|
(1, 2, 'Pull A'),
|
|
(1, 3, 'Legs A'),
|
|
(1, 4, 'Push B'),
|
|
(1, 5, 'Pull B'),
|
|
(1, 6, 'Legs B')
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Insert program exercises
|
|
-- Push A (day 1)
|
|
INSERT INTO program_exercises (program_day_id, exercise_id, sets, reps_min, reps_max, order_num) VALUES
|
|
(1, 1, 4, 6, 8, 1), -- Bench Press 4x6-8
|
|
(1, 2, 3, 8, 10, 2), -- OHP 3x8-10
|
|
(1, 3, 3, 10, 12, 3), -- Incline DB Press 3x10-12
|
|
(1, 4, 3, 12, 15, 4), -- Lateral Raises 3x12-15
|
|
(1, 5, 3, 10, 12, 5), -- Tricep Pushdowns 3x10-12
|
|
(1, 6, 3, 10, 12, 6) -- Overhead Extension 3x10-12
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Pull A (day 2)
|
|
INSERT INTO program_exercises (program_day_id, exercise_id, sets, reps_min, reps_max, order_num) VALUES
|
|
(2, 7, 4, 5, 6, 1), -- Deadlift 4x5-6
|
|
(2, 8, 4, 8, 10, 2), -- Barbell Rows 4x8-10
|
|
(2, 9, 3, 6, 10, 3), -- Pull-ups 3x6-10
|
|
(2, 10, 3, 15, 20, 4), -- Face Pulls 3x15-20
|
|
(2, 11, 3, 10, 12, 5), -- Barbell Curls 3x10-12
|
|
(2, 12, 3, 10, 12, 6) -- Hammer Curls 3x10-12
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Legs A (day 3)
|
|
INSERT INTO program_exercises (program_day_id, exercise_id, sets, reps_min, reps_max, order_num) VALUES
|
|
(3, 13, 4, 6, 8, 1), -- Squat 4x6-8
|
|
(3, 14, 3, 10, 12, 2), -- RDL 3x10-12
|
|
(3, 15, 3, 10, 12, 3), -- Leg Press 3x10-12
|
|
(3, 16, 3, 12, 15, 4), -- Leg Curls 3x12-15
|
|
(3, 17, 4, 12, 15, 5) -- Calf Raises 4x12-15
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Push B (day 4)
|
|
INSERT INTO program_exercises (program_day_id, exercise_id, sets, reps_min, reps_max, order_num) VALUES
|
|
(4, 2, 4, 6, 8, 1), -- OHP 4x6-8 (main lift)
|
|
(4, 1, 3, 8, 10, 2), -- Bench Press 3x8-10
|
|
(4, 3, 3, 10, 12, 3), -- Incline DB Press 3x10-12
|
|
(4, 4, 4, 12, 15, 4), -- Lateral Raises 4x12-15
|
|
(4, 5, 3, 10, 12, 5), -- Tricep Pushdowns 3x10-12
|
|
(4, 6, 3, 10, 12, 6) -- Overhead Extension 3x10-12
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Pull B (day 5)
|
|
INSERT INTO program_exercises (program_day_id, exercise_id, sets, reps_min, reps_max, order_num) VALUES
|
|
(5, 8, 4, 6, 8, 1), -- Barbell Rows 4x6-8 (main lift)
|
|
(5, 9, 4, 6, 10, 2), -- Pull-ups 4x6-10
|
|
(5, 7, 3, 8, 10, 3), -- Deadlift 3x8-10 (lighter)
|
|
(5, 10, 3, 15, 20, 4), -- Face Pulls 3x15-20
|
|
(5, 11, 4, 10, 12, 5), -- Barbell Curls 4x10-12
|
|
(5, 12, 3, 10, 12, 6) -- Hammer Curls 3x10-12
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Legs B (day 6)
|
|
INSERT INTO program_exercises (program_day_id, exercise_id, sets, reps_min, reps_max, order_num) VALUES
|
|
(6, 13, 3, 8, 10, 1), -- Squat 3x8-10
|
|
(6, 14, 4, 8, 10, 2), -- RDL 4x8-10 (main lift)
|
|
(6, 18, 3, 10, 12, 3), -- Walking Lunges 3x10-12
|
|
(6, 16, 4, 10, 12, 4), -- Leg Curls 4x10-12
|
|
(6, 17, 4, 12, 15, 5) -- Calf Raises 4x12-15
|
|
ON CONFLICT DO NOTHING;
|
|
|
|
-- Custom workouts created by users
|
|
CREATE TABLE IF NOT EXISTS custom_workouts (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
source_program_day_id INTEGER REFERENCES program_days(id) ON DELETE SET NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Exercises within a custom workout
|
|
CREATE TABLE IF NOT EXISTS custom_workout_exercises (
|
|
id SERIAL PRIMARY KEY,
|
|
custom_workout_id INTEGER NOT NULL REFERENCES custom_workouts(id) ON DELETE CASCADE,
|
|
exercise_id INTEGER NOT NULL REFERENCES exercises(id) ON DELETE CASCADE,
|
|
sets INTEGER NOT NULL DEFAULT 3,
|
|
reps_min INTEGER NOT NULL DEFAULT 8,
|
|
reps_max INTEGER NOT NULL DEFAULT 12,
|
|
rpe_target DECIMAL(3,1),
|
|
replaced_exercise_id INTEGER REFERENCES exercises(id) ON DELETE SET NULL,
|
|
order_index INTEGER NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Extend workout_logs to support custom workouts
|
|
ALTER TABLE workout_logs
|
|
ADD COLUMN IF NOT EXISTS source_type VARCHAR(20) DEFAULT 'program' CHECK (source_type IN ('program', 'custom')),
|
|
ADD COLUMN IF NOT EXISTS custom_workout_id INTEGER REFERENCES custom_workouts(id) ON DELETE SET NULL;
|
|
|
|
-- Indexes for custom workout tables
|
|
CREATE INDEX IF NOT EXISTS idx_custom_workouts_user ON custom_workouts(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_custom_workout_exercises_workout ON custom_workout_exercises(custom_workout_id);
|
|
CREATE INDEX IF NOT EXISTS idx_workout_logs_custom_workout ON workout_logs(custom_workout_id);
|