/** * 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 };