8.3 KiB
Flask Backend Auto-Detection Implementation
Summary
Implemented automatic detection and fallback between Flask backend (SQLite) and IndexedDB storage based on Docker environment variables. The system intelligently selects the appropriate storage backend at runtime without requiring code changes or rebuilds.
Changes Made
1. Storage Adapter System (src/lib/storage-adapter.ts)
Created a new unified storage adapter with three implementations:
-
FlaskBackendAdapter: HTTP client for Flask backend API
- Health check with 3-second timeout
- Full CRUD operations via REST API
- Export/import capabilities
- Statistics endpoint integration
-
IndexedDBAdapter: Browser-side storage
- Standard IndexedDB operations
- Async/await interface
- Object store management
-
AutoStorageAdapter: Smart detection and routing
- Checks environment variables (
USE_FLASK_BACKEND,VITE_USE_FLASK_BACKEND) - Tests Flask backend availability via
/healthendpoint - Falls back to IndexedDB if Flask unavailable
- Migration tools between backends
- Checks environment variables (
2. Updated Storage Library (src/lib/storage.ts)
Simplified the storage interface to use the new adapter:
- Removed complex dual-storage logic
- Clean async/await API
- Added
getBackendType()to check current backend - Migration methods for switching backends
3. Storage Management UI (src/components/StorageSettings.tsx)
Complete rewrite with:
- Backend type indicator (Flask vs IndexedDB)
- Storage statistics display
- Migration controls with URL input
- Clear backend-specific actions
- Real-time status updates
4. Docker Configuration
Environment Variables (.env.example)
VITE_USE_FLASK_BACKEND=false
VITE_FLASK_BACKEND_URL=http://localhost:5001
Docker Compose (docker-compose.yml)
frontend:
environment:
- USE_FLASK_BACKEND=true
- FLASK_BACKEND_URL=http://backend:5001
depends_on:
- backend
Entrypoint Script (docker-entrypoint.sh)
- Injects runtime environment variables into HTML
- Creates
runtime-config.jswith configuration - No rebuild required for config changes
Updated HTML (index.html)
- Loads
runtime-config.jsbefore app initialization - Environment variables available as
window.USE_FLASK_BACKENDandwindow.FLASK_BACKEND_URL
5. Documentation
Created docs/STORAGE_BACKEND.md covering:
- Storage backend options and tradeoffs
- Configuration for development and production
- Docker deployment examples
- Migration procedures
- API reference
- Troubleshooting guide
- Performance considerations
- Security notes
Updated README.md with:
- Storage backend configuration section
- Quick start for both backends
- Migration information
How It Works
Automatic Detection Flow
-
App Starts
StorageAdapter initializes ↓ Check USE_FLASK_BACKEND environment variable ↓ If true → Test Flask backend availability ↓ Success → Use FlaskBackendAdapter (with IndexedDB fallback ready) ↓ Failure → Use IndexedDBAdapter (with warning) -
Runtime Fallback (NEW)
Operation called (get/set/delete/keys/clear) ↓ Try Flask backend operation ↓ Success → Return result ↓ Failure → Automatically retry with IndexedDB fallback ↓ Log warning on first fallback (once per session) ↓ Return result from IndexedDB -
Runtime Configuration
Docker container starts ↓ docker-entrypoint.sh runs ↓ Inject environment variables into runtime-config.js ↓ HTML loads runtime-config.js ↓ Variables available to StorageAdapter -
Storage Operations
App calls storage.get('key') ↓ AutoStorageAdapter routes to active backend ↓ Flask: HTTP request to /api/storage/key IndexedDB: IndexedDB transaction ↓ Return data to app
Environment Variable Priority
- Docker runtime:
window.USE_FLASK_BACKEND(set by entrypoint script) - Vite environment:
import.meta.env.VITE_USE_FLASK_BACKEND - Default:
false(use IndexedDB)
Usage Examples
Development with IndexedDB (Default)
npm run dev
No configuration needed. All data stored in browser.
Development with Flask Backend
# Terminal 1: Start Flask backend
cd backend
python app.py
# Terminal 2: Configure and start frontend
echo "VITE_USE_FLASK_BACKEND=true" > .env
echo "VITE_FLASK_BACKEND_URL=http://localhost:5001" >> .env
npm run dev
Production with Docker
# Start both services
docker-compose up -d
# Environment variables in docker-compose.yml:
# USE_FLASK_BACKEND=true
# FLASK_BACKEND_URL=http://backend:5001
Migration Between Backends
import { storage } from '@/lib/storage'
// Check current backend
const backend = storage.getBackendType() // 'flask' or 'indexeddb'
// Migrate IndexedDB → Flask
const count = await storage.migrateToFlask('http://localhost:5001')
console.log(`Migrated ${count} items`)
// Page reloads to use Flask backend
// Migrate Flask → IndexedDB
const count = await storage.migrateToIndexedDB()
console.log(`Migrated ${count} items`)
// Page reloads to use IndexedDB
Flask Backend API
All endpoints work consistently regardless of storage backend:
# Health check
GET /health
# Storage operations
GET /api/storage/keys # List all keys
GET /api/storage/<key> # Get value
PUT /api/storage/<key> # Set value
DELETE /api/storage/<key> # Delete key
POST /api/storage/clear # Clear all
GET /api/storage/export # Export JSON
POST /api/storage/import # Import JSON
GET /api/storage/stats # Statistics
Benefits
For Development
- No server required: Default IndexedDB works out of the box
- Fast iteration: Browser storage with instant updates
- Offline capable: Work without internet connection
- Easy debugging: Chrome DevTools IndexedDB inspector
For Production
- Persistent storage: Data survives browser clears
- Multi-device: Access data from any browser
- Backup ready: SQLite file can be backed up
- Scalable: Easy to migrate to PostgreSQL later
For Deployment
- Zero configuration: Works with or without backend
- Flexible: Change backend without rebuilding image
- Graceful fallback: If backend fails, uses IndexedDB
- Docker-friendly: Environment variables configure everything
Testing
The implementation includes:
- Automatic fallback testing: If Flask backend unavailable, falls back to IndexedDB with console warning
- Health check: 3-second timeout prevents hanging
- Migration validation: Confirms data integrity during migration
- Backend detection: Logs selected backend to console for debugging
Future Enhancements
Potential improvements identified:
- PostgreSQL/MySQL support: Add database adapters
- Real-time sync: WebSocket for live updates
- Authentication: Add user auth to Flask backend
- Encryption: Encrypt sensitive data at rest
- Caching: Add Redis layer for performance
- Multi-tenancy: Support multiple users/teams
Breaking Changes
None. The implementation is fully backward compatible:
- Existing IndexedDB data continues to work
- No API changes required
- Optional feature that can be ignored
Files Modified
src/lib/storage-adapter.ts(NEW)src/lib/storage.ts(UPDATED)src/components/StorageSettings.tsx(UPDATED)index.html(UPDATED)docker-compose.yml(UPDATED).env.example(NEW)docker-entrypoint.sh(NEW)docs/STORAGE_BACKEND.md(NEW)README.md(UPDATED)
Success Criteria
✅ Auto-detects Flask backend via environment variable
✅ Falls back to IndexedDB if backend unavailable
✅ Works without any configuration (IndexedDB default)
✅ Docker environment variables configure backend
✅ Migration tools switch between backends
✅ No code changes or rebuilds required
✅ Full backward compatibility maintained
✅ Comprehensive documentation provided
Conclusion
The implementation successfully provides flexible storage backend selection with intelligent auto-detection and graceful fallback. Users can now deploy CodeForge with or without a backend server, and switch between storage backends at any time through environment variables or the UI.