15 KiB
Stadtbote - Project Documentation for AI Agents
Project Overview
Stadtbote is a Flutter-based mobile application for courier and delivery services. The app is designed for drivers to manage delivery jobs, track their location, communicate with dispatchers, and handle delivery confirmations including signatures and photos.
The application is primarily in German and targets the German logistics market ("Stadtbote" translates to "City Messenger").
Key Features
- Real-time job assignment and management (assigned, accepted, finished states)
- GPS location tracking and transmission to backend
- Interactive maps for navigation and job visualization
- Chat/messaging system with dispatchers
- Digital signature capture for delivery confirmation
- Photo capture for delivery documentation
- PDF document viewing
- Audio notifications for new jobs and messages
Technology Stack
Core Framework
- Flutter 3.x (Dart SDK >=3.9.0 <4.0.0)
- Dart programming language
State Management & Data Persistence
- ObjectBox (v4.0.3) - Local NoSQL database for offline data persistence
- SharedPreferences - For user preferences and app settings
- dart_mq - Internal message bus for component communication
- shared_map - Thread-safe shared memory for job state management
Network & Communication
- mqtt5_client (v4.4.0) - MQTT protocol for real-time server communication
- http (v1.3.0) - HTTP client for bootstrap and REST API calls
- GZip compression - All MQTT payloads are compressed
Location & Maps
- geolocator (v13.0.2) - GPS location services
- flutter_map (v8.1.0) - OpenStreetMap integration
- flutter_osm_plugin (v1.3.6) - Alternative OSM plugin
- latlong2 (v0.9.1) - Geographic coordinate calculations
UI Components
- flutter_chat_ui (v1.6.10) - Chat interface
- flutter_chat_types (v3.6.2) - Chat message types
- carousel_slider (v5.0.0) - Image carousels
- signature (v6.0.0) - Digital signature capture
- expandable (v5.0.1) - Collapsible UI sections
- badges (v3.1.1) - Notification badges
- animated_toggle_switch (v0.8.4) - Toggle switches
Media & Files
- image_picker (v1.1.2) - Camera integration for photos
- audioplayers (v6.2.0) - Audio notifications
- pdfrx (v2.2.20) - PDF document viewer
- image (v4.2.0) - Image processing
- archive (v4.0.3) - File compression utilities
- path_provider (v2.1.2) - File system access
Utilities
- uuid (v4.5.1) - Unique identifier generation
- mime (v2.0.0) - MIME type handling
- intl (v0.20.2) - Internationalization
- synchronized (v3.1.0) - Thread synchronization
- permission_handler (v11.4.0) - Runtime permission management
- url_launcher (v6.2.4) - External URL handling
- device_info_plus (v11.3.2) - Device information
- package_info_plus (v8.0.2) - App version information
Code Generation
- build_runner (v2.4.13) - Code generation runner
- json_serializable (v6.6.2) - JSON serialization code generation
- objectbox_generator (v4.0.3) - ObjectBox model generation
Project Structure
lib/
├── main.dart # Application entry point
├── objectbox.g.dart # Generated ObjectBox code (DO NOT EDIT)
│
├── content_views/ # Main UI pages/screens
│ ├── main_page.dart # Main dashboard with menu buttons
│ ├── assigned_jobs_page.dart # List of assigned/pending jobs
│ ├── accepted_jobs_page.dart # List of accepted jobs
│ ├── finished_jobs_page.dart # Job history
│ ├── messages_page.dart # Chat/messaging interface
│ ├── tour_details_page.dart # Tour/job detail view
│ ├── tour_list_page.dart # List of tours
│ ├── task_list_page.dart # Individual tasks within tours
│ ├── approach_area_page.dart # Map showing approach area
│ ├── set_desired_zip_page.dart # Set preferred postal code
│ ├── pdf_viewer_page.dart # PDF document viewer
│ └── utils/ # Content view utilities
│ ├── content_view_widget.dart # Base class for content views
│ └── widget_stack.dart # Navigation stack management
│
├── model/ # Data models (ObjectBox entities)
│ ├── job.dart # Delivery job entity
│ ├── job_tour.dart # Tour within a job
│ ├── tour_task.dart # Individual task in a tour
│ ├── tour_position.dart # Geographic position
│ ├── task_info.dart # Task information
│ ├── session_status.dart # Current session/user status
│ ├── status.dart # General status
│ ├── location_status.dart # Location/zip code status
│ ├── chat_message.dart # Chat message entity
│ ├── rank.dart # User ranking
│ ├── log_entry.dart # App log entries
│ ├── pictures.dart # Photo attachments
│ └── enqueued_message.dart # Pending MQTT messages
│
├── network_messages/ # JSON DTOs for network communication
│ ├── *.dart # Message classes
│ └── *.g.dart # Generated serialization code
│
├── popups/ # Dialog and popup widgets
│ ├── accept_jobs_popup.dart
│ ├── infos_popup.dart
│ ├── map_popup.dart
│ └── tasks_popups/ # Task-specific popups
│ ├── arrived_popup.dart
│ ├── signature_popup.dart
│ ├── take_photos_popup.dart
│ └── ...
│
├── tools/ # Core utilities and services
│ ├── constants.dart # App constants, message topics
│ ├── util.dart # Utility functions
│ ├── mqtt_core.dart # MQTT client implementation
│ ├── connection_status.dart # Connection state management
│ ├── page_base.dart # Base page class
│ ├── colored_safe_area.dart # UI component
│ ├── pdf_service.dart # PDF handling
│ ├── extended_stateful_builder.dart
│ ├── message_header.dart # Message envelope structure
│ └── messages/ # Internal message classes
│ ├── bwv_message.dart
│ ├── connect_client_message.dart
│ ├── job_received_message.dart
│ └── ...
│
└── messages/ # App-level message definitions
└── pop_content_view_message.dart
assets/ # Static resources
├── *.png # Icons and images
├── sounds/ # Audio files (MP3)
│ ├── aaa.mp3
│ ├── asbeep.mp3
│ └── job_received.mp3
└── json/ # Static JSON files
└── bootstrap_response.json
Architecture Overview
Message-Driven Architecture
The application uses a message-driven architecture with dart_mq as the internal message bus for decoupled component communication:
- Components subscribe to named message queues (topics)
- Messages are strongly typed and passed between UI, services, and data layers
- Key message topics are defined in
lib/tools/constants.dart
Data Flow
MQTT Server <-> MqttCore (mqtt_core.dart) <-> Message Bus <-> UI Components
|
v
ObjectBox Database
|
v
SharedPreferences
Key Components
-
MqttCore (
lib/tools/mqtt_core.dart)- Manages MQTT connection to backend (bootstrap.assecutor.de)
- Handles message encoding/decoding with GZip compression
- Implements automatic reconnection with exponential backoff
- Manages message queueing for offline scenarios
- Sends GPS tracking data every 120 seconds
-
Main App Structure (
lib/main.dart)- Initializes ObjectBox store
- Sets up location tracking service
- Configures message queues
- Manages navigation stack with custom
WidgetStack
-
Content Views (
lib/content_views/)- All pages extend
ContentViewWidget - Each view provides a custom header via
getHeaderWidget() - Navigation uses push/pop/replace operations via message bus
- All pages extend
-
Models (
lib/model/)- All entities use ObjectBox annotations (
@Entity,@Id, etc.) - Models support JSON serialization for network communication
externalIdfield used for server-side IDs, separate from ObjectBoxid
- All entities use ObjectBox annotations (
Build Commands
Development
# Get dependencies
flutter pub get
# Run code generation (required after model changes)
dart run build_runner build
# Run in debug mode
flutter run
# Run on specific device
flutter run -d <device_id>
Build for Production
# Android APK
flutter build apk
# Android App Bundle
flutter build appbundle
# iOS
flutter build ios
# Web
flutter build web
Code Generation
The project uses build_runner for code generation. Run this after modifying:
- ObjectBox entity classes (generates
objectbox.g.dart) - JSON serializable network message classes (generates
*.g.dartfiles)
dart run build_runner build
Code Style Guidelines
Linting
- Uses
flutter_lintsv5.0.0 (included viaanalysis_options.yaml) - Standard Flutter linting rules apply
- Specific lints can be disabled in
analysis_options.yaml
Naming Conventions
- Files: lowercase_with_underscores.dart
- Classes: PascalCase
- Methods/Variables: camelCase
- Constants: camelCase for local, no strict convention for global
- Private members: prefix with underscore
_
Import Style
- Use package imports for project files:
package:stadtbote/... - Group imports: Flutter/Dart core, third-party, project files
Comments
- Code comments are primarily in German
- Use
//for single-line comments - Use
/* */for multi-line comments
State Management Patterns
Job States
Jobs progress through three main states (defined in constants.dart):
stateAssigned = 0- Job assigned but not yet acceptedstateAccepted = 1- Job accepted by driverstateFinished = 2- Job completedstateFinishedNotConfirmed = 9- Finished but pending confirmation
Connection States
notConnected- Disconnected from MQTT brokerconnected- Connected and ready
Location Tracking
- Continuous GPS tracking when app is active
- Location sent every 120 seconds via MQTT
- Stored thread-safely using
Lockfrom synchronized package
Testing
Note: The project currently has no automated tests. When adding tests:
# Run tests
flutter test
Recommended test structure (to be created):
test/
├── model/ # Model unit tests
├── network_messages/ # Serialization tests
├── tools/ # Utility tests
└── widget/ # Widget tests
Security Considerations
Network Security
- MQTT connection uses authentication (username/password)
- Will message configured for connection loss detection
- All payloads are GZip compressed and UTF-8 encoded
- Bootstrap endpoint:
https://bootstrap.assecutor.de
Data Storage
- ObjectBox database is local to device
- SharedPreferences used for non-sensitive settings only
- No sensitive data encryption currently implemented
Permissions
The app requires these permissions:
- Location (GPS) - Continuous tracking during deliveries
- Camera - Photo capture for delivery confirmation
- Storage - Saving photos and PDFs
- Internet - MQTT and HTTP communication
Device Identification
- Each device generates a UUID stored in SharedPreferences
- Device info (manufacturer, model, OS version) sent during bootstrap
Deployment
Android
- Application ID:
de.assecutor.stadtbote - Min SDK: 28 (Android 9.0)
- Target/Compile SDK: 34-35
- Signing configured via
key.propertiesfile (not in repo) - ProGuard disabled for release builds
iOS
- Bundle identifier configured in Xcode project
- Location background mode required
- Camera permission required
Version Management
- Version defined in
pubspec.yaml(currently 347.0.0+347) - Build number increments with each release
- Version display uses
package_info_plus
Backend Integration
Bootstrap Process
- App sends device info to
https://bootstrap.assecutor.de/bootstrap - Server responds with MQTT broker details and topics
- App connects to MQTT broker with credentials
- Session initialized with
start_sessionmessage
MQTT Topics
Topics are dynamically assigned during bootstrap:
fromServerTopic- Server-to-client messagestoServerTopic- Client-to-server messages
Message Types
Server handles these message types:
session- Session initialization/updatesstatus- Status updatesranking- Driver rankingsjob- Job assignmentsjob_del- Job deletionssync_request- Data synchronizationlocation_status- Location-based statusmssg- Chat messagestrack- GPS tracking datalogout- User logout
Common Development Tasks
Adding a New Model
- Create class in
lib/model/with@Entity()annotation - Add
@Id()field for ObjectBox ID - Add fields with appropriate types
- Implement
fromJson()andtoJson()methods - Run
dart run build_runner build - Import model in
lib/objectbox.g.dartimports (auto-generated)
Adding a New Page
- Create file in
lib/content_views/ - Extend
ContentViewWidget - Implement
getHeaderWidget()method - Add navigation message in appropriate place
- Add page to message subscription if needed
Adding MQTT Message Types
- Create class in
lib/network_messages/ - Add
part 'filename.g.dart';directive - Use
@JsonSerializable()annotation - Run code generation
- Add handling in
MqttCore._setupMqtt()switch statement
Troubleshooting
Common Issues
Build fails with ObjectBox errors:
- Run
dart run build_runner buildto regenerate models
MQTT connection issues:
- Check bootstrap endpoint availability
- Verify device has internet connection
- Check that UUID is generated (first app launch)
Location not updating:
- Verify location permissions granted
- Check that location services are enabled on device
Missing generated files:
- Run
flutter pub getthendart run build_runner build
Language Notes
The application interface and all user-facing text is in German. When making changes:
- Keep UI text in German
- Keep code comments in German (following existing pattern)
- Internal identifiers (class names, variables) use English
- User-facing strings use German
Example German terms used in UI:
- "Zugewiesene Aufträge" - Assigned Jobs
- "Angenommene Aufträge" - Accepted Jobs
- "Erledigte Aufträge" - Finished Jobs
- "Abmelden" - Logout
- "Zurück" - Back