Files
votianlt/app/AGENTS.md

12 KiB

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

# Install dependencies
flutter pub get

# Generate ObjectBox code (after entity changes)
flutter pub run build_runner build

Development

# 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 <device_id>

Testing

# 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:

// Accessing services
final appState = AppState();
final chatService = ChatService();
final wsService = WebSocketService();
final dbService = DatabaseService();

DartMQ Pub/Sub

Custom lightweight message bus for decoupled communication:

// Subscribe to topics
final sub = DartMQ().subscribe<Map<String, dynamic>>(
  MQTopics.authResponse,
  (data) => handleAuth(data),
);

// Publish messages
DartMQ().publish<bool>(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

// 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<List<Job>> 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

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 (fromJsontoJsonfromJson)

Mocking

Use mocktail for mocking dependencies in service tests.


Database (ObjectBox)

Entity Definition Example

@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/:

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

{
  "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:

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