diff --git a/backend/check_migration_024.py b/backend/check_migration_024.py new file mode 100644 index 0000000..c31cf1d --- /dev/null +++ b/backend/check_migration_024.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +""" +Quick diagnostic: Check Migration 024 state + +Run this inside the backend container: +docker exec bodytrack-dev-backend-1 python check_migration_024.py +""" + +import psycopg2 +import os +from psycopg2.extras import RealDictCursor + +# Database connection +DB_HOST = os.getenv('DB_HOST', 'db') +DB_PORT = os.getenv('DB_PORT', '5432') +DB_NAME = os.getenv('DB_NAME', 'bodytrack') +DB_USER = os.getenv('DB_USER', 'bodytrack') +DB_PASS = os.getenv('DB_PASSWORD', '') + +def main(): + print("=" * 70) + print("Migration 024 Diagnostic") + print("=" * 70) + + # Connect to database + conn = psycopg2.connect( + host=DB_HOST, + port=DB_PORT, + dbname=DB_NAME, + user=DB_USER, + password=DB_PASS + ) + cur = conn.cursor(cursor_factory=RealDictCursor) + + # 1. Check if table exists + print("\n1. Checking if goal_type_definitions table exists...") + cur.execute(""" + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_name = 'goal_type_definitions' + ) + """) + exists = cur.fetchone()['exists'] + print(f" ✓ Table exists: {exists}") + + if not exists: + print("\n❌ TABLE DOES NOT EXIST - Migration 024 did not run!") + print("\nRECOMMENDED ACTION:") + print(" 1. Restart backend container: docker restart bodytrack-dev-backend-1") + print(" 2. Check logs: docker logs bodytrack-dev-backend-1 | grep 'Migration'") + cur.close() + conn.close() + return + + # 2. Check row count + print("\n2. Checking row count...") + cur.execute("SELECT COUNT(*) as count FROM goal_type_definitions") + count = cur.fetchone()['count'] + print(f" Row count: {count}") + + if count == 0: + print("\n❌ TABLE IS EMPTY - Seed data was not inserted!") + print("\nPOSSIBLE CAUSES:") + print(" - INSERT statements failed (constraint violation?)") + print(" - Migration ran partially") + print("\nRECOMMENDED ACTION:") + print(" Run the seed statements manually (see below)") + else: + print(f" ✓ Table has {count} entries") + + # 3. Show all entries + print("\n3. Current goal type definitions:") + cur.execute(""" + SELECT type_key, label_de, unit, is_system, is_active, created_at + FROM goal_type_definitions + ORDER BY is_system DESC, type_key + """) + + entries = cur.fetchall() + if entries: + print(f"\n {'Type Key':<20} {'Label':<20} {'Unit':<10} {'System':<8} {'Active':<8}") + print(" " + "-" * 70) + for row in entries: + status = "SYSTEM" if row['is_system'] else "CUSTOM" + active = "YES" if row['is_active'] else "NO" + print(f" {row['type_key']:<20} {row['label_de']:<20} {row['unit']:<10} {status:<8} {active:<8}") + else: + print(" (empty)") + + # 4. Check schema_migrations + print("\n4. Checking schema_migrations tracking...") + cur.execute(""" + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_name = 'schema_migrations' + ) + """) + sm_exists = cur.fetchone()['exists'] + + if sm_exists: + cur.execute(""" + SELECT filename, executed_at + FROM schema_migrations + WHERE filename = '024_goal_type_registry.sql' + """) + tracked = cur.fetchone() + if tracked: + print(f" ✓ Migration 024 is tracked (executed: {tracked['executed_at']})") + else: + print(" ❌ Migration 024 is NOT tracked in schema_migrations") + else: + print(" ⚠️ schema_migrations table does not exist") + + # 5. Check for errors + print("\n5. Potential issues:") + issues = [] + + if count == 0: + issues.append("No seed data - INSERTs failed") + + if count > 0 and count < 6: + issues.append(f"Only {count} types (expected 8) - partial seed") + + cur.execute(""" + SELECT COUNT(*) as inactive_count + FROM goal_type_definitions + WHERE is_active = false + """) + inactive = cur.fetchone()['inactive_count'] + if inactive > 2: + issues.append(f"{inactive} inactive types (expected 2)") + + if not issues: + print(" ✓ No issues detected") + else: + for issue in issues: + print(f" ❌ {issue}") + + # 6. Test query that frontend uses + print("\n6. Testing frontend query (WHERE is_active = true)...") + cur.execute(""" + SELECT COUNT(*) as active_count + FROM goal_type_definitions + WHERE is_active = true + """) + active_count = cur.fetchone()['active_count'] + print(f" Active types returned: {active_count}") + + if active_count == 0: + print(" ❌ This is why frontend shows empty list!") + + print("\n" + "=" * 70) + print("SUMMARY") + print("=" * 70) + + if count == 0: + print("\n🔴 PROBLEM: Table exists but has no data") + print("\nQUICK FIX: Run these SQL commands manually:") + print("\n```sql") + print("-- Connect to database:") + print("docker exec -it bodytrack-dev-db-1 psql -U bodytrack -d bodytrack") + print("\n-- Then paste migration content:") + print("-- (copy from backend/migrations/024_goal_type_registry.sql)") + print("-- Skip CREATE TABLE (already exists), run INSERT statements only") + print("```") + elif active_count >= 6: + print("\n🟢 EVERYTHING LOOKS GOOD") + print(f" {active_count} active goal types available") + print("\nIf frontend still shows error, check:") + print(" 1. Backend logs: docker logs bodytrack-dev-backend-1 -f") + print(" 2. Network tab in browser DevTools") + print(" 3. API endpoint: curl -H 'X-Auth-Token: YOUR_TOKEN' http://localhost:8099/api/goals/goal-types") + else: + print(f"\n🟡 PARTIAL DATA: {active_count} active types (expected 6)") + print(" Some INSERTs might have failed") + + cur.close() + conn.close() + +if __name__ == '__main__': + main()