quicui_supabase 2.0.1
quicui_supabase: ^2.0.1 copied to clipboard
Supabase implementation for QuicUI framework. Provides backend integration for dynamic UI rendering, real-time synchronization, and offline-first architecture.
QuicUI Supabase Plugin #
Supabase implementation for the QuicUI framework. Enables dynamic UI rendering, real-time synchronization, and offline-first architecture through Supabase cloud infrastructure.
Overview #
The QuicUI Supabase plugin provides a complete backend integration implementing the DataSource interface from QuicUI core. It handles:
- Screen Management: Fetch, save, search, and delete dynamic UI screens
- Real-Time Updates: Subscribe to live screen changes via WebSocket
- Offline Support: Queue operations when offline, auto-sync when reconnected
- Conflict Resolution: Intelligent handling of concurrent modifications
- PostgreSQL Backend: Leverage Supabase's PostgreSQL database for data persistence
- Authentication: Built-in Supabase Auth integration
Installation #
- Add to
pubspec.yaml:
dependencies:
quicui_supabase: ^2.0.0
- Configure Supabase in your project:
flutter pub add supabase_flutter
Quick Start #
1. Initialize Supabase #
import 'package:supabase_flutter/supabase_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(
url: 'https://your-project.supabase.co',
anonKey: 'your-anon-key',
);
runApp(const MyApp());
}
2. Register DataSource #
import 'package:quicui/quicui.dart';
import 'package:quicui_supabase/quicui_supabase.dart';
void setupQuicUI() async {
final dataSource = SupabaseDataSource(
supabaseUrl: 'https://your-project.supabase.co',
supabaseAnonKey: 'your-anon-key',
);
DataSourceProvider.instance.register(dataSource);
await dataSource.connect();
}
3. Use with QuicUI #
final repository = ScreenRepository(
dataSource: DataSourceProvider.instance.get(),
);
final screen = await repository.getScreen('home_screen');
final renderer = UIRenderer();
final widget = renderer.renderScreen(screen);
Usage Examples #
Fetch Screens #
final dataSource = DataSourceProvider.instance.get();
// Get single screen
final screen = await dataSource.fetchScreen('home_screen');
// Get multiple screens with pagination
final screens = await dataSource.fetchScreens(limit: 20, offset: 0);
// Search screens
final results = await dataSource.searchScreens('dashboard');
// Get total count
final count = await dataSource.getScreenCount();
Save/Update Screens #
final screen = Screen(
id: 'new_screen',
name: 'New Screen',
version: 1,
rootWidget: WidgetData(...),
metadata: null,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
isActive: true,
config: const ScreenConfig(),
);
await dataSource.saveScreen('new_screen', screen);
Real-Time Updates #
final stream = dataSource.subscribeToScreen('home_screen');
stream.listen((event) {
print('Event type: ${event.type}'); // insert, update, delete
print('Data: ${event.data.id}');
print('Timestamp: ${event.timestamp}');
});
// Unsubscribe when done
await dataSource.unsubscribe('home_screen');
Handle Offline Scenarios #
// Get pending items that failed to sync
final pendingItems = await dataSource.getPendingItems();
// Attempt to sync
final syncResult = await dataSource.syncData(pendingItems);
print('Synced: ${syncResult.synced}');
print('Failed: ${syncResult.failed}');
// Check specific errors
for (final error in syncResult.errors) {
print('Failed to ${error.operation}: ${error.error}');
}
Error Handling #
import 'package:quicui_supabase/quicui_supabase.dart';
try {
final screen = await dataSource.fetchScreen('missing');
} on ScreenNotFoundException catch (e) {
print('Screen not found: ${e.message}');
} on SupabaseDataSourceException catch (e) {
print('Supabase error: ${e.message}');
} on DataSourceException catch (e) {
print('Backend error: ${e.message}');
}
Database Schema #
The plugin expects the following Supabase tables:
screens table #
create table screens (
id text primary key,
name text not null,
version integer not null default 1,
root_widget jsonb not null,
metadata jsonb,
config jsonb,
is_active boolean default true,
created_at timestamp with time zone default now(),
updated_at timestamp with time zone default now()
);
-- Create index for search
create index screens_name_search on screens using gin(name gin_trgm_ops);
sync_queue table #
create table sync_queue (
id uuid primary key default gen_random_uuid(),
screen_id text not null,
operation text not null,
screen_data jsonb,
synced boolean default false,
retry_count integer default 0,
last_error text,
created_at timestamp with time zone default now(),
updated_at timestamp with time zone default now()
);
Enable Real-Time (Supabase UI) #
- Go to Database → Replication
- Enable real-time on
screenstable - Enable UPDATE, INSERT, DELETE events
Architecture #
QuicUI App
↓
ScreenRepository
↓
DataSourceProvider (Service Locator)
↓
SupabaseDataSource (This Plugin)
↓
Supabase Backend
├─ PostgreSQL (screens, sync_queue tables)
├─ Real-Time (WebSocket subscriptions)
└─ Auth (User authentication)
Features #
Screen Management #
- ✅
fetchScreen(screenId)- Get single screen - ✅
fetchScreens(limit, offset)- Paginated list - ✅
saveScreen(screenId, screen)- Create/update - ✅
deleteScreen(screenId)- Delete screen - ✅
searchScreens(query)- Full-text search - ✅
getScreenCount()- Total screen count
Real-Time Synchronization #
- ✅
subscribeToScreen(screenId)- Stream updates - ✅
unsubscribe(screenId)- Stop listening - ✅ WebSocket connections
- ✅ Automatic reconnection
Offline Support #
- ✅
getPendingItems()- Get queued operations - ✅
syncData(items)- Batch sync - ✅
resolveConflict(conflict)- Conflict resolution
Connection Management #
- ✅
connect()- Initialize connection - ✅
disconnect()- Cleanup - ✅
isConnected()- Check status
Testing #
Run tests with:
cd quicui_supabase
flutter test
Troubleshooting #
Connection Issues #
try {
await dataSource.connect();
} on SupabaseDataSourceException catch (e) {
print('Connection failed: ${e.message}');
print('Cause: ${e.originalError}');
}
Real-Time Not Working #
- Verify real-time is enabled on
screenstable - Check WebSocket connection in browser DevTools
- Ensure Supabase URL and key are correct
- Check Supabase project status/logs
Sync Failures #
final result = await dataSource.syncData(pendingItems);
for (final error in result.errors) {
print('${error.itemId}: ${error.error}');
}
Performance Tips #
- Use pagination:
fetchScreens(limit: 20, offset: 0) - Debounce search:
searchScreens(query)can be expensive - Subscribe only to needed screens
- Call
disconnect()when app closes - Use
isConnected()to check before operations
Migration from Direct Supabase #
If you're currently using Supabase directly in QuicUI:
// Before
final supabaseService = SupabaseService(...);
final screen = await supabaseService.getScreen('home');
// After
final dataSource = SupabaseDataSource(...);
DataSourceProvider.instance.register(dataSource);
final repository = ScreenRepository(dataSource: dataSource);
final screen = await repository.getScreen('home_screen');
API Reference #
See lib/src/supabase_data_source.dart for detailed API documentation.
Support #
License #
MIT License - See LICENSE file for details.
Related Packages #
- quicui - Main QuicUI framework
- supabase_flutter - Supabase client
- logger - Logging utility
❤️ Love QuicUI? #
If you're enjoying QuicUI and the Supabase plugin, consider supporting the development!
🚀 Why Support QuicUI? #
- 📚 Comprehensive documentation and guides
- �� Fast bug fixes and issue resolution
- 💡 New features and improvements based on community feedback
- 📞 Dedicated support and guidance
- 🎯 Long-term project sustainability
☕ Buy Me a Coffee #
Your support helps keep QuicUI thriving and enables faster development of new features!
Thank you for being part of the QuicUI community! 🙏