Files
fitaiProto/apps/admin/src/lib/migrations/create-report-tables.js
T

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