430 lines
12 KiB
Markdown
430 lines
12 KiB
Markdown
# 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 <device_id>
|
|
```
|
|
|
|
### 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<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
|
|
```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<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
|
|
```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
|