# Votian LT App - Agent Guidelines ## Project Overview **Votian LT** is a Flutter-based mobile application for logistics and transport management. The app enables drivers to manage transport jobs, complete tasks (photos, signatures, barcodes), communicate via real-time chat, and navigate to pickup/delivery locations. ### Key Features - **Job Management**: View and manage assigned transport jobs with cargo items - **Task System**: Complete various task types (confirmation, photo capture, signature, barcode scanning, todo lists, comments) - **Real-time Chat**: Job-specific and general chat via WebSocket - **Offline Support**: Full offline functionality with local ObjectBox database - **Navigation**: Integration with external maps and embedded WebView routing - **Push Notifications**: Local notifications for new jobs and messages - **Implementation**: When making changes, be careful not to damage existing functionalities. --- ## Technology Stack | Layer | Technology | |-------|------------| | Framework | Flutter 3.7+ with Dart | | State Management | Singleton pattern + Custom DartMQ pub/sub | | Local Database | ObjectBox (NoSQL) | | Real-time Communication | WebSocket (STOMP-style protocol) | | Backend Integration | WebSocket to `ws://localhost:8082/ws/messaging` | | UI Design | Material Design 3 | ### Key Dependencies (pubspec.yaml) - `web_socket_channel: ^3.0.0` - WebSocket client - `objectbox: ^4.0.3` + `objectbox_flutter_libs` - Local database - `camera: ^0.10.5+9` - Photo capture - `mobile_scanner: ^5.0.0` - Barcode scanning - `signature: ^5.5.0` - Signature capture canvas - `flutter_local_notifications: ^18.0.0` - Local notifications - `url_launcher: ^6.3.0` - External navigation - `webview_flutter: ^4.8.0` - Embedded maps - `image: ^4.2.0` - Image processing - `package_info_plus: ^8.0.0` - App version info --- ## Project Structure ``` lib/ ├── main.dart # App entry point, MaterialApp setup ├── app_state.dart # Global app state singleton (jobs, login) ├── navigation_observer.dart # Route observer for analytics ├── routing_view.dart # Embedded navigation WebView │ ├── models/ # Domain models (JSON serializable) │ ├── job.dart # Transport job with cargo items and tasks │ ├── cargo_item.dart # Cargo/load items │ ├── task.dart # Abstract task base class │ ├── tasks/ # Concrete task implementations │ │ ├── confirmation_task.dart │ │ ├── photo_task.dart │ │ ├── signature_task.dart │ │ ├── barcode_task.dart │ │ ├── todolist_task.dart │ │ ├── comment_task.dart │ │ └── generic_task.dart │ ├── chat.dart # Chat conversation │ ├── chat_message.dart # Individual message │ ├── message_envelope.dart # WebSocket message wrapper │ ├── acknowledgment_message.dart │ └── queued_message.dart # Offline message queue │ ├── entities/ # ObjectBox database entities │ ├── job_entity.dart │ ├── task_status_entity.dart │ ├── user_data_entity.dart │ ├── photo_entity.dart │ ├── queued_message_entity.dart │ └── chat_message_entity.dart │ ├── services/ # Business logic services (singletons) │ ├── websocket_service.dart # WebSocket connection & messaging │ ├── database_service.dart # ObjectBox database operations │ ├── chat_service.dart # Chat management │ ├── dart_mq.dart # In-app pub/sub message bus │ ├── notification_service.dart # Local notifications │ ├── message_handler.dart # Incoming message processing │ ├── ack_tracker.dart # Message acknowledgment tracking │ └── developer.dart # Developer utilities/logging │ ├── views/ # Main UI screens │ ├── login_view.dart # Authentication screen │ ├── jobs_view.dart # Job list screen │ ├── cargo_items_view.dart # Cargo details for a job │ ├── chats_view.dart # Chat list screen │ ├── chat_details_view.dart # Individual chat conversation │ └── task_view.dart # Task completion screen │ ├── tasks/ # Task-specific UI screens │ ├── photo_capture_screen.dart │ ├── signature_capture_screen.dart │ └── barcode_capture_screen.dart │ └── widgets/ # Reusable UI components ├── chat_photo_dialog.dart └── offline_banner.dart test/ # Unit and widget tests ├── models/ │ ├── job_parsing_test.dart │ ├── message_envelope_test.dart │ └── acknowledgment_message_test.dart └── services/ ├── ack_tracker_test.dart ├── message_handler_test.dart └── mqtt_integration_test.dart android/, ios/, macos/, linux/, windows/ # Platform-specific code ``` --- ## Build, Test, and Development Commands ### Setup ```bash # Install dependencies flutter pub get # Generate ObjectBox code (after entity changes) flutter pub run build_runner build ``` ### Development ```bash # Run static analysis flutter analyze # Format code (CI expects formatted code) dart format lib/ test/ # Run the app flutter run # Run on specific device flutter run -d ``` ### Testing ```bash # Run all tests flutter test # Run with coverage flutter test --coverage # Run specific test file flutter test test/models/job_parsing_test.dart ``` --- ## Architecture Patterns ### Singleton Services All major services use the singleton pattern for app-wide state: ```dart // Accessing services final appState = AppState(); final chatService = ChatService(); final wsService = WebSocketService(); final dbService = DatabaseService(); ``` ### DartMQ Pub/Sub Custom lightweight message bus for decoupled communication: ```dart // Subscribe to topics final sub = DartMQ().subscribe>( MQTopics.authResponse, (data) => handleAuth(data), ); // Publish messages DartMQ().publish(MQTopics.connectionStatus, true); // Cleanup sub.cancel(); ``` **Common Topics** (`lib/services/dart_mq.dart`): - `connection/status` - WebSocket connection state (bool) - `auth/response` - Authentication responses (Map) - `jobs/response` - Job list updates (List) - `jobsUpdated` - Job data changed notification (void) - `job/deleted` - Job deletion event (Map) - `job/created` - New job created (Map) - `chat/incoming` - New chat message (ChatMessage) ### Task System Tasks are polymorphic based on `taskType` field: | Task Type | Description | |-----------|-------------| | `CONFIRMATION` | Button tap confirmation | | `PHOTO` | Capture photos (min/max count) | | `SIGNATURE` | Capture signature as SVG | | `BARCODE` | Scan barcodes/QR codes | | `TODOLIST` | Checklist of items | | `COMMENT` | Text input field | | `GENERIC` | Fallback type | --- ## Coding Style Guidelines ### Dart/Flutter Conventions - **Indentation**: 2 spaces - **Trailing Commas**: Use trailing commas to encourage proper auto-formatting - **Naming**: - Classes: `UpperCamelCase` - Methods/variables: `lowerCamelCase` - Private members: `_leadingUnderscore` - Constants: `camelCase` or `UPPER_SNAKE_CASE` for static const ### Code Style Examples ```dart // Good: trailing commas for multi-line final job = Job( id: '123', jobNumber: 'JOB-001', status: 'ASSIGNED', // ... ); // Good: private helper methods String _formatAddress(String street, String city) { return '$street, $city'; } // Good: type annotations for public APIs Future> loadJobs() async { // ... } ``` ### Imports - Order: Dart SDK → Flutter → Third-party → Project (alphabetical within groups) - Use `package:votianlt_app/` prefix for project imports --- ## Testing Guidelines ### Test Structure ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:votianlt_app/models/job.dart'; void main() { group('Job Parsing', () { test('parses basic fields correctly', () { // Arrange final json = {'job': {'id': '123', ...}}; // Act final job = Job.fromJson(json); // Assert expect(job.id, '123'); }); }); } ``` ### Testing Patterns - Mirror the `lib/` directory structure in `test/` - Name tests after the unit: `job_parsing_test.dart` - Use `group()` for related assertions - Test both success and edge cases - Test round-trip serialization (`fromJson` → `toJson` → `fromJson`) ### Mocking Use `mocktail` for mocking dependencies in service tests. --- ## Database (ObjectBox) ### Entity Definition Example ```dart @Entity() class JobEntity { @Id() int id = 0; @Unique() String jobId; String jobData; // JSON-encoded @Property(type: PropertyType.date) DateTime createdAt; @Property(type: PropertyType.date) DateTime updatedAt; JobEntity({...}); } ``` ### Regenerating Code After modifying entities in `lib/entities/`: ```bash flutter pub run build_runner build ``` This generates `lib/objectbox.g.dart`. --- ## WebSocket Protocol ### Connection - URL: `ws://localhost:8082/ws/messaging` (desktop) - Android Emulator: `ws://10.0.2.2:8082/ws/messaging` ### Message Format ```json { "topic": "/client/auth", "payload": { ... } } ``` ### Client → Server Topics - `/server/login` - Authentication - `/server/jobs/assigned` - Request job list - `/server/message` - Send chat message - `/server/task_completed` - Mark task complete ### Server → Client Topics - `/client/{userId}/auth` - Auth response - `/client/{userId}/jobs` - Job list - `/client/{userId}/message` - Incoming chat - `/client/{userId}/job_deleted` - Job deleted - `/client/{userId}/job_created` - New job --- ## Security Considerations ### Credentials - Email/password stored in ObjectBox (encrypted at rest by OS) - Credentials cleared on logout - Auto-login with saved credentials ### WebSocket - Reconnection with 15-second interval - Message buffering when offline - Unique App ID per installation for client identification ### Secrets - Do not commit API keys or credentials - Server endpoint configurable in `WebSocketService._buildWebSocketUrl()` --- ## Platform-Specific Notes ### Android - Minimum SDK: Defined in `android/app/build.gradle` - Permissions in `AndroidManifest.xml`: - `INTERNET` - WebSocket communication - `CAMERA` - Photo/barcode capture - `WRITE_EXTERNAL_STORAGE` - Photo storage - `POST_NOTIFICATIONS` - Push notifications - `VIBRATE` - Notification vibration ### iOS - Camera and photo permissions in `ios/Runner/Info.plist` - Notification permissions configured --- ## Common Development Tasks ### Adding a New Task Type 1. Create model in `lib/models/tasks/new_task_type.dart` 2. Add to `Task.fromJson()` factory in `lib/models/task.dart` 3. Add UI screen in `lib/tasks/` if needed 4. Update `task_view.dart` to handle the new type 5. Add tests in `test/models/` ### Adding a New Database Entity 1. Create entity class in `lib/entities/` 2. Run `flutter pub run build_runner build` 3. Add CRUD operations in `DatabaseService` ### Modifying WebSocket Messages 1. Update message handler in `WebSocketService._handleMessage()` 2. Add topic constant to `MQTopics` if needed 3. Update `MessageHandler` for processing logic --- ## Localization The app uses German for UI text: - Job status: "Erstellt", "Zugewiesen", "In Bearbeitung", "Abgeschlossen" - Notifications: "Neue Jobs", "Neue Nachricht" - Chat: "Allgemeine Nachrichten" --- ## Debugging ### Logging Use the developer log utility: ```dart import 'package:votianlt_app/services/developer.dart' as developer; developer.log('Debug message', name: 'ComponentName'); ``` ### Common Issues 1. **WebSocket not connecting**: Check server is running on port 8082 2. **Database errors**: Run `flutter clean` and `flutter pub get` 3. **ObjectBox issues**: Regenerate with `build_runner` 4. **Camera not working**: Check platform permissions