Navigation

Entity Migration Guide

Replace failing Base44 entity calls with direct Supabase queries

Why Migrate?

❌ Base44 Entity API Issues:

  • • 500 errors on Idiom, CurrencyPack reads
  • • Slow query performance (no indexes)
  • • WebSocket connection failures
  • • Unpredictable availability

✅ Direct Supabase Benefits:

  • • 99.9% uptime SLA
  • • Proper database indexes (faster queries)
  • • Row Level Security (better permissions)
  • • Real-time subscriptions available
  • • No middleware overhead
Migration Strategy

✅ Keep Base44 for:

  • • Authentication (base44.auth.me, login, logout)
  • • Backend functions (they're stable)
  • • File uploads (if working)

🔄 Migrate to Supabase:

  • • ALL entity read operations (list, filter, get)
  • • ALL entity write operations (create, update, delete)
  • • User progress tracking
  • • Crossword puzzles
Step 1: Setup Supabase Client
// 1. Install Supabase client (if not already)
// npm install @supabase/supabase-js

// 2. Create a Supabase client utility
// File: components/lib/supabaseClient.js

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || 'YOUR_SUPABASE_URL';
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || 'YOUR_ANON_KEY';

export const supabase = createClient(supabaseUrl, supabaseAnonKey);

// 3. Use in components
import { supabase } from '@/components/lib/supabaseClient';

// For authenticated requests (RLS will handle permissions)
const { data, error } = await supabase
  .from('idioms')
  .select('*')
  .eq('is_approved', true);
Step 2: Authentication Pattern (Keep Base44)
// IMPORTANT: Keep Base44 for Authentication
import { base44 } from '@/api/base44Client';

// ✅ Still use Base44 for auth
const user = await base44.auth.me();
await base44.auth.updateMe({ pearls_of_wisdom: newBalance });
await base44.auth.logout();

// ✅ Use Supabase for data
const { data } = await supabase
  .from('user_progress')
  .select('*')
  .eq('created_by', user.email);

Step 3: Entity-by-Entity Migration

Idiom
HIGH❌ FAILING

❌ Base44 (Remove):

// ❌ OLD - Causes 500 errors
import { base44 } from '@/api/base44Client';

const idioms = await base44.entities.Idiom.list();
const idiom = await base44.entities.Idiom.create(data);
await base44.entities.Idiom.update(id, data);

✅ Supabase (Use):

// ✅ NEW - Direct Supabase
import { createClient } from '@supabase/supabase-js';

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
);

const { data: idioms } = await supabase
  .from('idioms')
  .select('*');

const { data: idiom } = await supabase
  .from('idioms')
  .insert(data)
  .select()
  .single();

await supabase
  .from('idioms')
  .update(data)
  .eq('id', id);

📝 Note: All idiom operations should go directly to Supabase

VocabularyWord
MEDIUM✅ WORKING (but migrate)

❌ Base44 (Remove):

// ❌ OLD
const words = await base44.entities.VocabularyWord.list();
await base44.entities.VocabularyWord.create(wordData);

✅ Supabase (Use):

// ✅ NEW
const { data: words } = await supabase
  .from('vocabulary_words')
  .select('*');

await supabase
  .from('vocabulary_words')
  .insert(wordData);

📝 Note: Migrate to reduce dependency on Base44

UserProgress
HIGH⚠️ SLOW

❌ Base44 (Remove):

// ❌ OLD - Slow queries
const progress = await base44.entities.UserProgress.filter({
  created_by: user.email,
  status: 'mastered'
});

✅ Supabase (Use):

// ✅ NEW - Indexed queries
const { data: progress } = await supabase
  .from('user_progress')
  .select('*')
  .eq('created_by', user.email)
  .eq('status', 'mastered');

📝 Note: Supabase has proper indexes for faster queries

DailyCrossword
HIGH❌ FAILING

❌ Base44 (Remove):

// ❌ OLD
const puzzle = await base44.entities.DailyCrossword.filter({
  puzzle_date: todayDate
});

✅ Supabase (Use):

// ✅ NEW
const { data: puzzle } = await supabase
  .from('daily_crosswords')
  .select('*')
  .eq('puzzle_date', todayDate)
  .single();

📝 Note: Critical for daily puzzle feature

Class & Enrollment
LOW✅ WORKING

❌ Base44 (Remove):

// ❌ OLD
const classes = await base44.entities.Class.filter({
  teacher_email: user.email
});

✅ Supabase (Use):

// ✅ NEW
const { data: classes } = await supabase
  .from('classes')
  .select('*')
  .eq('teacher_email', user.email);

📝 Note: Low priority - currently working but good to migrate

Step 4: React Query Pattern (Recommended)
// RECOMMENDED: Use React Query with Supabase
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { supabase } from '@/components/lib/supabaseClient';

// Read data
const { data: idioms, isLoading } = useQuery({
  queryKey: ['idioms'],
  queryFn: async () => {
    const { data, error } = await supabase
      .from('idioms')
      .select('*')
      .eq('is_approved', true);
    if (error) throw error;
    return data;
  }
});

// Write data
const queryClient = useQueryClient();
const createIdiom = useMutation({
  mutationFn: async (newIdiom) => {
    const { data, error } = await supabase
      .from('idioms')
      .insert(newIdiom)
      .select()
      .single();
    if (error) throw error;
    return data;
  },
  onSuccess: () => {
    queryClient.invalidateQueries(['idioms']);
  }
});
Migration Checklist
  • Install @supabase/supabase-js
  • Create supabaseClient.js utility
  • Migrate Idiom reads/writes (HIGH PRIORITY)
  • Migrate DailyCrossword queries (HIGH PRIORITY)
  • Migrate UserProgress tracking (HIGH PRIORITY)
  • Migrate VocabularyWord operations (MEDIUM)
  • Test all features after migration
  • Monitor error logs for any missed calls
Need Help?

Common Issues:

  • • Auth errors: Make sure you're still using base44.auth.me() for user data
  • • RLS errors: Check that Supabase RLS policies allow the operation
  • • Missing data: Verify data was migrated from Base44 to Supabase

Testing:

  • • Test as different user roles (student, teacher, admin)
  • • Check browser console for errors
  • • Monitor Supabase dashboard for query performance