---
description: "Supabase conventions for {{PROJECT_NAME}}"
alwaysApply: true
---

# Supabase Standards — {{PROJECT_NAME}}

## Row Level Security (RLS) awareness
- **ALWAYS** assume RLS is enabled — never write queries that assume full table access
- Test queries in the Supabase dashboard before implementing in Flutter
- If a query returns empty unexpectedly, check RLS policies first

## Queries
```dart
// ✅ Type-safe query with error handling
Future<List<Product>> getProducts() async {
  final response = await _supabase
    .from('products')
    .select('id, name, price, category_id, categories(name)')
    .eq('is_active', true)
    .order('created_at', ascending: false)
    .limit(50);
  return response.map(Product.fromMap).toList();
}
```

## Realtime subscriptions
```dart
StreamSubscription<List<Map<String, dynamic>>>? _sub;

void watchOrders(String userId) {
  _sub = _supabase
    .from('orders')
    .stream(primaryKey: ['id'])
    .eq('user_id', userId)
    .listen(
      (data) => _updateOrders(data),
      onError: (e) => _handleError(e),
    );
}

@override
void dispose() {
  _sub?.cancel(); // ALWAYS cancel in dispose()
  super.dispose();
}
```

## Auth session
- Use `supabase.auth.onAuthStateChange` stream — never poll auth state
- Persist session: `supabase-flutter` handles this automatically via secure storage
- `session.accessToken` expires — check `session.isExpired` before sensitive operations
