Skip to content

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:

  1. Location Capture: GPS captures your coordinates with high accuracy
  2. Reverse Geocoding: Coordinates are converted to a readable address (e.g., "Rua de Caicoli, Dili")
  3. Image Processing: Photos are compressed to optimize storage and upload
  4. Images Uploaded to S3 FIRST: Images are pre-uploaded to AWS S3 before the report is created (optimized for slow connections in Timor-Leste)
  5. Report Created with S3 References: A lightweight JSON request creates the report with the already-uploaded image references
  6. Instant Confirmation: You receive immediate confirmation with a report number
  7. Background Processing: AI image validation → damage analysis → Hedera blockchain → embeddings run server-side
  8. 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.
  9. AI-Generated Titles: For relevant images, AI automatically generates descriptive titles (e.g., "Medium Pothole Detected") to help authorities prioritize.
  10. 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:

  1. Automatic Detection: App detects connectivity issues and switches to offline mode
  2. Local Storage: Report is saved to your device's local database (Hive)
  3. GPS Still Works: Location is captured accurately (GPS doesn't need internet)
  4. Coordinates Only: Address is not available (reverse geocoding needs internet)
  5. 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.high setting
  • 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 Message

You'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:

  1. Tap your profile icon (top right)
  2. Scroll to "Quick Actions"
  3. 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:

  1. Connectivity Restored: App detects internet is back
  2. Check for Pending Reports: Looks for reports with "Pending" or "Failed" status
  3. Validate Authentication: Checks if your login token is still valid
  4. Token Refresh: If token expired, attempts to refresh it
  5. Sequential Upload: Uploads reports one at a time (oldest first)
  6. Address Resolution: Performs reverse geocoding to add addresses
  7. Image Upload: Uploads all images for each report
  8. Cleanup: Deletes successfully synced reports from device

Sync Process Details

For Each Report (Images-First):

  1. Update status to "Syncing"
  2. Check if report has address
  3. If no address, perform reverse geocoding using OpenStreetMap
  4. Pre-upload images to S3 FIRST (POST /api/v1/reports/pre-upload-image) - heaviest operation
  5. Create report with S3 references (POST /api/v1/reports with pre_uploaded_images) - lightweight JSON
  6. 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)
  7. Update status to "Synced"
  8. Delete report and images from device immediately
  9. 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:

  1. Check if report has an address
  2. If no address, query OpenStreetMap with coordinates
  3. Get address (e.g., "Dili, Timor-Leste")
  4. Include address in backend request
  5. 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

  1. Turn OFF WiFi and mobile data
  2. Open app (should already be logged in)
  3. Tap "+" to create report
  4. Select issue type and take photo
  5. Add title and description
  6. Submit report
  7. See "Report saved offline!" message

Expected: Report appears in Offline Reports with "Pending" status

Test Scenario 2: View Offline Reports

  1. Go to Profile → Offline Reports
  2. See list of pending reports
  3. Tap a report to view details
  4. See coordinates (no address yet)

Expected: All report details visible, can edit/delete

Test Scenario 3: Auto-Sync

  1. Turn WiFi/mobile data back ON
  2. Wait a few seconds
  3. Watch reports sync automatically
  4. Reports disappear as they sync

Expected: Progress indicator shown, reports deleted after sync

Test Scenario 4: Backend Unreachable

  1. Have internet but backend server is down/unreachable
  2. Try to create a report
  3. App automatically falls back to offline mode
  4. 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 Database

Syncing 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 copy

Backend 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_VALIDATION environment 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 number

Upload 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 TypeAI AnalysisDescription
potholeYesAI detects damage type, severity, confidence
road_cracksYesAI detects damage type, severity, confidence
road_collapseYesAI detects damage type, severity, confidence
street_lightingYesAI detects issue type, severity, confidence
traffic_signageYesAI detects issue type, severity, confidence
drainageYesAI detects issue type, severity, confidence
floodingYesAI detects issue type, severity, confidence
debrisYesAI detects issue type, severity, confidence
otherYesAI 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:

FilePurpose
lib/providers/report_provider.dartReport creation (online/offline routing, images-first)
lib/services/report_service.dartAPI calls (preUploadImage, createReport)
lib/services/sync_service.dartOffline sync with images-first upload
lib/services/offline_service.dartHive local storage for offline reports
lib/services/api_service.dartHTTP client with auto token refresh on 401
lib/services/auth_validator.dartJWT validation (local, lenient offline)
lib/services/connectivity_monitor.dartNetwork status via DNS lookup
lib/services/location_service.dartGPS + reverse geocoding
lib/utils/image_compressor.dartImage compression before upload

Backend (FastAPI):

FilePurpose
app/api/v1/endpoints/reports.pyEndpoints (pre-upload, create, upload image)
app/services/s3_service.pyAWS S3 upload/download/thumbnail
app/services/hedera_service.pyHedera Consensus Service blockchain
app/services/bedrock_service.pyAWS Bedrock AI (image validation, damage detection, embeddings)
app/crud/report.pyDB CRUD for reports, images, locations
app/schemas/report.pyPydantic 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.

Built for Timor-Leste