godcrm/backend/database/migrations/knex/043_create_fitness_tables.js
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

88 lines
5 KiB
JavaScript

// backend/database/migrations/knex/043_create_fitness_tables.js
// ADR-025: Fitness Module — exercises, workouts, sets
export async function up(knex) {
// fitness_exercises
await knex.schema.createTable('fitness_exercises', (table) => {
table.increments('id').primary();
table.integer('space_id').references('id').inTable('spaces');
table.string('name', 255).notNullable();
table.string('equipment', 100);
table.string('primary_muscle', 100);
table.string('secondary_muscle', 100);
table.string('category', 50);
table.timestamp('created_at').defaultTo(knex.fn.now());
});
// fitness_workouts
await knex.schema.createTable('fitness_workouts', (table) => {
table.increments('id').primary();
table.integer('space_id').references('id').inTable('spaces').notNullable();
table.string('title', 255);
table.text('description');
table.timestamp('started_at').notNullable();
table.timestamp('ended_at');
table.text('notes');
table.string('source', 50).defaultTo('manual');
table.timestamp('created_at').defaultTo(knex.fn.now());
table.timestamp('updated_at').defaultTo(knex.fn.now());
table.index('space_id', 'idx_fitness_workouts_space');
table.index(['space_id', 'started_at'], 'idx_fitness_workouts_date');
});
// fitness_sets
await knex.schema.createTable('fitness_sets', (table) => {
table.increments('id').primary();
table.integer('workout_id').references('id').inTable('fitness_workouts').onDelete('CASCADE');
table.integer('exercise_id').references('id').inTable('fitness_exercises');
table.string('exercise_name', 255);
table.integer('set_index').notNullable();
table.string('set_type', 50).defaultTo('normal');
table.decimal('weight_kg', 7, 2);
table.integer('reps');
table.decimal('rpe', 3, 1);
table.decimal('distance_km', 7, 3);
table.integer('duration_seconds');
table.boolean('is_pr').defaultTo(false);
table.timestamp('created_at').defaultTo(knex.fn.now());
table.index('workout_id', 'idx_fitness_sets_workout');
table.index('exercise_name', 'idx_fitness_sets_exercise');
});
// Partial index for PRs
await knex.raw('CREATE INDEX IF NOT EXISTS idx_fitness_sets_pr ON fitness_sets(is_pr) WHERE is_pr = true');
// Unique constraint for exercises per space
await knex.raw('CREATE UNIQUE INDEX IF NOT EXISTS idx_fitness_exercises_unique ON fitness_exercises(space_id, name) WHERE space_id IS NOT NULL');
// Seed global exercises
await knex('fitness_exercises').insert([
{ space_id: null, name: 'Bench Press', equipment: 'barbell', primary_muscle: 'Chest', category: 'compound' },
{ space_id: null, name: 'Squat', equipment: 'barbell', primary_muscle: 'Quads', category: 'compound' },
{ space_id: null, name: 'Deadlift', equipment: 'barbell', primary_muscle: 'Back', category: 'compound' },
{ space_id: null, name: 'Overhead Press', equipment: 'barbell', primary_muscle: 'Shoulders', category: 'compound' },
{ space_id: null, name: 'Barbell Row', equipment: 'barbell', primary_muscle: 'Back', category: 'compound' },
{ space_id: null, name: 'Pull-up', equipment: 'bodyweight', primary_muscle: 'Back', category: 'compound' },
{ space_id: null, name: 'Dip', equipment: 'bodyweight', primary_muscle: 'Chest', category: 'compound' },
{ space_id: null, name: 'Bicep Curl', equipment: 'dumbbell', primary_muscle: 'Biceps', category: 'isolation' },
{ space_id: null, name: 'Tricep Extension', equipment: 'cable', primary_muscle: 'Triceps', category: 'isolation' },
{ space_id: null, name: 'Leg Press', equipment: 'machine', primary_muscle: 'Quads', category: 'compound' },
{ space_id: null, name: 'Lat Pulldown', equipment: 'cable', primary_muscle: 'Back', category: 'compound' },
{ space_id: null, name: 'Leg Curl', equipment: 'machine', primary_muscle: 'Hamstrings', category: 'isolation' },
{ space_id: null, name: 'Leg Extension', equipment: 'machine', primary_muscle: 'Quads', category: 'isolation' },
{ space_id: null, name: 'Lateral Raise', equipment: 'dumbbell', primary_muscle: 'Shoulders', category: 'isolation' },
{ space_id: null, name: 'Face Pull', equipment: 'cable', primary_muscle: 'Shoulders', category: 'isolation' },
{ space_id: null, name: 'Calf Raise', equipment: 'machine', primary_muscle: 'Calves', category: 'isolation' },
{ space_id: null, name: 'Plank', equipment: 'bodyweight', primary_muscle: 'Core', category: 'isolation' },
{ space_id: null, name: 'Russian Twist', equipment: 'bodyweight', primary_muscle: 'Core', category: 'isolation' },
{ space_id: null, name: 'Incline Bench Press', equipment: 'barbell', primary_muscle: 'Chest', category: 'compound' },
{ space_id: null, name: 'Romanian Deadlift', equipment: 'barbell', primary_muscle: 'Hamstrings', category: 'compound' },
]);
}
export async function down(knex) {
await knex.schema.dropTableIfExists('fitness_sets');
await knex.schema.dropTableIfExists('fitness_workouts');
await knex.schema.dropTableIfExists('fitness_exercises');
}