How Report Creation Works in LafaekStreet
This document explains the complete report creation system in the LafaekStreet mobile app, covering both online and offline scenarios.
Overview
LafaekStreet allows citizens to report infrastructure issues (potholes, flooding, broken street lights, etc.) to authorities. The app works both online and offline, ensuring users can document issues immediately regardless of internet connectivity.
Report Creation Modes
Online Mode (Internet Available + Backend Reachable)
When you have internet and the backend server is reachable:
- Location Capture: GPS captures your coordinates with high accuracy
- Reverse Geocoding: Coordinates are converted to a readable address (e.g., "Rua de Caicoli, Dili")
- Image Processing: Photos are compressed to optimize storage and upload
- Images Uploaded to S3 FIRST: Images are pre-uploaded to AWS S3 before the report is created (optimized for slow connections in Timor-Leste)
- Report Created with S3 References: A lightweight JSON request creates the report with the already-uploaded image references
- Instant Confirmation: You receive immediate confirmation with a report number
- Background Processing: AI image validation → damage analysis → Hedera blockchain → embeddings run server-side
- AI Image Validation: If the uploaded image is not relevant to infrastructure (selfie, food, etc.), the report is auto-rejected and the user is notified. Rejection uses high confidence thresholds (e.g., 95%) via Amazon Bedrock.
- AI-Generated Titles: For relevant images, AI automatically generates descriptive titles (e.g., "Medium Pothole Detected") to help authorities prioritize.
- Secure Blockchain Submission: Transactions are submitted to Hedera and signed using AWS KMS (ECC_SECG_P256K1) for tamper-proof security.
Offline Mode (No Internet OR Backend Unreachable)
When you don't have internet OR the backend server can't be reached:
- Automatic Detection: App detects connectivity issues and switches to offline mode
- Local Storage: Report is saved to your device's local database (Hive)
- GPS Still Works: Location is captured accurately (GPS doesn't need internet)
- Coordinates Only: Address is not available (reverse geocoding needs internet)
- Auto-Sync Later: Report automatically syncs when connectivity is restored
Important: The app automatically falls back to offline mode if the backend is unreachable, even if you have internet. This ensures you can always create reports.
Step-by-Step: Creating a Report
1. Authentication
Before creating any report (online or offline), you must be logged in:
- Online Login: Username/password sent to backend, JWT token received
- Token Storage: Token stored securely on device (encrypted)
- Offline Validation: Token validated locally without network (checks expiry)
- Token Expiry: If token expires, you must login again when online
Why this matters: Your user ID from the token is attached to every report, even offline ones.
2. Location Capture
The app captures your precise location:
GPS Accuracy:
- Uses
LocationAccuracy.highsetting - Captures latitude, longitude, and accuracy (in meters)
- Works completely offline (GPS satellites, not internet)
- Timeout: 30 seconds to get location
Permissions:
- App requests location permissions if not granted
- You must enable location services on your device
- Without location, you cannot create a report
Address Resolution:
- Online: Coordinates converted to address using OpenStreetMap
- Offline: Only coordinates saved (address added during sync)
3. Issue Details
You provide information about the issue:
Required Fields:
- Issue Type: Pothole, flooding, street light, traffic sign, etc.
- Severity: Low, medium, high, critical
- Title: Brief description (e.g., "Large pothole on main road")
- Description: Detailed explanation
- Images: Photos of the issue (at least one required)
Image Handling:
- Images compressed to 80% quality
- Maximum width: 1920 pixels
- Stored locally until uploaded
- Order of images is preserved
4. Saving the Report
Online Mode (Images-First):
Compress Images → Pre-Upload Images to S3 → Create Report with S3 refs → Receive Report Number → Done
(heavy, done first) (lightweight JSON) (background processing below)
Background Processing:
Download from S3 → AI Image Validation → Relevant? → YES → AI Damage Analysis → Hedera → Embeddings
→ NO → Auto-Reject + Notify User (STOP)Offline Mode:
Create Report → Save to Hive Database → Mark as "Pending" → Show Success MessageYou'll see different confirmation messages:
- Online: "Report submitted successfully! Report #12345"
- Offline: "Report saved offline! It will sync when you're back online."
Offline Reports Management
Viewing Offline Reports
To see your pending offline reports:
- Tap your profile icon (top right)
- Scroll to "Quick Actions"
- Tap "Offline Reports" (orange cloud icon)
You'll see a list showing:
- Report title
- Location (coordinates if no address yet)
- Issue type and severity
- Status badge (Pending, Syncing, Failed)
- Created date
- Edit and Delete buttons
Report Status
Each offline report has a status:
- Pending: Waiting to be synced (yellow/orange badge)
- Syncing: Currently uploading to backend (blue badge)
- Failed: Sync attempt failed, will retry (red badge)
- Synced: Successfully uploaded (report deleted from device)
Editing Offline Reports
You can edit a report if:
- Status is "Pending" or "Failed"
- Status is NOT "Syncing" (upload in progress)
Deleting Offline Reports
You can delete a report if:
- Status is "Pending" or "Failed"
- Status is NOT "Syncing"
When deleted:
- Report removed from local database
- Associated images deleted from device
- Cannot be recovered
Automatic Synchronization
How Auto-Sync Works
The app continuously monitors your internet connection:
- Connectivity Restored: App detects internet is back
- Check for Pending Reports: Looks for reports with "Pending" or "Failed" status
- Validate Authentication: Checks if your login token is still valid
- Token Refresh: If token expired, attempts to refresh it
- Sequential Upload: Uploads reports one at a time (oldest first)
- Address Resolution: Performs reverse geocoding to add addresses
- Image Upload: Uploads all images for each report
- Cleanup: Deletes successfully synced reports from device
Sync Process Details
For Each Report (Images-First):
- Update status to "Syncing"
- Check if report has address
- If no address, perform reverse geocoding using OpenStreetMap
- Pre-upload images to S3 FIRST (POST /api/v1/reports/pre-upload-image) - heaviest operation
- Create report with S3 references (POST /api/v1/reports with
pre_uploaded_images) - lightweight JSON - Backend triggers background processing:
- AI Image Validation (relevance check - if not relevant, auto-rejects report)
- AI damage analysis, Hedera blockchain, embeddings (only if image is relevant)
- Update status to "Synced"
- Delete report and images from device immediately
- Move to next report
Why Images First? In Timor-Leste, internet connections are slow and unreliable. Image uploads are the largest data transfer (up to 10MB per image). By uploading images first, the heaviest network operation completes while the connection is available. The report creation is just a small JSON payload (~1KB).
Important: Reports are uploaded sequentially (one at a time), not in parallel. This ensures reliability and allows you to track progress.
Sync Triggers
Sync happens automatically when:
- Internet connectivity is restored
- App is opened with pending reports and internet available
- You manually tap the sync button (refresh icon)
Sync Progress
While syncing, you'll see:
- Progress indicator showing "Syncing X of Y reports"
- Current report being uploaded
- Success/failure notifications
Handling Sync Failures
If a report fails to sync:
Automatic Retry:
- Status changed to "Failed"
- Error message stored with report
- Will retry on next connectivity event
- Maximum 3 retry attempts
After 3 Failed Attempts:
- You're notified to review the report
- Can manually retry or delete the report
- Other reports continue syncing
Common Failure Reasons:
- Network timeout
- Server error
- Invalid data
- Token expired and refresh failed
Stuck Reports Recovery
If a report gets stuck in "Syncing" status (app closed during sync, connection lost, etc.):
- Automatic Recovery: Reports stuck for more than 5 minutes are automatically reset to "Failed"
- Recovery Trigger: Happens when you open the Offline Reports screen
- After Recovery: Report appears in pending list and can be retried
Address Resolution for Offline Reports
The Problem
When you create a report offline, the app cannot convert GPS coordinates to a readable address because reverse geocoding requires internet.
The Solution
During Sync: The app automatically performs reverse geocoding:
- Check if report has an address
- If no address, query OpenStreetMap with coordinates
- Get address (e.g., "Dili, Timor-Leste")
- Include address in backend request
- Address stored in database just like online reports
Fallback: If reverse geocoding fails during sync, the report is still uploaded with coordinates only.
What You See
In Offline Reports List:
- If address available: "📍 Rua de Caicoli, Dili"
- If no address yet: "📍 -8.556856, 125.560314"
After Sync:
- Backend database has the address
- Authorities see the full address, not just coordinates
Data Storage and Persistence
Local Storage (Hive Database)
What's Stored:
- Report ID (UUID)
- User ID (from JWT token)
- Title, description, issue type, severity
- GPS coordinates (latitude, longitude, accuracy)
- Address (if available)
- Image file paths
- Sync status and metadata
- Created timestamp
- Sync attempt count and errors
Storage Location:
- App's private documents directory
- Encrypted and secure
- Persists across app restarts
- Survives device reboots
Storage Limits:
- Maximum 100MB for offline reports
- Warning at 80% capacity
- Cannot create new reports when full
- Sync to free up space
Image Storage
Image Files:
- Stored in app's private cache directory
- Compressed to reduce size
- Original quality preserved for upload
- Deleted after successful sync
Image Metadata:
- File path
- File size
- Dimensions
- Capture timestamp
- Order in report
Data Persistence
Your offline reports are safe:
- ✅ Survive app closure
- ✅ Survive app restart
- ✅ Survive device reboot
- ✅ Survive app updates
- ❌ Lost if app is uninstalled (unless backed up)
Authentication and Security
JWT Token Management
Token Storage:
- Stored in flutter_secure_storage (encrypted)
- Never logged or exposed
- Cleared on logout
Token Validation:
- Checked before creating offline reports
- Validated locally (no network needed)
- Expiry checked against device time
- Safety margin: 5 minutes before expiry
Token Refresh:
- Attempted automatically during sync
- Uses refresh token endpoint
- If refresh fails, you must login again
- Offline reports preserved until you login
Security Measures
Local Data:
- Hive database encrypted
- Images in app-private storage
- No external access without root/jailbreak
API Communication:
- HTTPS only
- JWT token in authorization header
- Request validation on backend
Error Handling
Common Errors and Solutions
"Authentication required":
- Your token expired
- Login again when online
- Offline reports will sync after login
"Location services disabled":
- Enable GPS in device settings
- Grant location permissions to app
- Cannot create reports without location
"Storage limit reached":
- Sync pending reports to free space
- Delete unnecessary offline reports
- Check storage usage in app settings
"Network error during sync":
- Check internet connection
- App will retry automatically
- Can manually retry from Offline Reports screen
"Failed to capture location":
- Move to area with better GPS signal
- Wait for GPS to acquire satellites
- Retry location capture
Graceful Degradation
The app handles failures gracefully:
- No address? → Use coordinates only
- Sync fails? → Retry later automatically
- Token expired? → Attempt refresh, then notify user
- Storage full? → Prevent new reports, suggest sync
- Corrupted data? → Isolate and skip, continue with others
Testing Offline Reports
Test Scenario 1: Create Offline Report
- Turn OFF WiFi and mobile data
- Open app (should already be logged in)
- Tap "+" to create report
- Select issue type and take photo
- Add title and description
- Submit report
- See "Report saved offline!" message
Expected: Report appears in Offline Reports with "Pending" status
Test Scenario 2: View Offline Reports
- Go to Profile → Offline Reports
- See list of pending reports
- Tap a report to view details
- See coordinates (no address yet)
Expected: All report details visible, can edit/delete
Test Scenario 3: Auto-Sync
- Turn WiFi/mobile data back ON
- Wait a few seconds
- Watch reports sync automatically
- Reports disappear as they sync
Expected: Progress indicator shown, reports deleted after sync
Test Scenario 4: Backend Unreachable
- Have internet but backend server is down/unreachable
- Try to create a report
- App automatically falls back to offline mode
- Report saved locally
Expected: Same behavior as no internet scenario
Architecture Overview
System Components
Presentation Layer:
- Report screens (create, view, list)
- Sync status widgets
- Offline indicators
- State management (Provider)
Business Logic Layer:
- OfflineService: Manage local reports
- SyncService: Orchestrate synchronization
- ConnectivityMonitor: Track network status
- AuthValidator: Validate tokens locally
- LocationService: Capture GPS and geocode
Data Layer:
- Hive database: Local storage
- API service: Backend communication
- Secure storage: Token storage
- File system: Image storage
Data Flow
Creating Offline Report:
User Input → ReportProvider → AuthValidator → LocationService
↓
OfflineService
↓
Hive DatabaseSyncing Reports (Images-First):
ConnectivityMonitor → SyncProvider → SyncService → AuthValidator
↓
Load from Hive
↓
For each report:
1. Reverse geocode
2. Pre-upload images to S3 (heavy, first)
3. Create report with S3 refs (lightweight)
4. Delete local copyBackend Processing Pipeline
Processing Priority Order
Priority 1 (SYNC): S3 Image Upload - Done first on client side, blocking
Priority 2 (SYNC): DB Report Creation - Fast JSON request, blocking
Priority 3 (SYNC): DB Image Records - Attached via pre_uploaded_images, blocking
Priority 4 (ASYNC): AI Image Validation - Background: relevance check (NEW)
└─ If NOT relevant → Auto-reject, notify user, STOP all processing
└─ If relevant → Continue to Priority 5
Priority 5 (ASYNC): AI Damage Detection - Background task (Bedrock Nova model)
Priority 6 (ASYNC): Hedera Status Update - Background task (after AI completes)
Priority 7 (ASYNC): Embedding Generation - Background task (multimodal vector)
Priority 8 (ASYNC): Hedera Blockchain - Background task (skipped if rejected)AI Image Validation Gate
Before any expensive processing (damage analysis, Hedera, embeddings), the server validates that the uploaded image is actually relevant to infrastructure problems:
- Relevant images: Road cracks, potholes, flooding, damaged signs, broken lights, drainage issues, debris, road collapse, or other infrastructure problems
- Irrelevant images: Selfies, food, animals, indoor scenes, documents, memes, etc.
- Auto-rejection: If the AI determines the image is irrelevant (confidence ≥ 70%, typically seen up to 95%), the report status is changed to
rejected, the user receives a notification explaining what was detected, and all further processing is skipped. - AI Title Generation: For validated reports, AI (Amazon Bedrock) generates a more specific title than the user's initial input, such as "Large Pothole" or "Severe Flooding".
- Blockchain Security: All report submissions and status updates are signed using AWS KMS (ECC_SECG_P256K1) before being sent to Hedera HCS.
- Fail-open: If the AI service fails or returns an error, the report proceeds normally (not rejected)
- Configuration: Can be toggled via
FEATURE_AI_IMAGE_VALIDATIONenvironment variable
API Endpoints for Report Creation
Pre-Upload Image (call FIRST for each image):
POST /api/v1/reports/pre-upload-image
Authorization: Bearer {token}
Content-Type: multipart/form-data
Body: file (image/jpeg, image/png, image/webp, max 10MB)
Response 200:
{
"s3_key": "pre-uploads/{user_id}/{uuid}.jpg",
"image_url": "https://bucket.s3.amazonaws.com/...",
"thumbnail_url": "https://bucket.s3.amazonaws.com/.../thumbnails/...",
"thumbnail_s3_key": "pre-uploads/{user_id}/thumbnails/{uuid}.jpg",
"file_size": 245760,
"content_type": "image/jpeg"
}Create Report (call AFTER images are uploaded):
POST /api/v1/reports
Authorization: Bearer {token}
Content-Type: application/json
Body:
{
"title": "Pothole on Main Street",
"description": "Large pothole causing traffic issues",
"issue_type": "pothole",
"severity": "high",
"latitude": -8.5569,
"longitude": 125.5603,
"address": "Rua de Comoro, Dili",
"pre_uploaded_images": [
{
"s3_key": "pre-uploads/{user_id}/{uuid}.jpg",
"image_url": "https://...",
"thumbnail_url": "https://...",
"file_size": 245760,
"content_type": "image/jpeg"
}
]
}
Response 201: Report with images, user info, and report numberUpload Image (Legacy) - still supported for direct upload:
POST /api/v1/reports/{report_id}/images
Authorization: Bearer {token}
Content-Type: multipart/form-data
Body: file (max 10MB)Issue Types and AI Analysis
| Issue Type | AI Analysis | Description |
|---|---|---|
pothole | Yes | AI detects damage type, severity, confidence |
road_cracks | Yes | AI detects damage type, severity, confidence |
road_collapse | Yes | AI detects damage type, severity, confidence |
street_lighting | Yes | AI detects issue type, severity, confidence |
traffic_signage | Yes | AI detects issue type, severity, confidence |
drainage | Yes | AI detects issue type, severity, confidence |
flooding | Yes | AI detects issue type, severity, confidence |
debris | Yes | AI detects issue type, severity, confidence |
other | Yes | AI detects issue type, severity, confidence |
Constraints
- Max 1 image per report
- Max 10MB per image file
- Allowed image types: JPEG, PNG, WebP
- Report number format:
LS-YYMMDD-XXXX
Key Technical Files
Flutter App:
| File | Purpose |
|---|---|
lib/providers/report_provider.dart | Report creation (online/offline routing, images-first) |
lib/services/report_service.dart | API calls (preUploadImage, createReport) |
lib/services/sync_service.dart | Offline sync with images-first upload |
lib/services/offline_service.dart | Hive local storage for offline reports |
lib/services/api_service.dart | HTTP client with auto token refresh on 401 |
lib/services/auth_validator.dart | JWT validation (local, lenient offline) |
lib/services/connectivity_monitor.dart | Network status via DNS lookup |
lib/services/location_service.dart | GPS + reverse geocoding |
lib/utils/image_compressor.dart | Image compression before upload |
Backend (FastAPI):
| File | Purpose |
|---|---|
app/api/v1/endpoints/reports.py | Endpoints (pre-upload, create, upload image) |
app/services/s3_service.py | AWS S3 upload/download/thumbnail |
app/services/hedera_service.py | Hedera Consensus Service blockchain |
app/services/bedrock_service.py | AWS Bedrock AI (image validation, damage detection, embeddings) |
app/crud/report.py | DB CRUD for reports, images, locations |
app/schemas/report.py | Pydantic schemas (ReportCreate, PreUploadedImage) |
Best Practices
For Users
Creating Reports:
- ✅ Take clear photos of the issue
- ✅ Provide detailed descriptions
- ✅ Select accurate issue type and severity
- ✅ Ensure GPS has good signal
- ✅ Create reports immediately when you see issues
Managing Offline Reports:
- ✅ Sync regularly to free storage
- ✅ Review failed reports and retry
- ✅ Delete duplicates or mistakes
- ✅ Keep app updated for bug fixes
Connectivity:
- ✅ Connect to WiFi when possible for faster sync
- ✅ Don't worry about offline mode - it works automatically
- ✅ Check Offline Reports screen periodically
For Developers
Testing:
- ✅ Test both online and offline scenarios
- ✅ Test connectivity changes during operations
- ✅ Test token expiry and refresh
- ✅ Test storage limits
- ✅ Test sync interruptions
Monitoring:
- ✅ Track sync success/failure rates
- ✅ Monitor storage usage patterns
- ✅ Log errors for debugging
- ✅ Analyze user behavior
Frequently Asked Questions
Q: Why do offline reports show coordinates instead of addresses?
A: Reverse geocoding (converting coordinates to addresses) requires internet. Offline reports show coordinates until they're synced, at which point the address is automatically added to the backend database.
Q: What happens if I close the app during sync?
A: The sync is interrupted, but reports are automatically recovered. Reports stuck in "Syncing" status for more than 5 minutes are reset to "Failed" and will retry on next sync.
Q: Can I edit a report after it starts syncing?
A: No, reports cannot be edited while syncing. You can only edit reports with "Pending" or "Failed" status.
Q: How long are offline reports kept on my device?
A: Until they're successfully synced to the backend. After successful sync, they're immediately deleted from your device.
Q: What if my token expires while I have offline reports?
A: The app will attempt to refresh your token during sync. If refresh fails, you'll need to login again. Your offline reports are preserved and will sync after you login.
Q: Can I create reports without internet?
A: Yes! That's the whole point of offline mode. As long as you're logged in (token not expired), you can create reports offline.
Q: Why does the app fall back to offline mode even when I have internet?
A: If the backend server is unreachable (down, network issues, etc.), the app automatically uses offline mode to ensure you can still create reports.
Q: How accurate are the GPS coordinates?
A: The app uses high-accuracy GPS mode, typically accurate to within 5-10 meters in open areas. Accuracy may be lower in buildings or areas with poor GPS signal.
Q: What happens if my report is auto-rejected?
A: If you submit an image that is not related to infrastructure problems (e.g., a selfie, food photo, or random image), the AI will detect this and automatically reject your report. You will receive a notification explaining what was detected in the image and why it was rejected. You can create a new report with a relevant photo of the actual infrastructure issue.
Q: What happens if sync fails 3 times?
A: After 3 failed attempts, you're notified to review the report. You can manually retry or delete it. The app won't automatically retry anymore to avoid wasting battery and data.
Summary
The LafaekStreet report creation system is designed to work reliably in all conditions:
- ✅ Always Available: Create reports online or offline
- ✅ Automatic Fallback: Switches to offline mode when backend unreachable
- ✅ Accurate Location: High-accuracy GPS works offline
- ✅ Auto-Sync: Reports sync automatically when connectivity restored
- ✅ Address Resolution: Addresses added during sync for offline reports
- ✅ Reliable: Handles failures gracefully with automatic retry
- ✅ Secure: Encrypted storage and secure authentication
- ✅ User-Friendly: Clear status indicators and progress updates
Whether you're in a remote area with no signal or the backend server is temporarily down, you can always document infrastructure issues immediately. Your reports will reach the authorities as soon as connectivity is available.
