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