Files
thrilltrack-explorer/docs/TROUBLESHOOTING.md
gpt-engineer-app[bot] bcba0a4f0c Add documentation to files
2025-10-21 14:41:42 +00:00

13 KiB

Troubleshooting Guide

Common issues and their solutions for ThrillWiki.


Authentication Issues

Cannot Sign In

Symptom: Sign in button does nothing or shows error

Possible Causes:

  1. Invalid credentials
  2. Email not verified
  3. Account banned/deactivated
  4. Supabase connection error

Solutions:

// Check browser console for errors
// Look for auth errors in console

// Verify Supabase connection
const { data, error } = await supabase.auth.getSession();
console.log('Session:', data, error);

// Check if email verified (if required)
SELECT email, email_confirmed_at FROM auth.users WHERE email = '[user-email]';

MFA Not Working

Symptom: MFA code not accepted or not prompted

Possible Causes:

  1. Time sync issue (TOTP codes are time-based)
  2. Wrong factor ID
  3. Challenge not created
  4. AAL level not checked

Solutions:

// Verify device time is correct (CRITICAL for TOTP)
// Check enrolled factors
const { data } = await supabase.auth.mfa.listFactors();
console.log('Enrolled factors:', data);

// Create challenge manually
const factor = data.totp[0];
const { data: challenge } = await supabase.auth.mfa.challenge({
  factorId: factor.id
});

// Verify code
const { error } = await supabase.auth.mfa.verify({
  factorId: factor.id,
  challengeId: challenge.id,
  code: '[6-digit-code]'
});

Session Expired

Symptom: User logged out unexpectedly

Possible Causes:

  1. Session timeout (default 1 hour)
  2. Token refresh failed
  3. Multiple tabs/windows
  4. AAL2 expired (MFA users)

Solutions:

// Check session status
const { data: { session } } = await supabase.auth.getSession();
if (!session) {
  // Redirect to login
}

// Refresh session manually
const { data, error } = await supabase.auth.refreshSession();

// Monitor auth state changes
supabase.auth.onAuthStateChange((event, session) => {
  console.log('Auth event:', event, session);
});

Submission Issues

Submission Not Appearing in Queue

Symptom: Created submission doesn't show in moderation queue

Possible Causes:

  1. Database write failed
  2. Status filter hiding submission
  3. RLS blocking view
  4. Realtime subscription not connected

Solutions:

-- Check if submission created
SELECT * FROM content_submissions 
WHERE user_id = '[user-id]' 
ORDER BY created_at DESC LIMIT 5;

-- Check submission items
SELECT * FROM submission_items 
WHERE submission_id = '[submission-id]';

-- Check RLS policies
SET LOCAL ROLE authenticated;
SET LOCAL "request.jwt.claims" = '{"sub": "[moderator-user-id]"}';
SELECT * FROM content_submissions WHERE status = 'pending';

Cannot Approve Submission

Symptom: Approve button disabled or approval fails

Possible Causes:

  1. Lock expired
  2. No active lock
  3. Dependencies not approved
  4. Edge function error

Solutions:

// Check lock status
const { data: submission } = await supabase
  .from('content_submissions')
  .select('*, locked_until, assigned_to')
  .eq('id', submissionId)
  .single();

if (new Date(submission.locked_until) < new Date()) {
  console.error('Lock expired');
}

// Check dependencies
const { data: items } = await supabase
  .from('submission_items')
  .select('*, depends_on')
  .eq('submission_id', submissionId);

const blocked = items.filter(item => 
  item.depends_on && 
  items.find(dep => dep.id === item.depends_on && dep.status !== 'approved')
);
console.log('Blocked items:', blocked);

Image Upload Fails

Symptom: Image upload error or stuck at uploading

Possible Causes:

  1. File too large (>10MB)
  2. Invalid file type
  3. CloudFlare API error
  4. Network error
  5. CORS issue

Solutions:

// Check file size and type
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];

if (file.size > MAX_FILE_SIZE) {
  throw new Error('File too large');
}
if (!ALLOWED_TYPES.includes(file.type)) {
  throw new Error('Invalid file type');
}

// Check CloudFlare credentials
console.log('CF Account Hash:', import.meta.env.VITE_CLOUDFLARE_ACCOUNT_HASH);

// Test edge function
const { data, error } = await supabase.functions.invoke('upload-image', {
  body: { action: 'get-upload-url' }
});
console.log('Upload URL response:', data, error);

// Check network tab for CORS errors

Moderation Queue Issues

Lock Stuck

Symptom: Submission locked but moderator not actively reviewing

Possible Causes:

  1. Moderator closed browser without releasing lock
  2. Lock extension failed
  3. Database lock not expired

Solutions:

-- Find stuck locks
SELECT 
  id,
  submission_type,
  assigned_to,
  assigned_at,
  locked_until,
  EXTRACT(EPOCH FROM (NOW() - locked_until))/60 AS minutes_over
FROM content_submissions
WHERE locked_until IS NOT NULL
  AND locked_until < NOW()
  AND status = 'pending';

-- Release stuck lock (as admin)
UPDATE content_submissions
SET assigned_to = NULL,
    assigned_at = NULL,
    locked_until = NULL
WHERE id = '[submission-id]';

Realtime Not Working

Symptom: Queue doesn't update with new submissions

Possible Causes:

  1. Realtime subscription not connected
  2. RLS blocking realtime
  3. Filter mismatch
  4. Subscription channel wrong

Solutions:

// Check subscription status
const subscription = supabase
  .channel('moderation_queue')
  .on('postgres_changes', {
    event: '*',
    schema: 'public',
    table: 'content_submissions',
    filter: 'status=eq.pending'
  }, payload => {
    console.log('Realtime update:', payload);
  })
  .subscribe((status) => {
    console.log('Subscription status:', status);
  });

// Verify RLS allows realtime
SELECT * FROM content_submissions WHERE status = 'pending';
-- If this works, realtime should too

Versioning Issues

Version Not Created

Symptom: Entity updated but no version record

Possible Causes:

  1. Trigger not firing
  2. Session variables not set
  3. Trigger conditions not met
  4. Database error

Solutions:

-- Check if trigger exists
SELECT tgname, tgenabled 
FROM pg_trigger 
WHERE tgrelid = 'parks'::regclass;

-- Check session variables during update
SELECT 
  current_setting('app.current_user_id', true) AS user_id,
  current_setting('app.submission_id', true) AS submission_id;

-- Manual version creation (as admin)
INSERT INTO park_versions (
  park_id, version_number, created_by, change_type,
  name, slug, description, -- ... all fields
)
SELECT 
  id, 
  COALESCE((SELECT MAX(version_number) FROM park_versions WHERE park_id = p.id), 0) + 1,
  '[user-id]',
  'updated',
  name, slug, description -- ... all fields
FROM parks p
WHERE id = '[park-id]';

Version Comparison Fails

Symptom: Cannot compare versions or diff empty

Possible Causes:

  1. Version IDs invalid
  2. Function error
  3. No changes between versions

Solutions:

-- Verify versions exist
SELECT version_id, version_number, change_type 
FROM park_versions 
WHERE park_id = '[park-id]'
ORDER BY version_number DESC;

-- Test diff function
SELECT get_version_diff(
  'park',
  '[from-version-id]'::UUID,
  '[to-version-id]'::UUID
);

-- If null, no changes detected
-- Check if fields actually different
SELECT 
  (SELECT name FROM park_versions WHERE version_id = '[from]') AS old_name,
  (SELECT name FROM park_versions WHERE version_id = '[to]') AS new_name;

Performance Issues

Slow Queries

Symptom: Pages load slowly, timeouts

Possible Causes:

  1. Missing indexes
  2. N+1 queries
  3. Large dataset
  4. Complex joins

Solutions:

-- Find slow queries
SELECT 
  query,
  calls,
  total_exec_time,
  mean_exec_time,
  max_exec_time
FROM pg_stat_statements
WHERE mean_exec_time > 100
ORDER BY mean_exec_time DESC
LIMIT 20;

-- Add indexes
CREATE INDEX idx_rides_park_status ON rides(park_id, status);
CREATE INDEX idx_submissions_status_type ON content_submissions(status, submission_type);

-- Analyze query plan
EXPLAIN ANALYZE
SELECT * FROM rides WHERE park_id = '[park-id]' AND status = 'operating';

React Query Stale Data

Symptom: UI shows old data after update

Possible Causes:

  1. Cache not invalidated
  2. Stale time too long
  3. Background refetch disabled

Solutions:

// Invalidate specific queries after mutation
const mutation = useMutation({
  mutationFn: updatePark,
  onSuccess: () => {
    queryClient.invalidateQueries(['parks', parkId]);
    queryClient.invalidateQueries(['parks']); // List
  }
});

// Force refetch
await queryClient.refetchQueries(['parks']);

// Disable cache for testing
const { data } = useQuery({
  queryKey: ['parks'],
  queryFn: fetchParks,
  staleTime: 0,
  gcTime: 0,
});

Build/Deploy Issues

Build Fails

Symptom: npm run build errors

Possible Causes:

  1. TypeScript errors
  2. Missing dependencies
  3. Environment variables missing
  4. Out of memory

Solutions:

# Type check first
npm run typecheck

# Clear cache
rm -rf node_modules dist .next
npm install

# Build with verbose logs
npm run build -- --verbose

# Increase memory limit
NODE_OPTIONS=--max_old_space_size=4096 npm run build

Edge Function Fails

Symptom: 500 error from edge function

Possible Causes:

  1. Secrets not set
  2. Syntax error
  3. Timeout
  4. Memory limit

Solutions:

# Test locally
supabase functions serve upload-image

# Check logs
supabase functions logs upload-image

# Verify secrets
supabase secrets list

# Set secrets
supabase secrets set CLOUDFLARE_API_TOKEN=[value]

Database Issues

RLS Blocking Query

Symptom: Query returns empty when data exists

Possible Causes:

  1. User not authenticated
  2. Wrong user role
  3. Policy conditions not met
  4. AAL level insufficient

Solutions:

-- Test as authenticated user
SET LOCAL ROLE authenticated;
SET LOCAL "request.jwt.claims" = '{"sub": "[user-id]", "role": "authenticated"}';

-- Check policies
SELECT * FROM pg_policies WHERE tablename = 'content_submissions';

-- Disable RLS temporarily (DEVELOPMENT ONLY)
ALTER TABLE content_submissions DISABLE ROW LEVEL SECURITY;
-- Remember to re-enable!

Migration Fails

Symptom: supabase db push fails

Possible Causes:

  1. Conflicting constraints
  2. Data violates new schema
  3. Circular dependencies
  4. Permission issues

Solutions:

-- Check for constraint violations
SELECT * FROM parks WHERE name IS NULL OR name = '';

-- Fix data before migration
UPDATE parks SET name = 'Unnamed Park' WHERE name IS NULL;

-- Drop constraints temporarily
ALTER TABLE parks DROP CONSTRAINT IF EXISTS parks_name_check;

-- Recreate after data fixed
ALTER TABLE parks ADD CONSTRAINT parks_name_check CHECK (name IS NOT NULL AND name != '');

User Reports

"I can't submit a park"

Checklist:

  1. Is user authenticated?
  2. Is user banned?
  3. Are all required fields filled?
  4. Is form validation passing?
  5. Check browser console for errors

"My submission disappeared"

Checklist:

  1. Check submission status in database
  2. Was it approved/rejected?
  3. Check notification logs
  4. Verify submission wasn't deleted

"I can't see the moderation queue"

Checklist:

  1. Is user a moderator?
  2. Is MFA completed (if enrolled)?
  3. Check RLS policies
  4. Verify user_roles table

Emergency Procedures

Database Locked Up

-- Find blocking queries
SELECT 
  blocked_locks.pid AS blocked_pid,
  blocked_activity.usename AS blocked_user,
  blocking_locks.pid AS blocking_pid,
  blocking_activity.usename AS blocking_user,
  blocked_activity.query AS blocked_query,
  blocking_activity.query AS blocking_query
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype
JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;

-- Kill blocking query (CAREFUL!)
SELECT pg_terminate_backend([blocking_pid]);

Edge Function Infinite Loop

# Stop all executions
supabase functions delete [function-name]

# Fix and redeploy
supabase functions deploy [function-name]

Out of Database Connections

-- Check active connections
SELECT count(*) FROM pg_stat_activity;

-- Kill idle connections
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
  AND state_change < NOW() - INTERVAL '5 minutes';

Getting Help

If stuck:

  1. Check Documentation

  2. Search Issues

    • GitHub Issues
    • Supabase Discord
    • Stack Overflow
  3. Ask for Help

    • Create detailed issue
    • Include error messages
    • Provide reproduction steps
    • Share relevant code/logs
  4. Contact Support

    • For critical production issues
    • Email: [support email]

Last Updated: 2025-01-20