Scottish wildfire risk assessment mobile app with EFFIS integration
A Flutter mobile application that provides real-time wildfire risk assessment using data from the European Forest Fire Information System (EFFIS). The app delivers fire weather index (FWI) data with risk categorization for Scottish locations.
- Real-time FWI Data: Integration with EFFIS WMS GetFeatureInfo API
- Risk Assessment: Automatic risk level categorization (low, moderate, high, very high, extreme)
- Interactive Maps: Google Maps integration with fire incident markers (iOS crash-free ✅)
- iOS Integration: Complete crash-free solution with automated API key injection
- Cross-Platform Support: Works on iOS, Android, and web platforms
- Robust Error Handling: Comprehensive error management with retry logic
- Offline Resilience: Graceful handling of network issues with exponential backoff
- Demo Mode Transparency: Prominent "DEMO DATA" chip when using mock data (C4 compliance)
- Production Ready: 84.3% test coverage with 56/56 tests passing
- RiskLevel: Enum for wildfire risk categories with FWI thresholds
- ApiError: Structured error handling with reason categorization
- EffisFwiResult: Fire weather index data with location and temporal information
- EffisService: Abstract interface for FWI data retrieval
- EffisServiceImpl: Production implementation with EFFIS WMS integration
- WMS GetFeatureInfo API integration
- Exponential backoff retry logic
- Coordinate validation and transformation
- Comprehensive error mapping
- 56 tests passing (100% success rate)
- 36 model tests - Complete unit testing
- 13 service tests - Integration testing with mocked HTTP client
- 6 contract tests - Real fixture validation
- 1 fixture test - File integrity validation
| Component | Coverage | Status |
|---|---|---|
| Models | 94.2% | ✅ Excellent |
| Services | 84.7% | ✅ Good |
| Overall | 84.3% | ✅ Production Ready |
📊 Detailed Coverage Report: docs/TEST_COVERAGE.md
# Run all tests
flutter test
# Run with coverage
flutter test --coverage
# View coverage summary
lcov --summary coverage/lcov.info
# Generate HTML coverage report
genhtml coverage/lcov.info -o coverage/html# macOS (using Homebrew)
brew install lcov
# Ubuntu/Debian
sudo apt-get install lcov
# CentOS/RHEL
sudo yum install lcov-
Generate Coverage Data
flutter test --coverage- Creates
coverage/lcov.infowith detailed line coverage data - Includes all Dart files in
lib/directory - Excludes generated files and test files
- Creates
-
View Coverage Summary
lcov --summary coverage/lcov.info
- Displays overall coverage percentage
- Shows total lines found vs. hit
- Quick validation of coverage levels
-
Generate HTML Report
genhtml coverage/lcov.info -o coverage/html
- Creates browsable HTML report in
coverage/html/ - File-by-file coverage visualization
- Line-by-line coverage highlighting
- Access via
open coverage/html/index.html
- Creates browsable HTML report in
-
List Detailed Coverage
lcov --list coverage/lcov.info
- File-by-file coverage breakdown
- Individual file coverage percentages
- Useful for identifying low-coverage files
- Production Ready: ≥80% overall coverage ✅
- Excellent: ≥90% coverage
- Models: Target 95%+ (simple value objects)
- Services: Target 85%+ (complex business logic)
- Interactive Navigation: Click through directories and files
- Color-Coded Lines: Green (covered), Red (uncovered), Orange (partially covered)
- Function Coverage: Method-level coverage statistics
- Branch Coverage: Conditional logic coverage analysis
- Sortable Tables: Sort by coverage percentage, lines, functions
- Flutter SDK 3.0+
- Dart 3.0+
- iOS/Android development environment
dependencies:
flutter:
sdk: flutter
http: ^1.1.0 # HTTP client for API requests
dartz: ^0.10.1 # Functional programming (Either type)
equatable: ^2.0.5 # Value object equality
dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^5.4.2 # Mocking for unit tests
build_runner: ^2.4.7 # Code generation for mocks# Clone the repository
git clone <repository-url>
cd wildfire_mvp_v3
# Enable git hooks for auto-formatting (recommended)
git config core.hooksPath .githooks
# Install dependencies
flutter pub get
# Generate mock files
dart run build_runner build
# Verify code quality before committing (recommended)
dart format .
flutter analyze
# Run tests
flutter test
# Run the app (standard Flutter commands work automatically)
flutter run
# iOS with API keys (uses automatic injection via Xcode Build Phase)
flutter run -d ios --dart-define-from-file=env/dev.env.json📱 iOS Setup: For iOS Google Maps integration, see iOS Google Maps Integration Guide for complete setup instructions including API key configuration and crash-free deployment.
Controls whether the app uses live EFFIS data or mock data for testing.
Usage:
# Demo mode (default) - uses mock data, shows "DEMO DATA" chip
flutter run --dart-define=MAP_LIVE_DATA=false
# Production mode - uses live EFFIS data
flutter run --dart-define=MAP_LIVE_DATA=true
# Environment file approach
flutter run --dart-define-from-file=env/dev.env.jsonBehavior:
- false (default): Uses mock data, displays prominent amber "DEMO DATA" chip on map
- true: Uses live EFFIS WFS data, displays standard green/orange/blue source chip
CI Configuration:
The env/ci.env.json file defaults to MAP_LIVE_DATA=false to ensure tests run predictably with mock data.
Constitutional Compliance: This feature supports C4 (Trust & Transparency) by clearly indicating when demo/mock data is being used.
WildFire implements comprehensive accessibility features meeting WCAG 2.1 Level AA standards:
- ✅ Text Contrast: All text ≥4.5:1 contrast ratio
- ✅ UI Component Contrast: Interactive elements ≥3:1 contrast ratio
- ✅ Touch Targets: All interactive elements ≥44dp (iOS) / ≥48dp (Android)
- ✅ Screen Reader Support: Full semantic labels and announcements
- ✅ Dark Mode: System-aware theme switching with preserved contrast ratios
- ✅ Keyboard Navigation: Full keyboard accessibility (web)
WildFire uses a two-tier color system for semantic clarity:
| Palette | Purpose | Components |
|---|---|---|
| BrandPalette | App chrome, navigation, UI | AppBar, Buttons, TextFields, Cards, Chips |
| RiskPalette | Fire risk visualization only | RiskBanner, RiskResultChip |
Scottish-Themed Professional Colors:
// BrandPalette - Forest gradient (primary brand)
forest900: 0xFF0D4F48 // Deep forest (dark theme primary)
forest600: 0xFF287D71 // Primary brand color (light theme)
forest400: 0xFF39928A // Lighter variant
// Accent colors
mint400: 0xFF64C8BB // Success states
amber500: 0xFFF5A623 // Warning statesRisk Visualization Colors (RiskPalette - official wildfire risk scale):
veryLow: #00B3FF low: #2ECC71 moderate: #F1C40F
high: #E67E22 veryHigh: #E74C3C extreme: #C0392BAutomatically adapts to system preferences:
- Light Theme: Forest600 primary, offWhite surfaces, dark text
- Dark Theme: Forest400 primary, neutralGrey surfaces, light text
- Smooth Transitions: Instant theme switching without app restart
- Preserved Contrast: All WCAG 2.1 AA ratios maintained in both modes
// ✅ Correct: Use theme colors
Icon(Icons.home, color: Theme.of(context).colorScheme.primary)
Text('Welcome', style: TextStyle(color: Theme.of(context).colorScheme.onSurface))
// ✅ Correct: RiskPalette for risk widgets only
Container(color: RiskPalette.forLevel(RiskLevel.high)) // In RiskBanner
// ❌ Wrong: Ad-hoc colors violate consistency
Icon(Icons.home, color: Colors.green) // Use colorScheme insteadAll Material 3 components pre-themed for consistency:
- Buttons: ElevatedButton (primary), OutlinedButton (secondary), TextButton (tertiary)
- Input Fields: Consistent borders, labels, helper text, error states
- Navigation: AppBar, BottomNavigationBar with brand colors
- Feedback: SnackBars, Dialogs with accessible contrast
- 8 Golden Tests: Snapshot tests for themed components (light/dark)
- Automated Validation: CI/CD checks for theme consistency
- 65 Tests Passing: Comprehensive accessibility and theme coverage
📚 Detailed Guidelines: See docs/ux_cues.md for complete color system architecture and usage patterns.
- Endpoint:
https://ies-ows.jrc.ec.europa.eu/gwis - Service: WMS GetFeatureInfo
- Layer:
ecmwf.fwi(ECMWF Fire Weather Index) - Coordinate System: EPSG:3857 (Web Mercator)
- Format: GeoJSON FeatureCollection
- User-Agent:
WildFire/0.1 (prototype) - Accept:
application/json,*/*;q=0.8 - Timeout: 30 seconds (configurable)
- Retry Logic: Exponential backoff with jitter (max 10 retries)
lib/
├── models/
│ ├── api_error.dart # Error handling structures
│ ├── effis_fwi_result.dart # FWI data model
│ └── risk_level.dart # Risk categorization enum
├── services/
│ ├── effis_service.dart # Abstract service interface
│ └── effis_service_impl.dart # Production implementation
├── theme/
│ └── risk_palette.dart # UI color themes
└── main.dart # App entry point
test/
├── unit/
│ ├── models/ # Model unit tests
│ └── services/ # Service integration tests
├── contract/ # Contract tests with fixtures
└── fixtures/effis/ # JSON test fixtures
# Install dependencies
flutter pub get
# Run tests to verify setup
flutter test
# Start the application
flutter run- Make changes to models or services
- Run tests to verify functionality:
flutter test - Check coverage if needed:
flutter test --coverage
The app defaults to Scotland (low wildfire activity). To test with regions that typically have more fires:
# Test with Portugal (high summer fire activity)
flutter run -d android \
--dart-define=TEST_REGION=portugal \
--dart-define=MAP_LIVE_DATA=true
# Test with California
flutter run -d ios \
--dart-define=TEST_REGION=california \
--dart-define=MAP_LIVE_DATA=trueAvailable test regions: portugal, spain, greece, california, australia
📖 See docs/TEST_REGIONS.md for complete documentation including fire seasons, coordinates, and troubleshooting. 4. Commit changes with descriptive messages 5. Generate coverage reports for documentation
import 'package:wildfire_mvp_v3/services/effis_service_impl.dart';
import 'package:http/http.dart' as http;
// Initialize service
final httpClient = http.Client();
final effisService = EffisServiceImpl(httpClient: httpClient);
// Get FWI data for Edinburgh
final result = await effisService.getFwi(
lat: 55.9533,
lon: -3.1883,
timeout: Duration(seconds: 30),
maxRetries: 3,
);
// Handle result
result.fold(
(error) => print('Error: ${error.message}'),
(fwiResult) => print('FWI: ${fwiResult.fwi}, Risk: ${fwiResult.riskLevel}'),
);- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make changes and add tests
- Ensure tests pass:
flutter test - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
Documentation Consolidation Complete (Oct 28, 2025): Reduced from 30+ files to 26 comprehensive guides
- Google Maps API Setup ⭐ - Comprehensive setup guide (iOS/Android/Web, API keys, cost controls, EFFIS integration)
- iOS Google Maps Integration - Complete iOS setup, crash fixes, and best practices
- Cross-Platform Testing - Testing strategies across iOS, Android, and web
- Test Coverage Report - Comprehensive coverage analysis (executive summary, detailed analysis, debugging impact, roadmap)
- Integration Testing - Comprehensive testing methodology (strategies, GoogleMap limitations, CI/CD integration)
- Integration Test Results - Current status and manual procedures (test results, checklists, troubleshooting)
- Privacy Compliance - Constitutional gate compliance (C2, C3, C4)
- Security Audit - Security review and recommendations
- Web API Security - Secure API key management for web deployments
- macOS Web Support - Running on macOS with Google Maps via web
- Test Regions - Geographic testing regions and fire seasons
- UX Cues - User experience design guidelines
- Accessibility Statement - WCAG compliance and accessibility features
- Flutter Documentation - Official Flutter development guides
Documentation Quality: ✅ Production Ready - All essential workflows documented with comprehensive guides
- Version: MVP v3
- Status: ✅ Production Ready
- Test Coverage: 84.3% (56/56 tests passing)
- Last Updated: October 2, 2025
- Branch:
001-spec-a1-effisservice