233 lines
7.0 KiB
JavaScript
233 lines
7.0 KiB
JavaScript
/**
|
|
* Migration Script: Create new tables for report generation
|
|
*
|
|
* This script:
|
|
* 1. Creates the following tables:
|
|
* - daily_nutrition - Daily calorie tracking
|
|
* - meal_entries - Individual meal details
|
|
* - daily_hydration - Daily water intake tracking
|
|
* - fitness_profile_history - Profile change history
|
|
* - trainer_client_assignments - Trainer-client relationships
|
|
*
|
|
* 2. Fixes gym assignments for users without gymId:
|
|
* - Assigns superAdmin to their first gym
|
|
* - Assigns other users to gym of their trainer
|
|
*
|
|
* Run with: node apps/admin/src/lib/migrations/create-report-tables.js
|
|
*
|
|
* Note: Run this AFTER setting up the base database
|
|
*/
|
|
|
|
const Database = require("better-sqlite3");
|
|
|
|
// Use absolute path to the database
|
|
const dbPath = "/home/echo/dev/prototype/apps/admin/data/fitai.db";
|
|
|
|
function createReportTables() {
|
|
console.log("Starting report tables migration...\n");
|
|
console.log(`Database path: ${dbPath}\n`);
|
|
|
|
const db = new Database(dbPath);
|
|
|
|
// 1. Create daily_nutrition table
|
|
console.log("Creating daily_nutrition table...");
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS daily_nutrition (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL,
|
|
date TEXT NOT NULL,
|
|
total_calories INTEGER DEFAULT 0,
|
|
calorie_goal INTEGER DEFAULT 2000,
|
|
meals TEXT DEFAULT '[]',
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
UNIQUE(user_id, date)
|
|
)
|
|
`);
|
|
console.log(" ✓ daily_nutrition table created");
|
|
|
|
// 2. Create meal_entries table
|
|
console.log("Creating meal_entries table...");
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS meal_entries (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL,
|
|
daily_nutrition_id TEXT,
|
|
meal_type TEXT NOT NULL,
|
|
food_name TEXT NOT NULL,
|
|
calories INTEGER NOT NULL,
|
|
protein INTEGER,
|
|
carbs INTEGER,
|
|
fats INTEGER,
|
|
timestamp INTEGER NOT NULL,
|
|
created_at INTEGER NOT NULL
|
|
)
|
|
`);
|
|
console.log(" ✓ meal_entries table created");
|
|
|
|
// 3. Create daily_hydration table
|
|
console.log("Creating daily_hydration table...");
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS daily_hydration (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL,
|
|
date TEXT NOT NULL,
|
|
total_water INTEGER DEFAULT 0,
|
|
water_goal INTEGER DEFAULT 2000,
|
|
entries TEXT DEFAULT '[]',
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
UNIQUE(user_id, date)
|
|
)
|
|
`);
|
|
console.log(" ✓ daily_hydration table created");
|
|
|
|
// 4. Create fitness_profile_history table
|
|
console.log("Creating fitness_profile_history table...");
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS fitness_profile_history (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL,
|
|
fitness_profile_id TEXT NOT NULL,
|
|
change_type TEXT NOT NULL,
|
|
field_name TEXT NOT NULL,
|
|
previous_value TEXT,
|
|
new_value TEXT,
|
|
changed_at INTEGER NOT NULL,
|
|
created_at INTEGER NOT NULL
|
|
)
|
|
`);
|
|
console.log(" ✓ fitness_profile_history table created");
|
|
|
|
// 5. Create trainer_client_assignments table
|
|
console.log("Creating trainer_client_assignments table...");
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS trainer_client_assignments (
|
|
id TEXT PRIMARY KEY,
|
|
trainer_id TEXT NOT NULL,
|
|
client_id TEXT NOT NULL,
|
|
assigned_at INTEGER NOT NULL,
|
|
assigned_by TEXT,
|
|
is_active INTEGER DEFAULT 1,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
)
|
|
`);
|
|
console.log(" ✓ trainer_client_assignments table created");
|
|
|
|
// Create indexes for better query performance
|
|
console.log("\nCreating indexes...");
|
|
|
|
db.exec(`
|
|
CREATE INDEX IF NOT EXISTS idx_daily_nutrition_user_date
|
|
ON daily_nutrition(user_id, date)
|
|
`);
|
|
console.log(" ✓ Index: daily_nutrition.user_id + date");
|
|
|
|
db.exec(`
|
|
CREATE INDEX IF NOT EXISTS idx_meal_entries_user_timestamp
|
|
ON meal_entries(user_id, timestamp)
|
|
`);
|
|
console.log(" ✓ Index: meal_entries.user_id + timestamp");
|
|
|
|
db.exec(`
|
|
CREATE INDEX IF NOT EXISTS idx_daily_hydration_user_date
|
|
ON daily_hydration(user_id, date)
|
|
`);
|
|
console.log(" ✓ Index: daily_hydration.user_id + date");
|
|
|
|
db.exec(`
|
|
CREATE INDEX IF NOT EXISTS idx_fitness_profile_history_user
|
|
ON fitness_profile_history(user_id)
|
|
`);
|
|
console.log(" ✓ Index: fitness_profile_history.user_id");
|
|
|
|
db.exec(`
|
|
CREATE INDEX IF NOT EXISTS idx_trainer_client_assignments_trainer
|
|
ON trainer_client_assignments(trainer_id)
|
|
`);
|
|
console.log(" ✓ Index: trainer_client_assignments.trainer_id");
|
|
|
|
db.exec(`
|
|
CREATE INDEX IF NOT EXISTS idx_trainer_client_assignments_client
|
|
ON trainer_client_assignments(client_id)
|
|
`);
|
|
console.log(" ✓ Index: trainer_client_assignments.client_id");
|
|
|
|
db.exec(`
|
|
CREATE INDEX IF NOT EXISTS idx_trainer_client_assignments_active
|
|
ON trainer_client_assignments(trainer_id, client_id, is_active)
|
|
`);
|
|
console.log(" ✓ Index: trainer_client_assignments (composite)");
|
|
|
|
db.close();
|
|
|
|
console.log("\n=== Migration Complete ===");
|
|
console.log("All report generation tables created successfully!");
|
|
console.log("\nTables created:");
|
|
console.log(" - daily_nutrition");
|
|
console.log(" - meal_entries");
|
|
console.log(" - daily_hydration");
|
|
console.log(" - fitness_profile_history");
|
|
console.log(" - trainer_client_assignments");
|
|
console.log("\nIndexes created: 7");
|
|
|
|
// Fix gym assignments for users without gymId
|
|
console.log("\n=== Fixing Gym Assignments ===");
|
|
|
|
const usersWithoutGym = db
|
|
.prepare("SELECT id, email, role FROM users WHERE gym_id IS NULL")
|
|
.all();
|
|
|
|
console.log(`Found ${usersWithoutGym.length} users without gymId`);
|
|
|
|
let fixedCount = 0;
|
|
|
|
for (const user of usersWithoutGym) {
|
|
if (user.role === "superAdmin") {
|
|
// Get first gym
|
|
const gym = db.prepare("SELECT id FROM gyms LIMIT 1").get();
|
|
if (gym) {
|
|
db.prepare("UPDATE users SET gym_id = ? WHERE id = ?").run(
|
|
gym.id,
|
|
user.id,
|
|
);
|
|
console.log(` ✓ Fixed ${user.email} (superAdmin) -> gym ${gym.id}`);
|
|
fixedCount++;
|
|
}
|
|
} else {
|
|
// Try to find gym from trainer_clients table
|
|
const trainerClient = db
|
|
.prepare(
|
|
"SELECT gym_id FROM trainer_clients WHERE trainer_user_id = ? OR client_user_id = ? LIMIT 1",
|
|
)
|
|
.get(user.id, user.id);
|
|
|
|
if (trainerClient) {
|
|
db.prepare("UPDATE users SET gym_id = ? WHERE id = ?").run(
|
|
trainerClient.gym_id,
|
|
user.id,
|
|
);
|
|
console.log(
|
|
` ✓ Fixed ${user.email} (${user.role}) -> gym ${trainerClient.gym_id}`,
|
|
);
|
|
fixedCount++;
|
|
} else {
|
|
console.log(
|
|
` ⚠ Could not fix ${user.email} (${user.role}) - no trainer_clients record`,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(`\nFixed ${fixedCount} users without gymId`);
|
|
console.log("\nGym assignments update complete!");
|
|
}
|
|
|
|
// Run if called directly
|
|
if (require.main === module) {
|
|
createReportTables();
|
|
}
|
|
|
|
module.exports = { createReportTables };
|