12 KiB
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 clientobjectbox: ^4.0.3+objectbox_flutter_libs- Local databasecamera: ^0.10.5+9- Photo capturemobile_scanner: ^5.0.0- Barcode scanningsignature: ^5.5.0- Signature capture canvasflutter_local_notifications: ^18.0.0- Local notificationsurl_launcher: ^6.3.0- External navigationwebview_flutter: ^4.8.0- Embedded mapsimage: ^4.2.0- Image processingpackage_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:
camelCaseorUPPER_SNAKE_CASEfor static const
- Classes:
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 intest/ - 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
@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 communicationCAMERA- Photo/barcode captureWRITE_EXTERNAL_STORAGE- Photo storagePOST_NOTIFICATIONS- Push notificationsVIBRATE- Notification vibration
iOS
- Camera and photo permissions in
ios/Runner/Info.plist - Notification permissions configured
Common Development Tasks
Adding a New Task Type
- Create model in
lib/models/tasks/new_task_type.dart - Add to
Task.fromJson()factory inlib/models/task.dart - Add UI screen in
lib/tasks/if needed - Update
task_view.dartto handle the new type - Add tests in
test/models/
Adding a New Database Entity
- Create entity class in
lib/entities/ - Run
flutter pub run build_runner build - Add CRUD operations in
DatabaseService
Modifying WebSocket Messages
- Update message handler in
WebSocketService._handleMessage() - Add topic constant to
MQTopicsif needed - Update
MessageHandlerfor 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
- WebSocket not connecting: Check server is running on port 8082
- Database errors: Run
flutter cleanandflutter pub get - ObjectBox issues: Regenerate with
build_runner - Camera not working: Check platform permissions