Updated: October 19, 2025 Status: Phase 3 Complete ✅ (Backend Integration Ready)
This guide covers migrating the Scholar Dashboard from mock data to production Supabase backend.
What's Been Done:
- ✅ SQL migrations (scholar stats function, activity log table)
- ✅ Edge Functions (scholar-stats deployed)
- ✅ React hooks (useScholarStats, useActivityFeed, useScholarAuth)
- ✅ Component updates (ScholarPersonalDashboard using real data)
- ✅ Environment configuration (mock/real mode toggle)
What's Next:
- Switch from mock data to real data
- Test with production database
- Deploy to production
Ensure these migrations are applied to your Supabase project:
# Already applied by user
✅ 20251019_scholar_stats_function.sql
✅ 20251019_activity_log.sqlVerify migrations:
-- Check if function exists
SELECT proname FROM pg_proc WHERE proname = 'get_scholar_stats';
-- Check if activity_log table exists
SELECT tablename FROM pg_tables WHERE tablename = 'activity_log';
-- Verify realtime is enabled
SELECT * FROM pg_publication_tables WHERE pubname = 'supabase_realtime';# Already deployed by user
✅ supabase/functions/scholar-stats/index.tsVerify deployment:
# Check function exists
supabase functions list
# Test function locally
supabase functions serve scholar-stats
# Test with curl
curl -X POST https://zknbwylpnscmtwphmrbp.supabase.co/functions/v1/scholar-stats \
-H "Authorization: Bearer YOUR_ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"scholarId": "some-uuid"}'Ensure these Edge Functions exist (check supabase/functions/):
- ✅
scholar-stats- Scholar statistics -
get-similar-questions- Semantic matching (should already exist from Streamlit dashboard)
Check for get-similar-questions:
ls -la supabase/functions/get-similar-questions/File: scholar-admin-hub/.env.development
# Current (Mock Data Mode)
VITE_USE_MOCK_SCHOLAR_DATA=true
# Production (Real Data Mode)
VITE_USE_MOCK_SCHOLAR_DATA=falseTest locally:
cd scholar-admin-hub
npm run dev
# Navigate to http://localhost:5173/scholar/dashboard
# Check browser console for real data queriesBefore switching to real data, ensure you have test data:
-- Check scholars table has data
SELECT COUNT(*) FROM scholars;
-- Check question_submissions has data
SELECT COUNT(*) FROM question_submissions;
-- Check activity_log is populated
SELECT COUNT(*) FROM activity_log;Seed test data if needed:
-- Create test scholar
INSERT INTO scholars (id, full_name, email, primary_expertise, secondary_expertise)
VALUES (
gen_random_uuid(),
'Dr. Test Scholar',
'test@example.com',
ARRAY['Prayer', 'Fasting'],
ARRAY['Zakat', 'Hajj']
);
-- Create test question
INSERT INTO question_submissions (
question_text,
workflow_status,
user_urgency_level,
assigned_scholar_id,
ai_confidence_score
)
VALUES (
'How do I perform wudhu?',
'assigned',
'medium',
(SELECT id FROM scholars LIMIT 1),
0.85
);Checklist:
-
Scholar Stats:
// Open browser console on /scholar/dashboard // Should see API call to RPC function // Network tab: Filter for "get_scholar_stats"
-
Activity Feed:
// Check Network tab for "activity_log" query // Should see Supabase Realtime connection // Trigger status change to verify realtime updates
-
Questions Query:
// Check Network tab for "question_submissions" query // Should include join to scholars table // Verify filtering by assigned_scholar_id works
-
Authentication:
// If using Supabase Auth: // Should see GET /auth/v1/user request // Scholar ID should match auth.user().id
Current: Mock scholar ID ('current-scholar-id')
Target: Real Supabase Auth
If NOT using Supabase Auth yet:
- Dashboard will work with
VITE_USE_MOCK_SCHOLAR_DATA=false - Stats will be fetched but scholar ID will be mock
- Next phase: Implement proper auth
If using Supabase Auth:
- Scholar's
idmust match their authuser.id - Update
scholarstable to link to auth users:
-- Option 1: Use auth.uid() as scholar ID
ALTER TABLE scholars DROP CONSTRAINT IF EXISTS scholars_pkey;
ALTER TABLE scholars ALTER COLUMN id SET DEFAULT gen_random_uuid();
-- Option 2: Add separate auth_user_id column
ALTER TABLE scholars ADD COLUMN auth_user_id UUID REFERENCES auth.users(id);# 1. Start dev server
cd scholar-admin-hub
npm run dev
# 2. Open browser
# Navigate to: http://localhost:5173/scholar/dashboard
# 3. Check browser console
# Should see:
# - "Auth state changed: SIGNED_IN" (if using auth)
# - Network requests to Supabase RPC functions
# - Realtime subscription connectedScenario 1: Scholar Stats
1. Navigate to /scholar/dashboard
2. Check "Pending Review" card shows real count
3. Verify "Completed This Week" updates
4. Confirm stats refresh every 60 seconds
Scenario 2: Activity Feed
1. Open dashboard in two browser tabs
2. In Tab 1: Change question status
3. In Tab 2: Activity feed should update in real-time
4. Verify "Live" badge shows green pulse
Scenario 3: Question Filters
1. Navigate to /scholar (Question Queue)
2. Filter by status, urgency, scholar
3. Verify queries use Supabase filters (not client-side)
4. Check Network tab for .in() and .eq() operations
Symptoms: Stats show 0 or spinner forever
Solutions:
// Check browser console for errors
// Common issues:
// 1. RPC function not found
// → Run migration again: supabase db push
// 2. No data in tables
// → Seed test data (see Step 2)
// 3. Auth user not linked to scholar
// → Check scholars.id matches auth.uid()Symptoms: "No recent activity" message
Solutions:
-- Check if activity_log has data
SELECT * FROM activity_log ORDER BY created_at DESC LIMIT 10;
-- If empty, trigger an update
UPDATE question_submissions
SET workflow_status = 'in_review'
WHERE id = 'some-question-id';
-- Verify trigger fired
SELECT * FROM activity_log ORDER BY created_at DESC LIMIT 1;Symptoms: Activity feed doesn't update automatically
Solutions:
-- 1. Verify realtime is enabled
ALTER PUBLICATION supabase_realtime ADD TABLE activity_log;
-- 2. Check Supabase dashboard
-- Settings → API → Realtime → Check "activity_log" is enabled
-- 3. Check browser console
// Should see: "Realtime connection established"
// If not, check VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEYSymptoms: Questions load but details fail
Solutions:
// Check if question_submissions query includes scholar join
// Expected query:
.from('question_submissions')
.select('*, scholars(*)')
// If missing scholars data:
// 1. Verify foreign key: assigned_scholar_id references scholars(id)
// 2. Check RLS policies allow reading scholars tableAdd React Query DevTools for debugging:
npm install @tanstack/react-query-devtools// In App.tsx
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
<QueryClientProvider client={queryClient}>
<ScholarAuthProvider>
{/* ... routes ... */}
<ReactQueryDevtools initialIsOpen={false} />
</ScholarAuthProvider>
</QueryClientProvider>- Scholar Stats Query: Should complete in <200ms
- Questions Query: Should complete in <500ms (with pagination)
- Activity Feed: Should complete in <300ms
- Realtime Latency: <2s from trigger to update
Check query performance:
// Open React Query DevTools
// Look for:
// - Query status (success/error/loading)
// - Fetch duration
// - Cache hits vs misses
// - Stale time remainingFile: scholar-admin-hub/.env.production
# Supabase Configuration
VITE_SUPABASE_URL=https://zknbwylpnscmtwphmrbp.supabase.co
VITE_SUPABASE_ANON_KEY=your_anon_key_here
# Scholar Dashboard - PRODUCTION MODE
VITE_USE_MOCK_SCHOLAR_DATA=false
# Optional: Service role key (only if needed for admin functions)
# NEVER expose this in client bundle
# SUPABASE_SERVICE_ROLE_KEY=your_service_role_key# 1. Build production bundle
cd scholar-admin-hub
npm run build
# 2. Verify build output
ls -la dist/
# 3. Deploy (Netlify example)
netlify deploy --prod --dir=dist
# 4. Verify deployment
curl https://your-scholar-dashboard.netlify.app/scholar/dashboard- Dashboard loads without errors
- Stats display real data
- Activity feed shows recent activity
- Realtime updates work
- Question filters work
- No console errors
- No CORS errors
- Auth redirects work (if applicable)
Ensure Row Level Security is enabled:
-- Enable RLS on scholars table
ALTER TABLE scholars ENABLE ROW LEVEL SECURITY;
-- Policy: Scholars can read all scholars (for directory)
CREATE POLICY "Scholars can view all scholars"
ON scholars FOR SELECT
TO authenticated
USING (true);
-- Enable RLS on question_submissions
ALTER TABLE question_submissions ENABLE ROW LEVEL SECURITY;
-- Policy: Scholars can view questions assigned to them
CREATE POLICY "Scholars can view assigned questions"
ON question_submissions FOR SELECT
TO authenticated
USING (assigned_scholar_id = auth.uid());
-- Policy: Scholars can update their assigned questions
CREATE POLICY "Scholars can update assigned questions"
ON question_submissions FOR UPDATE
TO authenticated
USING (assigned_scholar_id = auth.uid());
-- Enable RLS on activity_log
ALTER TABLE activity_log ENABLE ROW LEVEL SECURITY;
-- Policy: Scholars can view all activity
CREATE POLICY "Scholars can view all activity"
ON activity_log FOR SELECT
TO authenticated
USING (true);- ✅
VITE_SUPABASE_ANON_KEY- Safe to expose (client-side) - ❌
SUPABASE_SERVICE_ROLE_KEY- NEVER expose in client bundle- Only use in Edge Functions
- Never include in VITE_ variables
-
Full Authentication:
- Implement Supabase Auth sign-in
- Add scholar profile management
- Role-based access control (scholar vs admin)
-
Enhanced Realtime:
- Question locking indicators (see who's editing)
- Collaborative editing
- Push notifications
-
Analytics:
- Scholar performance dashboard
- Question complexity scoring
- Response quality metrics
-
Optimizations:
- Implement infinite scroll pagination
- Add optimistic updates (update UI before API response)
- Background sync for offline mode
Issues: Check browser console and Network tab first
Migrations: See supabase/migrations/ for SQL schemas
Hooks: See scholar-admin-hub/src/scholar/hooks/ for API integration
Docs: See scholar-admin-hub/src/scholar/docs/BACKEND_API.md
Migration Complete ✅ Created: October 19, 2025 Purpose: Smooth transition from Streamlit (Python) to React 19 (TypeScript)