# Traccar Client Rewrite - Specification **Date**: 2026-04-30 **Project**: traccar_client **Type**: Fresh Flutter + Native Android GPS tracking app --- ## 1. Project Overview - **Purpose**: Reliable background GPS location tracking app for Android that reports to a self-hosted Traccar server - **Target Platform**: Android only - **Traccar Protocol**: Standard HTTP-based protocol (compatible with any self-hosted Traccar server) --- ## 2. Architecture ### 2.1 Technology Stack | Layer | Technology | Responsibility | |-------|------------|----------------| | **UI** | Flutter | Settings screen, main screen, status/log viewer | | **Bridge** | Platform Channels | MethodChannel + EventChannel between Flutter and Android | | **Service** | Kotlin Android | Foreground service for reliable background tracking | | **Location** | FusedLocationProviderClient (Google Play Services) | GPS location acquisition | | **Storage** | Room (SQLite) | Offline location buffer + event log | | **Network** | OkHttp | HTTP POST to Traccar server | | **Background** | WorkManager | Heartbeat scheduling, periodic sync | ### 2.2 Data Flow ``` [FusedLocationProvider] ↓ [DistanceFilterProcessor] → (discard if within threshold) ↓ [LocationTrackingService] → [Room: locations buffer] ← (if offline) ↓ [TraccarHttpClient] → POST to server → [Room: mark synced] ↑ (when online) [WorkManager] → periodic sync attempt ``` --- ## 3. Components ### 3.1 Flutter UI Layer | Screen | Purpose | |--------|---------| | `main_screen.dart` | Toggle tracking on/off, display last location, speed, timestamp | | `settings_screen.dart` | All configuration options | | `status_screen.dart` | Event log viewer for debugging | | `preferences.dart` | SharedPreferences wrapper for settings persistence | ### 3.2 Platform Bridge | Class | Type | Purpose | |-------|------|---------| | `location_bridge.dart` | Flutter | Platform channel wrapper | | `BridgeModule.kt` | Kotlin | Registers MethodChannel + EventChannel | ### 3.3 Android Service Layer | Class | Purpose | |-------|---------| | `LocationTrackingService` | Foreground service with persistent notification | | `FusedLocationProvider` | Google Play Services location API wrapper | | `DistanceFilterProcessor` | Distance/interval/angle filtering with Haversine | | `HeartbeatScheduler` | Stationary heartbeat via WorkManager | | `AppDatabase` | Room database | | `LocationDao` | CRUD for buffered locations | | `EventLogDao` | CRUD for event log entries | | `TraccarHttpClient` | HTTP POST with retry and auth | | `ConnectivityReceiver` | Network change listener | | `Location` | Data model | --- ## 4. Settings | Setting | Type | Default | Description | |---------|------|---------|-------------| | `serverUrl` | String | `https://demo.traccar.org` | Traccar server URL | | `deviceId` | String | Auto-generated 8-digit | Device identifier | | `accuracy` | String | `HIGH` | GPS accuracy: HIGH/HIGH_ACCURACY/BALANCED/LOW | | `distanceFilter` | int | `75` | Min distance between reports (meters) | | `interval` | int | `300` | Time-based fallback filter (seconds) | | `heartbeat` | int | `60` | Stationary heartbeat interval (seconds) | | `offlineBuffer` | bool | `true` | Queue locations when offline | | `stopDetection` | bool | `true` | Auto-stop tracking when stationary | | `password` | String | `""` | Basic auth password for server | --- ## 5. Foreground Notification **Layout**: ``` ┌─────────────────────────────────────────┐ │ 📍 Traccar Client [ON/OFF] │ ├─────────────────────────────────────────┤ │ Lat: 37.7749 Lon: -122.4194 │ │ Speed: 45 km/h │ │ Last: 09:41:23 │ └─────────────────────────────────────────┘ ``` **Updates**: Notification content updates in real-time as locations are captured and sent. --- ## 6. Traccar Protocol **Endpoint**: `{serverUrl}/?id={deviceId}&lat={lat}&lon={lon}×tamp={ts}&speed={speed}&...` **Parameters**: - `id` - Device identifier - `lat` - Latitude - `lon` - Longitude - `timestamp` - Unix timestamp (milliseconds) - `speed` - Speed in km/h - `bearing` - Heading in degrees - `accuracy` - GPS accuracy in meters - `altitude` - Altitude in meters - `is_moving` - 1 if moving, 0 if stationary **Authentication**: HTTP Basic Auth if password is set. --- ## 7. Offline Buffering **When offline**: 1. Location is captured and passes filters 2. Location is saved to Room `locations` table with `synced=0` 3. App continues tracking and buffering **When connectivity restored**: 1. WorkManager triggers sync 2. All buffered locations are sent to server 3. Locations marked as `synced=1` --- ## 8. Heartbeat Behavior | State | Behavior | |-------|----------| | **Moving** | Normal location updates based on distance/interval filters | | **Stationary** | Heartbeat fires every N seconds (configurable), triggers single location fix | | **Stop detected** | Tracking auto-stops if `stopDetection=true`, heartbeat continues | --- ## 9. Event Log **Logged Events**: | Event Type | When Logged | |------------|-------------| | `LOCATION` | Location captured and accepted | | `FILTERED` | Location filtered (reason: distance/interval/angle) | | `SYNC` | Location successfully sent to server | | `HEARTBEAT` | Heartbeat event fired | | `NETWORK_CHANGE` | Network went online/offline | | `ERROR` | Any error condition | **Log Entry Fields**: timestamp, event_type, message --- ## 10. File Structure ``` traccar_client/ ├── lib/ │ ├── main.dart │ ├── main_screen.dart │ ├── settings_screen.dart │ ├── status_screen.dart │ ├── preferences.dart │ └── bridge/ │ └── location_bridge.dart ├── android/app/src/main/ │ ├── kotlin/com/traccar/traccar_client/ │ │ ├── MainActivity.kt │ │ ├── BridgeModule.kt │ │ ├── service/ │ │ │ └── LocationTrackingService.kt │ │ ├── location/ │ │ │ ├── FusedLocationProvider.kt │ │ │ ├── DistanceFilterProcessor.kt │ │ │ └── HeartbeatScheduler.kt │ │ ├── storage/ │ │ │ ├── AppDatabase.kt │ │ │ ├── LocationDao.kt │ │ │ └── EventLogDao.kt │ │ ├── network/ │ │ │ ├── TraccarHttpClient.kt │ │ │ └── ConnectivityReceiver.kt │ │ └── model/ │ │ └── Location.kt │ └── AndroidManifest.xml ├── docs/ │ └── superpowers/ │ └── specs/ │ └── 2026-04-30-traccar-client-design.md └── pubspec.yaml ``` --- ## 11. Dependencies ### Flutter (pubspec.yaml) ```yaml dependencies: flutter: sdk: flutter shared_preferences: ^2.2.0 workmanager: ^0.5.0 sqflite: ^2.3.0 http: ^1.1.0 permission_handler: ^11.0.0 flutter_local_notifications: ^16.0.0 ``` ### Android (app/build.gradle) ```groovy implementation 'androidx.room:room-runtime:2.5.0' implementation 'com.google.android.gms:play-services-location:21.0.1' implementation 'androidx.work:work-runtime:2.8.0' implementation 'androidx.appcompat:appcompat:1.6.1' ``` --- ## 12. Android Permissions ```xml ``` --- ## 13. Verification Criteria | Test | Expected Result | |------|------------------| | Home→Office route (10km) | 20+ coordinate points captured | | Offline mode | Locations queued, synced when connection restored | | Stationary 5+ minutes | Heartbeat fires every N seconds (configurable) | | Arrival detection | Tracking stops, heartbeat continues | | App restart | Settings persist, tracking resumes | | Notification | Shows ON/OFF status, coordinates, speed, timestamp | --- ## 14. Implementation Phases 1. **Phase 1**: Project Setup - Flutter project, Android permissions, dependencies 2. **Phase 2**: Native Android Layer - Location service, Room database, HTTP client 3. **Phase 3**: Flutter UI Layer - Main screen, settings screen, status screen 4. **Phase 4**: Platform Channel Bridge - MethodChannel, EventChannel 5. **Phase 5**: Integration & Testing